# HG changeset patch # User Steve Losh # Date 1482341797 18000 # Node ID ce548c40237a9ac5959646e302add8115d18abc3 # Parent c261dec563656c6decd681c4a46248a8e00ff39e Clean up diff -r c261dec56365 -r ce548c40237a content/blog/2016/12/chip8-cpu.markdown --- 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 diff -r c261dec56365 -r ce548c40237a content/blog/2016/12/chip8-graphics.markdown --- 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