--- a/content/blog/2016/12/chip8-cpu.markdown Wed Dec 21 12:00:08 2016 -0500
+++ b/content/blog/2016/12/chip8-cpu.markdown Wed Dec 21 12:36:37 2016 -0500
@@ -1067,6 +1067,26 @@
(<<_8 (register r))))
```
+**Update:** as [fernly pointed out][shift-hn], this [may not have been the
+original intended behavior][shift-yahoo]. If we want to make our emulator match
+the original intent, it's pretty simple:
+
+```lisp
+(define-instruction op-shr (_ rx ry) ;; SHR
+ (setf (values (register ry) flag)
+ (>>_8 (register rx))))
+
+(define-instruction op-shl (_ rx ry) ;; SHL
+ (setf (values (register ry) flag)
+ (<<_8 (register rx))))
+```
+
+But I suspect that this will probably break some ROMs that rely on the
+incorrectly-documented behavior.
+
+[shift-hn]: https://news.ycombinator.com/item?id=13217352
+[shift-yahoo]: https://groups.yahoo.com/neo/groups/rcacosmac/conversations/topics/328
+
### Logical Operations
Next up are the logical `AND`/`OR`/`XOR` instructions. We could define these
--- a/content/blog/2016/12/chip8-graphics.markdown Wed Dec 21 12:00:08 2016 -0500
+++ b/content/blog/2016/12/chip8-graphics.markdown Wed Dec 21 12:36:37 2016 -0500
@@ -208,7 +208,7 @@
draws sprites. The instruction itself will delegate to a helper function:
```lisp
-(define-instruction op-draw (_ rx ry size) ;; DRW Vx, Vy, size
+(define-instruction op-draw (_ rx ry size) ;; DRW Vx, Vy, size
(draw-sprite chip (register rx) (register ry) size))
```
@@ -292,22 +292,21 @@
```lisp
(defun-inline wrap (chip x y)
- (cond
- ((chip-screen-wrapping-enabled chip)
- (values (mod x +screen-width+)
- (mod y +screen-height+)
- t))
- ((and (in-range-p 0 x +screen-width+)
- (in-range-p 0 y +screen-height+))
- (values x y t))
- (t (values nil nil nil))))
+ (cond ((chip-screen-wrapping-enabled chip)
+ (values (mod x +screen-width+)
+ (mod y +screen-height+)
+ t))
+ ((and (in-range-p 0 x +screen-width+)
+ (in-range-p 0 y +screen-height+))
+ (values x y t))
+ (t (values nil nil nil))))
```
`wrap` will take `x` and `y` coordinates and return three values:
* The screen X coordinate to draw to (if any).
* The screen Y coordinate to draw to (if any).
-* A boolean that will be `t` when the pixel should be draw, or `nil` if not.
+* A boolean that will be `t` when the pixel should be drawn, or `nil` if not.
[`in-range-p`][in-range-p] is a predicate from my utility library that checks if
`low <= val < high` (which is [often useful][dijkstra]).
@@ -369,6 +368,8 @@
nil)
```
+`xor` is the exclusive-or variant of `and`/`or` from Alexandria.
+
And we're finally done. `draw-sprite` is 22 lines, which is getting a bit long
by Lisp standards, so it might be worth breaking into separate functions. But
it's also the most performance-critical function in the emulator, so keeping it
@@ -538,7 +539,8 @@
(let ((chip (screen-chip screen)))
(when (chip8::chip-video-dirty chip)
(setf (chip8::chip-video-dirty chip) nil)
- (gl:tex-sub-image-2d :texture-2d 0 0 0 64 32 :luminance :unsigned-byte
+ (gl:tex-sub-image-2d :texture-2d 0 0 0 64 32
+ :luminance :unsigned-byte
(chip8::chip-video chip))))
;; Draw the quad