--- a/content/blog/2017/01/chip8-debugging-infrastructure.markdown Thu Jan 05 13:17:43 2017 +0000
+++ b/content/blog/2017/01/chip8-debugging-infrastructure.markdown Thu Jan 05 16:39:56 2017 +0000
@@ -1,8 +1,8 @@
+++
title = "CHIP-8 in Common Lisp: Debugging Infrastructure"
snip = "What's happening inside this computer?"
-date = 2017-01-03T18:50:00Z
-draft = true
+date = 2017-01-05T16:40:00Z
+draft = false
+++
@@ -39,8 +39,8 @@
All information about the state of the debugger (e.g. breakpoints, pause status,
etc) will be stored in a separate debugger data structure. We'll define a small
API for interacting with this structure. The `chip` struct will have
-a `debugger` slot and will use the debugger API to interact with it. Later on,
-the graphical debugger UI will also use this API.
+a `debugger` slot and will use the debugger API to interact with it. Later the
+graphical debugger UI will also use this API.
## The Debugger Data Structure
@@ -84,21 +84,24 @@
```lisp
(defun debugger-pause (debugger)
(with-debugger (debugger)
- (setf paused t print-needed t)))
+ (setf paused t)))
(defun debugger-unpause (debugger)
(with-debugger (debugger)
- (setf paused nil print-needed nil)))
-
-(defun debugger-toggle-pause (debugger)
- (if (debugger-paused debugger)
- (debugger-unpause debugger)
- (debugger-pause debugger)))
+ (setf paused nil)))
(defun debugger-paused-p (debugger)
(debugger-paused debugger))
+
+(defun debugger-toggle-pause (debugger)
+ (if (debugger-paused-p debugger)
+ (debugger-unpause debugger)
+ (debugger-pause debugger)))
```
+Notice how `debugger-toggle-pause` uses the lower-level API functions instead of
+directly modifying the slot. This will become important shortly.
+
Now we need to start modifying the emulator itself to pause execution when the
debugger is paused. Unfortunately this is going to be pretty invasive, but
I don't think there's much of a way around that.
@@ -166,7 +169,7 @@
(define-override (screen key-release-event) (ev)
(let* ((key (q+:key ev))
(pad-key (pad-key-for key))
- (debugger (chip8::chip-debugger chip)))
+ (debugger (chip8::chip-debugger chip))) ; NEW
(if pad-key
(chip8::keyup chip pad-key)
(qtenumcase key
@@ -228,6 +231,11 @@
(t t))))
```
+I didn't name it with a `-p` suffix because although it qualifies as a predicate
+according to the Common Lisp spec ("a function that returns a generalized
+boolean as its first value") it has side effects, and I generally don't expect
+predicates to modify state.
+
We can wire this into `emulate-cycle`, replacing the vanilla
`debugger-paused-p`:
@@ -266,8 +274,11 @@
```
Now we can walk through the code one instruction at a time by pausing the
-emulator and hitting `F7` to take a step. This is great, but is pretty useless
-unless we can also see what instruction is about to run.
+emulator and hitting `F7` to take a step. I picked `F7` because it matches the
+"take step" key for another emulator I use.
+
+This is all great, but pretty useless unless we can also see what instruction is
+about to run.
## Printing
@@ -334,6 +345,9 @@
(t t))))
```
+We didn't have to touch `debugger-toggle-pause` because it uses the lower-level
+API functions, so everything works properly.
+
Now we can implement `debugger-arrive`:
```lisp
@@ -396,10 +410,10 @@
nil))
```
-Note that we use our own `debugger-pause` API function here to make sure we
-handle setting the `paused` and `awaiting-arrival` slots properly. Now we can
-modify `debugger-check-wait` to use this function. We'll also need to update it
-to take the current instruction's address:
+Note that we use the `debugger-pause` API function here to make sure we handle
+setting the `paused` and `awaiting-arrival` slots properly. Now we can modify
+`debugger-check-wait` to use this function. We'll also need to update it to
+take the current instruction's address:
```lisp
; NEW