Card refactor and card panels
This commit is contained in:
parent
91e6eb6f6d
commit
758e4f79bb
|
@ -14,7 +14,7 @@ type Apple2 struct {
|
||||||
mmu *memoryManager
|
mmu *memoryManager
|
||||||
io *ioC0Page
|
io *ioC0Page
|
||||||
cg *CharacterGenerator
|
cg *CharacterGenerator
|
||||||
cards [8]card
|
cards [8]Card
|
||||||
isApple2e bool
|
isApple2e bool
|
||||||
commandChannel chan int
|
commandChannel chan int
|
||||||
cycleDurationNs float64 // Current speed. Inverse of the cpu clock in Ghz
|
cycleDurationNs float64 // Current speed. Inverse of the cpu clock in Ghz
|
||||||
|
|
|
@ -55,11 +55,16 @@ func setApple2eEnhanced(a *Apple2) {
|
||||||
addApple2ESoftSwitches(a.io)
|
addApple2ESoftSwitches(a.io)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Apple2) insertCard(c card, slot int) {
|
func (a *Apple2) insertCard(c Card, slot int) {
|
||||||
c.assign(a, slot)
|
c.assign(a, slot)
|
||||||
a.cards[slot] = c
|
a.cards[slot] = c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCards returns the array of inserted cards
|
||||||
|
func (a *Apple2) GetCards() [8]Card {
|
||||||
|
return a.cards
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
apple2RomSize = 12 * 1024
|
apple2RomSize = 12 * 1024
|
||||||
apple2eRomSize = 16 * 1024
|
apple2eRomSize = 16 * 1024
|
||||||
|
@ -113,24 +118,20 @@ func (a *Apple2) AddDisk2(slot int, diskRomFile string, diskImage, diskBImage st
|
||||||
|
|
||||||
// AddSmartPortDisk adds a smart port card and image
|
// AddSmartPortDisk adds a smart port card and image
|
||||||
func (a *Apple2) AddSmartPortDisk(slot int, hdImage string, trace bool) error {
|
func (a *Apple2) AddSmartPortDisk(slot int, hdImage string, trace bool) error {
|
||||||
var c cardHardDisk
|
c := NewCardHardDisk()
|
||||||
c.setTrace(trace)
|
c.trace = trace
|
||||||
c.loadRom(buildHardDiskRom(slot))
|
err := c.LoadImage(hdImage)
|
||||||
a.insertCard(&c, slot)
|
|
||||||
|
|
||||||
hd, err := openBlockDisk(hdImage)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.addDisk(hd)
|
a.insertCard(c, slot)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddVidHD adds a card with the signature of VidHD
|
// AddVidHD adds a card with the signature of VidHD
|
||||||
func (a *Apple2) AddVidHD(slot int) {
|
func (a *Apple2) AddVidHD(slot int) {
|
||||||
var c cardVidHD
|
c := NewCardVidHD()
|
||||||
c.loadRom(buildVidHDRom())
|
a.insertCard(c, slot)
|
||||||
a.insertCard(&c, slot)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddFastChip adds a card with the signature of VidHD
|
// AddFastChip adds a card with the signature of VidHD
|
||||||
|
@ -164,13 +165,8 @@ func (a *Apple2) AddMemoryExpansionCard(slot int, romFile string) error {
|
||||||
|
|
||||||
// AddThunderClockPlusCard inserts a ThunderClock Plus clock card
|
// AddThunderClockPlusCard inserts a ThunderClock Plus clock card
|
||||||
func (a *Apple2) AddThunderClockPlusCard(slot int, romFile string) error {
|
func (a *Apple2) AddThunderClockPlusCard(slot int, romFile string) error {
|
||||||
var c cardThunderClockPlus
|
c := NewCardThunderClockPlus()
|
||||||
data, err := loadResource(romFile)
|
a.insertCard(c, slot)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.loadRom(data)
|
|
||||||
a.insertCard(&c, slot)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
17
cardBase.go
17
cardBase.go
|
@ -1,12 +1,17 @@
|
||||||
package izapple2
|
package izapple2
|
||||||
|
|
||||||
type card interface {
|
// Card represents an Apple II card to be inserted in a slot
|
||||||
|
type Card interface {
|
||||||
loadRom(data []uint8)
|
loadRom(data []uint8)
|
||||||
assign(a *Apple2, slot int)
|
assign(a *Apple2, slot int)
|
||||||
|
|
||||||
|
GetName() string
|
||||||
|
GetInfo() map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
type cardBase struct {
|
type cardBase struct {
|
||||||
a *Apple2
|
a *Apple2
|
||||||
|
name string
|
||||||
romCsxx *memoryRangeROM
|
romCsxx *memoryRangeROM
|
||||||
romC8xx *memoryRangeROM
|
romC8xx *memoryRangeROM
|
||||||
romCxxx *memoryRangeROM
|
romCxxx *memoryRangeROM
|
||||||
|
@ -17,6 +22,14 @@ type cardBase struct {
|
||||||
_sswName [16]string
|
_sswName [16]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *cardBase) GetName() string {
|
||||||
|
return c.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cardBase) GetInfo() map[string]string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *cardBase) loadRom(data []uint8) {
|
func (c *cardBase) loadRom(data []uint8) {
|
||||||
if c.a != nil {
|
if c.a != nil {
|
||||||
panic("Assert failed. Rom must be loaded before inserting the card in the slot")
|
panic("Assert failed. Rom must be loaded before inserting the card in the slot")
|
||||||
|
@ -27,7 +40,7 @@ func (c *cardBase) loadRom(data []uint8) {
|
||||||
} 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 = newMemoryRangeROM(0, data, "Slor ROM")
|
c.romCsxx = newMemoryRangeROM(0, data, "Slot ROM")
|
||||||
c.romC8xx = newMemoryRangeROM(0xc800, data, "Slot C8 ROM")
|
c.romC8xx = newMemoryRangeROM(0xc800, data, "Slot C8 ROM")
|
||||||
} 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
|
||||||
|
|
342
cardHardDisk.go
342
cardHardDisk.go
|
@ -1,6 +1,9 @@
|
||||||
package izapple2
|
package izapple2
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
To implement a hard drive we just have to support boot from #PR7 and the PRODOS expextations.
|
To implement a hard drive we just have to support boot from #PR7 and the PRODOS expextations.
|
||||||
|
@ -14,11 +17,193 @@ See:
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type cardHardDisk struct {
|
// CardHardDisk represents a SmartPort card
|
||||||
|
type CardHardDisk struct {
|
||||||
cardBase
|
cardBase
|
||||||
|
|
||||||
|
filename string
|
||||||
|
trace bool
|
||||||
|
|
||||||
|
config CardHardDiskConfig
|
||||||
disk *blockDisk
|
disk *blockDisk
|
||||||
mliParams uint16
|
mliParams uint16
|
||||||
trace bool
|
}
|
||||||
|
|
||||||
|
// CardHardDiskConfig represents a SmartPort card configuration
|
||||||
|
type CardHardDiskConfig struct {
|
||||||
|
Filename string
|
||||||
|
Trace bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCardHardDisk creates a new SmartPort card
|
||||||
|
func NewCardHardDisk() *CardHardDisk {
|
||||||
|
var c CardHardDisk
|
||||||
|
c.name = "Smartport Card"
|
||||||
|
return &c
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInfo return smartport info
|
||||||
|
func (c *CardHardDisk) GetInfo() map[string]string {
|
||||||
|
info := make(map[string]string)
|
||||||
|
info["filename"] = c.filename
|
||||||
|
info["trace"] = strconv.FormatBool(c.trace)
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadImage loads a disk image
|
||||||
|
func (c *CardHardDisk) LoadImage(filename string) error {
|
||||||
|
hd, err := openBlockDisk(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.disk = hd
|
||||||
|
c.filename = filename
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
proDosDeviceCommandStatus = 0
|
||||||
|
proDosDeviceCommandRead = 1
|
||||||
|
proDosDeviceCommandWrite = 2
|
||||||
|
proDosDeviceCommandFormat = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
proDosDeviceNoError = uint8(0)
|
||||||
|
proDosDeviceErrorIO = uint8(0x27)
|
||||||
|
proDosDeviceErrorNoDevice = uint8(0x28)
|
||||||
|
proDosDeviceErrorWriteProtected = uint8(0x2b)
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *CardHardDisk) assign(a *Apple2, slot int) {
|
||||||
|
c.loadRom(buildHardDiskRom(slot))
|
||||||
|
|
||||||
|
c.addCardSoftSwitchR(0, func(*ioC0Page) uint8 {
|
||||||
|
// Prodos entry point
|
||||||
|
command := a.mmu.Peek(0x42)
|
||||||
|
unit := a.mmu.Peek(0x43)
|
||||||
|
address := uint16(a.mmu.Peek(0x44)) + uint16(a.mmu.Peek(0x45))<<8
|
||||||
|
block := uint16(a.mmu.Peek(0x46)) + uint16(a.mmu.Peek(0x47))<<8
|
||||||
|
if c.config.Trace {
|
||||||
|
fmt.Printf("[CardHardDisk] Prodos command %v on slot %v, unit $%x, block %v to $%x.\n", command, slot, unit, block, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch command {
|
||||||
|
case proDosDeviceCommandStatus:
|
||||||
|
return c.status(unit, address)
|
||||||
|
case proDosDeviceCommandRead:
|
||||||
|
return c.readBlock(block, address)
|
||||||
|
case proDosDeviceCommandWrite:
|
||||||
|
return c.writeBlock(block, address)
|
||||||
|
default:
|
||||||
|
// Prodos device command not supported
|
||||||
|
return proDosDeviceErrorIO
|
||||||
|
}
|
||||||
|
}, "HDCOMMAND")
|
||||||
|
c.addCardSoftSwitchR(1, func(*ioC0Page) uint8 {
|
||||||
|
// Blocks available, low byte
|
||||||
|
return uint8(c.disk.blocks)
|
||||||
|
}, "HDBLOCKSLO")
|
||||||
|
c.addCardSoftSwitchR(2, func(*ioC0Page) uint8 {
|
||||||
|
// Blocks available, high byte
|
||||||
|
return uint8(c.disk.blocks >> 8)
|
||||||
|
}, "HDBLOCKHI")
|
||||||
|
|
||||||
|
c.addCardSoftSwitchR(3, func(*ioC0Page) uint8 {
|
||||||
|
// Smart port entry point
|
||||||
|
command := c.a.mmu.Peek(c.mliParams + 1)
|
||||||
|
paramsAddress := uint16(c.a.mmu.Peek(c.mliParams+2)) + uint16(c.a.mmu.Peek(c.mliParams+3))<<8
|
||||||
|
unit := a.mmu.Peek(paramsAddress + 1)
|
||||||
|
address := uint16(a.mmu.Peek(paramsAddress+2)) + uint16(a.mmu.Peek(paramsAddress+3))<<8
|
||||||
|
block := uint16(a.mmu.Peek(paramsAddress+4)) + uint16(a.mmu.Peek(paramsAddress+5))<<8
|
||||||
|
if c.config.Trace {
|
||||||
|
fmt.Printf("[CardHardDisk] Smart port command %v on slot %v, unit $%x, block %v to $%x.\n", command, slot, unit, block, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch command {
|
||||||
|
case proDosDeviceCommandStatus:
|
||||||
|
return c.status(unit, address)
|
||||||
|
case proDosDeviceCommandRead:
|
||||||
|
return c.readBlock(block, address)
|
||||||
|
case proDosDeviceCommandWrite:
|
||||||
|
return c.writeBlock(block, address)
|
||||||
|
default:
|
||||||
|
// Smartport device command not supported
|
||||||
|
return proDosDeviceErrorIO
|
||||||
|
}
|
||||||
|
}, "HDSMARTPORT")
|
||||||
|
c.addCardSoftSwitchW(4, func(_ *ioC0Page, value uint8) {
|
||||||
|
c.mliParams = (c.mliParams & 0xff00) + uint16(value)
|
||||||
|
if c.config.Trace {
|
||||||
|
fmt.Printf("[CardHardDisk] Smart port LO: 0x%x.\n", c.mliParams)
|
||||||
|
}
|
||||||
|
}, "HDSMARTPORTLO")
|
||||||
|
c.addCardSoftSwitchW(5, func(_ *ioC0Page, value uint8) {
|
||||||
|
c.mliParams = (c.mliParams & 0x00ff) + (uint16(value) << 8)
|
||||||
|
if c.config.Trace {
|
||||||
|
fmt.Printf("[CardHardDisk] Smart port HI: 0x%x.\n", c.mliParams)
|
||||||
|
}
|
||||||
|
}, "HDSMARTPORTHI")
|
||||||
|
|
||||||
|
c.cardBase.assign(a, slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CardHardDisk) readBlock(block uint16, dest uint16) uint8 {
|
||||||
|
if c.config.Trace {
|
||||||
|
fmt.Printf("[CardHardDisk] Read block %v into $%x.\n", block, dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.disk.read(uint32(block))
|
||||||
|
if err != nil {
|
||||||
|
return proDosDeviceErrorIO
|
||||||
|
}
|
||||||
|
// Byte by byte transfer to memory using the full Poke code path
|
||||||
|
for i := uint16(0); i < uint16(proDosBlockSize); i++ {
|
||||||
|
c.a.mmu.Poke(dest+i, data[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return proDosDeviceNoError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CardHardDisk) writeBlock(block uint16, source uint16) uint8 {
|
||||||
|
if c.config.Trace {
|
||||||
|
fmt.Printf("[CardHardDisk] Write block %v from $%x.\n", block, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.disk.readOnly {
|
||||||
|
return proDosDeviceErrorWriteProtected
|
||||||
|
}
|
||||||
|
|
||||||
|
// Byte by byte transfer from memory using the full Peek code path
|
||||||
|
buf := make([]uint8, proDosBlockSize)
|
||||||
|
for i := uint16(0); i < uint16(proDosBlockSize); i++ {
|
||||||
|
buf[i] = c.a.mmu.Peek(source + i)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.disk.write(uint32(block), buf)
|
||||||
|
if err != nil {
|
||||||
|
return proDosDeviceErrorIO
|
||||||
|
}
|
||||||
|
|
||||||
|
return proDosDeviceNoError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CardHardDisk) status(unit uint8, dest uint16) uint8 {
|
||||||
|
if c.config.Trace {
|
||||||
|
fmt.Printf("[CardHardDisk] Status for %v into $%x.\n", unit, dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
// See http://www.1000bit.it/support/manuali/apple/technotes/smpt/tn.smpt.2.html
|
||||||
|
c.a.mmu.Poke(dest+0, 0x02) // One device
|
||||||
|
c.a.mmu.Poke(dest+1, 0xff) // No interrupt
|
||||||
|
c.a.mmu.Poke(dest+2, 0x00)
|
||||||
|
c.a.mmu.Poke(dest+3, 0x00) // Unknown manufacturer
|
||||||
|
c.a.mmu.Poke(dest+4, 0x01)
|
||||||
|
c.a.mmu.Poke(dest+5, 0x00) // Versión 1.0 final
|
||||||
|
c.a.mmu.Poke(dest+6, 0x00)
|
||||||
|
c.a.mmu.Poke(dest+7, 0x00) // Reserved
|
||||||
|
|
||||||
|
return proDosDeviceNoError
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildHardDiskRom(slot int) []uint8 {
|
func buildHardDiskRom(slot int) []uint8 {
|
||||||
|
@ -98,154 +283,3 @@ func buildHardDiskRom(slot int) []uint8 {
|
||||||
|
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
proDosDeviceCommandStatus = 0
|
|
||||||
proDosDeviceCommandRead = 1
|
|
||||||
proDosDeviceCommandWrite = 2
|
|
||||||
proDosDeviceCommandFormat = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
proDosDeviceNoError = uint8(0)
|
|
||||||
proDosDeviceErrorIO = uint8(0x27)
|
|
||||||
proDosDeviceErrorNoDevice = uint8(0x28)
|
|
||||||
proDosDeviceErrorWriteProtected = uint8(0x2b)
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *cardHardDisk) assign(a *Apple2, slot int) {
|
|
||||||
c.addCardSoftSwitchR(0, func(*ioC0Page) uint8 {
|
|
||||||
// Prodos entry point
|
|
||||||
command := a.mmu.Peek(0x42)
|
|
||||||
unit := a.mmu.Peek(0x43)
|
|
||||||
address := uint16(a.mmu.Peek(0x44)) + uint16(a.mmu.Peek(0x45))<<8
|
|
||||||
block := uint16(a.mmu.Peek(0x46)) + uint16(a.mmu.Peek(0x47))<<8
|
|
||||||
if c.trace {
|
|
||||||
fmt.Printf("[CardHardDisk] Prodos command %v on slot %v, unit $%x, block %v to $%x.\n", command, slot, unit, block, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch command {
|
|
||||||
case proDosDeviceCommandStatus:
|
|
||||||
return c.status(unit, address)
|
|
||||||
case proDosDeviceCommandRead:
|
|
||||||
return c.readBlock(block, address)
|
|
||||||
case proDosDeviceCommandWrite:
|
|
||||||
return c.writeBlock(block, address)
|
|
||||||
default:
|
|
||||||
// Prodos device command not supported
|
|
||||||
return proDosDeviceErrorIO
|
|
||||||
}
|
|
||||||
}, "HDCOMMAND")
|
|
||||||
c.addCardSoftSwitchR(1, func(*ioC0Page) uint8 {
|
|
||||||
// Blocks available, low byte
|
|
||||||
return uint8(c.disk.blocks)
|
|
||||||
}, "HDBLOCKSLO")
|
|
||||||
c.addCardSoftSwitchR(2, func(*ioC0Page) uint8 {
|
|
||||||
// Blocks available, high byte
|
|
||||||
return uint8(c.disk.blocks >> 8)
|
|
||||||
}, "HDBLOCKHI")
|
|
||||||
|
|
||||||
c.addCardSoftSwitchR(3, func(*ioC0Page) uint8 {
|
|
||||||
// Smart port entry point
|
|
||||||
command := c.a.mmu.Peek(c.mliParams + 1)
|
|
||||||
paramsAddress := uint16(c.a.mmu.Peek(c.mliParams+2)) + uint16(c.a.mmu.Peek(c.mliParams+3))<<8
|
|
||||||
unit := a.mmu.Peek(paramsAddress + 1)
|
|
||||||
address := uint16(a.mmu.Peek(paramsAddress+2)) + uint16(a.mmu.Peek(paramsAddress+3))<<8
|
|
||||||
block := uint16(a.mmu.Peek(paramsAddress+4)) + uint16(a.mmu.Peek(paramsAddress+5))<<8
|
|
||||||
if c.trace {
|
|
||||||
fmt.Printf("[CardHardDisk] Smart port command %v on slot %v, unit $%x, block %v to $%x.\n", command, slot, unit, block, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch command {
|
|
||||||
case proDosDeviceCommandStatus:
|
|
||||||
return c.status(unit, address)
|
|
||||||
case proDosDeviceCommandRead:
|
|
||||||
return c.readBlock(block, address)
|
|
||||||
case proDosDeviceCommandWrite:
|
|
||||||
return c.writeBlock(block, address)
|
|
||||||
default:
|
|
||||||
// Smartport device command not supported
|
|
||||||
return proDosDeviceErrorIO
|
|
||||||
}
|
|
||||||
}, "HDSMARTPORT")
|
|
||||||
c.addCardSoftSwitchW(4, func(_ *ioC0Page, value uint8) {
|
|
||||||
c.mliParams = (c.mliParams & 0xff00) + uint16(value)
|
|
||||||
if c.trace {
|
|
||||||
fmt.Printf("[CardHardDisk] Smart port LO: 0x%x.\n", c.mliParams)
|
|
||||||
}
|
|
||||||
}, "HDSMARTPORTLO")
|
|
||||||
c.addCardSoftSwitchW(5, func(_ *ioC0Page, value uint8) {
|
|
||||||
c.mliParams = (c.mliParams & 0x00ff) + (uint16(value) << 8)
|
|
||||||
if c.trace {
|
|
||||||
fmt.Printf("[CardHardDisk] Smart port HI: 0x%x.\n", c.mliParams)
|
|
||||||
}
|
|
||||||
}, "HDSMARTPORTHI")
|
|
||||||
|
|
||||||
c.cardBase.assign(a, slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cardHardDisk) readBlock(block uint16, dest uint16) uint8 {
|
|
||||||
if c.trace {
|
|
||||||
fmt.Printf("[CardHardDisk] Read block %v into $%x.\n", block, dest)
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := c.disk.read(uint32(block))
|
|
||||||
if err != nil {
|
|
||||||
return proDosDeviceErrorIO
|
|
||||||
}
|
|
||||||
// Byte by byte transfer to memory using the full Poke code path
|
|
||||||
for i := uint16(0); i < uint16(proDosBlockSize); i++ {
|
|
||||||
c.a.mmu.Poke(dest+i, data[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
return proDosDeviceNoError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cardHardDisk) writeBlock(block uint16, source uint16) uint8 {
|
|
||||||
if c.trace {
|
|
||||||
fmt.Printf("[CardHardDisk] Write block %v from $%x.\n", block, source)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.disk.readOnly {
|
|
||||||
return proDosDeviceErrorWriteProtected
|
|
||||||
}
|
|
||||||
|
|
||||||
// Byte by byte transfer from memory using the full Peek code path
|
|
||||||
buf := make([]uint8, proDosBlockSize)
|
|
||||||
for i := uint16(0); i < uint16(proDosBlockSize); i++ {
|
|
||||||
buf[i] = c.a.mmu.Peek(source + i)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := c.disk.write(uint32(block), buf)
|
|
||||||
if err != nil {
|
|
||||||
return proDosDeviceErrorIO
|
|
||||||
}
|
|
||||||
|
|
||||||
return proDosDeviceNoError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cardHardDisk) status(unit uint8, dest uint16) uint8 {
|
|
||||||
if c.trace {
|
|
||||||
fmt.Printf("[CardHardDisk] Status for %v into $%x.\n", unit, dest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// See http://www.1000bit.it/support/manuali/apple/technotes/smpt/tn.smpt.2.html
|
|
||||||
c.a.mmu.Poke(dest+0, 0x02) // One device
|
|
||||||
c.a.mmu.Poke(dest+1, 0xff) // No interrupt
|
|
||||||
c.a.mmu.Poke(dest+2, 0x00)
|
|
||||||
c.a.mmu.Poke(dest+3, 0x00) // Unknown manufacturer
|
|
||||||
c.a.mmu.Poke(dest+4, 0x01)
|
|
||||||
c.a.mmu.Poke(dest+5, 0x00) // Versión 1.0 final
|
|
||||||
c.a.mmu.Poke(dest+6, 0x00)
|
|
||||||
c.a.mmu.Poke(dest+7, 0x00) // Reserved
|
|
||||||
|
|
||||||
return proDosDeviceNoError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cardHardDisk) addDisk(disk *blockDisk) {
|
|
||||||
c.disk = disk
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cardHardDisk) setTrace(trace bool) {
|
|
||||||
c.trace = trace
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,12 +19,27 @@ uPD1990AC hookup:
|
||||||
bit 7 = data out
|
bit 7 = data out
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type cardThunderClockPlus struct {
|
// CardThunderClockPlus represents a ThunderClock+ card
|
||||||
microPD1990ac
|
type CardThunderClockPlus struct {
|
||||||
cardBase
|
cardBase
|
||||||
|
microPD1990ac
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cardThunderClockPlus) assign(a *Apple2, slot int) {
|
// NewCardThunderClockPlus creates a new CardThunderClockPlus
|
||||||
|
func NewCardThunderClockPlus() *CardThunderClockPlus {
|
||||||
|
var c CardThunderClockPlus
|
||||||
|
c.name = "ThunderClock+ Card"
|
||||||
|
|
||||||
|
data, err := loadResource("<internal>/ThunderclockPlusROM.bin")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
c.loadRom(data)
|
||||||
|
|
||||||
|
return &c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CardThunderClockPlus) assign(a *Apple2, slot int) {
|
||||||
c.addCardSoftSwitchR(0, func(*ioC0Page) uint8 {
|
c.addCardSoftSwitchR(0, func(*ioC0Page) uint8 {
|
||||||
bit := c.microPD1990ac.out()
|
bit := c.microPD1990ac.out()
|
||||||
// Get the next data bit from uPD1990AC on the MSB
|
// Get the next data bit from uPD1990AC on the MSB
|
||||||
|
|
14
cardVidHD.go
14
cardVidHD.go
|
@ -8,10 +8,18 @@ See:
|
||||||
http://www.applelogic.org/files/GSHARDWAREREF.pdf, page 89
|
http://www.applelogic.org/files/GSHARDWAREREF.pdf, page 89
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type cardVidHD struct {
|
// CardVidHD represents a VidHD card
|
||||||
|
type CardVidHD struct {
|
||||||
cardBase
|
cardBase
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewCardVidHD creates a new VidHD card
|
||||||
|
func NewCardVidHD() *CardVidHD {
|
||||||
|
var c CardVidHD
|
||||||
|
c.name = "VidHD Card"
|
||||||
|
return &c
|
||||||
|
}
|
||||||
|
|
||||||
func buildVidHDRom() []uint8 {
|
func buildVidHDRom() []uint8 {
|
||||||
data := make([]uint8, 256)
|
data := make([]uint8, 256)
|
||||||
|
|
||||||
|
@ -26,7 +34,9 @@ const (
|
||||||
ioDataNewVideo uint8 = 0x29
|
ioDataNewVideo uint8 = 0x29
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *cardVidHD) assign(a *Apple2, slot int) {
|
func (c *CardVidHD) assign(a *Apple2, slot int) {
|
||||||
|
c.loadRom(buildVidHDRom())
|
||||||
|
|
||||||
// The softswitches are outside the card reserved ss
|
// The softswitches are outside the card reserved ss
|
||||||
a.io.addSoftSwitchR(0x22, notImplementedSoftSwitchR, "VIDHD-TBCOLOR")
|
a.io.addSoftSwitchR(0x22, notImplementedSoftSwitchR, "VIDHD-TBCOLOR")
|
||||||
a.io.addSoftSwitchW(0x22, notImplementedSoftSwitchW, "VIDHD-TBCOLOR")
|
a.io.addSoftSwitchW(0x22, notImplementedSoftSwitchW, "VIDHD-TBCOLOR")
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -109,6 +108,5 @@ func (j *joysticks) ReadPaddle(i int) (uint8, bool) {
|
||||||
if info != nil {
|
if info != nil {
|
||||||
value = info.paddles[i%2]
|
value = info.paddles[i%2]
|
||||||
}
|
}
|
||||||
fmt.Printf("%v, %v, %v\n", i, j.info[0], value)
|
|
||||||
return value, value != unplugged
|
return value, value != unplugged
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"fyne.io/fyne"
|
||||||
|
"fyne.io/fyne/widget"
|
||||||
|
"github.com/ivanizag/izapple2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type panelCard struct {
|
||||||
|
w fyne.Widget
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPanelCard(slot int, card izapple2.Card) *panelCard {
|
||||||
|
var pc panelCard
|
||||||
|
|
||||||
|
form := widget.NewForm()
|
||||||
|
form.Append("slot", widget.NewLabel(strconv.Itoa(slot)))
|
||||||
|
|
||||||
|
info := card.GetInfo()
|
||||||
|
if info != nil {
|
||||||
|
for k, v := range info {
|
||||||
|
form.Append(k, widget.NewLabel(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pc.w = widget.NewGroup(card.GetName(), form)
|
||||||
|
return &pc
|
||||||
|
}
|
|
@ -1,23 +1,29 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fyne.io/fyne"
|
|
||||||
"fyne.io/fyne/widget"
|
"fyne.io/fyne/widget"
|
||||||
)
|
)
|
||||||
|
|
||||||
type panelDevices struct {
|
type panelDevices struct {
|
||||||
s *state
|
s *state
|
||||||
w fyne.Widget
|
w *widget.Box
|
||||||
joystick *panelJoystick
|
joystick *panelJoystick
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPanelDevices(s *state) *panelDevices {
|
func newPanelDevices(s *state) *panelDevices {
|
||||||
var pd panelDevices
|
var pd panelDevices
|
||||||
pd.s = s
|
pd.s = s
|
||||||
|
pd.w = widget.NewVBox()
|
||||||
|
|
||||||
pd.joystick = newPanelJoystick()
|
pd.joystick = newPanelJoystick()
|
||||||
|
pd.w.Append(pd.joystick.w)
|
||||||
|
|
||||||
pd.w = widget.NewVBox(pd.joystick.w)
|
var cards = s.a.GetCards()
|
||||||
|
for i, card := range cards {
|
||||||
|
if card != nil && card.GetName() != "" {
|
||||||
|
pd.w.Append(newPanelCard(i, card).w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &pd
|
return &pd
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ func newPanelJoystick() *panelJoystick {
|
||||||
|
|
||||||
pj.labelJoy1 = widget.NewLabel("")
|
pj.labelJoy1 = widget.NewLabel("")
|
||||||
pj.labelJoy2 = widget.NewLabel("")
|
pj.labelJoy2 = widget.NewLabel("")
|
||||||
widget.NewForm()
|
|
||||||
pj.w = widget.NewGroup(
|
pj.w = widget.NewGroup(
|
||||||
"Joysticks",
|
"Joysticks",
|
||||||
widget.NewForm(
|
widget.NewForm(
|
||||||
|
|
Loading…
Reference in New Issue