Separation of the Smartport card and the Smartport hard disk
This commit is contained in:
parent
d631ee7973
commit
5d857dda4b
|
@ -4,6 +4,8 @@ a2sdl.exe
|
||||||
frontend/a2sdl/a2sdl
|
frontend/a2sdl/a2sdl
|
||||||
frontend/a2sdl/*.woz
|
frontend/a2sdl/*.woz
|
||||||
frontend/a2sdl/*.dsk
|
frontend/a2sdl/*.dsk
|
||||||
|
frontend/a2sdl/*.po
|
||||||
|
frontend/a2sdl/*.2mg
|
||||||
frontend/a2fyne/a2fyne
|
frontend/a2fyne/a2fyne
|
||||||
frontend/headless/headless
|
frontend/headless/headless
|
||||||
frontend/*/snapshot.gif
|
frontend/*/snapshot.gif
|
||||||
|
|
|
@ -139,14 +139,12 @@ func (a *Apple2) AddDisk2Sequencer(slot int, diskImage, diskBImage string, track
|
||||||
|
|
||||||
// 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 {
|
||||||
c := NewCardHardDisk()
|
c := NewCardSmartport()
|
||||||
c.trace = trace
|
c.trace = trace
|
||||||
err := c.LoadImage(hdImage)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
a.insertCard(c, slot)
|
a.insertCard(c, slot)
|
||||||
return nil
|
|
||||||
|
err := c.LoadImage(hdImage)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddVidHD adds a card with the signature of VidHD
|
// AddVidHD adds a card with the signature of VidHD
|
||||||
|
|
|
@ -3,12 +3,10 @@ package izapple2
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/ivanizag/izapple2/storage"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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 expectations.
|
||||||
|
|
||||||
See:
|
See:
|
||||||
Beneath Prodos, section 6-6, 7-13 and 5-8. (http://www.apple-iigs.info/doc/fichiers/beneathprodos.pdf)
|
Beneath Prodos, section 6-6, 7-13 and 5-8. (http://www.apple-iigs.info/doc/fichiers/beneathprodos.pdf)
|
||||||
|
@ -19,188 +17,115 @@ See:
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// CardHardDisk represents a SmartPort card
|
// CardSmartport represents a SmartPort card
|
||||||
type CardHardDisk struct {
|
type CardSmartport struct {
|
||||||
cardBase
|
cardBase
|
||||||
|
hardDiskDevice smartPortDevice
|
||||||
|
hardDiskBlocks uint32
|
||||||
|
|
||||||
filename string
|
|
||||||
trace bool
|
|
||||||
|
|
||||||
disk *storage.BlockDisk
|
|
||||||
mliParams uint16
|
mliParams uint16
|
||||||
|
trace bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCardHardDisk creates a new SmartPort card
|
// NewCardSmartport creates a new SmartPort card
|
||||||
func NewCardHardDisk() *CardHardDisk {
|
func NewCardSmartport() *CardSmartport {
|
||||||
var c CardHardDisk
|
var c CardSmartport
|
||||||
c.name = "Smartport Card"
|
c.name = "Smartport Card"
|
||||||
return &c
|
return &c
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInfo returns smartport info
|
// GetInfo returns smartport info
|
||||||
func (c *CardHardDisk) GetInfo() map[string]string {
|
func (c *CardSmartport) GetInfo() map[string]string {
|
||||||
info := make(map[string]string)
|
info := make(map[string]string)
|
||||||
info["filename"] = c.filename
|
|
||||||
info["trace"] = strconv.FormatBool(c.trace)
|
info["trace"] = strconv.FormatBool(c.trace)
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadImage loads a disk image
|
// LoadImage loads a disk image
|
||||||
func (c *CardHardDisk) LoadImage(filename string) error {
|
func (c *CardSmartport) LoadImage(filename string) error {
|
||||||
hd, err := storage.OpenBlockDisk(filename)
|
device, err := NewSmartPortHardDisk(c, filename)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
|
device.trace = c.trace
|
||||||
|
c.hardDiskDevice = device
|
||||||
|
c.hardDiskBlocks = device.disk.GetSizeInBlocks() // Needed for the PRODOS status
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.disk = hd
|
|
||||||
c.filename = filename
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
func (c *CardSmartport) assign(a *Apple2, slot int) {
|
||||||
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.loadRom(buildHardDiskRom(slot))
|
||||||
|
|
||||||
c.addCardSoftSwitchR(0, func() uint8 {
|
c.addCardSoftSwitchR(0, func() uint8 {
|
||||||
// Prodos entry point
|
// Prodos entry point
|
||||||
command := a.mmu.Peek(0x42)
|
command := a.mmu.Peek(0x42)
|
||||||
unit := a.mmu.Peek(0x43)
|
unit := a.mmu.Peek(0x43) & 0x0f
|
||||||
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 {
|
// Generate Smarport compatible params
|
||||||
case proDosDeviceCommandStatus:
|
var params []uint8
|
||||||
return c.status(unit, address)
|
if command == proDosDeviceCommandStatus {
|
||||||
case proDosDeviceCommandRead:
|
params = []uint8{
|
||||||
return c.readBlock(block, address)
|
5, unit,
|
||||||
case proDosDeviceCommandWrite:
|
a.mmu.Peek(0x44), a.mmu.Peek(0x45), // data address
|
||||||
return c.writeBlock(block, address)
|
0,
|
||||||
default:
|
|
||||||
// Prodos device command not supported
|
|
||||||
return proDosDeviceErrorIO
|
|
||||||
}
|
}
|
||||||
}, "HDCOMMAND")
|
} else {
|
||||||
|
params = []uint8{
|
||||||
|
7, unit,
|
||||||
|
a.mmu.Peek(0x44), a.mmu.Peek(0x45), // data address
|
||||||
|
a.mmu.Peek(0x46), a.mmu.Peek(0x47), 0, // block number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result := c.hardDiskDevice.exec(command, params)
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[CardSmartport] PRODOS command $%x on slot %v, unit $%x, result $%02x.\n", command, slot, unit, result)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}, "SMARTPORTPRODOSCOMMAND")
|
||||||
|
|
||||||
c.addCardSoftSwitchR(1, func() uint8 {
|
c.addCardSoftSwitchR(1, func() uint8 {
|
||||||
// Blocks available, low byte
|
// Blocks available, low byte
|
||||||
return uint8(c.disk.GetSizeInBlocks())
|
return uint8(c.hardDiskBlocks)
|
||||||
}, "HDBLOCKSLO")
|
}, "HDBLOCKSLO")
|
||||||
c.addCardSoftSwitchR(2, func() uint8 {
|
c.addCardSoftSwitchR(2, func() uint8 {
|
||||||
// Blocks available, high byte
|
// Blocks available, high byte
|
||||||
return uint8(c.disk.GetSizeInBlocks() >> 8)
|
return uint8(c.hardDiskBlocks)
|
||||||
}, "HDBLOCKHI")
|
}, "HDBLOCKHI")
|
||||||
|
|
||||||
c.addCardSoftSwitchR(3, func() uint8 {
|
c.addCardSoftSwitchR(3, func() uint8 {
|
||||||
// Smart port entry point
|
// Smart port entry point
|
||||||
command := c.a.mmu.Peek(c.mliParams + 1)
|
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
|
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 {
|
paramsSize := int(a.mmu.Peek(paramsAddress + 0))
|
||||||
case proDosDeviceCommandStatus:
|
params := make([]uint8, paramsSize)
|
||||||
return c.status(unit, address)
|
for i := 0; i < paramsSize; i++ {
|
||||||
case proDosDeviceCommandRead:
|
params[i] = a.mmu.Peek(paramsAddress + uint16(i))
|
||||||
return c.readBlock(block, address)
|
|
||||||
case proDosDeviceCommandWrite:
|
|
||||||
return c.writeBlock(block, address)
|
|
||||||
default:
|
|
||||||
// Smartport device command not supported
|
|
||||||
return proDosDeviceErrorIO
|
|
||||||
}
|
}
|
||||||
}, "HDSMARTPORT")
|
unit := params[1]
|
||||||
|
|
||||||
|
result := c.hardDiskDevice.exec(command, params)
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[CardSmartport] Smart port command $%x on slot %v, unit $%x, result $%02x.\n", command, slot, unit, result)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}, "SMARTPORTEXEC")
|
||||||
|
|
||||||
c.addCardSoftSwitchW(4, func(value uint8) {
|
c.addCardSoftSwitchW(4, func(value uint8) {
|
||||||
c.mliParams = (c.mliParams & 0xff00) + uint16(value)
|
c.mliParams = (c.mliParams & 0xff00) + uint16(value)
|
||||||
if c.trace {
|
if c.trace {
|
||||||
fmt.Printf("[CardHardDisk] Smart port LO: 0x%x.\n", c.mliParams)
|
fmt.Printf("[CardSmartport] Smart port LO: 0x%x.\n", c.mliParams)
|
||||||
}
|
}
|
||||||
}, "HDSMARTPORTLO")
|
}, "HDSMARTPORTLO")
|
||||||
c.addCardSoftSwitchW(5, func(value uint8) {
|
c.addCardSoftSwitchW(5, func(value uint8) {
|
||||||
c.mliParams = (c.mliParams & 0x00ff) + (uint16(value) << 8)
|
c.mliParams = (c.mliParams & 0x00ff) + (uint16(value) << 8)
|
||||||
if c.trace {
|
if c.trace {
|
||||||
fmt.Printf("[CardHardDisk] Smart port HI: 0x%x.\n", c.mliParams)
|
fmt.Printf("[CardSmartport] Smart port HI: 0x%x.\n", c.mliParams)
|
||||||
}
|
}
|
||||||
}, "HDSMARTPORTHI")
|
}, "HDSMARTPORTHI")
|
||||||
|
|
||||||
c.cardBase.assign(a, slot)
|
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(len(data)); 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.IsReadOnly() {
|
|
||||||
return proDosDeviceErrorWriteProtected
|
|
||||||
}
|
|
||||||
|
|
||||||
// Byte by byte transfer from memory using the full Peek code path
|
|
||||||
buf := make([]uint8, storage.ProDosBlockSize)
|
|
||||||
for i := uint16(0); i < uint16(len(buf)); 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) // Version 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 {
|
||||||
data := make([]uint8, 256)
|
data := make([]uint8, 256)
|
||||||
ssBase := 0x80 + uint8(slot<<4)
|
ssBase := 0x80 + uint8(slot<<4)
|
|
@ -0,0 +1,46 @@
|
||||||
|
package izapple2
|
||||||
|
|
||||||
|
/*
|
||||||
|
A smartport device
|
||||||
|
*/
|
||||||
|
|
||||||
|
type smartPortDevice interface {
|
||||||
|
exec(command uint8, params []uint8) uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
proDosDeviceCommandStatus = 0
|
||||||
|
proDosDeviceCommandRead = 1
|
||||||
|
proDosDeviceCommandWrite = 2
|
||||||
|
proDosDeviceCommandFormat = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
proDosDeviceNoError = uint8(0)
|
||||||
|
proDosDeviceErrorIO = uint8(0x27)
|
||||||
|
proDosDeviceErrorNoDevice = uint8(0x28)
|
||||||
|
proDosDeviceErrorWriteProtected = uint8(0x2b)
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
func smartPortParam8(params []uint8, offset uint8) uint8 {
|
||||||
|
if int(offset) >= len(params) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return params[offset]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func smartPortParam16(params []uint8, offset uint8) uint16 {
|
||||||
|
if int(offset+1) >= len(params) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return uint16(params[offset]) + uint16(params[offset+1])<<8
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartPortParam24(params []uint8, offset uint8) uint32 {
|
||||||
|
if int(offset+2) >= len(params) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return uint32(params[offset]) + uint32(params[offset+1])<<8 + uint32(params[offset+2])<<16
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
package izapple2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ivanizag/izapple2/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
To implement a smartport hard drive we have to support the smartport commands.
|
||||||
|
|
||||||
|
See:
|
||||||
|
Beneath Prodos, section 6-6, 7-13 and 5-8. (http://www.apple-iigs.info/doc/fichiers/beneathprodos.pdf)
|
||||||
|
Apple IIc Technical Reference, 2nd Edition. Chapter 8. https://ia800207.us.archive.org/19/items/AppleIIcTechnicalReference2ndEd/Apple%20IIc%20Technical%20Reference%202nd%20ed.pdf
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// SmartPortHardDisk represents a SmartPort card
|
||||||
|
type SmartPortHardDisk struct {
|
||||||
|
host *CardSmartport // For DMA
|
||||||
|
filename string
|
||||||
|
trace bool
|
||||||
|
disk *storage.BlockDisk
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSmartPortHardDisk creates a new hard disk with the smartport interface
|
||||||
|
func NewSmartPortHardDisk(host *CardSmartport, filename string) (*SmartPortHardDisk, error) {
|
||||||
|
var d SmartPortHardDisk
|
||||||
|
d.host = host
|
||||||
|
d.filename = filename
|
||||||
|
|
||||||
|
hd, err := storage.OpenBlockDisk(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
d.disk = hd
|
||||||
|
|
||||||
|
return &d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *SmartPortHardDisk) exec(command uint8, params []uint8) uint8 {
|
||||||
|
var result uint8
|
||||||
|
|
||||||
|
switch command {
|
||||||
|
case proDosDeviceCommandStatus:
|
||||||
|
address := smartPortParam16(params, 2)
|
||||||
|
result = d.status(address)
|
||||||
|
|
||||||
|
case proDosDeviceCommandRead:
|
||||||
|
address := smartPortParam16(params, 2)
|
||||||
|
block := smartPortParam24(params, 4)
|
||||||
|
result = d.readBlock(block, address)
|
||||||
|
|
||||||
|
case proDosDeviceCommandWrite:
|
||||||
|
address := smartPortParam16(params, 2)
|
||||||
|
block := smartPortParam24(params, 4)
|
||||||
|
result = d.writeBlock(block, address)
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Prodos device command not supported
|
||||||
|
result = proDosDeviceErrorIO
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.trace {
|
||||||
|
fmt.Printf("[SmartPortHardDisk] Command $%x, return $%02x \n", command, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *SmartPortHardDisk) readBlock(block uint32, dest uint16) uint8 {
|
||||||
|
if d.trace {
|
||||||
|
fmt.Printf("[SmartPortHardDisk] Read block %v into $%x.\n", block, dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := d.disk.Read(block)
|
||||||
|
if err != nil {
|
||||||
|
return proDosDeviceErrorIO
|
||||||
|
}
|
||||||
|
// Byte by byte transfer to memory using the full Poke code path
|
||||||
|
for i := uint16(0); i < uint16(len(data)); i++ {
|
||||||
|
d.host.a.mmu.Poke(dest+i, data[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return proDosDeviceNoError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *SmartPortHardDisk) writeBlock(block uint32, source uint16) uint8 {
|
||||||
|
if d.trace {
|
||||||
|
fmt.Printf("[SmartPortHardDisk] Write block %v from $%x.\n", block, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.disk.IsReadOnly() {
|
||||||
|
return proDosDeviceErrorWriteProtected
|
||||||
|
}
|
||||||
|
|
||||||
|
// Byte by byte transfer from memory using the full Peek code path
|
||||||
|
buf := make([]uint8, storage.ProDosBlockSize)
|
||||||
|
for i := uint16(0); i < uint16(len(buf)); i++ {
|
||||||
|
buf[i] = d.host.a.mmu.Peek(source + i)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := d.disk.Write(block, buf)
|
||||||
|
if err != nil {
|
||||||
|
return proDosDeviceErrorIO
|
||||||
|
}
|
||||||
|
|
||||||
|
return proDosDeviceNoError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *SmartPortHardDisk) status(dest uint16) uint8 {
|
||||||
|
if d.trace {
|
||||||
|
fmt.Printf("[SmartPortHardDisk] Status into $%x.\n", dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
// See http://www.1000bit.it/support/manuali/apple/technotes/smpt/tn.smpt.2.html
|
||||||
|
d.host.a.mmu.Poke(dest+0, 0x02) // One device
|
||||||
|
d.host.a.mmu.Poke(dest+1, 0xff) // No interrupt
|
||||||
|
d.host.a.mmu.Poke(dest+2, 0x00)
|
||||||
|
d.host.a.mmu.Poke(dest+3, 0x00) // Unknown manufacturer
|
||||||
|
d.host.a.mmu.Poke(dest+4, 0x01)
|
||||||
|
d.host.a.mmu.Poke(dest+5, 0x00) // Version 1.0 final
|
||||||
|
d.host.a.mmu.Poke(dest+6, 0x00)
|
||||||
|
d.host.a.mmu.Poke(dest+7, 0x00) // Reserved
|
||||||
|
|
||||||
|
return proDosDeviceNoError
|
||||||
|
}
|
Loading…
Reference in New Issue