diff --git a/script/docs/instructions.md b/script/docs/instructions.md new file mode 100644 index 0000000..548da0d --- /dev/null +++ b/script/docs/instructions.md @@ -0,0 +1,502 @@ +## 0x80 Play Beep + +Stack Arguments: 0 +Inline Arguments: 0 + +Vars used: + + Byte_0493 + +Play's an audible beep on the Square 1 channel. + +## 0x81 Halt + +Stack Arguments: 0 +Inline Arguments: 0 + +Vars used: +N/A + +Infinite loop that does not return. + +## 0x82 Tape NMI Shenanigans + +Stack Arguments: 0 +Inline Arguments: 0 + +Vars: + + Byte_E0_TapeCtrl_Cache + Byte_EE + Byte_F2 + + Byte_0740 + Byte_07EF + Byte_07F3 + +JSRs: + + L2706_SetupNMI_ED00_LongJump + L2721_TurnOnNMI_LongJump + L2724_TurnOffNMI_LongJump + L2742 + + +## 0x83 Tape Wait + +Stack Arguments: 0 +Inline Arguments: 0 + +Vars: + + Byte_0740 + +JMPs to `L1329_WaitOn_EE` + +## 0x84 Jump + +Stack Arguments: 0 +Inline Arguments: 1 Word + +Vars: + + Code_Pointer + Argument_A + +Updates the script pointer to the inline address and continues script execution +from the new address. + +## 0x85 Call + +Stack Arguments: 0 +Inline Arguments: 1 Word + +Vars: + + Code_Pointer + Argument_A + Stack_Pointer + +Pushes return address to the stack and performs a Jump to the inline script +address. + +## 0x86 Return + +Stack Arguments: 0 (1 Word, implied) +Inline Arguments: 0 + +Vars: + + Stack_Pointer + Code_Pointer + +Remove a script address from the stack and update the `Code_Pointer` to it +before continuing execution. + +## 0x87 Loop + +Stack Arguments: 0 (4 implied) +Inline Arguments: 0 + +Args manually pulled from stack: + +- Limit +- Increment +- LoopVar +- LoopEntry + +ArgA `Stack_Pointer-6` +ArgB `(ArgD)` +ArgC `Stack_Pointer-2` +ArgD `Stack_Pointer-4` +ArgE `ArgA+1` + +Vars: + + Argument_A + Argument_B + Argument_C + Argument_D + Argument_E + Stack_Pointer + +JSRs: + + Handler_CB_Sum + Handler_C7_LessThan + +JMPs to `L49CD_LessThan` + +## 0x88 Play Sound + +Stack Arguments: 32 bytes (string copied to `$0700`) +Inline Arguments: 0 + +Plays a short SFX defined by a string. + +Vars: + + Pointer_A0 + Pointer_A2 + + Byte_0494 + Byte_0495 + Byte_0496 + Byte_0497 + Byte_0498 + Byte_0499 + Byte_04AC_AudioState + Byte_04AD + +Vars inside `L5C18_CopyPtrA0PtrA2`: + + Byte_0490_PtrA0Len + +Vars inside `L5A6F_DecodeAudioString_EntryPoint`: + + Pointer_A2 + Byte_04AC_AudioState + + Word_049A+0 (current channel ID) + Word_049A+1 (current channel mask) + + Byte_0497 Byte_0498 Byte_0499 + enable byte for each channel. RTS if != 1 on entry + written to with value of Byte_04B3 + + Byte_0494 Byte_0495 Byte_0496 + Pointer_A2 low for channel. looks like it's updated after reading a + string. + + Byte_049F Added to note lookup index; used with O stuff? + Byte_04B1 octave? value from Table_04A6 + Byte_04B2 T value + Byte_04B3 = Byte_04B1 * Byte_04B2 + + Table_049C Y# + Table_04A0 V## + Table_04A3 M# + Table_04A6 ?? note related. octave? value after letter + Table_04A9 O# + Table_04AE T# + + Table_B391 G?? + +JSRs: + + L5C08_DataLen_A0 + L5C18_CopyPtrA0PtrA2 + L5CC5_LongDelay + L5A6F_DecodeAudioString_EntryPoint + L5A8F_DecodeAudioString (if audio is turned on) + L5C42 (for weird chars?) + +Hard-coded addresses: + + $0700 (Pointer_A0) + $0420 (Pointer_A2) + $0441 (Pointer_A2) + $0462 (Pointer_A2) + +Copies data currently at `$0700` to three locations (`$0420`, `$0441`, `$0462`) + +### String format + +Three channels are encoded in this string, separated by a colon (`:`). The +string consists of letter and number pairs. The order of the individual pairs +in the overal string don't seem to matter. + +M# Loop & Constant volume + number is 0 or 1. + +V## Volume + number between 0 and 15, inclusive + +Y# Duty + number between 0 and 3, inclusive + +T# ?? $4001/$4006? + number between 1 and 9, inclusive (verify this) + +O# Note related (timer low/high stuff) + number between 1 and 6, inclusive + +A#-G# Notes and octaves? + number between 0 and 10, inclusive + +## 0x89 + +Stack Arguments: 3 +Inline Arguments: 0 + +## 0x8A Pop String to Address + +Stack Arguments: 0 +Inline Arguments: 1 Word + +Removes 32 bytes from the stack and writes them starting to the inline address. + +## 0x8B + +## 0x97 + +Arguments: 2 + +ArgA +ArgB + +Vars: + + Byte_0740 + Byte_44FE + Byte_4598 = Argument_B+0 + Byte_44FD + + Argument_A + Array_44FB+2 ($44FD) + +JSRs: + + L5592_CheckForZero + +Conditionally sets up NMI stuff depending on byte $0740 +If ArgA >= 3, setup some more stuff + +## 0xA9 + +Arguments: 1 + +ArgA + +Some sort of nametable restore operation? + +Writes smaller updates to the nametable for animation purposes. + +## 0x9D Something Tape (draw screen?) + +Arguments: 2 + +ArgA -> X +AgrB + +Vars: + + Byte_44FE + Array_44F8, X + Array_44CF, X + Array_457A, X + +If ArgB != 0 + + ldx ArgA + + lda #1 + sta Array_44F8, X + sta Array_44CF, X + + lda #0 + Array_457A, X + +else, check for zero from $44F9 through $44FC. + if non-zero, store #1 into `Byte_FF4E` and return. + else: + + ldx ArgA + lda #1 + sta Array_44F8, X + lda #0 + sta Byte_44F8 + +Then wait for `Array_44F8, X` to become zero. We're waiting for the IRQ to +finish writing data from the tape to RAM. + +After this, jump into opcode `0x9E` after the argument parsing to draw a +screen. + +## 0x9E Draw And Show Screen + +Arguments: 2 + +ArgA +ArgB + +If ArgB == 0, clear out a bunch of arguments and call `Handler_DD`. Clears +`Byte_44FE` afterwards and returns. + +If ArgB != 0, make sure data has been loaded off the tape and is ready to draw. +This is done by checking `Word_FF49, X` for a value of 1. If 1, increment it +and store it in `Byte_44FE` before returning. Continue otherwise. + +### Drawing + + lda #0 + sta Byte_0750 + sta Byte_4579 + sta Byte_457A ("Array_457A") + + lda ArgA + sta Byte_4C + + +### Data layout + +Data in RAM, starting at CPU address $5000 + + $5000 Word offset to palette data. Added to #$5004. + $5002 Word + $5004 Byte loop counter apparently?? adds #6 to #$5004 this many times in a + pointer. additional header data? + + // generic image header data + $5005 Byte Width (data row len (tile data len)) + $5006 Byte Height (row count (title count)) + Data length = Width*Height (stored in Word_61 and Word_6AFE) + + $5007 Word data length? offset offset to attr data? + + $5008 Byte X/Y coords + $5009 Byte X/Y coords + + + $500B Data start + +## 0xBB Push String / Push Data + +Stack Arguments: 0 +Inline Arguments: 32 bytes max (NULL terminated) + +Push a NULL terminated string to the stack. This opperation will increment the +stack pointer by 32 bytes, always. Even if more than 32 bytes are pushed to +the stack. The code pointer is properly incremented, so long as there is a +NULL byte within 255 bytes of the start of data. + +## 0xC1 Jump Switch + +Stack Arguments: 1 +Inline Arguments: 3+ + +ArgA + +## 0xC5 Equal + +If ArgA == ArgB + push 1 to stack +If ArgA != ArgB + push 0 to stack + +## 0xC6 Not Equal + +Stack Arguments: 2 +Stack Result: 1 + +If ArgA != ArgB + push 1 to stack +If ArgA == ArgB + push 0 to stack + +## 0xC7 Less Than + +If ArgA < ArgB + push 1 to stack +If ArgA >= ArgB + push 0 to stack + +## 0xC8 Less Than or Equal + +If ArgA <= ArgB + push 1 to stack +If ArgA > ArgB + push 0 to stack + +## 0xC9 Greater Than + +If ArgA > ArgB + push 1 to stack +If ArgA <= ArgB + push 0 to stack + +## 0xCA Greater Than or Equal To + +If ArgA >= ArgB + push 1 to stack +If ArgA < ArgB + push 0 to stack + +## 0xCB Add + +ArgA = ArgA + ArgB + +## 0xCC Subtract + +ArgA = ArgA - ArgB + +## 0xCD Multiply + +ArgA-ArgB = ArgA * ArgB + +## 0xCE Signed Divide + +ArgA = ArgA / ArgB + +## 0xCF Negate + +ArgA = 0 - ArgA + +## 0xD1 Controller Stuff + +Stack Arguments: 2 +Inline Arguments: 0 + +Vars: + + Argument_C+0 = Argument_A+0 + Argument_A = Word_B1 + Argument_B + Argument_B + + +# 0xD4 Set Cursor Location + +Stack Arguments: 3 + +Some sort of setup for 0xFE Draw Rom Character. + + Byte_0606 = ArgA + Byte_0604 = ArgB + Byte_0605 = ArgC + +## 0xE0 Modulo + +ArgA = ArgA % ArgB + +# 0xE7 Draw Metasprite + +Stack Arguments: 7 + +ArgA sprite ID? (read as byte, but high is used as temp) Some sort of list size or count (header count?) + This is used as a table lookup into a metasprite pointer table at $6980 +ArgB (byte) X Coord +ArgC (byte) Y Coord +ArgD (byte?) Palette override. If positive, bottom two bits are used directly for palette index. +ArgE (byte) switch of some sort. sets X to $00 if zero, $20 if not zero +ArgF (byte) Sprite flip. Uses two middle bits of value (`%0001_1000`) +ArgG (byte) Extra args on HW stack?? + +Header data for metasprites. This location is pointed to by a table at $6980. + +Width +Height +Count +Palette?? + +There is a table at $0140 that keeps track of sprite allocations. Each byte +corresponds to a hardware sprite and the value corresponds to a metasprite that +that hardware sprite is a part of. + +# 0xFE Draw Rom Character + +Stack Arguments: 4 +Inline Arguments: 1 Word + +Observed drawing a 1bpp kanji character taken from the SBX ROM charset. +Inline word seems to be an ID or index for the character to draw. + diff --git a/script/instructions.go b/script/instructions.go index ef4aa57..b33b6ee 100644 --- a/script/instructions.go +++ b/script/instructions.go @@ -60,6 +60,8 @@ var Instructions []*Instruction = []*Instruction{ &Instruction{ 0x9A, 0, 0, 0, false, ""}, &Instruction{ 0x9B, 0, 0, 0, false, "halt"}, &Instruction{ 0x9C, 0, 0, 0, false, "toggle_44FE"}, + + // Waits for data from the tape then jumps into 0x9E code &Instruction{ 0x9D, 2, 0, 0, false, "something_tape"}, // Calls 0xEB draw_overlay. Draws the whole screen from data previously @@ -206,7 +208,13 @@ var Instructions []*Instruction = []*Instruction{ &Instruction{ 0xDD, 5, 0, 0, false, "fill_box"}, &Instruction{ 0xDE, 3, 0, 0, false, ""}, - &Instruction{ 0xDF, 3, 0, 0, false, ""}, + + // ArgA: ?? + // ArgB: X (tile coords) + // ArgC: Y (tile coords) + // Draws an image on top of the background using data already + // loaded from *somewhere*. (seen using data from tape) + &Instruction{ 0xDF, 3, 0, 0, false, "draw_image"}, // Divide and return remainder &Instruction{ 0xE0, 2, 0, 1, false, "modulo"},