mirror of
https://github.com/freewilll/apple2-go.git
synced 2024-12-22 19:29:32 +00:00
Split IO into its own module
This commit is contained in:
parent
a5acfb9140
commit
f8ca059f18
176
mmu/io.go
Normal file
176
mmu/io.go
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
package mmu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"mos6502go/keyboard"
|
||||||
|
)
|
||||||
|
|
||||||
|
// https://mirrors.apple2.org.za/apple.cabi.net/Languages.Programming/MemoryMap.IIe.64K.128K.txt
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
SETAN0 = 0xC058 // 4-bit annunciator inputs
|
||||||
|
CLRAN0 = 0xC059
|
||||||
|
SETAN1 = 0xC05A
|
||||||
|
CLRAN1 = 0xC05B
|
||||||
|
SETAN2 = 0xC05C
|
||||||
|
CLRAN2 = 0xC05D
|
||||||
|
SETAN3 = 0xC05E
|
||||||
|
CLRAN3 = 0xC05F
|
||||||
|
|
||||||
|
OPNAPPLE = 0xC061 // open apple (command) key data
|
||||||
|
CLSAPPLE = 0xC062 // closed apple (option) key data
|
||||||
|
|
||||||
|
PDLTRIG = 0xC070 // trigger paddles
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handle soft switch addresses where both a read and a write has a side
|
||||||
|
// effect and the return value is meaningless
|
||||||
|
func readWrite(address uint16) bool {
|
||||||
|
switch address {
|
||||||
|
case CLRTEXT:
|
||||||
|
panic("CLRTEXT not implemented")
|
||||||
|
case SETTEXT:
|
||||||
|
return true
|
||||||
|
case TXTPAGE1:
|
||||||
|
return true
|
||||||
|
case TXTPAGE2:
|
||||||
|
return true
|
||||||
|
fmt.Println("TXTPAGE2 not implemented")
|
||||||
|
// panic("TXTPAGE2 not implemented")
|
||||||
|
return true
|
||||||
|
case CLRHIRES:
|
||||||
|
return true
|
||||||
|
case SETHIRES:
|
||||||
|
panic("SETIRES not implemented")
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadIO(address uint16) uint8 {
|
||||||
|
if readWrite(address) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
switch address {
|
||||||
|
case KEYBOARD, STROBE:
|
||||||
|
keyBoardData, strobe := keyboard.Read()
|
||||||
|
if address == KEYBOARD {
|
||||||
|
return keyBoardData
|
||||||
|
} else {
|
||||||
|
keyboard.ResetStrobe()
|
||||||
|
return strobe
|
||||||
|
}
|
||||||
|
case RDCXROM:
|
||||||
|
if UsingExternalSlotRom {
|
||||||
|
return 0x8d
|
||||||
|
} else {
|
||||||
|
return 0x0d
|
||||||
|
}
|
||||||
|
case RD80VID:
|
||||||
|
// using 80-column display mode not implemented
|
||||||
|
return 0x0d
|
||||||
|
|
||||||
|
// 4-bit annunciator inputs
|
||||||
|
case SETAN0, CLRAN0, SETAN1, CLRAN1, SETAN2, CLRAN2, SETAN3, CLRAN3:
|
||||||
|
// Annunciators not implemented
|
||||||
|
case OPNAPPLE:
|
||||||
|
// Open apple key not implemented
|
||||||
|
return 0
|
||||||
|
case CLSAPPLE:
|
||||||
|
// Closed apple key not implemented
|
||||||
|
case RD80COL:
|
||||||
|
// RD80COL not implemented
|
||||||
|
return 0x0d
|
||||||
|
case RDPAGE2:
|
||||||
|
// RDPAGE2 not implemented
|
||||||
|
return 0x0d
|
||||||
|
case RDALTCH:
|
||||||
|
// RDALTCH not implemented
|
||||||
|
return 0x0d
|
||||||
|
case SPEAKER:
|
||||||
|
// Speaker not implemented
|
||||||
|
// Not printing anything since this will generate a lot of noise
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("TODO read %04x\n", address))
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteIO(address uint16, value uint8) {
|
||||||
|
if readWrite(address) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch address {
|
||||||
|
case STROBE:
|
||||||
|
keyboard.ResetStrobe()
|
||||||
|
case CLRCXROM:
|
||||||
|
MapFirstHalfOfIO()
|
||||||
|
case SETCXROM:
|
||||||
|
MapSecondHalfOfIO()
|
||||||
|
case CLRALTCH:
|
||||||
|
return
|
||||||
|
case SETALTCH:
|
||||||
|
panic("SETALTCH not implemented")
|
||||||
|
case CLR80COL:
|
||||||
|
// CLR80COL not implemented
|
||||||
|
return
|
||||||
|
case SET80COL:
|
||||||
|
// SET80COL not implemented
|
||||||
|
case CLRC3ROM:
|
||||||
|
// CLRC3ROM not implemented
|
||||||
|
case SETC3ROM:
|
||||||
|
// SETC3ROM not implemented
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("TODO write %04x\n", address))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
89
mmu/mmu.go
89
mmu/mmu.go
@ -3,53 +3,12 @@ package mmu
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"mos6502go/keyboard"
|
|
||||||
"mos6502go/system"
|
"mos6502go/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
const RomPath = "apple2e.rom"
|
const RomPath = "apple2e.rom"
|
||||||
const StackPage = 1
|
const StackPage = 1
|
||||||
|
|
||||||
// https://mirrors.apple2.org.za/apple.cabi.net/Languages.Programming/MemoryMap.IIe.64K.128K.txt
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
var PhysicalMemory struct {
|
var PhysicalMemory struct {
|
||||||
MainMemory [0xc000]uint8
|
MainMemory [0xc000]uint8
|
||||||
UpperROM [0x3000]uint8
|
UpperROM [0x3000]uint8
|
||||||
@ -59,13 +18,19 @@ var PhysicalMemory struct {
|
|||||||
|
|
||||||
var PageTable [0x100][]uint8
|
var PageTable [0x100][]uint8
|
||||||
|
|
||||||
|
var UsingExternalSlotRom bool
|
||||||
|
|
||||||
func MapFirstHalfOfIO() {
|
func MapFirstHalfOfIO() {
|
||||||
|
UsingExternalSlotRom = false
|
||||||
|
|
||||||
for i := 0x1; i < 0x10; i++ {
|
for i := 0x1; i < 0x10; i++ {
|
||||||
PageTable[i+0xc0] = PhysicalMemory.RomC1[i*0x100 : i*0x100+0x100]
|
PageTable[i+0xc0] = PhysicalMemory.RomC1[i*0x100 : i*0x100+0x100]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func MapSecondHalfOfIO() {
|
func MapSecondHalfOfIO() {
|
||||||
|
UsingExternalSlotRom = true
|
||||||
|
|
||||||
for i := 0x1; i < 0x10; i++ {
|
for i := 0x1; i < 0x10; i++ {
|
||||||
PageTable[i+0xc0] = PhysicalMemory.RomC2[i*0x100 : i*0x100+0x100]
|
PageTable[i+0xc0] = PhysicalMemory.RomC2[i*0x100 : i*0x100+0x100]
|
||||||
}
|
}
|
||||||
@ -121,36 +86,25 @@ func InitRAM() {
|
|||||||
PageTable[i] = PhysicalMemory.MainMemory[i*0x100 : i*0x100+0x100]
|
PageTable[i] = PhysicalMemory.MainMemory[i*0x100 : i*0x100+0x100]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UsingExternalSlotRom = true
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadMemory(address uint16) uint8 {
|
func ReadMemory(address uint16) uint8 {
|
||||||
if (address >= 0xc000) && (address < 0xc100) {
|
if (address >= 0xc000) && (address < 0xc100) {
|
||||||
|
return ReadIO(address)
|
||||||
if (address == KEYBOARD) || (address == STROBE) {
|
|
||||||
keyBoardData, strobe := keyboard.Read()
|
|
||||||
if address == KEYBOARD {
|
|
||||||
return keyBoardData
|
|
||||||
} else {
|
} else {
|
||||||
keyboard.ResetStrobe()
|
|
||||||
return strobe
|
|
||||||
}
|
|
||||||
} else if address == RDCXROM {
|
|
||||||
// using external slot ROM not implemented
|
|
||||||
return 0
|
|
||||||
} else if address == RD80VID {
|
|
||||||
// using 80-column display mode not implemented
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("TODO read %04x\n", address)
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return PageTable[address>>8][address&0xff]
|
return PageTable[address>>8][address&0xff]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func WriteMemory(address uint16, value uint8) {
|
func WriteMemory(address uint16, value uint8) {
|
||||||
|
if (address >= 0xc000) && (address < 0xc100) {
|
||||||
|
WriteIO(address, value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if system.RunningInterruptTests && address == 0xbffc {
|
if system.RunningInterruptTests && address == 0xbffc {
|
||||||
oldValue := ReadMemory(address)
|
oldValue := ReadMemory(address)
|
||||||
system.WriteInterruptTestOpenCollector(address, oldValue, value)
|
system.WriteInterruptTestOpenCollector(address, oldValue, value)
|
||||||
@ -158,19 +112,6 @@ func WriteMemory(address uint16, value uint8) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if address >= 0xc000 {
|
|
||||||
if address == STROBE {
|
|
||||||
keyboard.ResetStrobe()
|
|
||||||
} else if address == CLRCXROM {
|
|
||||||
MapFirstHalfOfIO()
|
|
||||||
} else if address == SETCXROM {
|
|
||||||
MapSecondHalfOfIO()
|
|
||||||
} else {
|
|
||||||
fmt.Printf("TODO write %04x\n", address)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PageTable[uint8(address>>8)][uint8(address&0xff)] = value
|
PageTable[uint8(address>>8)][uint8(address&0xff)] = value
|
||||||
|
|
||||||
if system.RunningFunctionalTests && address == 0x200 {
|
if system.RunningFunctionalTests && address == 0x200 {
|
||||||
|
Loading…
Reference in New Issue
Block a user