64e956e4603b

Clean up the BCD stuff
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Sun, 18 Dec 2016 12:55:25 -0500
parents 58287c034c3c
children 6911e751d39a
branches/tags (none)
files content/blog/2016/12/chip8-cpu.markdown

Changes

--- a/content/blog/2016/12/chip8-cpu.markdown	Sat Dec 17 23:00:51 2016 -0500
+++ b/content/blog/2016/12/chip8-cpu.markdown	Sun Dec 18 12:55:25 2016 -0500
@@ -931,41 +931,48 @@
 </pre>
 
 We'll split this into two parts to make it easier to read.  First we'll make
-a `bcd` function to actually get the digits:
+a `digit` function to retrieve a digit of a number:
 
 ```lisp
-(defun-inline bcd (integer)
-  (values (-<> integer (floor <> 100) (mod <> 10))
-          (-<> integer (floor <> 10) (mod <> 10))
-          (-<> integer (floor <> 1) (mod <> 10))))
-
+(defun-inline digit (position integer &optional (base 10))
+  (-<> integer
+    (floor <> (expt base position))
+    (mod <> base)))
 ```
 
-And make sure it works on its own:
+We could have hard-coded the base 10, but part of the Common Lisp tradition is
+making flexible functions that can be reused in the future when it's not much
+harder to do so.
+
+Let's make sure it works on its own:
+
+```lisp
+(digit 0 135)
+1
 
-```
-[SBCL] CHIP8> (bcd 135)
+(digit 1 135)
+3
+
+(digit 2 135)
+5
 
-1
-3
-5
+(digit 0 #xD6 16)
+6
+
+(digit 1 #xD6 16)
+13     ; 13 in base 10 == D in base 16
 ```
 
 And then we can define the actual operation:
 
 ```lisp
 (define-instruction op-ld-bcd<vx (_ r _ _)              ;; LD B, Vx
-  (setf (values (aref memory (+ index 0)) ; hundreds
-                (aref memory (+ index 1)) ; tens
-                (aref memory (+ index 2))) ; ones
-        (bcd (register r))))
+  (let ((number (register r)))
+    (setf (aref memory (+ index 0)) (digit 2 number)
+          (aref memory (+ index 1)) (digit 1 number)
+          (aref memory (+ index 2)) (digit 0 number))))
 ```
 
-This takes advantage of the fact that you can use `(setf (values ...) ...)` to
-assign all the multiple values returned by `bcd` at once, without binding them
-to local variables (though because `bcd` itself is inline, there won't actually
-be any *returning* at all...).
-
 [BCD]: https://en.wikipedia.org/wiki/Binary-coded_decimal
 
 ### Arithmetic
@@ -1006,7 +1013,9 @@
         (-_8 (register rx) (register ry))))
 ```
 
-Again we use `(setf (values ...))` to avoid having to name intermediate results.
+This takes advantage of the fact that you can use `(setf (values ...) ...)` to
+assign the multiple values returned by a function, without binding them to local
+variables.
 
 Notice how we just assign to `flag`.  Under the hood that `flag` has been bound
 with our `with-chip` macro to mean `(chip-flag chip)`, which we defined way back