I found project 8 to be the most difficult so far (by a large margin), and when I was near completing it I found this cool trick. One of the hardest parts about debugging it is that if you run the .vm file(s) in the VME, each "step" does not correspond with one step in your ASM file. So if you have the ASM file open in the CPU emulator, and the .vm file open in the VME, you have to click "step" many times in CPU emu (i.e. anywhere from 5x - 50x) to match every single "step" you click in the VME (the reason you'd want to keep the CPU emu and VME in sync is to watch all your RAM locations and see where your problem is occurring).
So, the trick is that you have your asmWriter program add something like this at the beginning of every new .vm line that it translates:
The idea is that 7777 is a RAM location you know is not being used for anything. Now in the CPU emulator you can set RAM=0 as a debug breakpoint, and every time you hit the "fast forward" button in the CPU emu, it corresponds with one "step" in the VME. Helped me a lot, hope it helps someone else!
I agree that the VM is the hardest project in the book. There are many new concepts and you need to learn the Hack architecture and instruction set in great detail.
I learned programming in the days of mainframes, punch cards, and line printers. By reflex, I wrote my Hack assembler to generate a listing file:
// This file is part of the materials accompanying the book
// "The Elements of Computing Systems" by Nisan and Schocken,
// MIT Press. Book site: www.idc.ac.il/tecs
// File name: projects/06/max/Max.asm
// Computes M = max(M, M) where M stands for RAM
0 0 @0
1 FC10 D=M // D=first number
2 1 @1
3 F4D0 D=D-M // D=first number - second number
4 10 @OUTPUT_FIRST
5 E301 D;JGT // if D>0 (first is greater) goto output_first
I have my VM translator write the VM source lines as comments in the ASM output. Armed with the listing file generated by assembling my VM output I could quickly find the generated code by address, and set breakpoints as needed.
It would have been much quicker to use your trick.
It might be handy to include the VM source line number to make it easier to relate ASM and VM code:
Though I like the look of your asm file, pretty nifty with the line numbers and hex codes all neatly aligned!
Also, if you're sure it's unused, then 255 can be used in place of 7777 and you will always be looking at the bottom of your stack (rather than have to scroll through 7000 lines to get back to the RAM that matters, since it focuses on a RAM location every time it modifies it).
You can actually use a simpler technique. Just set a breakpoint on the value of A. So you just need one line to set a break point, for example:
So instead of setting a breakpoint when a specific RAM location gets a certain value, just set it when A gets a specific value. It is less intrusive (a single line per break point), and you do not get the "jumping" back and forth in the emulator.