mirror of
https://github.com/freewilll/apple2-go.git
synced 2024-09-27 01:55:21 +00:00
Added bank switched upper memory
This commit is contained in:
parent
a43fd7c08c
commit
f1dff51564
109
bank_switch_test.go
Normal file
109
bank_switch_test.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mos6502go/cpu"
|
||||||
|
"mos6502go/keyboard"
|
||||||
|
"mos6502go/mmu"
|
||||||
|
"mos6502go/system"
|
||||||
|
"mos6502go/video"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBankSwitching(t *testing.T) {
|
||||||
|
cpu.InitInstructionDecoder()
|
||||||
|
mmu.InitRAM()
|
||||||
|
mmu.InitApple2eROM()
|
||||||
|
mmu.InitIO()
|
||||||
|
cpu.Init()
|
||||||
|
keyboard.Init()
|
||||||
|
video.Init()
|
||||||
|
system.Init()
|
||||||
|
cpu.SetColdStartReset()
|
||||||
|
cpu.Reset()
|
||||||
|
|
||||||
|
// Sanity test that what we expect from the apple //e ROM is correct
|
||||||
|
assert.Equal(t, uint8(0x6f), mmu.ReadMemory(0xd000)) // read from ROM
|
||||||
|
assert.Equal(t, uint8(0xc3), mmu.ReadMemory(0xffff)) // read from ROM
|
||||||
|
|
||||||
|
// Verify ROM & RAM settings at startup
|
||||||
|
mmu.WipeRAM()
|
||||||
|
assert.Equal(t, uint8(0xc3), mmu.ReadMemory(0xffff)) // read from ROM
|
||||||
|
mmu.WriteMemory(0xffff, 0xff) // write to $ffff
|
||||||
|
assert.Equal(t, uint8(0xc3), mmu.ReadMemory(0xffff)) // ROM value is the same
|
||||||
|
assert.Equal(t, uint8(0xff), mmu.PhysicalMemory.MainMemory[0xffff]) // RAM has been updated
|
||||||
|
mmu.WriteMemory(0xd000, 0xfe) // write to $d000
|
||||||
|
assert.Equal(t, uint8(0x00), mmu.PhysicalMemory.MainMemory[0xc000]) // bank #1 RAM
|
||||||
|
assert.Equal(t, uint8(0xfe), mmu.PhysicalMemory.MainMemory[0xd000]) // bank #2 RAM
|
||||||
|
|
||||||
|
// Switch bank to 1, write and check physical memory
|
||||||
|
mmu.SetD000Bank(1)
|
||||||
|
mmu.SetUpperReadMappedToROM(false)
|
||||||
|
mmu.WriteMemory(0xd000, 0xfd) // write to $d000
|
||||||
|
assert.Equal(t, uint8(0xfd), mmu.PhysicalMemory.MainMemory[0xc000]) // bank #1 RAM
|
||||||
|
assert.Equal(t, uint8(0xfe), mmu.PhysicalMemory.MainMemory[0xd000]) // bank #2 RAM
|
||||||
|
|
||||||
|
// Enable RAM area for reading and check values
|
||||||
|
mmu.SetUpperReadMappedToROM(false)
|
||||||
|
assert.Equal(t, uint8(0xfd), mmu.ReadMemory(0xd000)) // read from bank #1 RAM
|
||||||
|
mmu.SetD000Bank(2)
|
||||||
|
assert.Equal(t, uint8(0xfe), mmu.ReadMemory(0xd000)) // read from bank #1 RAM
|
||||||
|
|
||||||
|
// Enable ROM area for reading and check values
|
||||||
|
mmu.SetUpperReadMappedToROM(true)
|
||||||
|
assert.Equal(t, uint8(0x6f), mmu.ReadMemory(0xd000)) // read from ROM
|
||||||
|
assert.Equal(t, uint8(0xc3), mmu.ReadMemory(0xffff)) // read from ROM
|
||||||
|
|
||||||
|
// Set d000 RAM to bank 1, RAM to read only and attempt writes
|
||||||
|
mmu.SetD000Bank(1)
|
||||||
|
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
|
||||||
|
mmu.WriteMemory(0xffff, 0x02) // attempt to write to read only RAM
|
||||||
|
assert.Equal(t, uint8(0xfd), mmu.PhysicalMemory.MainMemory[0xc000]) // bank #1 RAM is unchanged
|
||||||
|
assert.Equal(t, uint8(0xfe), mmu.PhysicalMemory.MainMemory[0xd000]) // bank #2 RAM is unchanged
|
||||||
|
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.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
|
||||||
|
assert.Equal(t, uint8(0xfe), mmu.PhysicalMemory.MainMemory[0xd000]) // bank #2 RAM is untouched
|
||||||
|
assert.Equal(t, uint8(0xfb), mmu.PhysicalMemory.MainMemory[0xffff]) // top of RAM has been updated
|
||||||
|
|
||||||
|
// Enable ROM area for reading and check values
|
||||||
|
mmu.SetUpperReadMappedToROM(true)
|
||||||
|
assert.Equal(t, uint8(0x6f), mmu.ReadMemory(0xd000)) // read from ROM
|
||||||
|
assert.Equal(t, uint8(0xc3), mmu.ReadMemory(0xffff)) // read from ROM
|
||||||
|
|
||||||
|
testSwitches(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
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, upperReadMappedToROM, mmu.UpperReadMappedToROM)
|
||||||
|
assert.Equal(t, d000Bank, mmu.D000Bank)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSwitches(t *testing.T) {
|
||||||
|
assertMemoryConfiguration(t, 0xc080, true, false, 2)
|
||||||
|
assertMemoryConfiguration(t, 0xc081, false, true, 2)
|
||||||
|
assertMemoryConfiguration(t, 0xc082, true, true, 2)
|
||||||
|
assertMemoryConfiguration(t, 0xc083, false, false, 2)
|
||||||
|
assertMemoryConfiguration(t, 0xc084, true, false, 2)
|
||||||
|
assertMemoryConfiguration(t, 0xc085, false, true, 2)
|
||||||
|
assertMemoryConfiguration(t, 0xc086, true, true, 2)
|
||||||
|
assertMemoryConfiguration(t, 0xc087, false, false, 2)
|
||||||
|
assertMemoryConfiguration(t, 0xc088, true, false, 1)
|
||||||
|
assertMemoryConfiguration(t, 0xc089, false, true, 1)
|
||||||
|
assertMemoryConfiguration(t, 0xc08a, true, true, 1)
|
||||||
|
assertMemoryConfiguration(t, 0xc08b, false, false, 1)
|
||||||
|
assertMemoryConfiguration(t, 0xc08c, true, false, 1)
|
||||||
|
assertMemoryConfiguration(t, 0xc08d, false, true, 1)
|
||||||
|
assertMemoryConfiguration(t, 0xc08e, true, true, 1)
|
||||||
|
assertMemoryConfiguration(t, 0xc08f, false, false, 1)
|
||||||
|
}
|
19
cpu/cpu.go
19
cpu/cpu.go
@ -94,14 +94,14 @@ func isN() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func push8(value uint8) {
|
func push8(value uint8) {
|
||||||
mmu.PageTable[mmu.StackPage][State.SP] = value
|
mmu.WritePageTable[mmu.StackPage][State.SP] = value
|
||||||
State.SP -= 1
|
State.SP -= 1
|
||||||
State.SP &= 0xff
|
State.SP &= 0xff
|
||||||
}
|
}
|
||||||
|
|
||||||
func push16(value uint16) {
|
func push16(value uint16) {
|
||||||
mmu.PageTable[mmu.StackPage][State.SP] = uint8(value >> 8)
|
mmu.WritePageTable[mmu.StackPage][State.SP] = uint8(value >> 8)
|
||||||
mmu.PageTable[mmu.StackPage][State.SP-1] = uint8(value & 0xff)
|
mmu.WritePageTable[mmu.StackPage][State.SP-1] = uint8(value & 0xff)
|
||||||
State.SP -= 2
|
State.SP -= 2
|
||||||
State.SP &= 0xff
|
State.SP &= 0xff
|
||||||
}
|
}
|
||||||
@ -109,14 +109,14 @@ func push16(value uint16) {
|
|||||||
func pop8() uint8 {
|
func pop8() uint8 {
|
||||||
State.SP += 1
|
State.SP += 1
|
||||||
State.SP &= 0xff
|
State.SP &= 0xff
|
||||||
return mmu.PageTable[mmu.StackPage][State.SP]
|
return mmu.ReadPageTable[mmu.StackPage][State.SP]
|
||||||
}
|
}
|
||||||
|
|
||||||
func pop16() uint16 {
|
func pop16() uint16 {
|
||||||
State.SP += 2
|
State.SP += 2
|
||||||
State.SP &= 0xff
|
State.SP &= 0xff
|
||||||
msb := uint16(mmu.PageTable[mmu.StackPage][State.SP])
|
msb := uint16(mmu.ReadPageTable[mmu.StackPage][State.SP])
|
||||||
lsb := uint16(mmu.PageTable[mmu.StackPage][State.SP-1])
|
lsb := uint16(mmu.ReadPageTable[mmu.StackPage][State.SP-1])
|
||||||
return lsb + msb<<8
|
return lsb + msb<<8
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -864,8 +864,11 @@ func SetColdStartReset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Reset() {
|
func Reset() {
|
||||||
|
mmu.InitROM()
|
||||||
|
mmu.InitRAM()
|
||||||
|
|
||||||
bootVector := 0xfffc
|
bootVector := 0xfffc
|
||||||
lsb := mmu.PageTable[bootVector>>8][bootVector&0xff] // TODO move readMemory to mmu
|
lsb := mmu.ReadPageTable[bootVector>>8][bootVector&0xff]
|
||||||
msb := mmu.PageTable[(bootVector+1)>>8][(bootVector+1)&0xff]
|
msb := mmu.ReadPageTable[(bootVector+1)>>8][(bootVector+1)&0xff]
|
||||||
State.PC = uint16(lsb) + uint16(msb)<<8
|
State.PC = uint16(lsb) + uint16(msb)<<8
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,8 @@ func TestCPU(t *testing.T) {
|
|||||||
RomPretendingToBeRAM[i] = bytes[0xc000+i]
|
RomPretendingToBeRAM[i] = bytes[0xc000+i]
|
||||||
}
|
}
|
||||||
for i := 0x0; i < 0x40; i++ {
|
for i := 0x0; i < 0x40; i++ {
|
||||||
mmu.PageTable[0xc0+i] = RomPretendingToBeRAM[i*0x100 : i*0x100+0x100]
|
mmu.ReadPageTable[0xc0+i] = RomPretendingToBeRAM[i*0x100 : i*0x100+0x100]
|
||||||
|
mmu.WritePageTable[0xc0+i] = RomPretendingToBeRAM[i*0x100 : i*0x100+0x100]
|
||||||
}
|
}
|
||||||
|
|
||||||
keyboard.Init()
|
keyboard.Init()
|
||||||
|
14
cpu/debug.go
14
cpu/debug.go
@ -40,7 +40,7 @@ func printInstruction(instruction string, showRegisters bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func PrintInstruction(showRegisters bool) {
|
func PrintInstruction(showRegisters bool) {
|
||||||
opcodeValue := mmu.PageTable[(State.PC)>>8][(State.PC)&0xff]
|
opcodeValue := mmu.ReadPageTable[(State.PC)>>8][(State.PC)&0xff]
|
||||||
opcode := OpCodes[opcodeValue]
|
opcode := OpCodes[opcodeValue]
|
||||||
mnemonic := opcode.Mnemonic
|
mnemonic := opcode.Mnemonic
|
||||||
size := opcode.AddressingMode.OperandSize
|
size := opcode.AddressingMode.OperandSize
|
||||||
@ -56,7 +56,7 @@ func PrintInstruction(showRegisters bool) {
|
|||||||
var suffix string
|
var suffix string
|
||||||
|
|
||||||
if opcode.AddressingMode.Mode == AmRelative {
|
if opcode.AddressingMode.Mode == AmRelative {
|
||||||
value = uint16(mmu.PageTable[(State.PC+1)>>8][(State.PC+1)&0xff])
|
value = uint16(mmu.ReadPageTable[(State.PC+1)>>8][(State.PC+1)&0xff])
|
||||||
var relativeAddress uint16
|
var relativeAddress uint16
|
||||||
if (value & 0x80) == 0 {
|
if (value & 0x80) == 0 {
|
||||||
relativeAddress = State.PC + 2 + uint16(value)
|
relativeAddress = State.PC + 2 + uint16(value)
|
||||||
@ -67,12 +67,12 @@ func PrintInstruction(showRegisters bool) {
|
|||||||
suffix = fmt.Sprintf(stringFormat, relativeAddress)
|
suffix = fmt.Sprintf(stringFormat, relativeAddress)
|
||||||
opcodes = fmt.Sprintf("%02x %02x ", opcodeValue, value)
|
opcodes = fmt.Sprintf("%02x %02x ", opcodeValue, value)
|
||||||
} else if size == 1 {
|
} else if size == 1 {
|
||||||
value = uint16(mmu.PageTable[(State.PC+1)>>8][(State.PC+1)&0xff])
|
value = uint16(mmu.ReadPageTable[(State.PC+1)>>8][(State.PC+1)&0xff])
|
||||||
suffix = fmt.Sprintf(stringFormat, value)
|
suffix = fmt.Sprintf(stringFormat, value)
|
||||||
opcodes = fmt.Sprintf("%02x %02x ", opcodeValue, value)
|
opcodes = fmt.Sprintf("%02x %02x ", opcodeValue, value)
|
||||||
} else if size == 2 {
|
} else if size == 2 {
|
||||||
lsb := mmu.PageTable[(State.PC+1)>>8][(State.PC+1)&0xff]
|
lsb := mmu.ReadPageTable[(State.PC+1)>>8][(State.PC+1)&0xff]
|
||||||
msb := mmu.PageTable[(State.PC+2)>>8][(State.PC+2)&0xff]
|
msb := mmu.ReadPageTable[(State.PC+2)>>8][(State.PC+2)&0xff]
|
||||||
value = uint16(lsb) + uint16(msb)*0x100
|
value = uint16(lsb) + uint16(msb)*0x100
|
||||||
suffix = fmt.Sprintf(stringFormat, value)
|
suffix = fmt.Sprintf(stringFormat, value)
|
||||||
opcodes = fmt.Sprintf("%02x %02x %02x ", opcodeValue, lsb, msb)
|
opcodes = fmt.Sprintf("%02x %02x %02x ", opcodeValue, lsb, msb)
|
||||||
@ -82,7 +82,7 @@ func PrintInstruction(showRegisters bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func AdvanceInstruction() {
|
func AdvanceInstruction() {
|
||||||
opcodeValue := mmu.PageTable[(State.PC)>>8][(State.PC)&0xff]
|
opcodeValue := mmu.ReadPageTable[(State.PC)>>8][(State.PC)&0xff]
|
||||||
opcode := OpCodes[opcodeValue]
|
opcode := OpCodes[opcodeValue]
|
||||||
size := opcode.AddressingMode.OperandSize + 1
|
size := opcode.AddressingMode.OperandSize + 1
|
||||||
State.PC += uint16(size)
|
State.PC += uint16(size)
|
||||||
@ -100,7 +100,7 @@ func DumpMemory(offset uint16) {
|
|||||||
}
|
}
|
||||||
fmt.Printf("%04x ", offset+i)
|
fmt.Printf("%04x ", offset+i)
|
||||||
}
|
}
|
||||||
fmt.Printf(" %02x", mmu.PageTable[(offset+i)>>8][(offset+i)&0xff])
|
fmt.Printf(" %02x", mmu.ReadPageTable[(offset+i)>>8][(offset+i)&0xff])
|
||||||
}
|
}
|
||||||
fmt.Print("\n")
|
fmt.Print("\n")
|
||||||
}
|
}
|
||||||
|
30
io_test.go
Normal file
30
io_test.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mos6502go/cpu"
|
||||||
|
"mos6502go/keyboard"
|
||||||
|
"mos6502go/mmu"
|
||||||
|
"mos6502go/system"
|
||||||
|
"mos6502go/video"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIoBankSwitching(t *testing.T) {
|
||||||
|
cpu.InitInstructionDecoder()
|
||||||
|
mmu.InitRAM()
|
||||||
|
mmu.InitApple2eROM()
|
||||||
|
mmu.InitIO()
|
||||||
|
cpu.Init()
|
||||||
|
keyboard.Init()
|
||||||
|
video.Init()
|
||||||
|
system.Init()
|
||||||
|
cpu.SetColdStartReset()
|
||||||
|
cpu.Reset()
|
||||||
|
|
||||||
|
mmu.MapFirstHalfOfIO()
|
||||||
|
assert.Equal(t, uint8(0xa2), mmu.ReadMemory(0xc600)) // read from Primary Slot 6 ROM
|
||||||
|
mmu.MapSecondHalfOfIO()
|
||||||
|
assert.Equal(t, uint8(0x8d), mmu.ReadMemory(0xc600)) // read from Primary Slot 6 ROM
|
||||||
|
}
|
10
mmu/io.go
10
mmu/io.go
@ -67,6 +67,7 @@ const (
|
|||||||
|
|
||||||
OPNAPPLE = 0xC061 // open apple (command) key data
|
OPNAPPLE = 0xC061 // open apple (command) key data
|
||||||
CLSAPPLE = 0xC062 // closed apple (option) key data
|
CLSAPPLE = 0xC062 // closed apple (option) key data
|
||||||
|
STATEREG = 0xC068 // Has no effect on //e
|
||||||
|
|
||||||
PDLTRIG = 0xC070 // trigger paddles
|
PDLTRIG = 0xC070 // trigger paddles
|
||||||
|
|
||||||
@ -134,6 +135,12 @@ func driveIsreadSequencing() bool {
|
|||||||
// Handle soft switch addresses where both a read and a write has a side
|
// Handle soft switch addresses where both a read and a write has a side
|
||||||
// effect and the return value is meaningless
|
// effect and the return value is meaningless
|
||||||
func readWrite(address uint16, isRead bool) bool {
|
func readWrite(address uint16, isRead bool) bool {
|
||||||
|
lsb := address & 0xff
|
||||||
|
if lsb >= 0x80 && lsb < 0x90 {
|
||||||
|
SetMemoryMode(uint8(lsb - 0x80))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
switch address {
|
switch address {
|
||||||
case CLR80VID:
|
case CLR80VID:
|
||||||
// 80 column card hasn't been implemented yet
|
// 80 column card hasn't been implemented yet
|
||||||
@ -162,6 +169,9 @@ func readWrite(address uint16, isRead bool) bool {
|
|||||||
case SETHIRES:
|
case SETHIRES:
|
||||||
VideoState.HiresMode = true
|
VideoState.HiresMode = true
|
||||||
return true
|
return true
|
||||||
|
case STATEREG:
|
||||||
|
// Ignore not implemented memory management reg
|
||||||
|
return true
|
||||||
|
|
||||||
// Drive stepper motor phase change
|
// Drive stepper motor phase change
|
||||||
case S6CLRDRVP0, S6SETDRVP0, S6CLRDRVP1, S6SETDRVP1, S6CLRDRVP2, S6SETDRVP2, S6CLRDRVP3, S6SETDRVP3:
|
case S6CLRDRVP0, S6SETDRVP0, S6CLRDRVP1, S6SETDRVP1, S6CLRDRVP2, S6SETDRVP2, S6CLRDRVP3, S6SETDRVP3:
|
||||||
|
160
mmu/mmu.go
160
mmu/mmu.go
@ -10,30 +10,88 @@ const RomPath = "apple2e.rom"
|
|||||||
const StackPage = 1
|
const StackPage = 1
|
||||||
|
|
||||||
var PhysicalMemory struct {
|
var PhysicalMemory struct {
|
||||||
MainMemory [0xc000]uint8
|
MainMemory [0x10000]uint8
|
||||||
UpperROM [0x3000]uint8
|
UpperROM [0x3000]uint8
|
||||||
RomC1 [0x1000]uint8
|
RomC1 [0x1000]uint8
|
||||||
RomC2 [0x1000]uint8
|
RomC2 [0x1000]uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
var PageTable [0x100][]uint8
|
var ReadPageTable [0x100][]uint8
|
||||||
|
var WritePageTable [0x100][]uint8
|
||||||
|
|
||||||
var UsingExternalSlotRom bool
|
// Memory mapping states
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
func ApplyMemoryConfiguration() {
|
||||||
|
// Map main RAM for read/write
|
||||||
|
for i := 0x0; i < 0xc0; i++ {
|
||||||
|
ReadPageTable[i] = PhysicalMemory.MainMemory[i*0x100 : i*0x100+0x100]
|
||||||
|
WritePageTable[i] = PhysicalMemory.MainMemory[i*0x100 : i*0x100+0x100]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map $c000
|
||||||
|
var ioRom *[0x1000]uint8
|
||||||
|
if UsingExternalSlotRom {
|
||||||
|
ioRom = &PhysicalMemory.RomC2
|
||||||
|
} else {
|
||||||
|
ioRom = &PhysicalMemory.RomC1
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0x1; i < 0x10; i++ {
|
||||||
|
ReadPageTable[0xc0+i] = (*ioRom)[i*0x100 : i*0x100+0x100]
|
||||||
|
WritePageTable[0xc0+i] = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map $d000
|
||||||
|
for i := 0xd0; i < 0xe0; i++ {
|
||||||
|
base := i*0x100 + D000Bank*0x1000 - 0x2000
|
||||||
|
if !UpperReadMappedToROM {
|
||||||
|
ReadPageTable[i] = PhysicalMemory.MainMemory[base : base+0x100]
|
||||||
|
}
|
||||||
|
|
||||||
|
if UpperRamReadOnly {
|
||||||
|
WritePageTable[i] = nil
|
||||||
|
} else {
|
||||||
|
WritePageTable[i] = PhysicalMemory.MainMemory[base : base+0x100]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map 0xe00 to 0xffff
|
||||||
|
for i := 0xe0; i < 0x100; i++ {
|
||||||
|
base := i * 0x100
|
||||||
|
if !UpperReadMappedToROM {
|
||||||
|
ReadPageTable[i] = PhysicalMemory.MainMemory[base : base+0x100]
|
||||||
|
}
|
||||||
|
if UpperRamReadOnly {
|
||||||
|
WritePageTable[i] = nil
|
||||||
|
} else {
|
||||||
|
WritePageTable[i] = PhysicalMemory.MainMemory[base : base+0x100]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if UpperReadMappedToROM {
|
||||||
|
for i := 0x00; i < 0x30; i++ {
|
||||||
|
ReadPageTable[i+0xd0] = PhysicalMemory.UpperROM[i*0x100 : i*0x100+0x100]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map 0xc100-0xcfff for reading from RomC1
|
||||||
func MapFirstHalfOfIO() {
|
func MapFirstHalfOfIO() {
|
||||||
UsingExternalSlotRom = false
|
UsingExternalSlotRom = false
|
||||||
|
ApplyMemoryConfiguration()
|
||||||
for i := 0x1; i < 0x10; i++ {
|
|
||||||
PageTable[i+0xc0] = PhysicalMemory.RomC1[i*0x100 : i*0x100+0x100]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Map 0xc100-0xcfff for reading from RomC2
|
||||||
func MapSecondHalfOfIO() {
|
func MapSecondHalfOfIO() {
|
||||||
UsingExternalSlotRom = true
|
UsingExternalSlotRom = true
|
||||||
|
ApplyMemoryConfiguration()
|
||||||
for i := 0x1; i < 0x10; i++ {
|
|
||||||
PageTable[i+0xc0] = PhysicalMemory.RomC2[i*0x100 : i*0x100+0x100]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// emptySlot zeroes all RAM for a slot
|
// emptySlot zeroes all RAM for a slot
|
||||||
@ -44,7 +102,7 @@ func emptySlot(slot int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func readApple2eROM() {
|
func loadApple2eROM() {
|
||||||
bytes, err := ioutil.ReadFile(RomPath)
|
bytes, err := ioutil.ReadFile(RomPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("Unable to read ROM: %s", err))
|
panic(fmt.Sprintf("Unable to read ROM: %s", err))
|
||||||
@ -63,33 +121,75 @@ func readApple2eROM() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func InitApple2eROM() {
|
func InitApple2eROM() {
|
||||||
readApple2eROM()
|
loadApple2eROM()
|
||||||
|
MapFirstHalfOfIO() // Map 0xc100-0xcfff for reading
|
||||||
// Map 0xc100-0xcfff
|
InitROM() // Map 0xd000-0xffff for reading
|
||||||
MapFirstHalfOfIO()
|
|
||||||
|
|
||||||
// Map 0xd000-0xffff
|
|
||||||
for i := 0x0; i < 0x30; i++ {
|
|
||||||
PageTable[i+0xd0] = PhysicalMemory.UpperROM[i*0x100 : i*0x100+0x100]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func InitROM() {
|
||||||
|
UpperReadMappedToROM = true
|
||||||
|
ApplyMemoryConfiguration()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetUpperReadMappedToROM(value bool) {
|
||||||
|
UpperReadMappedToROM = value
|
||||||
|
ApplyMemoryConfiguration()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetUpperRamReadOnly(value bool) {
|
||||||
|
UpperRamReadOnly = value
|
||||||
|
ApplyMemoryConfiguration()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetD000Bank(value int) {
|
||||||
|
D000Bank = value
|
||||||
|
ApplyMemoryConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitRAM() {
|
func InitRAM() {
|
||||||
// Map main RAM
|
UpperRamReadOnly = false
|
||||||
for i := 0x0; i < 0xc0; i++ {
|
D000Bank = 2
|
||||||
PageTable[i] = PhysicalMemory.MainMemory[i*0x100 : i*0x100+0x100]
|
ApplyMemoryConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
UsingExternalSlotRom = true
|
func WipeRAM() {
|
||||||
|
for i := 0; i < 0x10000; i++ {
|
||||||
|
PhysicalMemory.MainMemory[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return
|
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
|
||||||
|
} else {
|
||||||
|
UpperRamReadOnly = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((mode & 2) >> 1) ^ (mode & 1)) == 0 {
|
||||||
|
UpperReadMappedToROM = false
|
||||||
|
|
||||||
|
} else {
|
||||||
|
UpperReadMappedToROM = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode & 8) == 0 {
|
||||||
|
D000Bank = 2
|
||||||
|
} else {
|
||||||
|
D000Bank = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplyMemoryConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
} else {
|
} else {
|
||||||
return PageTable[address>>8][address&0xff]
|
return ReadPageTable[address>>8][address&0xff]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,11 +202,15 @@ func WriteMemory(address uint16, value uint8) {
|
|||||||
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)
|
||||||
PageTable[uint8(address>>8)][uint8(address&0xff)] = value
|
WritePageTable[uint8(address>>8)][uint8(address&0xff)] = value
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
PageTable[uint8(address>>8)][uint8(address&0xff)] = value
|
memory := WritePageTable[address>>8]
|
||||||
|
// If memory is nil, then it's read only. The write is ignored.
|
||||||
|
if memory != nil {
|
||||||
|
memory[uint8(address&0xff)] = value
|
||||||
|
}
|
||||||
|
|
||||||
if system.RunningFunctionalTests && address == 0x200 {
|
if system.RunningFunctionalTests && address == 0x200 {
|
||||||
testNumber := ReadMemory(0x200)
|
testNumber := ReadMemory(0x200)
|
||||||
|
@ -122,7 +122,7 @@ func drawTextBlock(screen *ebiten.Image, start int, end int) error {
|
|||||||
base := 128*(y%8) + 40*(y/8)
|
base := 128*(y%8) + 40*(y/8)
|
||||||
for x := 0; x < 40; x++ {
|
for x := 0; x < 40; x++ {
|
||||||
offset := textVideoMemory + base + x
|
offset := textVideoMemory + base + x
|
||||||
value := mmu.PageTable[offset>>8][offset&0xff]
|
value := mmu.ReadPageTable[offset>>8][offset&0xff]
|
||||||
|
|
||||||
if err := drawText(screen, x, y, value); err != nil {
|
if err := drawText(screen, x, y, value); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -138,7 +138,7 @@ func drawLoresBlock(screen *ebiten.Image, start int, end int) error {
|
|||||||
base := 128*(y%8) + 40*(y/8)
|
base := 128*(y%8) + 40*(y/8)
|
||||||
for x := 0; x < 40; x++ {
|
for x := 0; x < 40; x++ {
|
||||||
offset := textVideoMemory + base + x
|
offset := textVideoMemory + base + x
|
||||||
value := mmu.PageTable[offset>>8][offset&0xff]
|
value := mmu.ReadPageTable[offset>>8][offset&0xff]
|
||||||
if err := drawLores(screen, x, y, value); err != nil {
|
if err := drawLores(screen, x, y, value); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -186,7 +186,7 @@ func drawHiresScreen(screen *ebiten.Image) error {
|
|||||||
|
|
||||||
for x := 0; x < 40; x++ {
|
for x := 0; x < 40; x++ {
|
||||||
offset := yOffset + x
|
offset := yOffset + x
|
||||||
value := mmu.PageTable[offset>>8][offset&0xff]
|
value := mmu.ReadPageTable[offset>>8][offset&0xff]
|
||||||
value &= 0x7f
|
value &= 0x7f
|
||||||
|
|
||||||
for bit := 0; bit < 7; bit++ {
|
for bit := 0; bit < 7; bit++ {
|
||||||
|
Loading…
Reference in New Issue
Block a user