diff --git a/README.md b/README.md index 4764205..cf50a86 100644 --- a/README.md +++ b/README.md @@ -82,4 +82,14 @@ Assemble the tests * 80 column card * 48k aux memory * double hires -* joystick \ No newline at end of file +* 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 ./...) diff --git a/apple2.go b/apple2.go index 5f5ce7f..266c899 100644 --- a/apple2.go +++ b/apple2.go @@ -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() diff --git a/audio/audio.go b/audio/audio.go index f501be5..7e80f3b 100644 --- a/audio/audio.go +++ b/audio/audio.go @@ -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 diff --git a/audio/ebiten.go b/audio/ebiten.go index 59452f4..2c449c6 100644 --- a/audio/ebiten.go +++ b/audio/ebiten.go @@ -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 diff --git a/bank_switch_test.go b/bank_switch_test.go index a5ab1f8..23774c2 100644 --- a/bank_switch_test.go +++ b/bank_switch_test.go @@ -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 diff --git a/bell_test.go b/bell_test.go index 88850bb..38af0a0 100644 --- a/bell_test.go +++ b/bell_test.go @@ -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 diff --git a/cpu/cpu.go b/cpu/cpu.go index 4bb76b0..8d65274 100644 --- a/cpu/cpu.go +++ b/cpu/cpu.go @@ -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) diff --git a/cpu/debug.go b/cpu/debug.go index 451a1c8..c179d27 100644 --- a/cpu/debug.go +++ b/cpu/debug.go @@ -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("") diff --git a/cpu/opcodes.go b/cpu/opcodes.go index 3e84f64..a93945a 100644 --- a/cpu/opcodes.go +++ b/cpu/opcodes.go @@ -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() diff --git a/disk/disk.go b/disk/disk.go index f46f9fd..9b0db5b 100644 --- a/disk/disk.go +++ b/disk/disk.go @@ -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 diff --git a/keyboard/keyboard.go b/keyboard/keyboard.go index db6bf9a..1b250bf 100644 --- a/keyboard/keyboard.go +++ b/keyboard/keyboard.go @@ -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 diff --git a/mmu/io.go b/mmu/io.go index 57c1aeb..1fc0bb6 100644 --- a/mmu/io.go +++ b/mmu/io.go @@ -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) diff --git a/mmu/mmu.go b/mmu/mmu.go index 3a95d9c..a902c1b 100644 --- a/mmu/mmu.go +++ b/mmu/mmu.go @@ -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) diff --git a/system/system.go b/system/system.go index d6d2119..f4469ad 100644 --- a/system/system.go +++ b/system/system.go @@ -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 diff --git a/utils/utils.go b/utils/utils.go index 184c2a6..614d602 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -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) } diff --git a/video/video.go b/video/video.go index aa2fe65..1e6fd75 100644 --- a/video/video.go +++ b/video/video.go @@ -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++ {