Made golint happy

This commit is contained in:
Will Angenent 2018-05-28 17:31:52 +01:00
parent 01adea08ba
commit ca7f2d2e04
16 changed files with 370 additions and 315 deletions

View File

@ -82,4 +82,14 @@ Assemble the tests
* 80 column card
* 48k aux memory
* double hires
* joystick
* joystick
## Coding standards
Use `gofmt` to ensure standard go style consistency
go fmt $(go list ./... | grep -v /vendor/)
Use `golint` to ensure Google's style consistency
golint $(go list ./...)

View File

@ -65,7 +65,7 @@ func update(screen *ebiten.Image) error {
exitAtBreak := true // Die if a BRK instruction is seen
// Run for 1/60 of a second, the duration of an ebiten frame
cpu.Run(*showInstructions, breakAddress, exitAtBreak, *disableFirmwareWait, system.CpuFrequency/60)
cpu.Run(*showInstructions, breakAddress, exitAtBreak, *disableFirmwareWait, system.CPUFrequency/60)
// Process any audio speaker clicks from this frame
audio.ForwardToFrameCycle()

View File

@ -18,10 +18,11 @@ func Click() {
func attenuate(sample int16) int16 {
if system.AudioAttenuationCounter == 0 {
return 0
} else {
system.AudioAttenuationCounter--
return sample
}
system.AudioAttenuationCounter--
return sample
}
// ForwardToFrameCycle calculates how many audio samples need to be written to
@ -29,7 +30,7 @@ func attenuate(sample int16) int16 {
// flush and shove them into the channel.
func ForwardToFrameCycle() {
// 1023000/44100=23.19 cycles per audio sample
cyclesPerAudioSample := system.CpuFrequency / float64(system.AudioSampleRate)
cyclesPerAudioSample := system.CPUFrequency / float64(system.AudioSampleRate)
// Should be about 1023000/60=17050
elapsedCycles := system.FrameCycles - system.LastAudioCycles

View File

@ -10,11 +10,17 @@ import (
)
var (
audioContext *ebiten_audio.Context // Ebitem audio context
player *ebiten_audio.Player // Ebitem stream player
firstAudio bool // True at startup
Mute bool // Mute
ClickWhenDriveHeadMoves bool // Click speaker when the drive head moves
audioContext *ebiten_audio.Context // Ebitem audio context
player *ebiten_audio.Player // Ebitem stream player
firstAudio bool // True at startup
)
var (
// Mute ensures no samples are output
Mute bool
// ClickWhenDriveHeadMoves makes the speaker click once every time the stepper motor magnets change
ClickWhenDriveHeadMoves bool
)
// The streaming code is based on the ebiten sinewave example

View File

@ -11,9 +11,9 @@ import (
"github.com/stretchr/testify/assert"
)
func assertMemoryConfiguration(t *testing.T, address uint16, upperRamReadOnly bool, upperReadMappedToROM bool, d000Bank int) {
func assertMemoryConfiguration(t *testing.T, address uint16, upperRAMReadOnly bool, upperReadMappedToROM bool, d000Bank int) {
mmu.WriteMemory(address, 0x00)
assert.Equal(t, upperRamReadOnly, mmu.UpperRamReadOnly)
assert.Equal(t, upperRAMReadOnly, mmu.UpperRAMReadOnly)
assert.Equal(t, upperReadMappedToROM, mmu.UpperReadMappedToROM)
assert.Equal(t, d000Bank, mmu.D000Bank)
}
@ -67,7 +67,7 @@ func TestBankSwitching(t *testing.T) {
// Set d000 RAM to bank 1, RAM to read only and attempt writes
mmu.SetD000Bank(1)
mmu.SetUpperRamReadOnly(true)
mmu.SetUpperRAMReadOnly(true)
assert.Equal(t, uint8(0xfd), mmu.PhysicalMemory.MainMemory[0xc000]) // bank #1 RAM
assert.Equal(t, uint8(0xfe), mmu.PhysicalMemory.MainMemory[0xd000]) // bank #2 RAM
mmu.WriteMemory(0xd000, 0x01) // attempt to write to read only RAM
@ -77,7 +77,7 @@ func TestBankSwitching(t *testing.T) {
assert.Equal(t, uint8(0xff), mmu.PhysicalMemory.MainMemory[0xffff]) // top of RAM is unchanged
// Set RAM to write and write to it
mmu.SetUpperRamReadOnly(false)
mmu.SetUpperRAMReadOnly(false)
mmu.WriteMemory(0xd000, 0xfc) // write to RAM
mmu.WriteMemory(0xffff, 0xfb) // write to RAM
assert.Equal(t, uint8(0xfc), mmu.PhysicalMemory.MainMemory[0xc000]) // bank #1 RAM has been updated

View File

@ -24,7 +24,7 @@ func testBellCycles(delay int) {
exitAtBreak := false
disableFirmwareWait := false
cpu.State.PC = 0x800
cpu.Run(showInstructions, &breakAddress, exitAtBreak, disableFirmwareWait, system.CpuFrequency*1000)
cpu.Run(showInstructions, &breakAddress, exitAtBreak, disableFirmwareWait, system.CPUFrequency*1000)
// See http://apple2.org.za/gswv/a2zine/GS.WorldView/Resources/USEFUL.TABLES/WAIT.DELAY.CR.txt
expectedCycles := (26 + 27*delay + 5*delay*delay) / 2

View File

@ -9,16 +9,17 @@ import (
)
const (
CpuFlagC byte = 1 << iota // 0x01 carry
CpuFlagZ // 0x02 zero
CpuFlagI // 0x04 interrupt disable
CpuFlagD // 0x08 decimal mode
CpuFlagB // 0x10 break
CpuFlagR // 0x20 reserved (unused)
CpuFlagV // 0x40 overflow
CpuFlagN // 0x80 sign/negative
cpuFlagC byte = 1 << iota // 0x01 carry
cpuFlagZ // 0x02 zero
cpuFlagI // 0x04 interrupt disable
cpuFlagD // 0x08 decimal mode
cpuFlagB // 0x10 break
cpuFlagR // 0x20 reserved (unused)
cpuFlagV // 0x40 overflow
cpuFlagN // 0x80 sign/negative
)
// State contains the CPU state
var State struct {
A uint8 // accumulator
X uint8 // X register
@ -40,70 +41,70 @@ func Init() {
State.A = 0
State.X = 0
State.Y = 0
State.P = CpuFlagR | CpuFlagB | CpuFlagZ
State.P = cpuFlagR | cpuFlagB | cpuFlagZ
State.SP = 0xff
}
// setC sets the carry flag
func setC(value bool) {
if value {
State.P |= CpuFlagC
State.P |= cpuFlagC
} else {
State.P &= ^CpuFlagC
State.P &= ^cpuFlagC
}
}
// setV sets the overflow flag
func setV(value bool) {
if value {
State.P |= CpuFlagV
State.P |= cpuFlagV
} else {
State.P &= ^CpuFlagV
State.P &= ^cpuFlagV
}
}
// setN sets the sign/negative flag if the value is negative (>=0x80)
func setN(value uint8) {
if (value & 0x80) != 0 {
State.P |= CpuFlagN
State.P |= cpuFlagN
} else {
State.P &= ^CpuFlagN
State.P &= ^cpuFlagN
}
}
// setZ sets the zero flag if the value is zero
func setZ(value uint8) {
if value == 0 {
State.P |= CpuFlagZ
State.P |= cpuFlagZ
} else {
State.P &= ^CpuFlagZ
State.P &= ^cpuFlagZ
}
}
func isC() bool {
return (State.P & CpuFlagC) != 0
return (State.P & cpuFlagC) != 0
}
func isZ() bool {
return (State.P & CpuFlagZ) != 0
return (State.P & cpuFlagZ) != 0
}
func isD() bool {
return (State.P & CpuFlagD) != 0
return (State.P & cpuFlagD) != 0
}
func isV() bool {
return (State.P & CpuFlagV) != 0
return (State.P & cpuFlagV) != 0
}
func isN() bool {
return (State.P & CpuFlagN) != 0
return (State.P & cpuFlagN) != 0
}
// push8 pushes an 8 bit value to the stack
func push8(value uint8) {
mmu.WritePageTable[mmu.StackPage][State.SP] = value
State.SP -= 1
State.SP--
State.SP &= 0xff
}
@ -117,7 +118,7 @@ func push16(value uint16) {
// pop8 pulls an 8 bit value from the stack
func pop8() uint8 {
State.SP += 1
State.SP++
State.SP &= 0xff
return mmu.ReadPageTable[mmu.StackPage][State.SP]
}
@ -153,7 +154,7 @@ func branch(doBranch bool) {
// The number of cycles depends on if a page boundary was crossed
samePage := (State.PC & 0xff00) == (relativeAddress & 0xff00)
if samePage {
system.FrameCycles += 1
system.FrameCycles++
} else {
system.FrameCycles += 2
}
@ -479,7 +480,7 @@ func postProcessShift(addressMode byte, address uint16, value uint8) {
switch addressMode {
case amAccumulator:
State.A = value
State.PC += 1
State.PC++
system.FrameCycles += 2
case amZeroPage:
mmu.WriteMemory(address, value)
@ -523,27 +524,27 @@ func postProcessIncDec(addressMode byte) {
func brk() {
push16(State.PC + 2)
State.P |= CpuFlagB
State.P |= cpuFlagB
push8(State.P)
State.P |= CpuFlagI
State.P |= cpuFlagI
State.PC = uint16(mmu.ReadMemory(0xffff))<<8 + uint16(mmu.ReadMemory(0xfffe))
system.FrameCycles += 7
}
func irq() {
push16(State.PC)
State.P &= ^CpuFlagB
State.P &= ^cpuFlagB
push8(State.P)
State.P |= CpuFlagI
State.P |= cpuFlagI
State.PC = uint16(mmu.ReadMemory(0xffff))<<8 + uint16(mmu.ReadMemory(0xfffe))
system.FrameCycles += 7
}
func nmi() {
push16(State.PC)
State.P &= ^CpuFlagB
State.P &= ^cpuFlagB
push8(State.P)
State.P |= CpuFlagI
State.P |= cpuFlagI
State.PC = uint16(mmu.ReadMemory(0xfffb))<<8 + uint16(mmu.ReadMemory(0xfffa))
system.FrameCycles += 7
}
@ -572,7 +573,7 @@ func Run(showInstructions bool, breakAddress *uint16, exitAtBreak bool, disableF
}
// Handle an IRQ f there is one pending and interrupts are enabled
if system.PendingInterrupt && ((State.P & CpuFlagI) == 0) {
if system.PendingInterrupt && ((State.P & cpuFlagI) == 0) {
irq()
system.PendingInterrupt = false
continue
@ -761,23 +762,23 @@ func Run(showInstructions bool, breakAddress *uint16, exitAtBreak bool, disableF
State.PC++
system.FrameCycles += 2
case 0x58: // CLI
State.P &= ^CpuFlagI
State.P &= ^cpuFlagI
State.PC++
system.FrameCycles += 2
case 0x78: // SEI
State.P |= CpuFlagI
State.P |= cpuFlagI
State.PC++
system.FrameCycles += 2
case 0xb8: // CLV
State.P &= ^CpuFlagV
State.P &= ^cpuFlagV
State.PC++
system.FrameCycles += 2
case 0xd8: // CLD
State.P &= ^CpuFlagD
State.P &= ^cpuFlagD
State.PC++
system.FrameCycles += 2
case 0xf8: //SED
State.P |= CpuFlagD
State.P |= cpuFlagD
State.PC++
system.FrameCycles += 2
@ -795,12 +796,12 @@ func Run(showInstructions bool, breakAddress *uint16, exitAtBreak bool, disableF
case 0x08: // PHP
// From http://visual6502.org/wiki/index.php?title=6502_BRK_and_B_bit#the_B_flag_and_the_various_mechanisms
// software instructions BRK & PHP will push the B flag as being 1.
push8(State.P | CpuFlagB)
push8(State.P | cpuFlagB)
State.PC++
system.FrameCycles += 3
case 0x28: // PLP
// CpuFlagR is always supposed to be 1
State.P = pop8() | CpuFlagR
// cpuFlagR is always supposed to be 1
State.P = pop8() | cpuFlagR
State.PC++
system.FrameCycles += 4
case 0xea:
@ -810,7 +811,7 @@ func Run(showInstructions bool, breakAddress *uint16, exitAtBreak bool, disableF
case 0x00: // BRK
brk()
case 0x40: // RTI
State.P = pop8() | CpuFlagR
State.P = pop8() | cpuFlagR
value := pop16()
State.PC = value
system.FrameCycles += 6
@ -845,7 +846,7 @@ func Run(showInstructions bool, breakAddress *uint16, exitAtBreak bool, disableF
address, value := preProcessShift(addressMode)
value16 := uint16(value)
value16 <<= 1
if (State.P & CpuFlagC) != 0 {
if (State.P & cpuFlagC) != 0 {
value16 |= 0x01
}
setC((value16 & 0x100) != 0)
@ -856,7 +857,7 @@ func Run(showInstructions bool, breakAddress *uint16, exitAtBreak bool, disableF
case 0x6a, 0x66, 0x76, 0x6e, 0x7e: // ROR
address, value := preProcessShift(addressMode)
value16 := uint16(value)
if (State.P & CpuFlagC) != 0 {
if (State.P & cpuFlagC) != 0 {
value16 |= 0x100
}
setC((value16 & 0x01) != 0)

View File

@ -29,14 +29,14 @@ func printInstruction(instruction string, showRegisters bool) {
State.P,
)
printFlag(State.P, CpuFlagN, "n")
printFlag(State.P, CpuFlagV, "v")
fmt.Print("-") // CpuFlagR flag that's always 1
printFlag(State.P, CpuFlagB, "b")
printFlag(State.P, CpuFlagD, "d")
printFlag(State.P, CpuFlagI, "i")
printFlag(State.P, CpuFlagZ, "z")
printFlag(State.P, CpuFlagC, "c")
printFlag(State.P, cpuFlagN, "n")
printFlag(State.P, cpuFlagV, "v")
fmt.Print("-") // cpuFlagR flag that's always 1
printFlag(State.P, cpuFlagB, "b")
printFlag(State.P, cpuFlagD, "d")
printFlag(State.P, cpuFlagI, "i")
printFlag(State.P, cpuFlagZ, "z")
printFlag(State.P, cpuFlagC, "c")
}
fmt.Println("")

View File

@ -311,6 +311,7 @@ func initOpCodes() {
opCodes[0xFF] = opCode{mnemonic: "???", addressingMode: addressingModes[amExpansion]}
}
// InitInstructionDecoder initializes tables used for the instruction decoding
func InitInstructionDecoder() {
initAddressingModes()
initOpCodes()

View File

@ -123,7 +123,7 @@ func InitDiskImage() {
resetsectorWriteState()
}
// InitDiskImage reads a disk image from file
// ReadDiskImage reads a disk image from file
func ReadDiskImage(path string) {
imagePath = path
@ -329,7 +329,7 @@ func decodeAddressField(data []uint8) addressField {
return af
}
// Read a byte from the disk head and spin the disk along
// ReadTrackData reads a byte from the disk head and spins the disk along
func ReadTrackData() (result uint8) {
result = trackData[system.DriveState.BytePosition]
@ -377,7 +377,7 @@ func WriteTrackData(value uint8) {
}
sectorWriteState.RawData[sectorWriteState.RawDataPosition] = value
sectorWriteState.RawDataPosition += 1
sectorWriteState.RawDataPosition++
// Check for address prologue
if sectorWriteState.RawDataPosition > 2 && sectorWriteState.RawData[sectorWriteState.RawDataPosition-3] == 0xd5 &&
@ -393,7 +393,7 @@ func WriteTrackData(value uint8) {
} else if sectorWriteState.State == receivingData {
sectorWriteState.RawData[sectorWriteState.RawDataPosition] = value
sectorWriteState.RawDataPosition += 1
sectorWriteState.RawDataPosition++
if sectorWriteState.RawDataPosition == 0x56+0x100 {
// We have the full sector data

View File

@ -4,7 +4,7 @@ import (
"github.com/hajimehoshi/ebiten"
)
var ebitenAsciiMap map[ebiten.Key]uint8 // ebiten keys mapped to ASCII
var ebitenASCIIMap map[ebiten.Key]uint8 // ebiten keys mapped to ASCII
var shiftMap map[uint8]uint8 // ebiten keys mapped to ASCII when shift is pressed
var controlMap map[uint8]uint8 // ebiten keys mapped to ASCII when control is pressed
@ -19,68 +19,68 @@ func Init() {
strobe = 0
capsLock = true
ebitenAsciiMap = make(map[ebiten.Key]uint8)
ebitenASCIIMap = make(map[ebiten.Key]uint8)
shiftMap = make(map[uint8]uint8)
controlMap = make(map[uint8]uint8)
previousKeysPressed = make(map[uint8]bool)
ebitenAsciiMap[ebiten.KeyLeft] = 8
ebitenAsciiMap[ebiten.KeyTab] = 9
ebitenAsciiMap[ebiten.KeyDown] = 10
ebitenAsciiMap[ebiten.KeyUp] = 11
ebitenAsciiMap[ebiten.KeyEnter] = 13
ebitenAsciiMap[ebiten.KeyRight] = 21
ebitenAsciiMap[ebiten.KeyEscape] = 27
ebitenAsciiMap[ebiten.KeyDelete] = 127
ebitenASCIIMap[ebiten.KeyLeft] = 8
ebitenASCIIMap[ebiten.KeyTab] = 9
ebitenASCIIMap[ebiten.KeyDown] = 10
ebitenASCIIMap[ebiten.KeyUp] = 11
ebitenASCIIMap[ebiten.KeyEnter] = 13
ebitenASCIIMap[ebiten.KeyRight] = 21
ebitenASCIIMap[ebiten.KeyEscape] = 27
ebitenASCIIMap[ebiten.KeyDelete] = 127
ebitenAsciiMap[ebiten.Key0] = '0'
ebitenAsciiMap[ebiten.Key1] = '1'
ebitenAsciiMap[ebiten.Key2] = '2'
ebitenAsciiMap[ebiten.Key3] = '3'
ebitenAsciiMap[ebiten.Key4] = '4'
ebitenAsciiMap[ebiten.Key5] = '5'
ebitenAsciiMap[ebiten.Key6] = '6'
ebitenAsciiMap[ebiten.Key7] = '7'
ebitenAsciiMap[ebiten.Key8] = '8'
ebitenAsciiMap[ebiten.Key9] = '9'
ebitenAsciiMap[ebiten.KeyA] = 'a'
ebitenAsciiMap[ebiten.KeyB] = 'b'
ebitenAsciiMap[ebiten.KeyC] = 'c'
ebitenAsciiMap[ebiten.KeyD] = 'd'
ebitenAsciiMap[ebiten.KeyE] = 'e'
ebitenAsciiMap[ebiten.KeyF] = 'f'
ebitenAsciiMap[ebiten.KeyG] = 'g'
ebitenAsciiMap[ebiten.KeyH] = 'h'
ebitenAsciiMap[ebiten.KeyI] = 'i'
ebitenAsciiMap[ebiten.KeyJ] = 'j'
ebitenAsciiMap[ebiten.KeyK] = 'k'
ebitenAsciiMap[ebiten.KeyL] = 'l'
ebitenAsciiMap[ebiten.KeyM] = 'm'
ebitenAsciiMap[ebiten.KeyN] = 'n'
ebitenAsciiMap[ebiten.KeyO] = 'o'
ebitenAsciiMap[ebiten.KeyP] = 'p'
ebitenAsciiMap[ebiten.KeyQ] = 'q'
ebitenAsciiMap[ebiten.KeyR] = 'r'
ebitenAsciiMap[ebiten.KeyS] = 's'
ebitenAsciiMap[ebiten.KeyT] = 't'
ebitenAsciiMap[ebiten.KeyU] = 'u'
ebitenAsciiMap[ebiten.KeyV] = 'v'
ebitenAsciiMap[ebiten.KeyW] = 'w'
ebitenAsciiMap[ebiten.KeyX] = 'x'
ebitenAsciiMap[ebiten.KeyY] = 'y'
ebitenAsciiMap[ebiten.KeyZ] = 'z'
ebitenAsciiMap[ebiten.KeyApostrophe] = '\''
ebitenAsciiMap[ebiten.KeyBackslash] = '\\'
ebitenAsciiMap[ebiten.KeyComma] = ','
ebitenAsciiMap[ebiten.KeyEqual] = '='
ebitenAsciiMap[ebiten.KeyGraveAccent] = '`'
ebitenAsciiMap[ebiten.KeyLeftBracket] = '['
ebitenAsciiMap[ebiten.KeyMinus] = '-'
ebitenAsciiMap[ebiten.KeyPeriod] = '.'
ebitenAsciiMap[ebiten.KeyRightBracket] = ']'
ebitenAsciiMap[ebiten.KeySemicolon] = ';'
ebitenAsciiMap[ebiten.KeySlash] = '/'
ebitenAsciiMap[ebiten.KeySpace] = ' '
ebitenASCIIMap[ebiten.Key0] = '0'
ebitenASCIIMap[ebiten.Key1] = '1'
ebitenASCIIMap[ebiten.Key2] = '2'
ebitenASCIIMap[ebiten.Key3] = '3'
ebitenASCIIMap[ebiten.Key4] = '4'
ebitenASCIIMap[ebiten.Key5] = '5'
ebitenASCIIMap[ebiten.Key6] = '6'
ebitenASCIIMap[ebiten.Key7] = '7'
ebitenASCIIMap[ebiten.Key8] = '8'
ebitenASCIIMap[ebiten.Key9] = '9'
ebitenASCIIMap[ebiten.KeyA] = 'a'
ebitenASCIIMap[ebiten.KeyB] = 'b'
ebitenASCIIMap[ebiten.KeyC] = 'c'
ebitenASCIIMap[ebiten.KeyD] = 'd'
ebitenASCIIMap[ebiten.KeyE] = 'e'
ebitenASCIIMap[ebiten.KeyF] = 'f'
ebitenASCIIMap[ebiten.KeyG] = 'g'
ebitenASCIIMap[ebiten.KeyH] = 'h'
ebitenASCIIMap[ebiten.KeyI] = 'i'
ebitenASCIIMap[ebiten.KeyJ] = 'j'
ebitenASCIIMap[ebiten.KeyK] = 'k'
ebitenASCIIMap[ebiten.KeyL] = 'l'
ebitenASCIIMap[ebiten.KeyM] = 'm'
ebitenASCIIMap[ebiten.KeyN] = 'n'
ebitenASCIIMap[ebiten.KeyO] = 'o'
ebitenASCIIMap[ebiten.KeyP] = 'p'
ebitenASCIIMap[ebiten.KeyQ] = 'q'
ebitenASCIIMap[ebiten.KeyR] = 'r'
ebitenASCIIMap[ebiten.KeyS] = 's'
ebitenASCIIMap[ebiten.KeyT] = 't'
ebitenASCIIMap[ebiten.KeyU] = 'u'
ebitenASCIIMap[ebiten.KeyV] = 'v'
ebitenASCIIMap[ebiten.KeyW] = 'w'
ebitenASCIIMap[ebiten.KeyX] = 'x'
ebitenASCIIMap[ebiten.KeyY] = 'y'
ebitenASCIIMap[ebiten.KeyZ] = 'z'
ebitenASCIIMap[ebiten.KeyApostrophe] = '\''
ebitenASCIIMap[ebiten.KeyBackslash] = '\\'
ebitenASCIIMap[ebiten.KeyComma] = ','
ebitenASCIIMap[ebiten.KeyEqual] = '='
ebitenASCIIMap[ebiten.KeyGraveAccent] = '`'
ebitenASCIIMap[ebiten.KeyLeftBracket] = '['
ebitenASCIIMap[ebiten.KeyMinus] = '-'
ebitenASCIIMap[ebiten.KeyPeriod] = '.'
ebitenASCIIMap[ebiten.KeyRightBracket] = ']'
ebitenASCIIMap[ebiten.KeySemicolon] = ';'
ebitenASCIIMap[ebiten.KeySlash] = '/'
ebitenASCIIMap[ebiten.KeySpace] = ' '
shiftMap['1'] = '!'
shiftMap['2'] = '@'
@ -198,7 +198,7 @@ func Poll() {
newKeysPressed := make(map[uint8]bool)
// Query ebiten for all possible keys
for k, v := range ebitenAsciiMap {
for k, v := range ebitenASCIIMap {
if ebiten.IsKeyPressed(k) {
allKeysPressed[v] = true

269
mmu/io.go
View File

@ -14,83 +14,83 @@ import (
// https://github.com/cmosher01/Apple-II-Platform/blob/master/asminclude/iorom.asm
const (
KEYBOARD = 0xC000 // keyboard data (latched) (RD-only)
CLR80COL = 0xC000 // use 80-column memory mapping (WR-only)
SET80COL = 0xC001
CLRAUXRD = 0xC002 // read from auxilliary 48K
SETAUXRD = 0xC003
CLRAUXWR = 0xC004 // write to auxilliary 48K
SETAUXWR = 0xC005
CLRCXROM = 0xC006 // use external slot ROM
SETCXROM = 0xC007
CLRAUXZP = 0xC008 // use auxilliary ZP, stack, & LC
SETAUXZP = 0xC009
CLRC3ROM = 0xC00A // use external slot C3 ROM
SETC3ROM = 0xC00B
CLR80VID = 0xC00C // use 80-column display mode
SET80VID = 0xC00D
CLRALTCH = 0xC00E // use alternate character set ROM
SETALTCH = 0xC00F
STROBE = 0xC010 // strobe (unlatch) keyboard data
mKEYBOARD = 0xC000 // keyboard data (latched) (RD-only)
mCLR80COL = 0xC000 // use 80-column memory mapping (WR-only)
mSET80COL = 0xC001
mCLRAUXRD = 0xC002 // read from auxilliary 48K
mSETAUXRD = 0xC003
mCLRAUXWR = 0xC004 // write to auxilliary 48K
mSETAUXWR = 0xC005
mCLRCXROM = 0xC006 // use external slot ROM
mSETCXROM = 0xC007
mCLRAUXZP = 0xC008 // use auxilliary ZP, stack, & LC
mSETAUXZP = 0xC009
mCLRC3ROM = 0xC00A // use external slot C3 ROM
mSETC3ROM = 0xC00B
mCLR80VID = 0xC00C // use 80-column display mode
mSET80VID = 0xC00D
mCLRALTCH = 0xC00E // use alternate character set ROM
mSETALTCH = 0xC00F
mSTROBE = 0xC010 // strobe (unlatch) keyboard data
RDLCBNK2 = 0xC011 // reading from LC bank $Dx 2
RDLCRAM = 0xC012 // reading from LC RAM
RDRAMRD = 0xC013 // reading from auxilliary 48K
RDRAMWR = 0xC014 // writing to auxilliary 48K
RDCXROM = 0xC015 // using external slot ROM
RDAUXZP = 0xC016 // using auxilliary ZP, stack, & LC
RDC3ROM = 0xC017 // using external slot C3 ROM
RD80COL = 0xC018 // using 80-column memory mapping
RDVBLBAR = 0xC019 // not VBL (VBL signal low)
RDTEXT = 0xC01A // using text mode
RDMIXED = 0xC01B // using mixed mode
RDPAGE2 = 0xC01C // using text/graphics page2
RDHIRES = 0xC01D // using Hi-res graphics mode
RDALTCH = 0xC01E // using alternate character set ROM
RD80VID = 0xC01F // using 80-column display mode
SPEAKER = 0xC030 // toggle speaker diaphragm
mRDLCBNK2 = 0xC011 // reading from LC bank $Dx 2
mRDLCRAM = 0xC012 // reading from LC RAM
mRDRAMRD = 0xC013 // reading from auxilliary 48K
mRDRAMWR = 0xC014 // writing to auxilliary 48K
mRDCXROM = 0xC015 // using external slot ROM
mRDAUXZP = 0xC016 // using auxilliary ZP, stack, & LC
mRDC3ROM = 0xC017 // using external slot C3 ROM
mRD80COL = 0xC018 // using 80-column memory mapping
mRDVBLBAR = 0xC019 // not VBL (VBL signal low)
mRDTEXT = 0xC01A // using text mode
mRDMIXED = 0xC01B // using mixed mode
mRDPAGE2 = 0xC01C // using text/graphics page2
mRDHIRES = 0xC01D // using Hi-res graphics mode
mRDALTCH = 0xC01E // using alternate character set ROM
mRD80VID = 0xC01F // using 80-column display mode
mSPEAKER = 0xC030 // toggle speaker diaphragm
CLRTEXT = 0xC050 // enable text-only mode
SETTEXT = 0xC051
CLRMIXED = 0xC052 // enable graphics/text mixed mode
SETMIXED = 0xC053
TXTPAGE1 = 0xC054 // select page1/2 (or page1/1x)
TXTPAGE2 = 0xC055
CLRHIRES = 0xC056 // enable Hi-res graphics
SETHIRES = 0xC057
mCLRTEXT = 0xC050 // enable text-only mode
mSETTEXT = 0xC051
mCLRMIXED = 0xC052 // enable graphics/text mixed mode
mSETMIXED = 0xC053
mTXTPAGE1 = 0xC054 // select page1/2 (or page1/1x)
mTXTPAGE2 = 0xC055
mCLRHIRES = 0xC056 // enable Hi-res graphics
mSETHIRES = 0xC057
SETAN0 = 0xC058 // 4-bit annunciator inputs
CLRAN0 = 0xC059
SETAN1 = 0xC05A
CLRAN1 = 0xC05B
SETAN2 = 0xC05C
CLRAN2 = 0xC05D
SETAN3 = 0xC05E
CLRAN3 = 0xC05F
mSETAN0 = 0xC058 // 4-bit annunciator inputs
mCLRAN0 = 0xC059
mSETAN1 = 0xC05A
mCLRAN1 = 0xC05B
mSETAN2 = 0xC05C
mCLRAN2 = 0xC05D
mSETAN3 = 0xC05E
mCLRAN3 = 0xC05F
OPNAPPLE = 0xC061 // open apple (command) key data
CLSAPPLE = 0xC062 // closed apple (option) key data
STATEREG = 0xC068 // Has no effect on //e
mOPNAPPLE = 0xC061 // open apple (command) key data
mCLSAPPLE = 0xC062 // closed apple (option) key data
mSTATEREG = 0xC068 // Has no effect on //e
PDLTRIG = 0xC070 // trigger paddles
mPDLTRIG = 0xC070 // trigger paddles
// Slot 6 Drive IO
S6CLRDRVP0 = 0xC0E0 // stepper phase 0 (Q0)
S6SETDRVP0 = 0xC0E1 //
S6CLRDRVP1 = 0xC0E2 // stepper phase 1 (Q1)
S6SETDRVP1 = 0xC0E3 //
S6CLRDRVP2 = 0xC0E4 // stepper phase 2 (Q2)
S6SETDRVP2 = 0xC0E5 //
S6CLRDRVP3 = 0xC0E6 // stepper phase 3 (Q3)
S6SETDRVP3 = 0xC0E7 //
S6MOTOROFF = 0xC0E8 // drive motor (Q4)
S6MOTORON = 0xC0E9 //
S6SELDRV1 = 0xC0EA // drive select (Q5)
S6SELDRV2 = 0xC0EB //
S6Q6L = 0xC0EC // read (Q6)
S6Q6H = 0xC0ED // WP sense
S6Q7L = 0xC0EE // WP sense/read (Q7)
S6Q7H = 0xC0EF // write
mS6CLRDRVP0 = 0xC0E0 // stepper phase 0 (Q0)
mS6SETDRVP0 = 0xC0E1 //
mS6CLRDRVP1 = 0xC0E2 // stepper phase 1 (Q1)
mS6SETDRVP1 = 0xC0E3 //
mS6CLRDRVP2 = 0xC0E4 // stepper phase 2 (Q2)
mS6SETDRVP2 = 0xC0E5 //
mS6CLRDRVP3 = 0xC0E6 // stepper phase 3 (Q3)
mS6SETDRVP3 = 0xC0E7 //
mS6MOTOROFF = 0xC0E8 // drive motor (Q4)
mS6MOTORON = 0xC0E9 //
mS6SELDRV1 = 0xC0EA // drive select (Q5)
mS6SELDRV2 = 0xC0EB //
mS6Q6L = 0xC0EC // read (Q6)
mS6Q6H = 0xC0ED // WP sense
mS6Q7L = 0xC0EE // WP sense/read (Q7)
mS6Q7H = 0xC0EF // write
)
// VideoState has 3 booleans which determine the video configuration:
@ -106,6 +106,7 @@ var VideoState struct {
Mixed bool
}
// InitIO resets all IO states
func InitIO() {
// Empty slots that aren't yet implemented
emptySlot(3)
@ -138,81 +139,81 @@ func readWrite(address uint16, isRead bool) bool {
}
switch address {
case CLRAUXRD:
case mCLRAUXRD:
SetFakeAuxMemoryRead(false)
return true
case SETAUXRD:
case mSETAUXRD:
SetFakeAuxMemoryRead(true)
return true
case CLRAUXWR:
case mCLRAUXWR:
SetFakeAuxMemoryWrite(false)
return true
case SETAUXWR:
case mSETAUXWR:
SetFakeAuxMemoryWrite(true)
return true
case CLRAUXZP:
case mCLRAUXZP:
SetFakeAltZP(false)
return true
case SETAUXZP:
case mSETAUXZP:
SetFakeAltZP(true)
return true
case CLR80VID:
case mCLR80VID:
SetCol80(false)
return true
case SET80VID:
case mSET80VID:
SetCol80(true)
return true
case TXTPAGE1:
case mTXTPAGE1:
SetPage2(false)
return true
case TXTPAGE2:
case mTXTPAGE2:
SetPage2(true)
return true
case CLRTEXT:
case mCLRTEXT:
VideoState.TextMode = false
return true
case SETTEXT:
case mSETTEXT:
VideoState.TextMode = true
return true
case CLRMIXED:
case mCLRMIXED:
VideoState.Mixed = false
return true
case SETMIXED:
case mSETMIXED:
VideoState.Mixed = true
return true
case CLRHIRES:
case mCLRHIRES:
VideoState.HiresMode = false
return true
case SETHIRES:
case mSETHIRES:
VideoState.HiresMode = true
return true
case CLR80COL:
case mCLR80COL:
if !isRead {
SetStore80(false)
return true
} else {
return false
}
case SET80COL:
return false
case mSET80COL:
SetStore80(true)
return true
case STATEREG:
case mSTATEREG:
// Ignore not implemented memory management reg
return true
// Drive stepper motor phase change
case S6CLRDRVP0, S6SETDRVP0, S6CLRDRVP1, S6SETDRVP1, S6CLRDRVP2, S6SETDRVP2, S6CLRDRVP3, S6SETDRVP3:
magnet := (address - S6CLRDRVP0) / 2
on := ((address - S6CLRDRVP0) % 2) == 1
case mS6CLRDRVP0, mS6SETDRVP0, mS6CLRDRVP1, mS6SETDRVP1, mS6CLRDRVP2, mS6SETDRVP2, mS6CLRDRVP3, mS6SETDRVP3:
magnet := (address - mS6CLRDRVP0) / 2
on := ((address - mS6CLRDRVP0) % 2) == 1
if !on {
// Turn off the magnet in Phases
system.DriveState.Phases &= ^(1 << magnet)
@ -225,10 +226,10 @@ func readWrite(address uint16, isRead bool) bool {
// Move head if a neighboring magnet is on and all others are off
direction := int8(0)
if (system.DriveState.Phases & (1 << uint8((system.DriveState.Phase+1)&3))) != 0 {
direction += 1
direction++
}
if (system.DriveState.Phases & (1 << uint8((system.DriveState.Phase+3)&3))) != 0 {
direction -= 1
direction--
}
// Move the head
@ -251,37 +252,37 @@ func readWrite(address uint16, isRead bool) bool {
return true
case S6MOTOROFF:
case mS6MOTOROFF:
system.DriveState.Spinning = false
return true
case S6MOTORON:
case mS6MOTORON:
system.DriveState.Spinning = true
return true
case S6SELDRV1:
case mS6SELDRV1:
system.DriveState.Drive = 1
return true
case S6SELDRV2:
case mS6SELDRV2:
system.DriveState.Drive = 2
return true
case S6Q6L:
case mS6Q6L:
if !isRead {
system.DriveState.Q6 = false
return true
}
return false
case S6Q6H:
case mS6Q6H:
if isRead {
system.DriveState.Q6 = true
return true
}
return false
case S6Q7L:
case mS6Q7L:
system.DriveState.Q7 = false
return true
case S6Q7H:
case mS6Q7H:
system.DriveState.Q7 = true
return true
@ -299,64 +300,60 @@ func ReadIO(address uint16) uint8 {
switch address {
case KEYBOARD, STROBE:
case mKEYBOARD, mSTROBE:
keyBoardData, strobe := keyboard.Read()
if address == KEYBOARD {
if address == mKEYBOARD {
return keyBoardData
} else {
keyboard.ResetStrobe()
return strobe
}
keyboard.ResetStrobe()
return strobe
case RDRAMRD, RDRAMWR, RDAUXZP:
case mRDRAMRD, mRDRAMWR, mRDAUXZP:
panic("Read/write aux memory not implemented")
return 0x0d
case RDCXROM:
case mRDCXROM:
if UsingExternalSlotRom {
return 0x8d
} else {
return 0x0d
}
return 0x0d
case RD80VID:
case mRD80VID:
// using 80-column display mode not implemented
return 0x0d
case RDPAGE2:
case mRDPAGE2:
if Page2 {
return 0x8d
} else {
return 0x0d
}
return 0x0d
// 4-bit annunciator inputs
case SETAN0, CLRAN0, SETAN1, CLRAN1, SETAN2, CLRAN2, SETAN3, CLRAN3:
case mSETAN0, mCLRAN0, mSETAN1, mCLRAN1, mSETAN2, mCLRAN2, mSETAN3, mCLRAN3:
// Annunciators not implemented
case OPNAPPLE:
case mOPNAPPLE:
// Open apple key not implemented
return 0
case CLSAPPLE:
case mCLSAPPLE:
// Closed apple key not implemented
case RD80COL:
case mRD80COL:
if Store80 {
return 0x8d
} else {
return 0x0d
}
return 0x0d
case RDALTCH:
case mRDALTCH:
// RDALTCH not implemented, but it's also used, so don't fail on it.
return 0x0d
case SPEAKER:
case mSPEAKER:
audio.Click()
return 0
case S6Q6L:
case mS6Q6L:
// A read from disk
return disk.ReadTrackData()
@ -367,7 +364,7 @@ func ReadIO(address uint16) uint8 {
return 0
}
// ReadIO does a write in the $c000-$c0ff area
// WriteIO does a write in the $c000-$c0ff area
func WriteIO(address uint16, value uint8) {
// Try the generic readWrite and return if it has handled the write
if readWrite(address, false) {
@ -376,29 +373,29 @@ func WriteIO(address uint16, value uint8) {
switch address {
case STROBE:
case mSTROBE:
keyboard.ResetStrobe()
case CLRCXROM:
case mCLRCXROM:
MapFirstHalfOfIO()
case SETCXROM:
case mSETCXROM:
MapSecondHalfOfIO()
case CLRALTCH:
case mCLRALTCH:
return
case SETALTCH:
case mSETALTCH:
panic("SETALTCH not implemented")
case CLR80COL:
case mCLR80COL:
// CLR80COL not implemented
return
case CLRC3ROM:
case mCLRC3ROM:
// CLRC3ROM not implemented
case SETC3ROM:
case mSETC3ROM:
// SETC3ROM not implemented
case S6Q6H:
case mS6Q6H:
// A write to disk
disk.WriteTrackData(value)

View File

@ -7,8 +7,11 @@ import (
"github.com/freewilll/apple2/system"
)
const RomPath = "apple2e.rom" // So far only one ROM is supported and it's loaded at startup
const StackPage = 1 // The 6502 stack is at 0x100
// RomPath is a hardcoded path to an Apple //e ROM file that's loaded at startup
const RomPath = "apple2e.rom"
// StackPage is the location of the 6504 stack
const StackPage = 1
// PhysicalMemory contains all the unmapped memory, ROM and RAM
var PhysicalMemory struct {
@ -18,8 +21,10 @@ var PhysicalMemory struct {
RomC2 [0x1000]uint8 // Second half of IO ROM
}
// Page tables for read & write
// ReadPageTable is the page table for reads
var ReadPageTable [0x100][]uint8
// WritePageTable is the page table for writes
var WritePageTable [0x100][]uint8
// Memory mapping states
@ -27,7 +32,7 @@ var (
D000Bank int // one maps to $c000, two maps to $d000
UsingExternalSlotRom bool // Which IO ROM is being used
UpperReadMappedToROM bool // Do reads go to the RAM or ROM
UpperRamReadOnly bool // Is the upper RAM read only
UpperRAMReadOnly bool // Is the upper RAM read only
FakeAuxMemoryRead bool // Aux memory isn't implemented
FakeAuxMemoryWrite bool // Aux memory isn't implemented
FakeAltZP bool // Aux memory isn't implemented
@ -37,7 +42,7 @@ var (
Page2 bool // Main memory Page2 is selected
)
// Make page tables for current RAM, ROM and IO configuration
// ApplyMemoryConfiguration creates the page tables for current RAM, ROM and IO configuration
func ApplyMemoryConfiguration() {
// Map main RAM for read/write
for i := 0x0; i < 0xc0; i++ {
@ -65,7 +70,7 @@ func ApplyMemoryConfiguration() {
ReadPageTable[i] = PhysicalMemory.MainMemory[base : base+0x100]
}
if UpperRamReadOnly {
if UpperRAMReadOnly {
WritePageTable[i] = nil
} else {
WritePageTable[i] = PhysicalMemory.MainMemory[base : base+0x100]
@ -78,7 +83,7 @@ func ApplyMemoryConfiguration() {
if !UpperReadMappedToROM {
ReadPageTable[i] = PhysicalMemory.MainMemory[base : base+0x100]
}
if UpperRamReadOnly {
if UpperRAMReadOnly {
WritePageTable[i] = nil
} else {
WritePageTable[i] = PhysicalMemory.MainMemory[base : base+0x100]
@ -93,13 +98,13 @@ func ApplyMemoryConfiguration() {
}
// Map 0xc100-0xcfff for reading from RomC1
// MapFirstHalfOfIO maps 0xc100-0xcfff for reading from RomC1
func MapFirstHalfOfIO() {
UsingExternalSlotRom = false
ApplyMemoryConfiguration()
}
// Map 0xc100-0xcfff for reading from RomC2
// MapSecondHalfOfIO map 0xc100-0xcfff for reading from RomC2
func MapSecondHalfOfIO() {
UsingExternalSlotRom = true
ApplyMemoryConfiguration()
@ -131,61 +136,66 @@ func loadApple2eROM() {
}
}
// InitApple2eROM loads the ROM and inits the ROM page tables
func InitApple2eROM() {
loadApple2eROM()
MapFirstHalfOfIO() // Map 0xc100-0xcfff for reading
InitROM() // Map 0xd000-0xffff for reading
}
// Set upper memory area for reading from ROM
// InitROM sets the upper memory area for reading from ROM
func InitROM() {
UpperReadMappedToROM = true
ApplyMemoryConfiguration()
}
// SetUpperReadMappedToROM sets the upper area so that reads are done from the ROM if true or RAM if false
func SetUpperReadMappedToROM(value bool) {
UpperReadMappedToROM = value
ApplyMemoryConfiguration()
}
func SetUpperRamReadOnly(value bool) {
UpperRamReadOnly = value
// SetUpperRAMReadOnly sets the upper RAM area to read only
func SetUpperRAMReadOnly(value bool) {
UpperRAMReadOnly = value
ApplyMemoryConfiguration()
}
// Set d000 bank to map to $c000 or $d000 in the physical memory
// SetD000Bank sets the $d000 bank to map to $c000 or $d000 in the physical memory
func SetD000Bank(value int) {
D000Bank = value
ApplyMemoryConfiguration()
}
// Aux memory hasn't been implemented. If aux memory is selected, and a read
// SetFakeAuxMemoryRead sets an internal state to fake aux memory reads. Aux memory hasn't been implemented. If aux memory is selected, and a read
// is attempted, then nonsense must be returned.
func SetFakeAuxMemoryRead(value bool) {
FakeAuxMemoryRead = value
ApplyMemoryConfiguration()
}
// Aux memory hasn't been implemented. If aux memory is selected, and a write
// SetFakeAuxMemoryWrite sets an internal state to fake aux memory writes. Aux memory hasn't been implemented. If aux memory is selected, and a write
// is attempted, then it must be ignored.
func SetFakeAuxMemoryWrite(value bool) {
FakeAuxMemoryWrite = value
ApplyMemoryConfiguration()
}
// Alternate zero page isn't implemented
// SetFakeAltZP sets an internal state to fake a missing alternate zero page. Alternate zero page isn't implemented
func SetFakeAltZP(value bool) {
FakeAltZP = value
ApplyMemoryConfiguration()
}
// 80 column card isn't implemented
// SetCol80 sets an internal state to fake a missing 80 column card
func SetCol80(value bool) {
Col80 = value
// No changes are needed when this is toggled
}
// Page switching is only implemented for the main memory
// SetPage2 sets page1/page2 in text, lores or hires. This only works if the
// 80 column card is disabled since the 80 columns card has not yet nbeen
// implemented.
func SetPage2(value bool) {
// If the 80 column card is enabled, then this toggles aux memory
// Otherwise, page1/page2 is toggled in the main memory
@ -197,7 +207,7 @@ func SetPage2(value bool) {
}
}
// 80 column card isn't implemented
// SetStore80 sets an internal state to fake a missing 80 column card
func SetStore80(value bool) {
Store80 = value
FakePage2 = value
@ -206,7 +216,7 @@ func SetStore80(value bool) {
// InitRAM sets all default RAM memory settings and resets the page tables
func InitRAM() {
UpperRamReadOnly = false
UpperRAMReadOnly = false
D000Bank = 2
FakeAuxMemoryRead = false // Aux memory isn't implemented
FakeAuxMemoryWrite = false // Aux memory isn't implemented
@ -217,22 +227,23 @@ func InitRAM() {
ApplyMemoryConfiguration()
}
// WipeRAM wipes all the physical RAM
func WipeRAM() {
for i := 0; i < 0x10000; i++ {
PhysicalMemory.MainMemory[i] = 0
}
}
// SetMemoryMode is used to set UpperRamReadOnly, UpperReadMappedToROM and D000Bank number
// SetMemoryMode is used to set UpperRAMReadOnly, UpperReadMappedToROM and D000Bank number
func SetMemoryMode(mode uint8) {
// mode corresponds to a read/write to $c080 with
// $c080 mode=$00
// $c08f mode=$0f
if (mode & 1) == 0 {
UpperRamReadOnly = true
UpperRAMReadOnly = true
} else {
UpperRamReadOnly = false
UpperRAMReadOnly = false
}
if (((mode & 2) >> 1) ^ (mode & 1)) == 0 {
@ -266,18 +277,18 @@ func ReadMemory(address uint16) uint8 {
if address >= 0x200 {
// Return nothingness
return uint8(0x00)
} else {
if FakeAltZP {
return uint8(0x00)
}
}
if FakeAltZP {
return uint8(0x00)
}
}
// Implicit else, we're reading the main non-IO RAM
return ReadPageTable[address>>8][address&0xff]
}
// ReadMemory writes to the ROM or RAM page table
// WriteMemory writes to the ROM or RAM page table
func WriteMemory(address uint16, value uint8) {
if (address >= 0xc000) && (address < 0xc100) {
WriteIO(address, value)

View File

@ -4,22 +4,46 @@ package system
// the packages.
const (
CpuFrequency = 1023000 // 6402 CPU frequency in Hz
AudioSampleRate = 44100 // Audio sample rate in Hz
// CPUFrequency is the 6502 CPU frequency in Hz
CPUFrequency = 1023000
// AudioSampleRate is the audio sample rate in Hz
AudioSampleRate = 44100
)
var (
PendingInterrupt bool // Set when an interrupt has just happened
PendingNMI bool // Set when a non maskable interrupt has just happened
RunningTests bool // For testing
RunningFunctionalTests bool // For testing
RunningInterruptTests bool // For testing
Cycles uint64 // Total CPU cycles executed
FrameCycles uint64 // CPU cycles executed in the current frame
AudioChannel chan int16 // Audio channel
LastAudioValue int16 // + or - value of the current square wave
LastAudioCycles uint64 // Last CPU cycle when audio was sent to the channel
AudioAttenuationCounter uint64 // Counter to keep track of when the audio should be zeroed after inactivity
// PendingInterrupt is set when an interrupt has just happened
PendingInterrupt bool
// PendingNMI is set when a non maskable interrupt has just happened
PendingNMI bool
// RunningTests is set when tests are running
RunningTests bool
// RunningFunctionalTests is set when functional tests are running
RunningFunctionalTests bool
// RunningInterruptTests is set when interupt tests are running
RunningInterruptTests bool
// Cycles is the total CPU cycles executed
Cycles uint64
// FrameCycles is the CPU cycles executed in the current frame
FrameCycles uint64
// AudioChannel is the audio channel used to produce and consume audio samples between the cpu and audio packages
AudioChannel chan int16
// LastAudioValue is the + or - value of the current square wave
LastAudioValue int16
// LastAudioCycles is the ast CPU cycle when audio was sent to the channel
LastAudioCycles uint64
// AudioAttenuationCounter is a counter to keep track of when the audio should be zeroed after inactivity
AudioAttenuationCounter uint64
)
// DriveState has the state of the disk drive
@ -40,7 +64,7 @@ func Init() {
LastAudioValue = 0x2000
}
// Handle a write to a magic test address that triggers an interrupt and/or an NMI
// WriteInterruptTestOpenCollector handles a write to a magic test address that triggers an interrupt and/or an NMI
func WriteInterruptTestOpenCollector(address uint16, oldValue uint8, value uint8) {
oldInterrupt := (oldValue & 0x1) == 0x1
oldNMI := (oldValue & 0x2) == 0x2

View File

@ -60,7 +60,7 @@ func RunUntilBreakPoint(t *testing.T, breakAddress uint16, seconds int, showInst
system.LastAudioCycles = 0
exitAtBreak := false
disableFirmwareWait := false
cpu.Run(showInstructions, &breakAddress, exitAtBreak, disableFirmwareWait, uint64(system.CpuFrequency*seconds))
cpu.Run(showInstructions, &breakAddress, exitAtBreak, disableFirmwareWait, uint64(system.CPUFrequency*seconds))
if cpu.State.PC != breakAddress {
t.Fatalf("Did not reach breakpoint at %04x. Got to %04x", breakAddress, cpu.State.PC)
}

View File

@ -12,9 +12,11 @@ import (
)
const (
ScreenSizeFactor = 1 // Factor by which the whole screen is resized
textVideoMemory = 0x400 // Base location of page 1 text video memory
flashFrames = 11 // Number of frames when FLASH mode is toggled
// ScreenSizeFactor is the fFactor by which the whole screen is resized
ScreenSizeFactor = 1
textVideoMemory = 0x400 // Base location of page 1 text video memory
flashFrames = 11 // Number of frames when FLASH mode is toggled
)
// drawTextLoresByte is a function definition used for mixed text/lores rendering
@ -25,7 +27,9 @@ var (
flashCounter int // Counter used for flashing characters on the text screen
flashOn bool // Are we currently flashing?
loresSquares [16]*ebiten.Image // Colored blocks for lores rendering
ShowFPS bool // Show FPS in corner?
// ShowFPS determines if the FPS is shown in the corner of the video
ShowFPS bool
)
// initTextCharMap initializes the text character map
@ -130,7 +134,7 @@ func drawText(screen *ebiten.Image, x int, y int, value uint8) error {
// drawLores draws two colored lores squares at the equivalent text location x,y.
func drawLores(screen *ebiten.Image, x int, y int, value uint8) error {
// Convert the 8 bit value to two 4 bit values
var values [2]uint8 = [2]uint8{value & 0xf, value >> 4}
var values = [2]uint8{value & 0xf, value >> 4}
// Render top & bottom squares
for i := 0; i < 2; i++ {