mirror of
https://github.com/ivanizag/izapple2.git
synced 2025-03-11 12:32:15 +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 {
|
func newApple2e() *Apple2 {
|
||||||
var a Apple2
|
var a Apple2
|
||||||
a.Name = "Apple IIe"
|
a.Name = "Apple IIe"
|
||||||
|
a.isApple2e = true
|
||||||
a.mmu = newMemoryManager(&a)
|
a.mmu = newMemoryManager(&a)
|
||||||
a.cpu = core6502.NewNMOS6502(a.mmu)
|
a.cpu = core6502.NewNMOS6502(a.mmu)
|
||||||
a.io = newIoC0Page(&a)
|
a.io = newIoC0Page(&a)
|
||||||
@ -34,6 +35,7 @@ func newApple2e() *Apple2 {
|
|||||||
func newApple2eEnhanced() *Apple2 {
|
func newApple2eEnhanced() *Apple2 {
|
||||||
var a Apple2
|
var a Apple2
|
||||||
a.Name = "Apple //e"
|
a.Name = "Apple //e"
|
||||||
|
a.isApple2e = true
|
||||||
a.mmu = newMemoryManager(&a)
|
a.mmu = newMemoryManager(&a)
|
||||||
a.cpu = core6502.NewCMOS65c02(a.mmu)
|
a.cpu = core6502.NewCMOS65c02(a.mmu)
|
||||||
a.io = newIoC0Page(&a)
|
a.io = newIoC0Page(&a)
|
||||||
@ -82,18 +84,8 @@ func (a *Apple2) LoadRom(filename string) error {
|
|||||||
return errors.New("Rom size not supported")
|
return errors.New("Rom size not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
romStart := 0
|
romBase := 0x10000 - size
|
||||||
mmu := a.mmu
|
a.mmu.physicalROM[0] = newMemoryRangeROM(uint16(romBase), data)
|
||||||
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:])
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
cardBase.go
17
cardBase.go
@ -7,9 +7,9 @@ type card interface {
|
|||||||
|
|
||||||
type cardBase struct {
|
type cardBase struct {
|
||||||
a *Apple2
|
a *Apple2
|
||||||
romCsxx *memoryRange
|
romCsxx *memoryRangeROM
|
||||||
romC8xx *memoryRange
|
romC8xx *memoryRangeROM
|
||||||
romCxxx *memoryRange
|
romCxxx *memoryRangeROM
|
||||||
slot int
|
slot int
|
||||||
_ssr [16]softSwitchR
|
_ssr [16]softSwitchR
|
||||||
_ssw [16]softSwitchW
|
_ssw [16]softSwitchW
|
||||||
@ -23,16 +23,16 @@ func (c *cardBase) loadRom(data []uint8) {
|
|||||||
}
|
}
|
||||||
if len(data) == 0x100 {
|
if len(data) == 0x100 {
|
||||||
// Just 256 bytes in Cs00
|
// Just 256 bytes in Cs00
|
||||||
c.romCsxx = newMemoryRange(0, data)
|
c.romCsxx = newMemoryRangeROM(0, data)
|
||||||
} else if len(data) == 0x800 {
|
} else if len(data) == 0x800 {
|
||||||
// The file has C800 to C8FF
|
// The file has C800 to C8FF
|
||||||
// The 256 bytes in Cx00 are copied from the first page in C800
|
// The 256 bytes in Cx00 are copied from the first page in C800
|
||||||
c.romCsxx = newMemoryRange(0, data)
|
c.romCsxx = newMemoryRangeROM(0, data)
|
||||||
c.romC8xx = newMemoryRange(0xc800, data)
|
c.romC8xx = newMemoryRangeROM(0xc800, data)
|
||||||
} else if len(data) == 0x1000 {
|
} else if len(data) == 0x1000 {
|
||||||
// The file covers the full Cxxx range. Only showing the page
|
// The file covers the full Cxxx range. Only showing the page
|
||||||
// corresponding to the slot used.
|
// corresponding to the slot used.
|
||||||
c.romCxxx = newMemoryRange(0xc000, data)
|
c.romCxxx = newMemoryRangeROM(0xc000, data)
|
||||||
} else {
|
} else {
|
||||||
panic("Invalid ROM size")
|
panic("Invalid ROM size")
|
||||||
}
|
}
|
||||||
@ -44,7 +44,8 @@ func (c *cardBase) assign(a *Apple2, slot int) {
|
|||||||
if slot != 0 {
|
if slot != 0 {
|
||||||
if c.romCsxx != nil {
|
if c.romCsxx != nil {
|
||||||
// Relocate to the assigned slot
|
// 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)
|
a.mmu.setCardROM(slot, c.romCsxx)
|
||||||
}
|
}
|
||||||
if c.romC8xx != nil {
|
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 {
|
if slot != 2 {
|
||||||
// To make ifwork on other slots, patch C2, A0 and A1
|
// 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.writeState = lcWriteEnabled
|
||||||
c.altBank = true // Start on bank2
|
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++ {
|
for i := uint8(0x0); i <= 0xf; i++ {
|
||||||
iCopy := i
|
iCopy := i
|
||||||
c.addCardSoftSwitchR(iCopy, func(*ioC0Page) uint8 {
|
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.
|
// ExecuteInstruction transforms the state given after a single instruction is executed.
|
||||||
func (s *State) ExecuteInstruction() {
|
func (s *State) ExecuteInstruction() {
|
||||||
pc := s.reg.getPC()
|
pc := s.reg.getPC()
|
||||||
opcodeID := s.mem.Peek(pc)
|
opcodeID := s.mem.PeekCode(pc)
|
||||||
opcode := s.opcodes[opcodeID]
|
opcode := s.opcodes[opcodeID]
|
||||||
|
|
||||||
if opcode.cycles == 0 {
|
if opcode.cycles == 0 {
|
||||||
@ -65,7 +65,7 @@ func (s *State) ExecuteInstruction() {
|
|||||||
s.lineCache = make([]uint8, maxInstructionSize)
|
s.lineCache = make([]uint8, maxInstructionSize)
|
||||||
}
|
}
|
||||||
for i := uint16(0); i < opcode.bytes; i++ {
|
for i := uint16(0); i < opcode.bytes; i++ {
|
||||||
s.lineCache[i] = s.mem.Peek(pc)
|
s.lineCache[i] = s.mem.PeekCode(pc)
|
||||||
pc++
|
pc++
|
||||||
}
|
}
|
||||||
s.reg.setPC(pc)
|
s.reg.setPC(pc)
|
||||||
|
@ -6,6 +6,10 @@ import "io/ioutil"
|
|||||||
type Memory interface {
|
type Memory interface {
|
||||||
Peek(address uint16) uint8
|
Peek(address uint16) uint8
|
||||||
Poke(address uint16, value 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 {
|
func getWord(m Memory, address uint16) uint16 {
|
||||||
|
@ -12,10 +12,9 @@ type memoryManager struct {
|
|||||||
// Slots area: 0xc000 to 0xcfff
|
// Slots area: 0xc000 to 0xcfff
|
||||||
cardsROM [8]memoryHandler //0xcs00 to 0xcSff. 256 bytes for each card
|
cardsROM [8]memoryHandler //0xcs00 to 0xcSff. 256 bytes for each card
|
||||||
cardsROMExtra [8]memoryHandler // 0xc800 to 0xcfff. 2048 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
|
// Upper area ROM: 0xc000 to 0xffff (or 0xd000 to 0xffff on the II+)
|
||||||
physicalROM [4]memoryHandler // 0xd000 to 0xffff, 12 Kb. Up to four
|
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
|
// 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.
|
physicalLangRAM []*memoryRange // 0xd000 to 0xffff, 12KB. Up to 8 banks.
|
||||||
@ -43,6 +42,10 @@ type memoryManager struct {
|
|||||||
|
|
||||||
// Configuration switches, Base64A
|
// Configuration switches, Base64A
|
||||||
romPage uint8 // Active ROM page
|
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 (
|
const (
|
||||||
@ -57,6 +60,8 @@ const (
|
|||||||
addressLimitSlots uint16 = 0xc7ff
|
addressLimitSlots uint16 = 0xc7ff
|
||||||
addressLimitSlotsExtra uint16 = 0xcfff
|
addressLimitSlotsExtra uint16 = 0xcfff
|
||||||
addressLimitDArea uint16 = 0xdfff
|
addressLimitDArea uint16 = 0xdfff
|
||||||
|
|
||||||
|
invalidAddressPage uint16 = 0x0001
|
||||||
)
|
)
|
||||||
|
|
||||||
type memoryHandler interface {
|
type memoryHandler interface {
|
||||||
@ -74,14 +79,14 @@ func newMemoryManager(a *Apple2) *memoryManager {
|
|||||||
|
|
||||||
func (mmu *memoryManager) accessCArea(address uint16) memoryHandler {
|
func (mmu *memoryManager) accessCArea(address uint16) memoryHandler {
|
||||||
if mmu.intCxROMActive {
|
if mmu.intCxROMActive {
|
||||||
return mmu.physicalROMe
|
return mmu.physicalROM[mmu.romPage]
|
||||||
}
|
}
|
||||||
// First slot area
|
// First slot area
|
||||||
if address <= addressLimitSlots {
|
if address <= addressLimitSlots {
|
||||||
slot := uint8((address >> 8) & 0x07)
|
slot := uint8((address >> 8) & 0x07)
|
||||||
mmu.activeSlot = slot
|
mmu.activeSlot = slot
|
||||||
if !mmu.slotC3ROMActive && (slot == 3) {
|
if !mmu.slotC3ROMActive && (slot == 3) {
|
||||||
return mmu.physicalROMe
|
return mmu.physicalROM[mmu.romPage]
|
||||||
}
|
}
|
||||||
return mmu.cardsROM[slot]
|
return mmu.cardsROM[slot]
|
||||||
}
|
}
|
||||||
@ -89,10 +94,11 @@ func (mmu *memoryManager) accessCArea(address uint16) memoryHandler {
|
|||||||
if address == ioC8Off {
|
if address == ioC8Off {
|
||||||
// Reset extra slot area owner
|
// Reset extra slot area owner
|
||||||
mmu.activeSlot = 0
|
mmu.activeSlot = 0
|
||||||
|
mmu.lastAddressPage = invalidAddressPage
|
||||||
}
|
}
|
||||||
|
|
||||||
if !mmu.slotC3ROMActive && (mmu.activeSlot == 3) {
|
if !mmu.slotC3ROMActive && (mmu.activeSlot == 3) {
|
||||||
return mmu.physicalROMe
|
return mmu.physicalROM[mmu.romPage]
|
||||||
}
|
}
|
||||||
return mmu.cardsROMExtra[mmu.activeSlot]
|
return mmu.cardsROMExtra[mmu.activeSlot]
|
||||||
}
|
}
|
||||||
@ -130,6 +136,23 @@ func (mmu *memoryManager) getVideoRAM(ext bool) *memoryRange {
|
|||||||
return mmu.physicalMainRAM
|
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 {
|
func (mmu *memoryManager) accessRead(address uint16) memoryHandler {
|
||||||
if address <= addressLimitZero {
|
if address <= addressLimitZero {
|
||||||
return mmu.getPhysicalMainRAM(mmu.altZeroPage)
|
return mmu.getPhysicalMainRAM(mmu.altZeroPage)
|
||||||
@ -148,6 +171,7 @@ func (mmu *memoryManager) accessRead(address uint16) memoryHandler {
|
|||||||
return mmu.getPhysicalMainRAM(mmu.altMainRAMActiveRead)
|
return mmu.getPhysicalMainRAM(mmu.altMainRAMActiveRead)
|
||||||
}
|
}
|
||||||
if address <= addressLimitIO {
|
if address <= addressLimitIO {
|
||||||
|
mmu.lastAddressPage = invalidAddressPage
|
||||||
return mmu.apple2.io
|
return mmu.apple2.io
|
||||||
}
|
}
|
||||||
if address <= addressLimitSlotsExtra {
|
if address <= addressLimitSlotsExtra {
|
||||||
@ -192,7 +216,27 @@ func (mmu *memoryManager) accessWrite(address uint16) memoryHandler {
|
|||||||
func (mmu *memoryManager) Peek(address uint16) uint8 {
|
func (mmu *memoryManager) Peek(address uint16) uint8 {
|
||||||
mh := mmu.accessRead(address)
|
mh := mmu.accessRead(address)
|
||||||
if mh == nil {
|
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 0xf4 // Or some random number
|
||||||
}
|
}
|
||||||
return mh.peek(address)
|
return mh.peek(address)
|
||||||
@ -201,12 +245,10 @@ func (mmu *memoryManager) Peek(address uint16) uint8 {
|
|||||||
// Poke sets the data at the given address
|
// Poke sets the data at the given address
|
||||||
func (mmu *memoryManager) Poke(address uint16, value uint8) {
|
func (mmu *memoryManager) Poke(address uint16, value uint8) {
|
||||||
mh := mmu.accessWrite(address)
|
mh := mmu.accessWrite(address)
|
||||||
if mh == nil {
|
if mh != nil {
|
||||||
//fmt.Printf("Writing to void addressing 0x%x\n", address)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mh.poke(address, value)
|
mh.poke(address, value)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Memory initialization
|
// Memory initialization
|
||||||
func (mmu *memoryManager) setCardROM(slot int, mh memoryHandler) {
|
func (mmu *memoryManager) setCardROM(slot int, mh memoryHandler) {
|
||||||
|
@ -3,17 +3,46 @@ package apple2
|
|||||||
type memoryRange struct {
|
type memoryRange struct {
|
||||||
base uint16
|
base uint16
|
||||||
data []uint8
|
data []uint8
|
||||||
|
basePtr uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
type memoryRangeROM struct {
|
||||||
|
memoryRange
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMemoryRange(base uint16, data []uint8) *memoryRange {
|
func newMemoryRange(base uint16, data []uint8) *memoryRange {
|
||||||
var m memoryRange
|
var m memoryRange
|
||||||
m.base = base
|
m.base = base
|
||||||
m.data = data
|
m.data = data
|
||||||
|
m.setBase(base)
|
||||||
return &m
|
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 {
|
func (m *memoryRange) peek(address uint16) uint8 {
|
||||||
|
// Safe version:
|
||||||
return m.data[address-m.base]
|
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) {
|
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 {
|
func (m *memoryRange) subRange(a, b uint16) []uint8 {
|
||||||
return m.data[a-m.base : b-m.base]
|
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