Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- TilEm Debugger Guide
- ### USER
- How do I use TilEm's debugger? Official documentation: http://lpg.ticalc.org/prj_tilem/doc/user_manual.pdf
- Assume that I have a decent knowledge of how a Ti-83(+) works, like the stack, registers, flags, etc.
- ### ASSISTANT
- Given your background in TI-83+ assembly and Z80 architecture, you can skip the basics of what registers and the stack are and focus on how TilEm (specifically TilEm2) exposes and manipulates these internal states.
- Based on the official user manual, here is a comprehensive guide to utilizing the debugger features.
- ### 1. Entering and Exiting the Debugger
- * **Pause:** To open the debugger, you must pause the emulator. You can do this by pressing **`ESC`**, clicking the **Pause** button on the toolbar, or selecting **Pause** from the right-click context menu.
- * **Run/Resume:** Press **`F5`** to resume execution and deactivate the debugger interface.
- ### 2. Debugger Interface & Views
- The debugger window is divided into several synchronized widgets:
- #### Disassembly View
- * **Function:** Displays Z80 mnemonics and tracks the Program Counter (PC).
- * **Navigation:**
- * **`Ctrl+L` (Go to Address):** Jump to a specific memory address.
- * **`Alt+Home`:** Jump directly to the current PC.
- * **`Alt+PageUp` / `Alt+PageDown`:** This is a unique navigation feature. It allows you to step through the **stack** entries. When you select a stack entry, pressing these shortcuts will jump the Disassembly View to the specific instruction that pushed or modified that stack value.
- * **Quick Breakpoints:** You can right-click any instruction in this view and select **"Breakpoint Here"** to toggle a breakpoint instantly.
- #### Register View
- * **Function:** Displays all standard Z80 registers (A, B, C, D, E, H, L) and their shadow counterparts (AF', BC', DE', HL').
- * **Special Registers:** It explicitly shows `IX`, `IY`, `SP`, `PC`, Interrupt Mode (`IM`), Interrupt Vector (`I`), and the Interrupt Enable flag (`EI`).
- * **Flags:** The F register is broken down into individual flags: **S Z Y H X P N C**.
- * **Editing:** You can edit register values on the fly by clicking on them and typing a new hexadecimal value.
- #### Stack View
- * **Function:** visualizes the stack as a list of `Address: Value` pairs (growing downwards from `FFFF`).
- * **Usage:** Select an entry in this view and use the "Go" menu (or `Alt+PageUp`/`Alt+PageDown`) to find the source code that manipulated that stack position.
- #### Memory View
- * **Function:** A standard hexadecimal dump of the calculator's memory map.
- * **Editing:** You can click and edit bytes in RAM. Attempts to edit ROM pages will generally be ignored or rejected.
- ### 3. Execution Control (Stepping)
- The toolbar provides standard debugging controls:
- * **Step:** Executes a single Z80 instruction (equivalent to F11 in many IDEs).
- * **Step Over:** Executes the next instruction but runs through subroutines (like `CALL`) entirely, stopping at the instruction immediately following the call.
- * **Finish Subroutine:** Runs execution until the current subroutine returns (exiting the current `CALL` or `RST` frame).
- ### 4. Breakpoints (`Ctrl+B`)
- Access the advanced Breakpoint dialog via **Debug > Breakpoints** or by pressing **`Ctrl+B`**. TilEm supports several breakpoint types that are highly specific to Z80 development:
- * **Memory Address:** Break when the PC reaches a specific address. You can configure this to break on **Reading**, **Writing**, or **Executing**. You can also specify a **Range** of addresses (useful for catching out-of-bounds variable access).
- * **Z80 Instruction:** Break on a specific opcode in hex.
- * *Example:* Entering `C9` will pause execution every time a `RET` instruction is encountered.
- * **I/O Port:** Break when the Z80 interacts with specific hardware ports.
- * *Example:* Set to **Read** on Port `01` to catch direct keyboard scanning operations.
- * **Global/Edge Cases:**
- * **Break on invalid instructions:** Useful for catching corrupted PC pointers.
- * **Break on undocumented instructions:** Useful if you are relying on specific Z80 quirks or want to avoid them.
- ### 5. Workflow Integration (Assembler Labels)
- Since TilEm deals in raw hex addresses, debugging is difficult if you don't know where your labels reside in memory.
- * **The Solution:** Configure your assembler (e.g., SPASM) to generate a listing file (`.lst`) using the `-T` flag (or equivalent).
- * **Usage:** This file maps your assembly labels (like `DrawGbuf` or `MainLoop`) to the exact hex addresses that TilEm displays, allowing you to set breakpoints precisely (e.g., setting a breakpoint at `9E4F` knowing it corresponds to `DrawGbuf`).
- ### 6. Additional Hardware Tools
- * **Keypad Matrix (`View > Keypad`):** Opens a widget that visualizes the hardware key matrix. It shows exactly which Z80 port bit and group corresponds to each physical key on the calculator, which is essential for debugging custom input routines.
- * **Address Notation:** You can toggle between logical and absolute addressing in the debugger settings to match your project's memory paging configuration.
- ### USER
- Make an example of this program:
- .nolist
- #include "ti83plus.inc"
- .list
- .org userMem-2
- .db $BB,$6D
- programStart:
- ;leading section copied verbatim from prior entry in the thread being responded to
- res 5,(iy+0) ;No "Done"
- res 0,(iy+$12) ;No run indicator
- res 5,(iy+$44) ;MathPrint is turned off
- bcall(_ClrLCDFull)
- call setRandSeed
- ;ld hl,$0001
- ;ld (appbackupscreen),hl
- ld b,100
- _:
- call rand
- push bc
- bcall(_DispHL)
- bcall(_NewLine)
- pop bc
- djnz -_
- ret
- setRandSeed:
- ld hl,(appbackupscreen)
- ld a,r
- ld e,a
- ld a,r ;probably not the best way to do this given limited spread of r across so short a span.
- ld d,a
- adc hl,de
- jr nz,$+3
- inc hl ;ensure hl is nonzero
- ld (appbackupscreen),hl
- ret
- ;implements
- ; x ^= x << 7
- ; x ^= x >> 9
- ; x ^= x << 8
- ;
- rand:
- ld hl,(appbackupscreen)
- ;x ^ (x << 7)
- ;note: in the op, we lose most of H. H0 moves to H7 and L1:7 moves to H0:6
- ; H7 H6 H5 H4 H3 H2 H1 H0 | L7 L6 L5 L4 L3 L2 L1 L0
- ; H0 L7 L6 L5 L4 L3 L2 L1 | L0 -- -- -- -- -- -- --
- ld a,h
- rra ;move H0 to carry, discard accumulator.
- ld a,L ;move L0:7 to accumulator.
- rra ;move CA to A7, L1:7 to A0:6, discarding L0
- xor h
- ld h,a ;apply H
- ld a,L
- and %00000001 ;isolate A0
- rrca ;move to A7
- xor L ;this op clears carry, nothing else sets it
- ld L,a ;apply L
- ; x ^ (x >> 9)
- ;note: in this op, we lose all of L and the low bit of H for the temp shift
- ld a,h
- rra ;relies on carry being cleared, as is above.
- xor a,L
- ld L,a ;apply H to L
- ; x ^ (x << 8)
- ld a,L
- xor a,H
- ld H,a ;eh?
- ld (appbackupscreen),hl
- ret
- .end
- .end
- ### ASSISTANT
- Here is a practical, step-by-step walkthrough of how you would debug this specific program using TilEm’s features.
- ### Phase 1: Preparation and Breakpoints
- Because TilEm only displays raw hex addresses, you first need to know where your labels live in memory.
- 1. **Compile with a Listing File:** Assemble your code using a flag that generates a listing file (e.g., `spasm -T myprog.asm myprog.8xp`).
- 2. **Find your Addresses:** Open the `.lst` file to find the hex addresses for your labels. For this example, let's assume:
- * `programStart` = `$9D95`
- * `rand` = `$9DD3`
- * `appbackupscreen` = `$8452` (Standard TI-83+ RAM location)
- **Setting the Trap:**
- 1. Run the program in TilEm. It will start printing numbers.
- 2. Press **`ESC`** to pause the emulator and open the Debugger.
- 3. In the **Disassembly View**, scroll up to your main loop until you find the `call rand` instruction.
- 4. Right-click that `call rand` instruction and select **"Breakpoint Here"**.
- 5. Press **`F5`** to resume. The emulator will run through the current iteration, finish the loop, and automatically pause right before entering the `rand` subroutine for the next number.
- ### Phase 2: Verifying Bitwise Logic (Register & Flag View)
- Now that you are paused at `call rand`, you want to verify that your xorshift math is actually doing what you think it's doing.
- 1. **Enter the Subroutine:** Click the **Step** button on the toolbar. The PC will move to the first instruction of `rand` (`ld hl,(appbackupscreen)`).
- 2. **Watch the Seed:** Look at the **Register View**. `H` and `L` should now contain the current seed value.
- 3. **Trace the Shifts:** Keep clicking **Step** to move through the `x ^= x << 7` block.
- * Watch the **A** register fill with bits.
- * Pay close attention to the **Flags** section at the bottom of the Register View. When you hit `rra` or `rrca`, watch the **C** (Carry) flag toggle.
- 4. **Verify Assumptions:** In your code comments, you noted: `note: in this op, we lose all of L... relies on carry being cleared`.
- * When you step down to the `x ^= x >> 9` block, look at the **C** flag *before* the first `rra`. If it is `1` instead of `0`, you have found a bug in your bitwise logic!
- ### Phase 3: Stack Inspection and OS Calls
- Once you have verified the math inside `rand`, you want to get back to the main loop without stepping through hundreds of instructions.
- 1. **Exit the Subroutine:** Click **Finish Subroutine** on the toolbar. TilEm will execute the rest of `rand` and pause exactly on the instruction *after* the `call rand` in your main loop.
- 2. **Step Over ROM Calls:** You are now at `push bc`. Click **Step Over**.
- * *Note: If you click "Step" on the `bcall(_DispHL)`, you will dive deep into the TI-OS ROM. Always use **Step Over** for `bcall` or `call` unless you specifically want to debug the OS.*
- 3. **Inspect the Stack:** Click **Step Over** on `bcall(_DispHL)` and `bcall(_NewLine)`.
- 4. **The Stack View Trick:**
- * Look at the **Stack View** widget. You should see the value of your `B` register (which was pushed earlier) sitting at the top of the stack.
- * Click on that stack entry with your mouse.
- * Press **`Alt+PageUp`**. The **Disassembly View** will instantly jump back to the exact `push bc` instruction that placed that value on the stack, allowing you to verify your loop logic at a glance.
- 5. Press **Step Over** on `pop bc` and verify in the **Register View** that `B` has been successfully restored before the `djnz` loop check.
- ### Phase 4: Verifying Memory Persistence
- Finally, you want to ensure that `rand` is actually saving the new seed back to RAM so the sequence doesn't repeat.
- 1. **Navigate to RAM:** In the **Memory View** widget, scroll down (or use the address jump feature if available in your specific version's UI) to `$8452` (`appbackupscreen`).
- 2. **Observe the Bytes:** Note the two bytes currently sitting at `$8452` and `$8453`.
- 3. **Run and Pause:** Press **`F5`** to let the calculator run for a second, then press **`ESC`** to pause it again.
- 4. **Verify:** Look at `$8452` in the Memory View. The hex values should have changed, confirming that your `ld (appbackupscreen),hl` instruction at the end of `rand` successfully persisted the new state for the next loop iteration.
Advertisement