[script] Improve CDL logic

- CDL data can now be output to a file.  If --cdl-output isn't given,
  but --cdl is given, the input file is overwritten with the new data.
  If no CDL file is given no data is written.
- Count arguments as "Code"
- The SmartParse function no longer creates a new CDL.  It will use and
  update what it was given.
- The just-stats command does not write CDL data even though it
  generates it.

Variable length arguments are not properly handled yet.  Currently, just
the OP code and first argument (length) are set at Code.  The rest are
ignored.
This commit is contained in:
Zorchenhimer 2025-09-14 18:06:46 -04:00
parent 11cfad1e1a
commit bfc7beb382
Signed by: Zorchenhimer
GPG Key ID: 70A1AB767AAB9C20
4 changed files with 131 additions and 12 deletions

View File

@ -21,6 +21,7 @@ type Arguments struct {
StatsFile string `arg:"--stats" help:"file to write some statistics to"`
LabelFile string `arg:"--labels" help:"file containing address/label pairs"`
CDL string `arg:"--cdl" help:"CodeDataLog json file"`
CDLOutput string `arg:"--cdl-output"`
Smart bool `arg:"--smart"`
start int
@ -103,10 +104,6 @@ func run(args *Arguments) error {
return 0
})
//for _, lbl := range scr.Labels {
// fmt.Println(lbl)
//}
for _, token := range scr.Tokens {
fmt.Fprintln(outfile, token.String(scr.Labels))
}
@ -124,6 +121,22 @@ func run(args *Arguments) error {
}
}
if scr.CDL != nil {
cdlout := args.CDL
if args.CDLOutput != "" {
cdlout = args.CDLOutput
}
if cdlout == "" {
return nil
}
err = scr.CDL.WriteToFile(cdlout)
if err != nil {
return fmt.Errorf("Error writing CDL file: %w", err)
}
}
return nil
}

View File

@ -6,6 +6,7 @@ import (
"encoding/json"
"strconv"
"fmt"
"slices"
)
type CodeDataLog struct {
@ -28,8 +29,101 @@ var (
cdlUnknown cdlBit = 0x00
cdlCode cdlBit = 0x01
cdlData cdlBit = 0x02
//cdlOpCode cdlBit = 0x04
)
func (cdl *CodeDataLog) WriteToFile(filename string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
_, werr := cdl.WriteTo(file)
err = file.Close()
if err != nil {
return err
}
return werr
}
func getRanges(list []int) []CdlRange {
//fmt.Printf("getRanges(%v)\n", list)
data := []CdlRange{}
start := -1
//end := -1
prev := -1
for _, addr := range list {
if start == -1 {
start = addr
}
if prev != -1 && prev != addr-1 {
data = append(data, CdlRange{
Start: fmt.Sprintf("0x%X", start),
End: fmt.Sprintf("0x%X", prev),
})
//fmt.Printf("start: 0x%X end: 0x%X\n", start, prev)
start = addr
}
prev = addr
}
if start != -1 && prev != -1 {
data = append(data, CdlRange{
Start: fmt.Sprintf("0x%X", start),
End: fmt.Sprintf("0x%X", prev),
})
//fmt.Println("start:", start, "end:", prev)
}
return data
}
func (cdl *CodeDataLog) WriteTo(w io.Writer) (int64, error) {
clean := &CodeDataLog{
Code: []CdlRange{},
Data: []CdlRange{},
}
keys := []int{}
for k, _ := range cdl.cache {
keys = append(keys, k)
}
slices.Sort(keys)
code := []int{}
data := []int{}
for _, k := range keys {
b := cdl.cache[k]
if b & cdlCode == cdlCode {
code = append(code, k)
}
if b & cdlData == cdlData {
data = append(data, k)
}
}
clean.Code = getRanges(code)
clean.Data = getRanges(data)
raw, err := json.MarshalIndent(clean, "", "\t")
if err != nil {
return 0, err
}
n, err := w.Write(raw)
return int64(n), err
}
func (cdl *CodeDataLog) setData(scriptOffset int) {
if cdl.cache == nil {
err := cdl.doCache()

View File

@ -45,8 +45,6 @@ func SmartParse(rawinput []byte, startAddr int, cdl *CodeDataLog) (*Script, erro
}
p := &Parser{
// Don't use CDL that was passed in
cdl: &CodeDataLog{},
script: &Script{
Tokens: []*Token{},
@ -54,12 +52,18 @@ func SmartParse(rawinput []byte, startAddr int, cdl *CodeDataLog) (*Script, erro
StackAddress: (int(rawinput[1])<<8) | int(rawinput[0]),
StartAddress: startAddr,
Labels: make(map[int]*Label), // map[location]name
CDL: cdl,
},
rawinput: rawinput,
startAddr: startAddr,
}
if p.script.CDL == nil {
p.script.CDL = &CodeDataLog{}
}
tokenMap := make(map[int]*Token)
// starting point is the third byte in the script.
@ -95,7 +99,7 @@ INNER:
//fmt.Printf("{$%04X} %s\n", token.Offset, token.String(map[int]*Label{}))
p.cdl.setCode(p.current)
p.script.CDL.setCode(p.current)
if raw < 0x80 {
continue
}
@ -181,21 +185,21 @@ func Parse(rawinput []byte, startAddr int, cdl *CodeDataLog) (*Script, error) {
}
p := &Parser{
cdl: cdl,
script: &Script{
Tokens: []*Token{},
Warnings: []string{},
StackAddress: (int(rawinput[1])<<8) | int(rawinput[0]),
StartAddress: startAddr,
Labels: make(map[int]*Label), // map[location]name
CDL: cdl,
},
rawinput: rawinput,
startAddr: startAddr,
}
tokenMap := make(map[int]*Token)
if p.cdl == nil {
p.cdl = &CodeDataLog{}
if p.script.CDL == nil {
p.script.CDL = &CodeDataLog{}
}
//earliestVar := len(p.rawinput)-2
@ -217,8 +221,8 @@ func Parse(rawinput []byte, startAddr int, cdl *CodeDataLog) (*Script, error) {
p.script.Tokens = append(p.script.Tokens, token)
tokenMap[token.Offset] = token
if raw < 0x80 || p.cdl.IsData(p.current+startAddr) { // || p.current >= earliestVar {
if p.cdl.IsData(p.current+startAddr) {
if raw < 0x80 || p.script.CDL.IsData(p.current+startAddr) { // || p.current >= earliestVar {
if p.script.CDL.IsData(p.current+startAddr) {
token.IsData = true
//fmt.Print(".")
//fmt.Printf("%#v\n", token)
@ -321,6 +325,7 @@ func (p *Parser) parseToken(token *Token, raw byte) error {
switch op.OpCount {
case -1: // null terminated
for ; p.current < len(p.rawinput); p.current++ {
p.script.CDL.setCode(p.current)
val := ByteVal(p.rawinput[p.current])
args = append(args, val)
if p.rawinput[p.current] == 0x00 {
@ -332,6 +337,7 @@ func (p *Parser) parseToken(token *Token, raw byte) error {
// FIXME: wtf makes this different from -3??
p.current++
l := int(p.rawinput[p.current])
p.script.CDL.setCode(p.current)
args = append(args, ByteVal(l))
p.current++
for c := 0; c < l; c++ {
@ -349,6 +355,7 @@ func (p *Parser) parseToken(token *Token, raw byte) error {
p.current++
l := int(p.rawinput[p.current])
args = append(args, ByteVal(l))
p.script.CDL.setCode(p.current)
p.current++
for c := 0; c < l; c++ {
args = append(args, WordVal([2]byte{p.rawinput[p.current], p.rawinput[p.current+1]}))
@ -358,7 +365,10 @@ func (p *Parser) parseToken(token *Token, raw byte) error {
case 2:
args = append(args, WordVal([2]byte{p.rawinput[p.current+1], p.rawinput[p.current+2]}))
p.script.CDL.setCode(p.current+1)
p.script.CDL.setCode(p.current+2)
p.current+=2
//fmt.Printf("var at $%04X\n", val.Int())
//if val.Int() > p.startAddr && val.Int() < p.startAddr+len(p.rawinput) && p.earliestVar > val.Int() {
// fmt.Printf("new earliest: $%04X\n", val.Int())
@ -367,6 +377,7 @@ func (p *Parser) parseToken(token *Token, raw byte) error {
case 1:
p.current++
p.script.CDL.setCode(p.current)
args = append(args, ByteVal(p.rawinput[p.current]))
}

View File

@ -11,6 +11,7 @@ type Script struct {
StackAddress int
Labels map[int]*Label
CDL *CodeDataLog
}
func (s *Script) Stats() Stats {