2022-10-24 21:09:06 +00:00
|
|
|
package izapple2
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
/*
|
|
|
|
A smartPort device
|
|
|
|
*/
|
|
|
|
|
|
|
|
type smartPortDevice interface {
|
|
|
|
exec(call *smartPortCall) uint8
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
2022-10-31 21:57:18 +00:00
|
|
|
smartPortCommandStatus = 0
|
|
|
|
smartPortCommandReadBlock = 1
|
|
|
|
smartPortCommandWriteBlock = 2
|
|
|
|
smartPortCommandFormat = 3
|
|
|
|
smartPortCommandControl = 4
|
|
|
|
smartPortCommandInit = 5
|
|
|
|
smartPortCommandOpen = 6
|
|
|
|
smartPortCommandClose = 7
|
|
|
|
smartPortCommandRead = 8
|
|
|
|
smartPortCommandWrite = 9
|
2022-10-24 21:09:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2022-10-31 21:57:18 +00:00
|
|
|
smartPortStatusCodeDevice = 0
|
|
|
|
smartPortStatusCodeDeviceControlBlock = 1
|
|
|
|
smartPortStatusCodeNewline = 2
|
|
|
|
smartPortStatusCodeDeviceInfo = 3
|
2022-10-24 21:09:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2022-10-31 21:57:18 +00:00
|
|
|
smartPortStatusCodeTypeBlock = uint8(1) << 7
|
|
|
|
smartPortStatusCodeTypeWrite = uint8(1) << 6
|
|
|
|
smartPortStatusCodeTypeRead = uint8(1) << 5
|
|
|
|
smartPortStatusCodeTypeOnline = uint8(1) << 4
|
|
|
|
smartPortStatusCodeTypeFormat = uint8(1) << 3
|
|
|
|
smartPortStatusCodeTypeProtected = uint8(1) << 2
|
|
|
|
smartPortStatusCodeTypeInterruping = uint8(1) << 1
|
|
|
|
smartPortStatusCodeTypeOpen = uint8(1) << 0
|
2022-10-24 21:09:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2022-10-31 21:57:18 +00:00
|
|
|
smartPortNoError = uint8(0)
|
|
|
|
smartPortBadCommand = uint8(1)
|
|
|
|
smartPortErrorIO = uint8(0x27)
|
|
|
|
smartPortErrorNoDevice = uint8(0x28)
|
|
|
|
smartPortErrorWriteProtected = uint8(0x2b)
|
2022-10-24 21:09:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
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 {
|
2022-10-31 21:57:18 +00:00
|
|
|
if spc.command != smartPortCommandStatus {
|
|
|
|
panic("Status code paremeter requeted for a non status smartPort call")
|
2022-10-24 21:09:06 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-10-31 21:47:53 +00:00
|
|
|
func (spc *smartPortCall) paramData(offset uint8) []uint8 {
|
|
|
|
address := uint16(spc.param8(offset)) +
|
|
|
|
uint16(spc.param8(offset+1))<<8
|
|
|
|
|
|
|
|
size := spc.host.a.mmu.peekWord(address)
|
|
|
|
|
|
|
|
data := make([]uint8, size)
|
|
|
|
for i := 0; i < int(size); i++ {
|
|
|
|
data[i] = spc.host.a.mmu.Peek(address + 2 + uint16(i))
|
|
|
|
}
|
|
|
|
|
|
|
|
return data
|
|
|
|
}
|
|
|
|
|
2022-10-24 21:09:06 +00:00
|
|
|
func (spc *smartPortCall) String() string {
|
|
|
|
switch spc.command {
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortCommandStatus:
|
2022-10-24 21:09:06 +00:00
|
|
|
return fmt.Sprintf("STATUS(%v, unit=%v, code=%v)",
|
|
|
|
spc.command, spc.unit(),
|
|
|
|
spc.statusCode())
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortCommandReadBlock:
|
2022-10-31 21:47:53 +00:00
|
|
|
return fmt.Sprintf("READBLOCK(%v, unit=%v, block=%v)",
|
2022-10-24 21:09:06 +00:00
|
|
|
spc.command, spc.unit(),
|
|
|
|
spc.param24(4))
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortCommandWriteBlock:
|
2022-10-31 21:47:53 +00:00
|
|
|
return fmt.Sprintf("WRITEBLOCK(%v, unit=%v, block=%v)",
|
2022-10-24 21:09:06 +00:00
|
|
|
spc.command, spc.unit(),
|
|
|
|
spc.param24(4))
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortCommandControl:
|
2022-10-31 21:47:53 +00:00
|
|
|
return fmt.Sprintf("CONTROL(%v, unit=%v, code=%v)",
|
|
|
|
spc.command, spc.unit(),
|
|
|
|
spc.param8(4))
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortCommandInit:
|
2022-10-31 21:47:53 +00:00
|
|
|
return fmt.Sprintf("INIT(%v, unit=%v)",
|
|
|
|
spc.command, spc.unit())
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortCommandOpen:
|
2022-10-31 21:47:53 +00:00
|
|
|
return fmt.Sprintf("OPEN(%v, unit=%v)",
|
|
|
|
spc.command, spc.unit())
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortCommandClose:
|
2022-10-31 21:47:53 +00:00
|
|
|
return fmt.Sprintf("CLOSE(%v, unit=%v)",
|
|
|
|
spc.command, spc.unit())
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortCommandRead:
|
2022-10-31 21:47:53 +00:00
|
|
|
return fmt.Sprintf("READ(%v, unit=%v, pos=%v, len=%v)",
|
|
|
|
spc.command, spc.unit(),
|
|
|
|
spc.param24(6),
|
|
|
|
spc.param16(4))
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortCommandWrite:
|
2022-10-31 21:47:53 +00:00
|
|
|
return fmt.Sprintf("WRITE(%v, unit=%v, pos=%v, len=%v)",
|
|
|
|
spc.command, spc.unit(),
|
|
|
|
spc.param24(6),
|
|
|
|
spc.param16(4))
|
2022-10-24 21:09:06 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
return fmt.Sprintf("UNKNOWN(%v, unit=%v)",
|
|
|
|
spc.command, spc.unit())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func smartPortErrorMessage(code uint8) string {
|
|
|
|
switch code {
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortNoError:
|
2022-10-24 21:09:06 +00:00
|
|
|
return "SUCCESS"
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortBadCommand:
|
2022-10-24 21:09:06 +00:00
|
|
|
return "BAD_COMMAND"
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortErrorIO:
|
2022-10-24 21:09:06 +00:00
|
|
|
return "ERROR_IO"
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortErrorNoDevice:
|
2022-10-24 21:09:06 +00:00
|
|
|
return "NO_DEVICE"
|
2022-10-31 21:57:18 +00:00
|
|
|
case smartPortErrorWriteProtected:
|
2022-10-24 21:09:06 +00:00
|
|
|
return "WRITE_PROTECT_ERROR"
|
|
|
|
default:
|
|
|
|
return string(code)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|