231 lines
6.4 KiB
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
|
|
}
|