mirror of
https://github.com/freewilll/apple2-go.git
synced 2024-06-08 06:29:28 +00:00
Added comments to mmu package
This commit is contained in:
parent
b549d0e33d
commit
5e330c1373
|
@ -898,7 +898,7 @@ func SetColdStartReset() {
|
||||||
|
|
||||||
// Reset sets the CPU and memory states so that a next call to cpu.Run() calls the firmware reset code
|
// Reset sets the CPU and memory states so that a next call to cpu.Run() calls the firmware reset code
|
||||||
func Reset() {
|
func Reset() {
|
||||||
mmu.InitROM()
|
mmu.InitROM() // Set upper memory area for reading from ROM
|
||||||
mmu.InitRAM()
|
mmu.InitRAM()
|
||||||
|
|
||||||
bootVector := 0xfffc
|
bootVector := 0xfffc
|
||||||
|
|
118
mmu/io.go
118
mmu/io.go
|
@ -93,6 +93,13 @@ const (
|
||||||
S6Q7H = 0xC0EF // write
|
S6Q7H = 0xC0EF // write
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// VideoState has 3 booleans which determine the video configuration:
|
||||||
|
// TextMode HiresMode Mixed
|
||||||
|
// text 1 0 N/A
|
||||||
|
// lores + text 0 0 1
|
||||||
|
// lores 0 0 0
|
||||||
|
// hires N/A 1 0
|
||||||
|
// hires + text N/A 1 1
|
||||||
var VideoState struct {
|
var VideoState struct {
|
||||||
TextMode bool
|
TextMode bool
|
||||||
HiresMode bool
|
HiresMode bool
|
||||||
|
@ -113,6 +120,7 @@ func InitIO() {
|
||||||
system.DriveState.Q6 = false
|
system.DriveState.Q6 = false
|
||||||
system.DriveState.Q7 = false
|
system.DriveState.Q7 = false
|
||||||
|
|
||||||
|
// Initialize video
|
||||||
VideoState.TextMode = true
|
VideoState.TextMode = true
|
||||||
VideoState.HiresMode = false
|
VideoState.HiresMode = false
|
||||||
VideoState.Mixed = false
|
VideoState.Mixed = false
|
||||||
|
@ -120,12 +128,8 @@ func InitIO() {
|
||||||
disk.InitDiskImage()
|
disk.InitDiskImage()
|
||||||
}
|
}
|
||||||
|
|
||||||
func driveIsreadSequencing() bool {
|
// Handle soft switch addresses between $c000-$c0ff where both a read and a write has a side
|
||||||
return (!system.DriveState.Q6) && (!system.DriveState.Q7)
|
// effect. Returns true if the read/write has been handled.
|
||||||
}
|
|
||||||
|
|
||||||
// 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, isRead bool) bool {
|
func readWrite(address uint16, isRead bool) bool {
|
||||||
lsb := address & 0xff
|
lsb := address & 0xff
|
||||||
if lsb >= 0x80 && lsb < 0x90 {
|
if lsb >= 0x80 && lsb < 0x90 {
|
||||||
|
@ -140,48 +144,56 @@ func readWrite(address uint16, isRead bool) bool {
|
||||||
case SETAUXRD:
|
case SETAUXRD:
|
||||||
SetFakeAuxMemoryRead(true)
|
SetFakeAuxMemoryRead(true)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case CLRAUXWR:
|
case CLRAUXWR:
|
||||||
SetFakeAuxMemoryWrite(false)
|
SetFakeAuxMemoryWrite(false)
|
||||||
return true
|
return true
|
||||||
case SETAUXWR:
|
case SETAUXWR:
|
||||||
SetFakeAuxMemoryWrite(true)
|
SetFakeAuxMemoryWrite(true)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case CLRAUXZP:
|
case CLRAUXZP:
|
||||||
SetFakeAltZP(false)
|
SetFakeAltZP(false)
|
||||||
return true
|
return true
|
||||||
case SETAUXZP:
|
case SETAUXZP:
|
||||||
SetFakeAltZP(true)
|
SetFakeAltZP(true)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case CLR80VID:
|
case CLR80VID:
|
||||||
SetCol80(false)
|
SetCol80(false)
|
||||||
return true
|
return true
|
||||||
case SET80VID:
|
case SET80VID:
|
||||||
SetCol80(true)
|
SetCol80(true)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case TXTPAGE1:
|
case TXTPAGE1:
|
||||||
SetPage2(false)
|
SetPage2(false)
|
||||||
return true
|
return true
|
||||||
case TXTPAGE2:
|
case TXTPAGE2:
|
||||||
SetPage2(true)
|
SetPage2(true)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case CLRTEXT:
|
case CLRTEXT:
|
||||||
VideoState.TextMode = false
|
VideoState.TextMode = false
|
||||||
return true
|
return true
|
||||||
case SETTEXT:
|
case SETTEXT:
|
||||||
VideoState.TextMode = true
|
VideoState.TextMode = true
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case CLRMIXED:
|
case CLRMIXED:
|
||||||
VideoState.Mixed = false
|
VideoState.Mixed = false
|
||||||
return true
|
return true
|
||||||
case SETMIXED:
|
case SETMIXED:
|
||||||
VideoState.Mixed = true
|
VideoState.Mixed = true
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case CLRHIRES:
|
case CLRHIRES:
|
||||||
VideoState.HiresMode = false
|
VideoState.HiresMode = false
|
||||||
return true
|
return true
|
||||||
case SETHIRES:
|
case SETHIRES:
|
||||||
VideoState.HiresMode = true
|
VideoState.HiresMode = true
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case CLR80COL:
|
case CLR80COL:
|
||||||
if !isRead {
|
if !isRead {
|
||||||
SetStore80(false)
|
SetStore80(false)
|
||||||
|
@ -192,6 +204,7 @@ func readWrite(address uint16, isRead bool) bool {
|
||||||
case SET80COL:
|
case SET80COL:
|
||||||
SetStore80(true)
|
SetStore80(true)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case STATEREG:
|
case STATEREG:
|
||||||
// Ignore not implemented memory management reg
|
// Ignore not implemented memory management reg
|
||||||
return true
|
return true
|
||||||
|
@ -200,37 +213,40 @@ func readWrite(address uint16, isRead bool) bool {
|
||||||
case S6CLRDRVP0, S6SETDRVP0, S6CLRDRVP1, S6SETDRVP1, S6CLRDRVP2, S6SETDRVP2, S6CLRDRVP3, S6SETDRVP3:
|
case S6CLRDRVP0, S6SETDRVP0, S6CLRDRVP1, S6SETDRVP1, S6CLRDRVP2, S6SETDRVP2, S6CLRDRVP3, S6SETDRVP3:
|
||||||
magnet := (address - S6CLRDRVP0) / 2
|
magnet := (address - S6CLRDRVP0) / 2
|
||||||
on := ((address - S6CLRDRVP0) % 2) == 1
|
on := ((address - S6CLRDRVP0) % 2) == 1
|
||||||
|
if !on {
|
||||||
if on {
|
// Turn off the magnet in Phases
|
||||||
system.DriveState.Phases |= (1 << magnet)
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
if (system.DriveState.Phases & (1 << uint8((system.DriveState.Phase+3)&3))) != 0 {
|
|
||||||
direction -= 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if direction != 0 {
|
|
||||||
system.DriveState.Phase += direction
|
|
||||||
|
|
||||||
if system.DriveState.Phase < 0 {
|
|
||||||
system.DriveState.Phase = 0
|
|
||||||
}
|
|
||||||
if system.DriveState.Phase == 80 {
|
|
||||||
system.DriveState.Phase = 79
|
|
||||||
}
|
|
||||||
|
|
||||||
disk.MakeTrackData(uint8(system.DriveState.Phase))
|
|
||||||
|
|
||||||
if audio.ClickWhenDriveHeadMoves {
|
|
||||||
audio.Click()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
system.DriveState.Phases &= ^(1 << magnet)
|
system.DriveState.Phases &= ^(1 << magnet)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implicit else, a magnet has been switched on
|
||||||
|
system.DriveState.Phases |= (1 << magnet)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
if (system.DriveState.Phases & (1 << uint8((system.DriveState.Phase+3)&3))) != 0 {
|
||||||
|
direction -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the head
|
||||||
|
if direction != 0 {
|
||||||
|
system.DriveState.Phase += direction
|
||||||
|
|
||||||
|
if system.DriveState.Phase < 0 {
|
||||||
|
system.DriveState.Phase = 0
|
||||||
|
}
|
||||||
|
if system.DriveState.Phase == 80 {
|
||||||
|
system.DriveState.Phase = 79
|
||||||
|
}
|
||||||
|
|
||||||
|
disk.MakeTrackData(uint8(system.DriveState.Phase))
|
||||||
|
|
||||||
|
if audio.ClickWhenDriveHeadMoves {
|
||||||
|
audio.Click()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -241,12 +257,14 @@ func readWrite(address uint16, isRead bool) bool {
|
||||||
case S6MOTORON:
|
case S6MOTORON:
|
||||||
system.DriveState.Spinning = true
|
system.DriveState.Spinning = true
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case S6SELDRV1:
|
case S6SELDRV1:
|
||||||
system.DriveState.Drive = 1
|
system.DriveState.Drive = 1
|
||||||
return true
|
return true
|
||||||
case S6SELDRV2:
|
case S6SELDRV2:
|
||||||
system.DriveState.Drive = 2
|
system.DriveState.Drive = 2
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case S6Q6L:
|
case S6Q6L:
|
||||||
if !isRead {
|
if !isRead {
|
||||||
system.DriveState.Q6 = false
|
system.DriveState.Q6 = false
|
||||||
|
@ -259,6 +277,7 @@ func readWrite(address uint16, isRead bool) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
||||||
case S6Q7L:
|
case S6Q7L:
|
||||||
system.DriveState.Q7 = false
|
system.DriveState.Q7 = false
|
||||||
return true
|
return true
|
||||||
|
@ -271,12 +290,15 @@ func readWrite(address uint16, isRead bool) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadIO does a read in the $c000-$c0ff area
|
||||||
func ReadIO(address uint16) uint8 {
|
func ReadIO(address uint16) uint8 {
|
||||||
|
// Try the generic readWrite and return if it has handled the read
|
||||||
if readWrite(address, true) {
|
if readWrite(address, true) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
switch address {
|
switch address {
|
||||||
|
|
||||||
case KEYBOARD, STROBE:
|
case KEYBOARD, STROBE:
|
||||||
keyBoardData, strobe := keyboard.Read()
|
keyBoardData, strobe := keyboard.Read()
|
||||||
if address == KEYBOARD {
|
if address == KEYBOARD {
|
||||||
|
@ -285,15 +307,18 @@ func ReadIO(address uint16) uint8 {
|
||||||
keyboard.ResetStrobe()
|
keyboard.ResetStrobe()
|
||||||
return strobe
|
return strobe
|
||||||
}
|
}
|
||||||
|
|
||||||
case RDRAMRD, RDRAMWR, RDAUXZP:
|
case RDRAMRD, RDRAMWR, RDAUXZP:
|
||||||
panic("Read/write aux memory not implemented")
|
panic("Read/write aux memory not implemented")
|
||||||
return 0x0d
|
return 0x0d
|
||||||
|
|
||||||
case RDCXROM:
|
case RDCXROM:
|
||||||
if UsingExternalSlotRom {
|
if UsingExternalSlotRom {
|
||||||
return 0x8d
|
return 0x8d
|
||||||
} else {
|
} else {
|
||||||
return 0x0d
|
return 0x0d
|
||||||
}
|
}
|
||||||
|
|
||||||
case RD80VID:
|
case RD80VID:
|
||||||
// using 80-column display mode not implemented
|
// using 80-column display mode not implemented
|
||||||
return 0x0d
|
return 0x0d
|
||||||
|
@ -308,24 +333,33 @@ func ReadIO(address uint16) uint8 {
|
||||||
// 4-bit annunciator inputs
|
// 4-bit annunciator inputs
|
||||||
case SETAN0, CLRAN0, SETAN1, CLRAN1, SETAN2, CLRAN2, SETAN3, CLRAN3:
|
case SETAN0, CLRAN0, SETAN1, CLRAN1, SETAN2, CLRAN2, SETAN3, CLRAN3:
|
||||||
// Annunciators not implemented
|
// Annunciators not implemented
|
||||||
|
|
||||||
case OPNAPPLE:
|
case OPNAPPLE:
|
||||||
// Open apple key not implemented
|
// Open apple key not implemented
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
case CLSAPPLE:
|
case CLSAPPLE:
|
||||||
// Closed apple key not implemented
|
// Closed apple key not implemented
|
||||||
|
|
||||||
case RD80COL:
|
case RD80COL:
|
||||||
if Store80 {
|
if Store80 {
|
||||||
return 0x8d
|
return 0x8d
|
||||||
} else {
|
} else {
|
||||||
return 0x0d
|
return 0x0d
|
||||||
}
|
}
|
||||||
|
|
||||||
case RDALTCH:
|
case RDALTCH:
|
||||||
// RDALTCH not implemented
|
// RDALTCH not implemented, but it's also used, so don't fail on it.
|
||||||
return 0x0d
|
return 0x0d
|
||||||
|
|
||||||
case SPEAKER:
|
case SPEAKER:
|
||||||
audio.Click()
|
audio.Click()
|
||||||
|
return 0
|
||||||
|
|
||||||
case S6Q6L:
|
case S6Q6L:
|
||||||
|
// A read from disk
|
||||||
return disk.ReadTrackData()
|
return disk.ReadTrackData()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("TODO read %04x\n", address))
|
panic(fmt.Sprintf("TODO read %04x\n", address))
|
||||||
}
|
}
|
||||||
|
@ -333,31 +367,41 @@ func ReadIO(address uint16) uint8 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadIO does a write in the $c000-$c0ff area
|
||||||
func WriteIO(address uint16, value uint8) {
|
func WriteIO(address uint16, value uint8) {
|
||||||
|
// Try the generic readWrite and return if it has handled the write
|
||||||
if readWrite(address, false) {
|
if readWrite(address, false) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch address {
|
switch address {
|
||||||
|
|
||||||
case STROBE:
|
case STROBE:
|
||||||
keyboard.ResetStrobe()
|
keyboard.ResetStrobe()
|
||||||
|
|
||||||
case CLRCXROM:
|
case CLRCXROM:
|
||||||
MapFirstHalfOfIO()
|
MapFirstHalfOfIO()
|
||||||
case SETCXROM:
|
case SETCXROM:
|
||||||
MapSecondHalfOfIO()
|
MapSecondHalfOfIO()
|
||||||
|
|
||||||
case CLRALTCH:
|
case CLRALTCH:
|
||||||
return
|
return
|
||||||
case SETALTCH:
|
case SETALTCH:
|
||||||
panic("SETALTCH not implemented")
|
panic("SETALTCH not implemented")
|
||||||
|
|
||||||
case CLR80COL:
|
case CLR80COL:
|
||||||
// CLR80COL not implemented
|
// CLR80COL not implemented
|
||||||
return
|
return
|
||||||
|
|
||||||
case CLRC3ROM:
|
case CLRC3ROM:
|
||||||
// CLRC3ROM not implemented
|
// CLRC3ROM not implemented
|
||||||
case SETC3ROM:
|
case SETC3ROM:
|
||||||
// SETC3ROM not implemented
|
// SETC3ROM not implemented
|
||||||
|
|
||||||
case S6Q6H:
|
case S6Q6H:
|
||||||
|
// A write to disk
|
||||||
disk.WriteTrackData(value)
|
disk.WriteTrackData(value)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("TODO write %04x\n", address))
|
panic(fmt.Sprintf("TODO write %04x\n", address))
|
||||||
}
|
}
|
||||||
|
|
36
mmu/mmu.go
36
mmu/mmu.go
|
@ -7,16 +7,18 @@ import (
|
||||||
"github.com/freewilll/apple2/system"
|
"github.com/freewilll/apple2/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
const RomPath = "apple2e.rom"
|
const RomPath = "apple2e.rom" // So far only one ROM is supported and it's loaded at startup
|
||||||
const StackPage = 1
|
const StackPage = 1 // The 6502 stack is at 0x100
|
||||||
|
|
||||||
|
// PhysicalMemory contains all the unmapped memory, ROM and RAM
|
||||||
var PhysicalMemory struct {
|
var PhysicalMemory struct {
|
||||||
MainMemory [0x10000]uint8
|
MainMemory [0x10000]uint8 // Main RAM
|
||||||
UpperROM [0x3000]uint8
|
UpperROM [0x3000]uint8 // $c000-$ffff ROM area
|
||||||
RomC1 [0x1000]uint8
|
RomC1 [0x1000]uint8 // First half of IO ROM
|
||||||
RomC2 [0x1000]uint8
|
RomC2 [0x1000]uint8 // Second half of IO ROM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Page tables for read & write
|
||||||
var ReadPageTable [0x100][]uint8
|
var ReadPageTable [0x100][]uint8
|
||||||
var WritePageTable [0x100][]uint8
|
var WritePageTable [0x100][]uint8
|
||||||
|
|
||||||
|
@ -35,6 +37,7 @@ var (
|
||||||
Page2 bool // Main memory Page2 is selected
|
Page2 bool // Main memory Page2 is selected
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Make page tables for current RAM, ROM and IO configuration
|
||||||
func ApplyMemoryConfiguration() {
|
func ApplyMemoryConfiguration() {
|
||||||
// Map main RAM for read/write
|
// Map main RAM for read/write
|
||||||
for i := 0x0; i < 0xc0; i++ {
|
for i := 0x0; i < 0xc0; i++ {
|
||||||
|
@ -102,7 +105,7 @@ func MapSecondHalfOfIO() {
|
||||||
ApplyMemoryConfiguration()
|
ApplyMemoryConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
// emptySlot zeroes all RAM for a slot
|
// emptySlot zeroes all RAM for a slot, effectively disabling the slot
|
||||||
func emptySlot(slot int) {
|
func emptySlot(slot int) {
|
||||||
for i := slot * 0x100; i < (slot+1)*0x100; i++ {
|
for i := slot * 0x100; i < (slot+1)*0x100; i++ {
|
||||||
PhysicalMemory.RomC1[i] = 0
|
PhysicalMemory.RomC1[i] = 0
|
||||||
|
@ -134,6 +137,7 @@ func InitApple2eROM() {
|
||||||
InitROM() // Map 0xd000-0xffff for reading
|
InitROM() // Map 0xd000-0xffff for reading
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set upper memory area for reading from ROM
|
||||||
func InitROM() {
|
func InitROM() {
|
||||||
UpperReadMappedToROM = true
|
UpperReadMappedToROM = true
|
||||||
ApplyMemoryConfiguration()
|
ApplyMemoryConfiguration()
|
||||||
|
@ -149,31 +153,39 @@ func SetUpperRamReadOnly(value bool) {
|
||||||
ApplyMemoryConfiguration()
|
ApplyMemoryConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set d000 bank to map to $c000 or $d000 in the physical memory
|
||||||
func SetD000Bank(value int) {
|
func SetD000Bank(value int) {
|
||||||
D000Bank = value
|
D000Bank = value
|
||||||
ApplyMemoryConfiguration()
|
ApplyMemoryConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
func SetFakeAuxMemoryRead(value bool) {
|
||||||
FakeAuxMemoryRead = value
|
FakeAuxMemoryRead = value
|
||||||
ApplyMemoryConfiguration()
|
ApplyMemoryConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
func SetFakeAuxMemoryWrite(value bool) {
|
||||||
FakeAuxMemoryWrite = value
|
FakeAuxMemoryWrite = value
|
||||||
ApplyMemoryConfiguration()
|
ApplyMemoryConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Alternate zero page isn't implemented
|
||||||
func SetFakeAltZP(value bool) {
|
func SetFakeAltZP(value bool) {
|
||||||
FakeAltZP = value
|
FakeAltZP = value
|
||||||
ApplyMemoryConfiguration()
|
ApplyMemoryConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 80 column card isn't implemented
|
||||||
func SetCol80(value bool) {
|
func SetCol80(value bool) {
|
||||||
Col80 = value
|
Col80 = value
|
||||||
// No changes are needed when this is toggled
|
// No changes are needed when this is toggled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Page switching is only implemented for the main memory
|
||||||
func SetPage2(value bool) {
|
func SetPage2(value bool) {
|
||||||
// If the 80 column card is enabled, then this toggles aux memory
|
// If the 80 column card is enabled, then this toggles aux memory
|
||||||
// Otherwise, page1/page2 is toggled in the main memory
|
// Otherwise, page1/page2 is toggled in the main memory
|
||||||
|
@ -185,12 +197,14 @@ func SetPage2(value bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 80 column card isn't implemented
|
||||||
func SetStore80(value bool) {
|
func SetStore80(value bool) {
|
||||||
Store80 = value
|
Store80 = value
|
||||||
FakePage2 = value
|
FakePage2 = value
|
||||||
ApplyMemoryConfiguration()
|
ApplyMemoryConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InitRAM sets all default RAM memory settings and resets the page tables
|
||||||
func InitRAM() {
|
func InitRAM() {
|
||||||
UpperRamReadOnly = false
|
UpperRamReadOnly = false
|
||||||
D000Bank = 2
|
D000Bank = 2
|
||||||
|
@ -209,6 +223,7 @@ func WipeRAM() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetMemoryMode is used to set UpperRamReadOnly, UpperReadMappedToROM and D000Bank number
|
||||||
func SetMemoryMode(mode uint8) {
|
func SetMemoryMode(mode uint8) {
|
||||||
// mode corresponds to a read/write to $c080 with
|
// mode corresponds to a read/write to $c080 with
|
||||||
// $c080 mode=$00
|
// $c080 mode=$00
|
||||||
|
@ -236,6 +251,7 @@ func SetMemoryMode(mode uint8) {
|
||||||
ApplyMemoryConfiguration()
|
ApplyMemoryConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadMemory reads the ROM or RAM page table
|
||||||
func ReadMemory(address uint16) uint8 {
|
func ReadMemory(address uint16) uint8 {
|
||||||
if (address >= 0xc000) && (address < 0xc100) {
|
if (address >= 0xc000) && (address < 0xc100) {
|
||||||
return ReadIO(address)
|
return ReadIO(address)
|
||||||
|
@ -257,15 +273,18 @@ func ReadMemory(address uint16) uint8 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implicit else, we're reading the main non-IO RAM
|
||||||
return ReadPageTable[address>>8][address&0xff]
|
return ReadPageTable[address>>8][address&0xff]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadMemory writes to the ROM or RAM page table
|
||||||
func WriteMemory(address uint16, value uint8) {
|
func WriteMemory(address uint16, value uint8) {
|
||||||
if (address >= 0xc000) && (address < 0xc100) {
|
if (address >= 0xc000) && (address < 0xc100) {
|
||||||
WriteIO(address, value)
|
WriteIO(address, value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Magic routine to trigger an interrupt, used in the CPU interrupt tests
|
||||||
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)
|
||||||
|
@ -284,11 +303,14 @@ func WriteMemory(address uint16, value uint8) {
|
||||||
}
|
}
|
||||||
|
|
||||||
memory := WritePageTable[address>>8]
|
memory := WritePageTable[address>>8]
|
||||||
|
|
||||||
// If memory is nil, then it's read only. The write is ignored.
|
// If memory is nil, then it's read only. The write is ignored.
|
||||||
if memory != nil {
|
if memory != nil {
|
||||||
memory[uint8(address&0xff)] = value
|
memory[uint8(address&0xff)] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If doing CPU functional tests, 0x200 has the test number in it. A write to
|
||||||
|
// it means a test passed or the tests are complete.
|
||||||
if system.RunningFunctionalTests && address == 0x200 {
|
if system.RunningFunctionalTests && address == 0x200 {
|
||||||
testNumber := ReadMemory(0x200)
|
testNumber := ReadMemory(0x200)
|
||||||
if testNumber == 0xf0 {
|
if testNumber == 0xf0 {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user