d5779be0dd59

Proofread
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Mon, 02 Jan 2017 15:28:31 +0000
parents 668bb0e9c534
children d0331d381b31
branches/tags (none)
files content/blog/2017/01/chip8-disassembly.markdown

Changes

--- a/content/blog/2017/01/chip8-disassembly.markdown	Mon Jan 02 15:11:10 2017 +0000
+++ b/content/blog/2017/01/chip8-disassembly.markdown	Mon Jan 02 15:28:31 2017 +0000
@@ -10,11 +10,11 @@
 Lisp.  After adding a screen, input, and sound the core of the emulator is
 essentially complete.
 
-I've been guiding you through the code step by step and it might look pretty
-simple, but that's only because I went down all the dead ends myself first.  In
+I've been guiding you through the code step by step and it might look simple,
+but that's only because I went down all the dead ends myself first.  In
 practice, when you're writing an emulator for a system you'll need a way to
-debug the execution of code, and the first step is to be able to *read* the
-code, so let's look at how to add a disassembler to our simple CHIP-8 emulator.
+debug the execution of code.  The first step is to be able to *read* the code,
+so let's look at how to add a disassembler to our simple CHIP-8 emulator.
 
 The full series of posts so far:
 
@@ -91,7 +91,7 @@
 
 There are a lot of other ways we could have done this, like making a proper
 parser or adding functionality to `define-opcode`, but since there's not that
-many instructions I think this is pretty reasonable.  Now we can pass in a raw,
+many instructions I think this is reasonable.  Now we can pass in a raw,
 two-byte instruction and get out something readable:
 
 ```
@@ -139,15 +139,16 @@
 instruction to the screen.  Running it for a single instruction would print
 something like:
 
-```
-Address    Disassembly
- |          |
- v          v
-200: 8055 (SUB V0 V5)
-      ^
-      |
-      Raw instruction
-```
+<pre class="lineart">
+    200: 8055 (SUB V0 V5)
+     ^    ^   ^
+     |    |   |
+     |    |  Disassembly
+     |    |
+     |   Raw instruction
+     |
+    Address
+</pre>
 
 The helper function `instruction-information` is simple, but we'll be using it
 in the future for something else, so it's nice to have:
@@ -174,10 +175,9 @@
              (aref array (1+ index))))
 ```
 
-These functions *could* be combined into a single, bigger function, but I'm
-a strong believer in having each function do exactly one thing only.  And as
-we'll see, each of these "simple" tasks is going to get more complicated in the
-real world.
+These functions *could* be combined into a single bigger function, but I'm
+a strong believer in having each function do exactly one thing.  And as we'll
+see, each of these "simple" tasks is going to get more complicated later.
 
 Now we can dump the disassembly for a ROM to see how it works:
 
@@ -224,18 +224,18 @@
 valid opcodes it will return `nil`.
 
 The CHIP-8 (like [most computers][neumann]) uses the same memory to hold both
-program code (instructions) and data.  This includes things like player health,
-score, location, and most importantly: the sprites that will be drawn on the
-screen.
+program code (instructions) and data.  Data includes things like player
+health, score, location, and most importantly: the sprites that will be drawn on
+the screen.
 
 [neumann]: https://en.wikipedia.org/wiki/Von_Neumann_architecture
 
 Unfortunately there's no way to know for sure whether a given memory location
 contains an instruction (and thus needs to be disassembled) or is intended to be
 a piece of data.  Indeed, someone like [Mel][] could conceivably figure out
-a way to use a particular sequence of instructions as a sprite!  So our
-disassembler will just always show the disassembly for anything that *might* be
-an instruction.
+a way to make a particular sequence of instructions perform double duty as
+a sprite!  So our disassembler will just always show the disassembly for
+anything that *might* be an instruction.
 
 [Mel]: http://www.catb.org/jargon/html/story-of-mel.html
 
@@ -247,7 +247,6 @@
 
 We could add a separate function to draw out the sprite data, but the CHIP-8's
 sprites are so simple that we can just tack it on to the disassembly output.
-
 [Remember][cowgod-disp] that each byte of memory defines one eight-pixel-wide
 row of a sprite, and that `DRW X, Y, Size` will draw `Size` rows of a sprite
 using contiguous bytes in memory.  So if memory contains something like this (at
@@ -280,22 +279,19 @@
 *one* byte long.  Our sprites would get pretty mangled if we printed two of
 their rows per line of disassembly — for example, `4` would look like this:
 
-```
-                                   byte 1  byte 2
-                                   1111111122222222
-064: 9090 (SNE V0 V9)              █  █    █  █
-066: F010                          ████    █
-068: 10F0 (JP F0)                     █
-```
+<pre class="lineart">                                       byte 1  byte 2
+                                       1111111122222222
+    064: 9090 (SNE V0 V9)              █  █    █  █
+    066: F010                          ████    █
+    068: 10F0 (JP F0)                     █    ████
+</pre>
 
 Not ideal.  One option would be to make every instruction of disassembly two
 lines long, but that's painful to read when trying to look at the code portions
-of the ROM.
-
-We can get around this with a delightful little hack: using characters from
-[Unicode Block Elements][block] to cram two rows of sprite data into a single
-line of output.  Let's start by defining a `bit-diagram` function that will take
-a two-byte-wide integer and return an ASCII diagram of its bits:
+of the ROM.  We can get around this with a delightful little hack: using
+characters from [Unicode Block Elements][block] to cram two rows of sprite data
+into a single line of output.  Let's start by defining a `bit-diagram` function
+that will take a two-byte-wide integer and return an ASCII diagram of its bits:
 
 [block]: https://en.wikipedia.org/wiki/Block_Elements
 
@@ -305,11 +301,10 @@
            (for low-bit :from 7 :downto 0)
            (for hi = (logbitp high-bit integer))
            (for lo = (logbitp low-bit integer))
-           (collect (cond
-                      ((and hi lo) #\full_block)
-                      (hi #\upper_half_block)
-                      (lo #\lower_half_block)
-                      (t #\space))
+           (collect (cond ((and hi lo) #\full_block)
+                          (hi          #\upper_half_block)
+                          (lo          #\lower_half_block)
+                          (t           #\space))
                     :result-type 'string)))
 ```