go-studybox/rom/decoder.go

231 lines
6.4 KiB
Go

package rom
import (
"bytes"
"fmt"
"strings"
//"encoding/binary"
)
// Returns packet, next state, and error (if any)
type decodeFunction func(page *Page, data []byte, startIdx int) (Packet, int, error)
// Map of states. Each state is a map of types
var definedPackets = map[int]map[byte]decodeFunction{
0: map[byte]decodeFunction{ // state 3 in firmware.org
0x01: decodeHeader,
},
1: map[byte]decodeFunction{ // state 1 in firmware.org
0x00: decodeMarkDataEnd,
},
2: map[byte]decodeFunction{ // state 2 in firmware.org
0x02: decodeSetWorkRamLoad,
0x03: decodeMarkDataStart,
0x04: decodeMarkDataStart,
0x05: decodeDelay,
},
}
// Main decoding loop is here
func (page *Page) decode(data []byte) error {
var err error
page.Packets = []Packet{}
page.state = 0
for idx := 0; idx < len(data); {
if data[idx] != 0xC5 {
// Padding after the last valid packet.
dataLeft := len(data) - idx
page.Packets = append(page.Packets, &packetPadding{
Length: dataLeft,
address: page.DataOffset + idx,
raw: data[idx:len(data)]})
return nil
}
stateArg := data[idx+1]
var packet Packet
if page.state == 1 && stateArg != 0x00 { // stateArg is length here?
// bulk data
packet, page.state, err = decodeBulkData(page, data, idx)
if err != nil {
return err
}
} else {
df, ok := definedPackets[page.state][stateArg]
if !ok {
return fmt.Errorf("State %d packet with type %02X isn't implemented",
page.state, stateArg)
}
packet, page.state, err = df(page, data, idx)
if err != nil {
return err
}
}
page.Packets = append(page.Packets, packet)
idx += len(packet.RawBytes())
}
return nil
}
func decodeHeader(page *Page, data []byte, idx int) (Packet, int, error) {
if !bytes.Equal(data[idx+1:idx+5], []byte{0x01, 0x01, 0x01, 0x01}) {
return nil, 0, fmt.Errorf("Packet header at offset %08X has invalid payload: $%08X",
idx+page.DataOffset, data[idx+1:idx+5])
}
if data[idx+5] != data[idx+6] {
return nil, 0, fmt.Errorf("Packet header at offset %08X has missmatched page numbers at offset %08X: %02X vs %02X",
idx+page.DataOffset,
idx+page.DataOffset+5,
data[idx+5],
data[idx+6],
)
}
ph := &packetHeader{
PageNumber: uint8(data[idx+6]),
Checksum: data[idx+8],
address: page.DataOffset + idx,
}
checksum := calcChecksum(data[idx : idx+7])
if checksum != ph.Checksum {
return nil, 0, fmt.Errorf("Invalid checksum for header packet starting at offset %08X. Got %02X, expected %02X",
page.DataOffset+idx, checksum, ph.Checksum)
}
return ph, 2, nil
}
func decodeDelay(page *Page, data []byte, idx int) (Packet, int, error) {
if data[idx+1] != data[idx+2] {
return nil, 0, fmt.Errorf("State 2 packet at offset %08X has missmatched type [%08X]: %d vs %d",
idx+page.DataOffset, idx+1+page.DataOffset, data[idx+1], data[idx+2])
}
count := 0
var i int
for i = idx + 3; i < len(data) && data[i] != 0x00 && data[i] != 0xC5; i++ {
count++
}
if count%2 != 0 {
fmt.Printf("0xAA delay packet at offset %08X has odd number of 0xAA's", idx+page.FileOffset)
}
pd := &packetDelay{
Length: count,
address: page.DataOffset + idx,
}
checksum := calcChecksum(data[idx : idx+count+3])
if checksum != 0xC5 {
return nil, 0, fmt.Errorf("Invalid checksum for delay packet starting at offset %08X. Got %02X, expected %02X",
pd.address, checksum, 0xC5)
}
idx += count + 3
return pd, 1, nil
}
func decodeMarkDataStart(page *Page, data []byte, idx int) (Packet, int, error) {
packet := &packetMarkDataStart{
Type: data[idx+1],
ArgA: data[idx+3],
ArgB: data[idx+4],
checksum: data[idx+5],
address: page.DataOffset + idx,
}
checksum := calcChecksum(data[idx : idx+5])
if checksum != packet.checksum {
return nil, 0, fmt.Errorf("Invalid checksum for UnknownS2T3 packet starting at offset %08X. Got %02X, expected %02X",
packet.address, checksum, packet.checksum)
}
return packet, 1, nil
}
func decodeMarkDataEnd(page *Page, data []byte, idx int) (Packet, int, error) {
packet := &packetMarkDataEnd{
Type: data[idx+2],
Reset: (data[idx+2]&0xF0 == 0xF0), // what is this?
checksum: data[idx+3],
address: page.DataOffset + idx,
}
checksum := calcChecksum(data[idx : idx+3])
if checksum != packet.checksum {
return nil, 0, fmt.Errorf("Invalid checksum for UnknownS2T3 packet starting at offset %08X. Got %02X, expected %02X",
packet.address, checksum, packet.checksum)
}
newstate := 2
//if page.Data[idx+2]&0xF0 == 0xF0 {
// // this changes to state 3, not zero!
// newstate = 0
//}
return packet, newstate, nil
}
// C5 02 02 nn mm zz
// Map 8k ram bank nn to $6000-$7FFF; set load address to $mm00; zz = checksum
func decodeSetWorkRamLoad(page *Page, data []byte, idx int) (Packet, int, error) {
if data[idx+1] != data[idx+2] {
return nil, 0, fmt.Errorf("State 1 packet at offset %08X has missmatched type [%08X]: %d vs %d",
idx+page.DataOffset, idx+1+page.DataOffset, data[idx+1], data[idx+2])
}
packet := &packetWorkRamLoad{
bankId: data[idx+3],
loadAddressHigh: data[idx+4],
checksum: data[idx+5],
address: page.DataOffset + idx,
}
checksum := calcChecksum(data[idx : idx+5])
if checksum != packet.checksum {
return nil, 0, fmt.Errorf("Invalid checksum for SetWorkRamLoad packet starting at offset %08X. Got %02X, expected %02X",
packet.address, checksum, packet.checksum)
}
return packet, 1, nil
}
func decodeBulkData(page *Page, data []byte, idx int) (Packet, int, error) {
// idx+1: length of data
// idx+2: data start
if data[idx+1] == 0 {
return nil, 0, fmt.Errorf("Bulk data packet has a length of zero at offset %08X",
page.DataOffset+idx)
}
packet := &packetBulkData{
address: page.DataOffset + idx,
}
datalen := int(data[idx+1])
packet.Data = data[idx+2 : idx+2+datalen]
packet.checksum = data[idx+2+len(packet.Data)]
// checksum includes the packet ID and data length values
checksum := calcChecksum(data[idx : idx+int(data[idx+1])+2])
if checksum != packet.checksum {
data := []string{}
for _, b := range packet.Data {
data = append(data, fmt.Sprintf("$%02X", b))
}
fmt.Printf("checksum data: %s\n", strings.Join(data, " "))
fmt.Printf("checksum address: %08X\n", packet.address+len(packet.Data)+2)
return nil, 0, fmt.Errorf("Invalid checksum for BulkData packet starting at offset %08X. Got %02X, expected %02X",
packet.address, checksum, packet.checksum)
}
return packet, 1, nil
}