izapple2/cardBase.go

198 lines
5.1 KiB
Go
Raw Permalink Normal View History

2020-10-03 21:38:26 +00:00
package izapple2
2019-03-02 19:41:25 +00:00
import (
2021-05-09 17:48:54 +00:00
"fmt"
)
2020-10-13 22:26:47 +00:00
// Card represents an Apple II card to be inserted in a slot
type Card interface {
2024-03-24 19:15:16 +00:00
loadRom(data []uint8, layout cardRomLayout) error
2019-05-18 14:43:51 +00:00
assign(a *Apple2, slot int)
2020-10-27 23:43:33 +00:00
reset()
2020-10-13 22:26:47 +00:00
2024-01-29 23:33:53 +00:00
setName(name string)
setDebug(debug bool)
2020-10-13 22:26:47 +00:00
GetName() string
GetInfo() map[string]string
2019-05-18 14:43:51 +00:00
}
2019-03-02 19:41:25 +00:00
type cardBase struct {
2020-10-14 19:54:51 +00:00
a *Apple2
name string
2024-01-29 23:33:53 +00:00
trace bool
romCsxx *memoryRangeROM
romC8xx memoryHandler
romCxxx memoryHandler
2020-10-14 19:54:51 +00:00
slot int
2019-10-20 22:00:42 +00:00
_ssr [16]softSwitchR
_ssw [16]softSwitchW
_ssrName [16]string
_sswName [16]string
2019-03-02 19:41:25 +00:00
}
2024-01-29 23:33:53 +00:00
func (c *cardBase) setName(name string) {
c.name = name
}
2020-10-13 22:26:47 +00:00
func (c *cardBase) GetName() string {
return c.name
}
func (c *cardBase) GetInfo() map[string]string {
return nil
}
2024-01-29 23:33:53 +00:00
func (c *cardBase) setDebug(debug bool) {
c.trace = debug
}
2020-10-27 23:43:33 +00:00
func (c *cardBase) reset() {
// nothing
}
2024-03-24 19:15:16 +00:00
type cardRomLayout int
const (
cardRomSimple cardRomLayout = iota // The ROM is on the slot area, there can be more than one page
cardRomUpper // The ROM is on the full C800 area. The slot area copies C8xx
cardRomUpperHalfEnd // The ROM is on half of the C800 areas. The slot area copies CBxx
cardRomFull // The ROM is on the full Cxxx area, with pages for each slot position
)
func (c *cardBase) loadRomFromResource(resource string, layout cardRomLayout) error {
2022-01-28 18:25:52 +00:00
data, _, err := LoadResource(resource)
2020-10-14 19:54:51 +00:00
if err != nil {
// The resource should be internal and never fail
2024-01-06 20:48:23 +00:00
return err
2020-10-14 19:54:51 +00:00
}
2024-03-24 19:15:16 +00:00
err = c.loadRom(data, layout)
if err != nil {
return err
}
2024-01-06 20:48:23 +00:00
return nil
2020-10-14 19:54:51 +00:00
}
2024-03-24 19:15:16 +00:00
func (c *cardBase) loadRom(data []uint8, layout cardRomLayout) error {
2019-05-18 14:43:51 +00:00
if c.a != nil {
2024-03-24 19:15:16 +00:00
return fmt.Errorf("ROM must be loaded before inserting the card in the slot")
2019-05-18 14:43:51 +00:00
}
2024-03-24 19:15:16 +00:00
switch layout {
case cardRomSimple:
if len(data) == 0x100 {
// Just 256 bytes in Cs00
c.romCsxx = newMemoryRangeROM(0, data, "Slot ROM")
} else if len(data)%0x100 == 0 {
// The ROM covers many 256 bytes pages of Csxx
// Used on the Dan 2 controller card
c.romCsxx = newMemoryRangePagedROM(0, data, "Slot paged ROM", uint8(len(data)/0x100))
} else {
return fmt.Errorf("invalid ROM size for simple layout")
}
case cardRomUpper:
if len(data) == 0x800 {
// The file has C800 to CFFF
// The 256 bytes in Cx00 are copied from the first page in C800
c.romCsxx = newMemoryRangeROM(0, data, "Slot ROM")
c.romC8xx = newMemoryRangeROM(0xc800, data, "Slot C8 ROM")
} else {
return fmt.Errorf("invalid ROM size for upper layout")
}
case cardRomUpperHalfEnd:
if len(data) == 0x400 {
// The file has C800 to CBFF for ROM
// The 256 bytes in Cx00 are copied from the last page in C800-CBFF
// Used on the Videx 80 columns card
c.romCsxx = newMemoryRangeROM(0, data[0x300:], "Slot ROM")
c.romC8xx = newMemoryRangeROM(0xc800, data, "Slot C8 ROM")
} else {
return fmt.Errorf("invalid ROM size for upper half end layout")
}
case cardRomFull:
if len(data) == 0x1000 {
// The file covers the full Cxxx range. Only showing the page
// corresponding to the slot used.
c.romCxxx = newMemoryRangeROM(0xc000, data, "Slot ROM")
} else if len(data)%0x1000 == 0 {
// The ROM covers the full Cxxx range with several pages
c.romCxxx = newMemoryRangePagedROM(0xc000, data, "Slot paged ROM", uint8(len(data)/0x1000))
} else {
return fmt.Errorf("invalid ROM size for full layout")
}
default:
return fmt.Errorf("invalid card ROM layout")
}
2024-03-24 19:15:16 +00:00
return nil
2019-05-18 14:43:51 +00:00
}
func (c *cardBase) assign(a *Apple2, slot int) {
c.a = a
2019-03-02 19:41:25 +00:00
c.slot = slot
if slot != 0 {
if c.romCsxx != nil {
// Relocate to the assigned slot
c.romCsxx.setBase(uint16(0xc000 + slot*0x100))
a.mmu.setCardROM(slot, c.romCsxx)
}
if c.romC8xx != nil {
a.mmu.setCardROMExtra(slot, c.romC8xx)
}
if c.romCxxx != nil {
a.mmu.setCardROM(slot, c.romCxxx)
a.mmu.setCardROMExtra(slot, c.romCxxx)
}
}
2019-03-02 19:41:25 +00:00
for i := 0; i < 0x10; i++ {
2020-08-30 19:11:43 +00:00
if c._ssr[i] != nil {
a.io.addSoftSwitchR(uint8(0xC80+slot*0x10+i), c._ssr[i], c._ssrName[i])
}
if c._ssw[i] != nil {
a.io.addSoftSwitchW(uint8(0xC80+slot*0x10+i), c._ssw[i], c._sswName[i])
}
2019-03-02 19:41:25 +00:00
}
}
2019-05-18 14:43:51 +00:00
2019-10-20 22:00:42 +00:00
func (c *cardBase) addCardSoftSwitchR(address uint8, ss softSwitchR, name string) {
c._ssr[address] = ss
c._ssrName[address] = name
}
func (c *cardBase) addCardSoftSwitchW(address uint8, ss softSwitchW, name string) {
c._ssw[address] = ss
c._sswName[address] = name
}
2021-05-09 17:48:54 +00:00
2022-03-08 19:11:26 +00:00
func (c *cardBase) addCardSoftSwitchRW(address uint8, ss softSwitchR, name string) {
c._ssr[address] = ss
c._ssrName[address] = name
2022-08-05 17:43:17 +00:00
c._ssw[address] = func(uint8) {
ss()
2022-03-08 19:11:26 +00:00
}
c._sswName[address] = name
}
2022-08-05 17:43:17 +00:00
type softSwitches func(address uint8, data uint8, write bool) uint8
2021-05-09 17:48:54 +00:00
func (c *cardBase) addCardSoftSwitches(sss softSwitches, name string) {
for i := uint8(0x0); i <= 0xf; i++ {
address := i
2022-08-05 17:43:17 +00:00
c.addCardSoftSwitchR(address, func() uint8 {
return sss(address, 0, false)
}, fmt.Sprintf("%v%XR", name, address))
2022-08-05 17:43:17 +00:00
c.addCardSoftSwitchW(address, func(value uint8) {
sss(address, value, true)
}, fmt.Sprintf("%v%XW", name, address))
2021-05-09 17:48:54 +00:00
}
}
2024-01-29 23:33:53 +00:00
func (c *cardBase) tracef(format string, args ...interface{}) {
if c.trace {
prefixedFormat := fmt.Sprintf("[%s] %v", c.name, format)
fmt.Printf(prefixedFormat, args...)
}
}