Fujinet network device
parent
5d857dda4b
commit
718f0b60b3
@ -0,0 +1,143 @@
|
||||
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)
|
||||
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
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,121 @@
|
||||
package izapple2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
The network device as implemented by Fujinet:
|
||||
|
||||
See:
|
||||
https://github.com/FujiNetWIFI/fujinet-platformio/blob/master/lib/device/iwm/network.cpp
|
||||
|
||||
*/
|
||||
|
||||
// SmartPortFujinet represents a Fujinet device
|
||||
type SmartPortFujinet struct {
|
||||
host *CardSmartPort // For DMA
|
||||
trace bool
|
||||
}
|
||||
|
||||
// NewSmartPortFujinet creates a new fujinet device
|
||||
func NewSmartPortFujinet(host *CardSmartPort) *SmartPortFujinet {
|
||||
var d SmartPortFujinet
|
||||
d.host = host
|
||||
|
||||
return &d
|
||||
}
|
||||
|
||||
func (d *SmartPortFujinet) exec(call *smartPortCall) uint8 {
|
||||
var result uint8
|
||||
|
||||
switch call.command {
|
||||
case proDosDeviceCommandStatus:
|
||||
address := call.param16(2)
|
||||
result = d.status(call.statusCode(), address)
|
||||
|
||||
case proDosDeviceCommandRead:
|
||||
address := call.param16(2)
|
||||
block := call.param24(4)
|
||||
result = d.readBlock(block, address)
|
||||
|
||||
case proDosDeviceCommandWrite:
|
||||
address := call.param16(2)
|
||||
block := call.param24(4)
|
||||
result = d.writeBlock(block, address)
|
||||
|
||||
default:
|
||||
// Prodos device command not supported
|
||||
result = proDosDeviceErrorIO
|
||||
}
|
||||
|
||||
if d.trace {
|
||||
fmt.Printf("[SmartPortFujinet] Command %v, return %s \n",
|
||||
call, smartPortErrorMessage(result))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (d *SmartPortFujinet) readBlock(block uint32, dest uint16) uint8 {
|
||||
if d.trace {
|
||||
fmt.Printf("[SmartPortFujinet] Read block %v into $%x.\n", block, dest)
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
return proDosDeviceNoError
|
||||
}
|
||||
|
||||
func (d *SmartPortFujinet) writeBlock(block uint32, source uint16) uint8 {
|
||||
if d.trace {
|
||||
fmt.Printf("[SmartPortFujinet] Write block %v from $%x.\n", block, source)
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
return proDosDeviceNoError
|
||||
}
|
||||
|
||||
func (d *SmartPortFujinet) status(code uint8, dest uint16) uint8 {
|
||||
|
||||
switch code {
|
||||
case prodosDeviceStatusCodeDevice:
|
||||
// See iwmNetwork::encode_status_reply_packet()
|
||||
d.host.a.mmu.Poke(dest, prodosDeviceStatusCodeTypeRead&prodosDeviceStatusCodeTypeOnline)
|
||||
d.host.a.mmu.Poke(dest+1, 0x00)
|
||||
d.host.a.mmu.Poke(dest+2, 0x00)
|
||||
d.host.a.mmu.Poke(dest+3, 0x00) // Block size is 0
|
||||
|
||||
case prodosDeviceStatusCodeDeviceInfo:
|
||||
// See iwmNetwork::encode_status_reply_packet()
|
||||
d.host.a.mmu.Poke(dest, prodosDeviceStatusCodeTypeRead&prodosDeviceStatusCodeTypeOnline)
|
||||
d.host.a.mmu.Poke(dest+1, 0x00)
|
||||
d.host.a.mmu.Poke(dest+2, 0x00)
|
||||
d.host.a.mmu.Poke(dest+3, 0x00) // Block size is 0
|
||||
d.host.a.mmu.Poke(dest+4, 0x07) // Name length
|
||||
d.host.a.mmu.Poke(dest+5, 'N')
|
||||
d.host.a.mmu.Poke(dest+6, 'E')
|
||||
d.host.a.mmu.Poke(dest+7, 'T')
|
||||
d.host.a.mmu.Poke(dest+8, 'W')
|
||||
d.host.a.mmu.Poke(dest+9, 'O')
|
||||
d.host.a.mmu.Poke(dest+10, 'R')
|
||||
d.host.a.mmu.Poke(dest+11, 'K')
|
||||
d.host.a.mmu.Poke(dest+12, ' ')
|
||||
d.host.a.mmu.Poke(dest+13, ' ')
|
||||
d.host.a.mmu.Poke(dest+14, ' ')
|
||||
d.host.a.mmu.Poke(dest+15, ' ')
|
||||
d.host.a.mmu.Poke(dest+16, ' ')
|
||||
d.host.a.mmu.Poke(dest+17, ' ')
|
||||
d.host.a.mmu.Poke(dest+18, ' ')
|
||||
d.host.a.mmu.Poke(dest+19, ' ')
|
||||
d.host.a.mmu.Poke(dest+20, ' ')
|
||||
d.host.a.mmu.Poke(dest+20, 0x02) // Type hard disk
|
||||
d.host.a.mmu.Poke(dest+20, 0x00) // Subtype network (comment in network.cpp has 0x0a)
|
||||
d.host.a.mmu.Poke(dest+23, 0x00)
|
||||
d.host.a.mmu.Poke(dest+24, 0x01) // Firmware
|
||||
}
|
||||
|
||||
return proDosDeviceNoError // The return code is always success
|
||||
}
|
Loading…
Reference in New Issue