
CHIP-8 in Common Lisp: The CPU - stevelosh
http://stevelosh.com/blog/2016/12/chip8-cpu/
======
fernly
I believe this suffers, as do several other CHIP-8 emulators I've seen, from
the early mis-documentation of the SHR and SHL instructions. Forgive me if I
am reading this incorrectly; I am not used to Lisp:

    
    
        (define-instruction op-shr (_ r _ _) ;; SHR
          (setf (values (register r) flag)
                 (>>_8 (register r))))
        (define-instruction op-shl (_ r _ _) ;; SHL
          (setf (values (register r) flag)
                (<<_8 (register r))))
    

Since there is only one reg argument, it seems these are shifting the source
register in place. It should put the shifted value of the source register into
the target register (8XY6: VX <\- VY>>1) This was recently clarified in an
exchange on the retrocomputing forum [1].

[1]
[https://groups.yahoo.com/neo/groups/rcacosmac/conversations/...](https://groups.yahoo.com/neo/groups/rcacosmac/conversations/messages/328)

~~~
aidenn0
Your analysis looks correct.

FWIW:

    
    
        (setf (values X Y) Z)
    

is roughly equivalent to the Python:

    
    
        (X, Y) = Z
    

So

    
    
        (setf (values (register r) flag)
              (<<_8 (register r)))
    

might be idiomatically in python:

    
    
        (registers[r], flag) = leftShift8(registers[r])
    

And in any event is using the same register "r" as both source and
destination.

------
krat0sprakhar
This is awesome! A couple of days ago, I'd asked an asinine comment[0] about
building a NES emulator & someone had suggested to start with a CHIP-8
emulator first. For someone who's looking to write the same in Clojure, I'm
super glad that Steve wrote this guide!

0 -
[https://news.ycombinator.com/item?id=13145864](https://news.ycombinator.com/item?id=13145864)

------
macournoyer
CHIP-8 is pretty fun! Here's one I made in JavaScript w/ debugger:
[http://greatcodeclub.github.io/chip8/](http://greatcodeclub.github.io/chip8/)

Code:
[https://github.com/greatcodeclub/chip8](https://github.com/greatcodeclub/chip8)

------
davexunit
This is very neat, but he's right that some won't like the unhygienic variable
definitions in the with-chip macro. ;) If I were to do this in Scheme, I'd use
a "parameter" called 'current-chip' (think of it like a dynamically scoped
variable) and write getter/setter procedures that operate on the current chip.
This way everything would remain hygienic. I guess it's just another example
of the usual difference in software design between CL and Scheme programmers.

I'm excited to see this blog series develop to the point where there is
graphical output.

~~~
bitwize
Lack of macro hygiene is just peachy keen among Scheme programmers as long as
you are explicit about which identifier bindings can leak into, or out of, the
macro definition from the macro call site.

Scheme standards before R6RS[0] were a rough consensus on which language
features everyone could agree on as useful additions. That's why only syntax-
rules made the cut, not because Scheme programmers object to the ability to
break hygiene. Implementors disagreed on which mechanism for breaking hygiene
was most "correct", so none made the cut and unhygienic macros weren't
standardized.

[0] R6RS, in a break from Scheme tradition, adopted a systemd-esque "come up
with a standard for these needed features, any standard, and everybody else
needs to fall in line whether or not they like it" approach.

~~~
davexunit
>Lack of macro hygiene is just peachy keen among Scheme programmers as long as
you are explicit about which identifier bindings can leak into, or out of, the
macro definition from the macro call site.

I haven't encountered a single case where I didn't prefer hygiene over an
unhygienic solution.

~~~
lmohseni
I'm not a lisp master, so please take the following with a grain of salt:

One case where you'd want unhygienic capture is with anaphoric macros, which
introduce a binding (usually named `it` as in english). For example, using an
anaphoric if called aif, we can transform:

    
    
        (let ((result (big-long-calculation)))
          (if result
              (foo result)))
    

into:

    
    
        (aif (big-long-calculation)
            (foo it))
    

cf:
[http://www.bookshelf.jp/texi/onlisp/onlisp_15.html](http://www.bookshelf.jp/texi/onlisp/onlisp_15.html)

~~~
davexunit
Ah yes, that is a use-case. Though, if I were to implement something like
that, I would add an extra set of parens around (big-long-calculation) and
specify the name to bind the value to:

    
    
        (aif (it (big-long-calculation))
          (foo it))

~~~
groovy2shoes
Yep, that's how I do it in Scheme myself, though I've called the construct
`let-if` :)

------
Avshalom
Okay but can I get a chip-8 emulator written in dcpu-16 assembly running on
redstone?

