144 lines
3.5 KiB
Go
144 lines
3.5 KiB
Go
|
package izapple2
|
||
|
|
||
|
import "fmt"
|
||
|
|
||
|
/*
|
||
|
A smartPort device
|
||
|
*/
|
||
|
|
||
|
type smartPortDevice interface {
|
||
|
exec(call *smartPortCall) uint8
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
proDosDeviceCommandStatus = 0
|
||
|
proDosDeviceCommandRead = 1
|
||
|
proDosDeviceCommandWrite = 2
|
||
|
proDosDeviceCommandFormat = 3
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
prodosDeviceStatusCodeDevice = 0
|
||
|
prodosDeviceStatusCodeDeviceControlBlock = 1
|
||
|
prodosDeviceStatusCodeNewline = 2
|
||
|
prodosDeviceStatusCodeDeviceInfo = 3
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
prodosDeviceStatusCodeTypeBlock = uint8(1) << 7
|
||
|
prodosDeviceStatusCodeTypeWrite = uint8(1) << 6
|
||
|
prodosDeviceStatusCodeTypeRead = uint8(1) << 5
|
||
|
prodosDeviceStatusCodeTypeOnline = uint8(1) << 4
|
||
|
prodosDeviceStatusCodeTypeFormat = uint8(1) << 3
|
||
|
prodosDeviceStatusCodeTypeProtected = uint8(1) << 2
|
||
|
prodosDeviceStatusCodeTypeInterruping = uint8(1) << 1
|
||
|
prodosDeviceStatusCodeTypeOpen = uint8(1) << 0
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
proDosDeviceNoError = uint8(0)
|
||
|
proDosDeviceBadCommand = uint8(1)
|
||
|
proDosDeviceErrorIO = uint8(0x27)
|
||
|
proDosDeviceErrorNoDevice = uint8(0x28)
|
||
|
proDosDeviceErrorWriteProtected = uint8(0x2b)
|
||
|
)
|
||
|
|
||
|
type smartPortCall struct {
|
||
|
host *CardSmartPort
|
||
|
command uint8
|
||
|
|
||
|
address uint16 // When the params are on the Apple memory
|
||
|
params []uint8 // When the params are built externally as on a ProDOS to SP translation
|
||
|
}
|
||
|
|
||
|
func newSmartPortCall(host *CardSmartPort, command uint8, address uint16) *smartPortCall {
|
||
|
var spc smartPortCall
|
||
|
spc.host = host
|
||
|
spc.command = command
|
||
|
spc.address = address
|
||
|
spc.params = nil
|
||
|
return &spc
|
||
|
}
|
||
|
|
||
|
func newSmartPortCallSynthetic(host *CardSmartPort, command uint8, params []uint8) *smartPortCall {
|
||
|
var spc smartPortCall
|
||
|
spc.host = host
|
||
|
spc.command = command
|
||
|
spc.address = 0xffff
|
||
|
spc.params = params
|
||
|
return &spc
|
||
|
}
|
||
|
|
||
|
func (spc *smartPortCall) unit() uint8 {
|
||
|
return spc.param8(1)
|
||
|
}
|
||
|
|
||
|
func (spc *smartPortCall) statusCode() uint8 {
|
||
|
if spc.command != proDosDeviceCommandStatus {
|
||
|
panic("Status code paremeter requeted for a non status smartport call")
|
||
|
}
|
||
|
return spc.param8(4)
|
||
|
}
|
||
|
|
||
|
func (spc *smartPortCall) param8(offset uint8) uint8 {
|
||
|
if spc.params == nil {
|
||
|
return spc.host.a.mmu.Peek(spc.address + uint16(offset))
|
||
|
}
|
||
|
|
||
|
if int(offset) >= len(spc.params) {
|
||
|
panic("Synthetised smartpot call out of range")
|
||
|
}
|
||
|
|
||
|
return spc.params[offset]
|
||
|
}
|
||
|
|
||
|
func (spc *smartPortCall) param16(offset uint8) uint16 {
|
||
|
return uint16(spc.param8(offset)) +
|
||
|
uint16(spc.param8(offset+1))<<8
|
||
|
}
|
||
|
|
||
|
func (spc *smartPortCall) param24(offset uint8) uint32 {
|
||
|
return uint32(spc.param8(offset)) +
|
||
|
uint32(spc.param8(offset+1))<<8 +
|
||
|
uint32(spc.param8(offset+2))<<16
|
||
|
}
|
||
|
|
||
|
func (spc *smartPortCall) String() string {
|
||
|
switch spc.command {
|
||
|
case proDosDeviceCommandStatus:
|
||
|
return fmt.Sprintf("STATUS(%v, unit=%v, code=%v)",
|
||
|
spc.command, spc.unit(),
|
||
|
spc.statusCode())
|
||
|
case proDosDeviceCommandRead:
|
||
|
return fmt.Sprintf("READ(%v, unit=%v, block=%v)",
|
||
|
spc.command, spc.unit(),
|
||
|
spc.param24(4))
|
||
|
case proDosDeviceCommandWrite:
|
||
|
return fmt.Sprintf("WRITE(%v, unit=%v, block=%v)",
|
||
|
spc.command, spc.unit(),
|
||
|
spc.param24(4))
|
||
|
|
||
|
default:
|
||
|
return fmt.Sprintf("UNKNOWN(%v, unit=%v)",
|
||
|
spc.command, spc.unit())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func smartPortErrorMessage(code uint8) string {
|
||
|
switch code {
|
||
|
case proDosDeviceNoError:
|
||
|
return "SUCCESS"
|
||
|
case proDosDeviceBadCommand:
|
||
|
return "BAD_COMMAND"
|
||
|
case proDosDeviceErrorIO:
|
||
|
return "ERROR_IO"
|
||
|
case proDosDeviceErrorNoDevice:
|
||
|
return "NO_DEVICE"
|
||
|
case proDosDeviceErrorWriteProtected:
|
||
|
return "WRITE_PROTECT_ERROR"
|
||
|
default:
|
||
|
return string(code)
|
||
|
|
||
|
}
|
||
|
}
|