mirror of
https://github.com/ivanizag/izapple2.git
synced 2025-01-30 05:34:27 +00:00
ROM memory changes and some speed improvements
This commit is contained in:
parent
81c77c7700
commit
c82e57d895
@ -21,6 +21,7 @@ func newApple2plus() *Apple2 {
|
||||
func newApple2e() *Apple2 {
|
||||
var a Apple2
|
||||
a.Name = "Apple IIe"
|
||||
a.isApple2e = true
|
||||
a.mmu = newMemoryManager(&a)
|
||||
a.cpu = core6502.NewNMOS6502(a.mmu)
|
||||
a.io = newIoC0Page(&a)
|
||||
@ -34,6 +35,7 @@ func newApple2e() *Apple2 {
|
||||
func newApple2eEnhanced() *Apple2 {
|
||||
var a Apple2
|
||||
a.Name = "Apple //e"
|
||||
a.isApple2e = true
|
||||
a.mmu = newMemoryManager(&a)
|
||||
a.cpu = core6502.NewCMOS65c02(a.mmu)
|
||||
a.io = newIoC0Page(&a)
|
||||
@ -82,18 +84,8 @@ func (a *Apple2) LoadRom(filename string) error {
|
||||
return errors.New("Rom size not supported")
|
||||
}
|
||||
|
||||
romStart := 0
|
||||
mmu := a.mmu
|
||||
if size == apple2eRomSize {
|
||||
// The extra 4kb ROM is first in the rom file.
|
||||
// It starts with 256 unused bytes not mapped to 0xc000.
|
||||
a.isApple2e = true
|
||||
extraRomSize := apple2eRomSize - apple2RomSize
|
||||
mmu.physicalROMe = newMemoryRange(0xc000, data[0:extraRomSize])
|
||||
romStart = extraRomSize
|
||||
}
|
||||
|
||||
mmu.physicalROM[0] = newMemoryRange(0xd000, data[romStart:])
|
||||
romBase := 0x10000 - size
|
||||
a.mmu.physicalROM[0] = newMemoryRangeROM(uint16(romBase), data)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
17
cardBase.go
17
cardBase.go
@ -7,9 +7,9 @@ type card interface {
|
||||
|
||||
type cardBase struct {
|
||||
a *Apple2
|
||||
romCsxx *memoryRange
|
||||
romC8xx *memoryRange
|
||||
romCxxx *memoryRange
|
||||
romCsxx *memoryRangeROM
|
||||
romC8xx *memoryRangeROM
|
||||
romCxxx *memoryRangeROM
|
||||
slot int
|
||||
_ssr [16]softSwitchR
|
||||
_ssw [16]softSwitchW
|
||||
@ -23,16 +23,16 @@ func (c *cardBase) loadRom(data []uint8) {
|
||||
}
|
||||
if len(data) == 0x100 {
|
||||
// Just 256 bytes in Cs00
|
||||
c.romCsxx = newMemoryRange(0, data)
|
||||
c.romCsxx = newMemoryRangeROM(0, data)
|
||||
} else if len(data) == 0x800 {
|
||||
// The file has C800 to C8FF
|
||||
// The 256 bytes in Cx00 are copied from the first page in C800
|
||||
c.romCsxx = newMemoryRange(0, data)
|
||||
c.romC8xx = newMemoryRange(0xc800, data)
|
||||
c.romCsxx = newMemoryRangeROM(0, data)
|
||||
c.romC8xx = newMemoryRangeROM(0xc800, data)
|
||||
} else if len(data) == 0x1000 {
|
||||
// The file covers the full Cxxx range. Only showing the page
|
||||
// corresponding to the slot used.
|
||||
c.romCxxx = newMemoryRange(0xc000, data)
|
||||
c.romCxxx = newMemoryRangeROM(0xc000, data)
|
||||
} else {
|
||||
panic("Invalid ROM size")
|
||||
}
|
||||
@ -44,7 +44,8 @@ func (c *cardBase) assign(a *Apple2, slot int) {
|
||||
if slot != 0 {
|
||||
if c.romCsxx != nil {
|
||||
// Relocate to the assigned slot
|
||||
c.romCsxx.base = uint16(0xc000 + slot*0x100)
|
||||
//c.romCsxx.base = uint16(0xc000 + slot*0x100)
|
||||
c.romCsxx.setBase(uint16(0xc000 + slot*0x100))
|
||||
a.mmu.setCardROM(slot, c.romCsxx)
|
||||
}
|
||||
if c.romC8xx != nil {
|
||||
|
@ -71,7 +71,7 @@ func (c *cardInOut) assign(a *Apple2, slot int) {
|
||||
}
|
||||
}
|
||||
|
||||
c.romCsxx = newMemoryRange(0xC200, data[0:255])
|
||||
c.romCsxx = newMemoryRangeROM(0xC200, data[0:255])
|
||||
|
||||
if slot != 2 {
|
||||
// To make ifwork on other slots, patch C2, A0 and A1
|
||||
|
@ -46,12 +46,7 @@ func (c *cardLanguage) assign(a *Apple2, slot int) {
|
||||
c.writeState = lcWriteEnabled
|
||||
c.altBank = true // Start on bank2
|
||||
|
||||
if a.isApple2e {
|
||||
// The Apple //e with 128kb has two blocks of language upper RAM
|
||||
a.mmu.initLanguageRAM(2)
|
||||
} else {
|
||||
a.mmu.initLanguageRAM(1)
|
||||
}
|
||||
a.mmu.initLanguageRAM(1)
|
||||
for i := uint8(0x0); i <= 0xf; i++ {
|
||||
iCopy := i
|
||||
c.addCardSoftSwitchR(iCopy, func(*ioC0Page) uint8 {
|
||||
|
@ -54,7 +54,7 @@ func (s *State) executeLine(line []uint8) {
|
||||
// ExecuteInstruction transforms the state given after a single instruction is executed.
|
||||
func (s *State) ExecuteInstruction() {
|
||||
pc := s.reg.getPC()
|
||||
opcodeID := s.mem.Peek(pc)
|
||||
opcodeID := s.mem.PeekCode(pc)
|
||||
opcode := s.opcodes[opcodeID]
|
||||
|
||||
if opcode.cycles == 0 {
|
||||
@ -65,7 +65,7 @@ func (s *State) ExecuteInstruction() {
|
||||
s.lineCache = make([]uint8, maxInstructionSize)
|
||||
}
|
||||
for i := uint16(0); i < opcode.bytes; i++ {
|
||||
s.lineCache[i] = s.mem.Peek(pc)
|
||||
s.lineCache[i] = s.mem.PeekCode(pc)
|
||||
pc++
|
||||
}
|
||||
s.reg.setPC(pc)
|
||||
|
@ -6,6 +6,10 @@ import "io/ioutil"
|
||||
type Memory interface {
|
||||
Peek(address uint16) uint8
|
||||
Poke(address uint16, value uint8)
|
||||
|
||||
// PeekCode can bu used to optimize the memory manager to requests with more
|
||||
// locality. It must return the same as a call to Peek()
|
||||
PeekCode(address uint16) uint8
|
||||
}
|
||||
|
||||
func getWord(m Memory, address uint16) uint16 {
|
||||
|
@ -12,10 +12,9 @@ type memoryManager struct {
|
||||
// Slots area: 0xc000 to 0xcfff
|
||||
cardsROM [8]memoryHandler //0xcs00 to 0xcSff. 256 bytes for each card
|
||||
cardsROMExtra [8]memoryHandler // 0xc800 to 0xcfff. 2048 bytes for each card
|
||||
physicalROMe memoryHandler // 0xc100 to 0xcfff, Zero or 4kb in the Apple2e
|
||||
|
||||
// Upper area ROM: 0xd000 to 0xffff
|
||||
physicalROM [4]memoryHandler // 0xd000 to 0xffff, 12 Kb. Up to four
|
||||
// Upper area ROM: 0xc000 to 0xffff (or 0xd000 to 0xffff on the II+)
|
||||
physicalROM [4]memoryHandler // 0xc000 (or 0xd000) to 0xffff, 16 (or 12) Kb. Up to four banks
|
||||
|
||||
// Language card upper area RAM: 0xd000 to 0xffff. One bank for regular LC cards, up to 8 with Saturn
|
||||
physicalLangRAM []*memoryRange // 0xd000 to 0xffff, 12KB. Up to 8 banks.
|
||||
@ -43,6 +42,10 @@ type memoryManager struct {
|
||||
|
||||
// Configuration switches, Base64A
|
||||
romPage uint8 // Active ROM page
|
||||
|
||||
// Resolution cache
|
||||
lastAddressPage uint16 // The first byte is the page. The second is zero when the cached is valid.
|
||||
lastAddressHandler memoryHandler
|
||||
}
|
||||
|
||||
const (
|
||||
@ -57,6 +60,8 @@ const (
|
||||
addressLimitSlots uint16 = 0xc7ff
|
||||
addressLimitSlotsExtra uint16 = 0xcfff
|
||||
addressLimitDArea uint16 = 0xdfff
|
||||
|
||||
invalidAddressPage uint16 = 0x0001
|
||||
)
|
||||
|
||||
type memoryHandler interface {
|
||||
@ -74,14 +79,14 @@ func newMemoryManager(a *Apple2) *memoryManager {
|
||||
|
||||
func (mmu *memoryManager) accessCArea(address uint16) memoryHandler {
|
||||
if mmu.intCxROMActive {
|
||||
return mmu.physicalROMe
|
||||
return mmu.physicalROM[mmu.romPage]
|
||||
}
|
||||
// First slot area
|
||||
if address <= addressLimitSlots {
|
||||
slot := uint8((address >> 8) & 0x07)
|
||||
mmu.activeSlot = slot
|
||||
if !mmu.slotC3ROMActive && (slot == 3) {
|
||||
return mmu.physicalROMe
|
||||
return mmu.physicalROM[mmu.romPage]
|
||||
}
|
||||
return mmu.cardsROM[slot]
|
||||
}
|
||||
@ -89,10 +94,11 @@ func (mmu *memoryManager) accessCArea(address uint16) memoryHandler {
|
||||
if address == ioC8Off {
|
||||
// Reset extra slot area owner
|
||||
mmu.activeSlot = 0
|
||||
mmu.lastAddressPage = invalidAddressPage
|
||||
}
|
||||
|
||||
if !mmu.slotC3ROMActive && (mmu.activeSlot == 3) {
|
||||
return mmu.physicalROMe
|
||||
return mmu.physicalROM[mmu.romPage]
|
||||
}
|
||||
return mmu.cardsROMExtra[mmu.activeSlot]
|
||||
}
|
||||
@ -130,6 +136,23 @@ func (mmu *memoryManager) getVideoRAM(ext bool) *memoryRange {
|
||||
return mmu.physicalMainRAM
|
||||
}
|
||||
|
||||
func (mmu *memoryManager) accessReadCached(address uint16) memoryHandler {
|
||||
page := address & 0xff00
|
||||
if address&0xff00 == mmu.lastAddressPage {
|
||||
//fmt.Printf(" hit %v\n", mmu.apple2.cpu.GetCycles())
|
||||
return mmu.lastAddressHandler
|
||||
}
|
||||
|
||||
//fmt.Printf("Not hit %v\n", mmu.apple2.cpu.GetCycles())
|
||||
mh := mmu.accessRead(address)
|
||||
if address&0xf000 != 0xc000 {
|
||||
// Do not cache 0xC area as it may reconfigure the MMU
|
||||
mmu.lastAddressPage = page
|
||||
mmu.lastAddressHandler = mh
|
||||
}
|
||||
return mh
|
||||
}
|
||||
|
||||
func (mmu *memoryManager) accessRead(address uint16) memoryHandler {
|
||||
if address <= addressLimitZero {
|
||||
return mmu.getPhysicalMainRAM(mmu.altZeroPage)
|
||||
@ -148,6 +171,7 @@ func (mmu *memoryManager) accessRead(address uint16) memoryHandler {
|
||||
return mmu.getPhysicalMainRAM(mmu.altMainRAMActiveRead)
|
||||
}
|
||||
if address <= addressLimitIO {
|
||||
mmu.lastAddressPage = invalidAddressPage
|
||||
return mmu.apple2.io
|
||||
}
|
||||
if address <= addressLimitSlotsExtra {
|
||||
@ -192,7 +216,27 @@ func (mmu *memoryManager) accessWrite(address uint16) memoryHandler {
|
||||
func (mmu *memoryManager) Peek(address uint16) uint8 {
|
||||
mh := mmu.accessRead(address)
|
||||
if mh == nil {
|
||||
//fmt.Printf("Reading void addressing 0x%x\n", address)
|
||||
return 0xf4 // Or some random number
|
||||
}
|
||||
return mh.peek(address)
|
||||
}
|
||||
|
||||
// Peek returns the data on the given address optimized for more local requests
|
||||
func (mmu *memoryManager) PeekCode(address uint16) uint8 {
|
||||
page := address & 0xff00
|
||||
var mh memoryHandler
|
||||
if page == mmu.lastAddressPage {
|
||||
mh = mmu.lastAddressHandler
|
||||
} else {
|
||||
mh = mmu.accessRead(address)
|
||||
if address&0xf000 != 0xc000 {
|
||||
// Do not cache 0xC area as it may reconfigure the MMU
|
||||
mmu.lastAddressPage = page
|
||||
mmu.lastAddressHandler = mh
|
||||
}
|
||||
}
|
||||
|
||||
if mh == nil {
|
||||
return 0xf4 // Or some random number
|
||||
}
|
||||
return mh.peek(address)
|
||||
@ -201,11 +245,9 @@ func (mmu *memoryManager) Peek(address uint16) uint8 {
|
||||
// Poke sets the data at the given address
|
||||
func (mmu *memoryManager) Poke(address uint16, value uint8) {
|
||||
mh := mmu.accessWrite(address)
|
||||
if mh == nil {
|
||||
//fmt.Printf("Writing to void addressing 0x%x\n", address)
|
||||
return
|
||||
if mh != nil {
|
||||
mh.poke(address, value)
|
||||
}
|
||||
mh.poke(address, value)
|
||||
}
|
||||
|
||||
// Memory initialization
|
||||
|
@ -1,19 +1,48 @@
|
||||
package apple2
|
||||
|
||||
type memoryRange struct {
|
||||
base uint16
|
||||
data []uint8
|
||||
base uint16
|
||||
data []uint8
|
||||
basePtr uintptr
|
||||
}
|
||||
|
||||
type memoryRangeROM struct {
|
||||
memoryRange
|
||||
}
|
||||
|
||||
func newMemoryRange(base uint16, data []uint8) *memoryRange {
|
||||
var m memoryRange
|
||||
m.base = base
|
||||
m.data = data
|
||||
m.setBase(base)
|
||||
return &m
|
||||
}
|
||||
|
||||
func newMemoryRangeROM(base uint16, data []uint8) *memoryRangeROM {
|
||||
var m memoryRangeROM
|
||||
m.base = base
|
||||
m.data = data
|
||||
m.setBase(base)
|
||||
return &m
|
||||
}
|
||||
|
||||
func (m *memoryRange) setBase(base uint16) {
|
||||
m.base = base
|
||||
//p := unsafe.Pointer(&m.data[0])
|
||||
//m.basePtr = (uintptr)(p) - (uintptr)(base)
|
||||
}
|
||||
|
||||
func (m *memoryRange) peek(address uint16) uint8 {
|
||||
// Safe version:
|
||||
return m.data[address-m.base]
|
||||
|
||||
// Really overkill
|
||||
// go-vet warns the caching of basePtr
|
||||
// This wouldn't have a warning
|
||||
// indexp := unsafe.Pointer((uintptr)(unsafe.Pointer(&m.data[0])) - (uintptr)(m.base) + uintptr(address))
|
||||
// But it makes sense to precalculate that
|
||||
//indexp := unsafe.Pointer(m.basePtr + uintptr(address))
|
||||
//return *(*uint8)(indexp)
|
||||
}
|
||||
|
||||
func (m *memoryRange) poke(address uint16, value uint8) {
|
||||
@ -23,3 +52,7 @@ func (m *memoryRange) poke(address uint16, value uint8) {
|
||||
func (m *memoryRange) subRange(a, b uint16) []uint8 {
|
||||
return m.data[a-m.base : b-m.base]
|
||||
}
|
||||
|
||||
func (m *memoryRangeROM) poke(address uint16, value uint8) {
|
||||
// Ignore
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user