I removed my scaffolding code, and the unit tests use the interpreter's I/O routines. I updated prompt.txt and asked Claude a more constrained task. After loading the prompt, I asked it to fetch my source and implement the COMPARE function. The good news is the generate source assembles on the first try! I haven't tested it yet, but the dialog was interesting, so I am posting it here
Me: Fetch all the relevant source files and implement the compare function.
Claude's response:
Code: Select all
Let me fetch all the relevant source files first.
Good, I have everything I need. Now let me implement COMPARE. Let me carefully work through the design before writing code.
Design considerations:
Stack: ( addr1 u1 addr2 u2 -- n ) → consumes 4 cells, leaves 1
Returns 0 (equal), $FFFF (-1, str1 < str2), $0001 (1, str1 > str2)
Compare byte-by-byte; if equal up to MIN(u1,u2), shorter string is less
Must switch to 8-bit mode for byte fetches, like C@, MOVE, etc.
Y is the IP — must be saved with PHY/PLY before using Y as an index
Can't use X or Y directly in arithmetic/logic — need TXA/TYA
Use the JSR/helper pattern (like SLASHMOD) since we need Y as a loop counter
SCRATCH0 and SCRATCH1 are available ZP pointers; TMPA/TMPB for counters
Stack-relative locals for the two addresses, like MOVE_CODE uses
Stack layout on entry (X = PSP):
0,X = u2
2,X = addr2
4,X = u1
6,X = addr1
Plan:
Use JSR COMPARE_IMPL pattern so Y is free inside the helper
Pop all 4 args, find MIN(u1,u2) as loop count
Loop byte-by-byte comparing; on first difference return $FFFF or $0001
After loop, compare lengths: equal → 0, u1 < u2 → $FFFF, u1 > u2 → $0001
Push result, then NEXT
Claude emitted the code and it assembles, so I will unit test it now. But what I found interesting was this part of the plan:
"Use JSR COMPARE_IMPL pattern so Y is free inside the helper"
What's interesting is that pattern isn't used to free the Y register. It's used to allow another Forth primitive to JSR into an implementation to reuse code. The mathematics functions use this, but they also save Y and use stack locals. So Claude assumed that pattern was required to use that technique.
After I reviewed the code, I spotted my first bug. On entry to the code segment below C contains the desired result. But the PLA, PLA stomps on it, so the STA 0,X does work. The fix is PLY, PLY, PLY to preserve C.
@store_result:
;----------------------------------------------------------
; Tear down hw stack locals, restore IP, push result.
;----------------------------------------------------------
PLA ; discard addr1
PLA ; discard addr2
PLY ; Restore IP
DEX
DEX
STA 0,X ; Push result onto parameter stack
Update: Good news, after fixing that bug COMPARE passed unit testing.