Compare commits

...

2 Commits

Author SHA1 Message Date
6bafaa8443 project12 - add files 2025-12-07 19:32:48 -05:00
bcad75646f Remove reflections 2025-12-07 19:24:43 -05:00
48 changed files with 1215 additions and 233 deletions

22
12/Array.jack Normal file
View File

@@ -0,0 +1,22 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Array.jack
/**
* Represents an array.
* In the Jack language, arrays are instances of the Array class.
* Once declared, the array entries can be accessed using the usual
* syntax arr[i]. Each array entry can hold a primitive data type as
* well as any object type. Different array entries can have different
* data types.
*/
class Array {
/** Constructs a new Array of the given size. */
function Array new(int size) {
}
/** Disposes this array. */
method void dispose() {
}
}

View File

@@ -0,0 +1,15 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/ArrayTest/ArrayTest.tst
load,
output-file ArrayTest.out,
compare-to ArrayTest.cmp,
output-list RAM[8000]%D2.6.1 RAM[8001]%D2.6.1 RAM[8002]%D2.6.1 RAM[8003]%D2.6.1;
repeat 1000000 {
vmstep;
}
output;

40
12/ArrayTest/Main.jack Normal file
View File

@@ -0,0 +1,40 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/ArrayTest/Main.jack
/** Test program for the OS Array class. */
class Main {
/** Performs several Array manipulations. */
function void main() {
var Array r; // stores test results
var Array a, b, c;
let r = 8000;
let a = Array.new(3);
let a[2] = 222;
let r[0] = a[2]; // RAM[8000] = 222
let b = Array.new(3);
let b[1] = a[2] - 100;
let r[1] = b[1]; // RAM[8001] = 122
let c = Array.new(500);
let c[499] = a[2] - b[1];
let r[2] = c[499]; // RAM[8002] = 100
do a.dispose();
do b.dispose();
let b = Array.new(3);
let b[0] = c[499] - 90;
let r[3] = b[0]; // RAM[8003] = 10
do c.dispose();
do b.dispose();
return;
}
}

55
12/Keyboard.jack Normal file
View File

@@ -0,0 +1,55 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Keyboard.jack
/**
* A library for handling user input from the keyboard.
*/
class Keyboard {
/** Initializes the keyboard. */
function void init() {
}
/**
* Returns the character of the currently pressed key on the keyboard;
* if no key is currently pressed, returns 0.
*
* Recognizes all ASCII characters, as well as the following keys:
* new line = 128 = String.newline()
* backspace = 129 = String.backspace()
* left arrow = 130
* up arrow = 131
* right arrow = 132
* down arrow = 133
* home = 134
* End = 135
* page up = 136
* page down = 137
* insert = 138
* delete = 139
* ESC = 140
* F1 - F12 = 141 - 152
*/
function char keyPressed() {
}
/** Waits until a key is pressed on the keyboard and released,
* then echoes the key to the screen, and returns the character
* of the pressed key. */
function char readChar() {
}
/** Displays the message on the screen, reads from the keyboard the entered
* text until a newline character is detected, echoes the text to the screen,
* and returns its value. Also handles user backspaces. */
function String readLine(String message) {
}
/** Displays the message on the screen, reads from the keyboard the entered
* text until a newline character is detected, echoes the text to the screen,
* and returns its integer value (until the first non-digit character in the
* entered text is detected). Also handles user backspaces. */
function int readInt(String message) {
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

93
12/KeyboardTest/Main.jack Normal file
View File

@@ -0,0 +1,93 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/KeyboardTest/Main.jack
/** Test program for the OS Keyboard class. */
class Main {
/** Gets input from the user and verifies its contents. */
function void main() {
var char c, key;
var String s;
var int i;
var boolean ok;
let ok = false;
do Output.printString("keyPressed test:");
do Output.println();
while (~ok) {
do Output.printString("Please press the 'space' key");
while (key = 0) {
let key = Keyboard.keyPressed();
}
let c = key;
while (~(key = 0)) {
let key = Keyboard.keyPressed();
}
do Output.println();
if (c = 32) {
do Output.printString("ok");
do Output.println();
let ok = true;
}
}
let ok = false;
do Output.printString("readChar test:");
do Output.println();
do Output.printString("(Verify that the pressed character is echoed to the screen)");
do Output.println();
while (~ok) {
do Output.printString("Please press the number '3': ");
let c = Keyboard.readChar();
do Output.println();
if (c = 51) {
do Output.printString("ok");
do Output.println();
let ok = true;
}
}
let ok = false;
do Output.printString("readLine test:");
do Output.println();
do Output.printString("(Verify echo and usage of 'backspace')");
do Output.println();
while (~ok) {
let s = Keyboard.readLine("Please type 'JACK' and press enter: ");
if (s.length() = 4) {
if ((s.charAt(0) = 74) & (s.charAt(1) = 65) & (s.charAt(2) = 67) & (s.charAt(3) = 75)) {
do Output.printString("ok");
do Output.println();
let ok = true;
}
}
}
let ok = false;
do Output.printString("readInt test:");
do Output.println();
do Output.printString("(Verify echo and usage of 'backspace')");
do Output.println();
while (~ok) {
let i = Keyboard.readInt("Please type '-32123' and press enter: ");
if (i = (-32123)) {
do Output.printString("ok");
do Output.println();
let ok = true;
}
}
do Output.println();
do Output.printString("Test completed successfully");
return;
}
}

49
12/Math.jack Normal file
View File

@@ -0,0 +1,49 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Math.jack
/**
* A library of commonly used mathematical functions.
* All functions runs in O(n), where n is the number of bits used
* for representing a two's complement integer value (16 in the Hack computer).
* Note: Jack compilers implement multiplication and division
* using calls to OS functions in this class.
*/
class Math {
static int n; // Number of bits used for representing a two's complement integer
static Array powersOfTwo; // Stores 2^0, 2^1, 2^2,..., 2^(n-1)
// Initializes the Math library.
function void init() {
}
/** Returns the product of x and y.
* When a Jack compiler detects the multiplication operator '*'
* in an expression, it handles it by invoking this method.
* Thus, in Jack, x * y and Math.multiply(x,y) return the same value. */
function int multiply(int x, int y) {
}
/** Returns the integer part of x / y.
* When a Jack compiler detects the division operator '/'
* an an expression, it handles it by invoking this method.
* Thus, x/y and Math.divide(x,y) return the same value. */
function int divide(int x, int y) {
}
/** Returns the integer part of the square root of x. */
function int sqrt(int x) {
}
/** Returns the greater value. */
function int max(int a, int b) {
}
/** Returns the smaller value. */
function int min(int a, int b) {
}
/** Returns the absolute value of x. */
function int abs(int x) {
}
}

34
12/MathTest/Main.jack Normal file
View File

@@ -0,0 +1,34 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/MathTest/Main.jack
// Tests the OS Math class.
class Main {
// Performs various mathematical operations, using calls to the Math class methods.
function void main() {
var Array r; // Stores the test results;
let r = 8000; // Base address
let r[0] = 2 * 3; // 6
let r[1] = r[0] * (-30); // 6 * (-30) = -180
let r[2] = r[1] * 100; // (-180) * 100 = -18000
let r[3] = 1 * r[2]; // 1 * (-18000) = -18000
let r[4] = r[3] * 0; // 0
let r[5] = 9 / 3; // 3
let r[6] = (-18000) / 6; // -3000
let r[7] = 32766 / (-32767); // (2^15 - 2) / (2^15 - 1) = 0
let r[8] = Math.sqrt(9); // 3
let r[9] = Math.sqrt(32767); // 181
let r[10] = Math.min(345, 123); // 123
let r[11] = Math.max(123, -345); // 123
let r[12] = Math.abs(27); // 27
let r[13] = Math.abs(-32767); // 32767
return;
}
}

15
12/MathTest/MathTest.tst Normal file
View File

@@ -0,0 +1,15 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/MathTest/MathTest.tst
load,
output-file MathTest.out,
compare-to MathTest.cmp,
output-list RAM[8000]%D2.6.1 RAM[8001]%D2.6.1 RAM[8002]%D2.6.1 RAM[8003]%D2.6.1 RAM[8004]%D2.6.1 RAM[8005]%D2.6.1 RAM[8006]%D2.6.1 RAM[8007]%D2.6.1 RAM[8008]%D2.6.1 RAM[8009]%D2.6.1 RAM[8010]%D2.6.1 RAM[8011]%D2.6.1 RAM[8012]%D2.6.1 RAM[8013]%D2.6.1;
repeat 1000000 {
vmstep;
}
output;

33
12/Memory.jack Normal file
View File

@@ -0,0 +1,33 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Memory.jack
/**
* This library provides two services: direct access to the computer's main
* memory (RAM), and allocation and recycling of memory blocks. The Hack RAM
* consists of 32,768 words, each holding a 16-bit binary number.
*/
class Memory {
/** Initializes the class. */
function void init() {
}
/** Returns the RAM value at the given address. */
function int peek(int address) {
}
/** Sets the RAM value at the given address to the given value. */
function void poke(int address, int value) {
}
/** Finds an available RAM block of the given size and returns
* a reference to its base address. */
function int alloc(int size) {
}
/** De-allocates the given object (cast as an array) by making
* it available for future allocations. */
function void deAlloc(Array o) {
}
}

53
12/MemoryTest/Main.jack Normal file
View File

@@ -0,0 +1,53 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/MemoryTest/Main.jack
/** Test program for the OS Memory class. */
class Main {
/** Performs various memory manipulations. */
function void main() {
var int temp, err;
var Array a, b, c;
do Memory.poke(8000, 333); // RAM[8000] = 333
let temp = Memory.peek(8000);
do Memory.poke(8001, temp + 1); // RAM[8001] = 334
let a = Array.new(3); // uses Memory.alloc
let a[2] = 222;
do Memory.poke(8002, a[2]); // RAM[8002] = 222
let err = 0;
let b = Array.new(3);
let b[1] = a[2] - 100;
if (b = a) { // Fail compare if b = a
let err = 1; }
do Memory.poke(8003, b[1] + err); // RAM[8003] = 122
let err = 0;
let c = Array.new(500);
let c[499] = a[2] - b[1];
if (c = a) { // Fail compare if c = a
let err = 1; }
if (c = b) { // Fail compare if c = b
let err = err + 10; }
do Memory.poke(8004, c[499]+err); // RAM[8004] = 100
do a.dispose(); // uses Memory.deAlloc
do b.dispose();
let err = 0;
let b = Array.new(3);
let b[0] = c[499] - 90;
if (b = c) { // Fail compare if b = c
let err = 1; }
do Memory.poke(8005, b[0] + err); // RAM[8005] = 10
do c.dispose();
do b.dispose();
return;
}
}

View File

@@ -0,0 +1,183 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/MemoryTest/Main.jack
/** Test program for the OS Memory class. */
class Main {
/** Test Memory.peek(), poke(), alloc() and deAlloc().
*
* This test is also a diagnostic. RAM[17000] is incremented before and
* after every call so that the failure point can be accurately determined
* when using command line testing. Return values from all alloc() calls
* are also stored in the test results to aid debugging.
*/
function void main() {
var int temp;
var Array a, b, c, out;
let out = 17000; // Address where test results will be stored.
// Test poke() and peek().
let out[0] = 10; // poke test
do Memory.poke(out + 1, 333); // RAM[17001] = 333
let out[0] = 11; // peek test
let temp = Memory.peek(out + 1);
let out[2] = temp + 1; // RAM[17002] = 334
let out[0] = 12; // peek/poke test complete
// Allocate a memory block.
// Validate that the returned block is entirely within the heap,
// Test aborts if the block is not valid.
let out[0] = 20;
let a = Memory.alloc(20);
let out[3] = a; // RAM[17003] = block address
let out[0] = 21;
do Main.checkRange(a, 20);
let out[0] = 22;
// Allocate a SMALLER memory block.
// Validate that the returned block is entirely within the heap,
// and that it does not overlap block 'a'.
// Test aborts if the block is not valid or overlaps.
//
// Common failure: first block was not removed from free list so space
// for this block was found within the first block.
let out[0] = 30;
let b = Memory.alloc(3);
let out[4] = b; // RAM[17004] = block address
let out[0] = 31;
do Main.checkRange(b, 3);
let out[0] = 32;
do Main.checkOverlap(b, 3, a, 3);
let out[0] = 33;
// Allocate a memory block.
// Validate that the returned block is entirely within the heap,
// and that it does not overlap blocks 'a' or 'b'.
// Test aborts if the block is not valid or overlaps.
let out[0] = 40;
let c = Memory.alloc(500);
let out[5] = c; // RAM[17005] = block address
let out[0] = 41;
do Main.checkRange(c, 500);
let out[0] = 42;
do Main.checkOverlap(c, 500, a, 3);
let out[0] = 43;
do Main.checkOverlap(c, 500, b, 3);
let out[0] = 44;
// Deallocate blocks 'a' and 'b', retaining 'c'.
//
// Common failure: free list corrupted by deAlloc().
let out[0] = 50;
do Memory.deAlloc(a);
let out[0] = 51;
do Memory.deAlloc(b);
let out[0] = 52;
// Allocate a memory block.
// Validate that the returned block is entirely within the heap,
// and that it does not overlap blocks 'c'.
// Test aborts if the block is not valid or overlaps.
//
// Common failure: free list corrupted by deAlloc().
let out[0] = 60;
let b = Memory.alloc(3);
let out[6] = b; // RAM[17006] = block address
let out[0] = 61;
do Main.checkRange(b, 3);
let out[0] = 62;
do Main.checkOverlap(b, 3, c, 500);
let out[0] = 63;
// Deallocate blocks 'b' and 'c'.
let out[0] = 70;
do Memory.deAlloc(c);
let out[0] = 71;
do Memory.deAlloc(b);
let out[0] = 72;
// Test that deallocated blocks are placed on the free list and can
// be reused.
let out[0] = 70;
let a = Memory.alloc(8000);
let out[7] = a; // RAM[17007] = block address
let out[0] = 71;
do Main.checkRange(a, 8000);
let out[0] = 72;
do Memory.deAlloc(a);
let out[0] = 73;
let a = Memory.alloc(7000);
let out[0] = 74;
do Main.checkRange(a, 7000);
let out[0] = 75;
do Memory.deAlloc(a);
let out[8] = a; // RAM[17008] = block address
// Test complete.
let out[0] = 100;
// At this point all allocated blocks have been deallocated.
//
// You can inspect the free list and confirm that all of the heap is
// contained in the free segments.
//
// If you implemented defragmentation in dealloc(), the free list
// should contain only one segment, consisting of the entire heap.
return;
}
/** Check that block a(a_len) is in the heap.
*
* If the block begins or ends outside of the heap, calls Sys.halt()
*/
function void checkRange(int a, int a_len) {
var int a_high;
let a_high = (a + a_len)-1;
if ((a < 2048) | ((a_high) > 16383)) {
// Block is not entirely within heap.
do Sys.halt();
}
return;
}
/** Check that block a(a_len) does not overlap block b(b_len).
* Assumes that both blocks have been range checked.
*
* If the blocks overlap, calls Sys.halt()
*/
function void checkOverlap(int a, int a_len, int b, int b_len) {
var int a_high, b_high;
let a_high = (a + a_len)-1;
let b_high = (b + b_len)-1;
if ( ~ ((a > b_high) | (a_high < b))) {
// Block overlaps excluded range.
do Sys.halt();
}
return;
}
}

View File

@@ -0,0 +1,18 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/MemoryTest/MemoryDiag/MemoryDiag.tst
echo "At the end of this test it is normal to see some pixels set on the screen";
load,
output-file MemoryDiag.out,
compare-to MemoryDiag.cmp,
output-list RAM[17000]%D2.6.1 RAM[17001]%D2.6.1 RAM[17002]%D2.6.1
RAM[17003]%D2.6.1 RAM[17004]%D2.6.1 RAM[17005]%D2.6.1 RAM[17006]%D2.6.1
RAM[17007]%D2.6.1 RAM[17008]%D2.6.1;
repeat 1000000 {
vmstep;
}
output;

View File

@@ -0,0 +1,55 @@
<html>
<h4>MemoryDiag is both a pass/fail test and a diagnostic.</h4>
<p>
MemoryDiag tests the following:
<ol>
<li>Memory.peek() and Memory.poke() read from and write to the specified memory address.</li>
<li>Memory.alloc() returns RAM blocks that are fully contained within the heap address range 2048-16383.</li>
<li>Memory.alloc() does not return RAM blocks that overlap each other.</li>
<li>RAM blocks deallocated by Memory.deAlloc() are made available for Memory.alloc() to reuse.</li>
</ol>
The block reuse test allocates and deallocates an 8000 word block. It then tries to allocates a 7000 word block which must be allocated from the deallocated 8000 word block. If the 8000 word block is not available for reuse, there will only be about 6300 words available in the heap so you will get an ERR6.
<p>
<i>At the end of this test it is normal to see some pixels set on the screen.</i> This is because the results of the test are written to RAM[17000]&nbsp;&ndash; RAM[17008] which is in the Screen memory. MemoryDiag does not put its results in the first 16K of RAM because it must not interfere with the Memory.jack that is being tested.
<h4>Using MemoryDiag as a diagnostic</h4>
RAM[17000] is set to a unique value before every system call and address validation. This allows the exact failure location in the test to be identified when automated testing is used. At the end of the test, RAM[17000] is set to 100.
<p>
When the test fails to compare, look at the MemoryDiag.out file and note the RAM[17000] value. This is the test <i>step</i> that failed. Look through the Main.jack code and find the corresponding<br>
&emsp;&emsp;<tt>let out[0] = <i>step</i>;</tt><br>
statement. The function immediately following this statement is where the failure occurred.
<p>
For example, if RAM[17000] is 51, the<br>
&emsp;&emsp;<tt>do Memory.deAlloc(b);</tt><br>
call did not return. Either there was a simulation error like a bad address or deAlloc() got stuck in a loop.
<h4>Sample MemoryDiag output files</h4>
<i>Note that RAM[17003]&nbsp;&ndash; RAM[17008] are "don't care" values in the MemoryDiag.cmp file.</i>
<p>
Supplied Memory.vm passes:
<pre style="padding-left:2em;">
|RAM[17000|RAM[17001|RAM[17002|RAM[17003|RAM[17004|RAM[17005|RAM[17006|RAM[17007|RAM[17008|
| 100 | 333 | 334 | 2050 | 2072 | 2077 | 2050 | 2050 | 2050 |
</pre>
Memory.Jack using the Coursera implementation passes:
<pre style="padding-left:2em;">
|RAM[17000|RAM[17001|RAM[17002|RAM[17003|RAM[17004|RAM[17005|RAM[17006|RAM[17007|RAM[17008|
| 100 | 333 | 334 | 16364 | 16359 | 15857 | 15852 | 7850 | 8850 |
</pre>
Broken Memory.jack fails (alloc() returns duplicate block address):
<pre style="padding-left:2em;">
|RAM[17000|RAM[17001|RAM[17002|RAM[17003|RAM[17004|RAM[17005|RAM[17006|RAM[17007|RAM[17008|
| 32 | 333 | 334 | 2050 | 2050 | 0 | 0 | 0 | 0 |
</pre>
Broken Memory.jack fails (deAlloc() does not recycle memory blocks):
<pre style="padding-left:2em;">
|RAM[17000|RAM[17001|RAM[17002|RAM[17003|RAM[17004|RAM[17005|RAM[17006|RAM[17007|RAM[17008|
| 73 | 333 | 334 | 16364 | 16359 | 15857 | 15852 | 7850 | 0 |
</pre>
</html>
<p>

View File

@@ -0,0 +1,15 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/MemoryTest/MemoryTest.tst
load,
output-file MemoryTest.out,
compare-to MemoryTest.cmp,
output-list RAM[8000]%D2.6.1 RAM[8001]%D2.6.1 RAM[8002]%D2.6.1 RAM[8003]%D2.6.1 RAM[8004]%D2.6.1 RAM[8005]%D2.6.1;
repeat 1000000 {
vmstep;
}
output;

9
12/MemoryTest/README.txt Normal file
View File

@@ -0,0 +1,9 @@
There are some specific wrong values that indicate that your Memory.jack
returned identical pointers to allocated segments. Look at Main.jack to
see where the pointers a, b and c are used.
RAM[8003] = 123 b = a
RAM[8004] = 101 c = a
RAM[8004] = 110 c = b
RAM[8004] = 111 c = a and c = b
RAM[8005] = 11 new b = c

202
12/Output.jack Normal file
View File

@@ -0,0 +1,202 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Output.jack
/**
* A library of functions for writing text on the screen.
* The Hack physical screen consists of 512 rows of 256 pixels each.
* The library uses a fixed font, in which each character is displayed
* within a frame which is 11 pixels high (including 1 pixel for inter-line
* spacing) and 8 pixels wide (including 2 pixels for inter-character spacing).
* The resulting grid accommodates 23 rows (indexed 0..22, top to bottom)
* of 64 characters each (indexed 0..63, left to right). The top left
* character position on the screen is indexed (0,0). A cursor, implemented
* as a small filled square, indicates where the next character will be displayed.
*/
class Output {
// Character map for displaying characters
static Array charMaps;
/** Initializes the screen, and locates the cursor at the screen's top-left. */
function void init() {
}
// Initializes the character map array
function void initMap() {
var int i;
let charMaps = Array.new(127);
// Black square, used for displaying non-printable characters.
do Output.create(0,63,63,63,63,63,63,63,63,63,0,0);
// Assigns the bitmap for each character in the charachter set.
// The first parameter is the character index, the next 11 numbers
// are the values of each row in the frame that represents this character.
do Output.create(32,0,0,0,0,0,0,0,0,0,0,0); //
do Output.create(33,12,30,30,30,12,12,0,12,12,0,0); // !
do Output.create(34,54,54,20,0,0,0,0,0,0,0,0); // "
do Output.create(35,0,18,18,63,18,18,63,18,18,0,0); // #
do Output.create(36,12,30,51,3,30,48,51,30,12,12,0); // $
do Output.create(37,0,0,35,51,24,12,6,51,49,0,0); // %
do Output.create(38,12,30,30,12,54,27,27,27,54,0,0); // &
do Output.create(39,12,12,6,0,0,0,0,0,0,0,0); // '
do Output.create(40,24,12,6,6,6,6,6,12,24,0,0); // (
do Output.create(41,6,12,24,24,24,24,24,12,6,0,0); // )
do Output.create(42,0,0,0,51,30,63,30,51,0,0,0); // *
do Output.create(43,0,0,0,12,12,63,12,12,0,0,0); // +
do Output.create(44,0,0,0,0,0,0,0,12,12,6,0); // ,
do Output.create(45,0,0,0,0,0,63,0,0,0,0,0); // -
do Output.create(46,0,0,0,0,0,0,0,12,12,0,0); // .
do Output.create(47,0,0,32,48,24,12,6,3,1,0,0); // /
do Output.create(48,12,30,51,51,51,51,51,30,12,0,0); // 0
do Output.create(49,12,14,15,12,12,12,12,12,63,0,0); // 1
do Output.create(50,30,51,48,24,12,6,3,51,63,0,0); // 2
do Output.create(51,30,51,48,48,28,48,48,51,30,0,0); // 3
do Output.create(52,16,24,28,26,25,63,24,24,60,0,0); // 4
do Output.create(53,63,3,3,31,48,48,48,51,30,0,0); // 5
do Output.create(54,28,6,3,3,31,51,51,51,30,0,0); // 6
do Output.create(55,63,49,48,48,24,12,12,12,12,0,0); // 7
do Output.create(56,30,51,51,51,30,51,51,51,30,0,0); // 8
do Output.create(57,30,51,51,51,62,48,48,24,14,0,0); // 9
do Output.create(58,0,0,12,12,0,0,12,12,0,0,0); // :
do Output.create(59,0,0,12,12,0,0,12,12,6,0,0); // ;
do Output.create(60,0,0,24,12,6,3,6,12,24,0,0); // <
do Output.create(61,0,0,0,63,0,0,63,0,0,0,0); // =
do Output.create(62,0,0,3,6,12,24,12,6,3,0,0); // >
do Output.create(64,30,51,51,59,59,59,27,3,30,0,0); // @
do Output.create(63,30,51,51,24,12,12,0,12,12,0,0); // ?
do Output.create(65,0,0,0,0,0,0,0,0,0,0,0); // A ** TO BE FILLED **
do Output.create(66,31,51,51,51,31,51,51,51,31,0,0); // B
do Output.create(67,28,54,35,3,3,3,35,54,28,0,0); // C
do Output.create(68,15,27,51,51,51,51,51,27,15,0,0); // D
do Output.create(69,63,51,35,11,15,11,35,51,63,0,0); // E
do Output.create(70,63,51,35,11,15,11,3,3,3,0,0); // F
do Output.create(71,28,54,35,3,59,51,51,54,44,0,0); // G
do Output.create(72,51,51,51,51,63,51,51,51,51,0,0); // H
do Output.create(73,30,12,12,12,12,12,12,12,30,0,0); // I
do Output.create(74,60,24,24,24,24,24,27,27,14,0,0); // J
do Output.create(75,51,51,51,27,15,27,51,51,51,0,0); // K
do Output.create(76,3,3,3,3,3,3,35,51,63,0,0); // L
do Output.create(77,33,51,63,63,51,51,51,51,51,0,0); // M
do Output.create(78,51,51,55,55,63,59,59,51,51,0,0); // N
do Output.create(79,30,51,51,51,51,51,51,51,30,0,0); // O
do Output.create(80,31,51,51,51,31,3,3,3,3,0,0); // P
do Output.create(81,30,51,51,51,51,51,63,59,30,48,0);// Q
do Output.create(82,31,51,51,51,31,27,51,51,51,0,0); // R
do Output.create(83,30,51,51,6,28,48,51,51,30,0,0); // S
do Output.create(84,63,63,45,12,12,12,12,12,30,0,0); // T
do Output.create(85,51,51,51,51,51,51,51,51,30,0,0); // U
do Output.create(86,51,51,51,51,51,30,30,12,12,0,0); // V
do Output.create(87,51,51,51,51,51,63,63,63,18,0,0); // W
do Output.create(88,51,51,30,30,12,30,30,51,51,0,0); // X
do Output.create(89,51,51,51,51,30,12,12,12,30,0,0); // Y
do Output.create(90,63,51,49,24,12,6,35,51,63,0,0); // Z
do Output.create(91,30,6,6,6,6,6,6,6,30,0,0); // [
do Output.create(92,0,0,1,3,6,12,24,48,32,0,0); // \
do Output.create(93,30,24,24,24,24,24,24,24,30,0,0); // ]
do Output.create(94,8,28,54,0,0,0,0,0,0,0,0); // ^
do Output.create(95,0,0,0,0,0,0,0,0,0,63,0); // _
do Output.create(96,6,12,24,0,0,0,0,0,0,0,0); // `
do Output.create(97,0,0,0,14,24,30,27,27,54,0,0); // a
do Output.create(98,3,3,3,15,27,51,51,51,30,0,0); // b
do Output.create(99,0,0,0,30,51,3,3,51,30,0,0); // c
do Output.create(100,48,48,48,60,54,51,51,51,30,0,0); // d
do Output.create(101,0,0,0,30,51,63,3,51,30,0,0); // e
do Output.create(102,28,54,38,6,15,6,6,6,15,0,0); // f
do Output.create(103,0,0,30,51,51,51,62,48,51,30,0); // g
do Output.create(104,3,3,3,27,55,51,51,51,51,0,0); // h
do Output.create(105,12,12,0,14,12,12,12,12,30,0,0); // i
do Output.create(106,48,48,0,56,48,48,48,48,51,30,0); // j
do Output.create(107,3,3,3,51,27,15,15,27,51,0,0); // k
do Output.create(108,14,12,12,12,12,12,12,12,30,0,0); // l
do Output.create(109,0,0,0,29,63,43,43,43,43,0,0); // m
do Output.create(110,0,0,0,29,51,51,51,51,51,0,0); // n
do Output.create(111,0,0,0,30,51,51,51,51,30,0,0); // o
do Output.create(112,0,0,0,30,51,51,51,31,3,3,0); // p
do Output.create(113,0,0,0,30,51,51,51,62,48,48,0); // q
do Output.create(114,0,0,0,29,55,51,3,3,7,0,0); // r
do Output.create(115,0,0,0,30,51,6,24,51,30,0,0); // s
do Output.create(116,4,6,6,15,6,6,6,54,28,0,0); // t
do Output.create(117,0,0,0,27,27,27,27,27,54,0,0); // u
do Output.create(118,0,0,0,51,51,51,51,30,12,0,0); // v
do Output.create(119,0,0,0,51,51,51,63,63,18,0,0); // w
do Output.create(120,0,0,0,51,30,12,12,30,51,0,0); // x
do Output.create(121,0,0,0,51,51,51,62,48,24,15,0); // y
do Output.create(122,0,0,0,63,27,12,6,51,63,0,0); // z
do Output.create(123,56,12,12,12,7,12,12,12,56,0,0); // {
do Output.create(124,12,12,12,12,12,12,12,12,12,0,0); // |
do Output.create(125,7,12,12,12,56,12,12,12,7,0,0); // }
do Output.create(126,38,45,25,0,0,0,0,0,0,0,0); // ~
return;
}
// Creates the character map array of the given character index, using the given values.
function void create(int index, int a, int b, int c, int d, int e,
int f, int g, int h, int i, int j, int k) {
var Array map;
let map = Array.new(11);
let charMaps[index] = map;
let map[0] = a;
let map[1] = b;
let map[2] = c;
let map[3] = d;
let map[4] = e;
let map[5] = f;
let map[6] = g;
let map[7] = h;
let map[8] = i;
let map[9] = j;
let map[10] = k;
return;
}
// Returns the character map (array of size 11) of the given character.
// If the given character is invalid or non-printable, returns the
// character map of a black square.
function Array getMap(char c) {
if ((c < 32) | (c > 126)) {
let c = 0;
}
return charMaps[c];
}
/** Moves the cursor to the j-th column of the i-th row,
* and erases the character displayed there. */
function void moveCursor(int i, int j) {
}
/** Displays the given character at the cursor location,
* and advances the cursor one column forward. */
function void printChar(char c) {
}
/** displays the given string starting at the cursor location,
* and advances the cursor appropriately. */
function void printString(String s) {
}
/** Displays the given integer starting at the cursor location,
* and advances the cursor appropriately. */
function void printInt(int i) {
}
/** Advances the cursor to the beginning of the next line. */
function void println() {
}
/** Moves the cursor one column back. */
function void backSpace() {
}
}

42
12/OutputTest/Main.jack Normal file
View File

@@ -0,0 +1,42 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/OutputTest/Main.jack
/** Test program for the OS Output class. */
class Main {
/** Outputs the entire character set to the screen using all the
* methods of the Output class. */
function void main() {
var String s;
let s = String.new(1);
do s.appendChar(String.doubleQuote());
do Output.moveCursor(0, 63);
do Output.printChar(66);
do Output.moveCursor(22, 0);
do Output.printChar(67);
do Output.moveCursor(22, 63);
do Output.printChar(68);
do Output.printChar(65);
do Output.moveCursor(2, 0);
do Output.printString("0123456789");
do Output.println();
do Output.printString("ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz");
do Output.println();
do Output.printString("!#$%&'()*+,-./:;<=>?@[\]^_`{|}~");
do Output.printString(s);
do Output.println();
do Output.printInt(-12345);
do Output.backSpace();
do Output.printInt(6789);
return;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

42
12/Screen.jack Normal file
View File

@@ -0,0 +1,42 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Screen.jack
/**
* A library of functions for displaying graphics on the screen.
* The Hack physical screen consists of 512 rows (indexed 0..511, top to bottom)
* of 256 pixels each (indexed 0..255, left to right). The top left pixel on
* the screen is indexed (0,0).
*/
class Screen {
/** Initializes the Screen. */
function void init() {
}
/** Erases the entire screen. */
function void clearScreen() {
}
/** Sets the current color, to be used for all subsequent drawXXX commands.
* Black is represented by true, white by false. */
function void setColor(boolean b) {
}
/** Draws the (x,y) pixel, using the current color. */
function void drawPixel(int x, int y) {
}
/** Draws a line from pixel (x1,y1) to pixel (x2,y2), using the current color. */
function void drawLine(int x1, int y1, int x2, int y2) {
}
/** Draws a filled rectangle whose top left corner is (x1, y1)
* and bottom right corner is (x2,y2), using the current color. */
function void drawRectangle(int x1, int y1, int x2, int y2) {
}
/** Draws a filled circle of radius r<=181 around (x,y), using the current color. */
function void drawCircle(int x, int y, int r) {
}
}

36
12/ScreenTest/Main.jack Normal file
View File

@@ -0,0 +1,36 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/ScreenTest/Main.jack
/** Test program for the OS Screen class. */
class Main {
/** Draws a sample pictue on the screen using lines and circles. */
function void main() {
do Screen.drawLine(0,220,511,220); // base line
do Screen.drawRectangle(280,90,410,220); // house
do Screen.setColor(false);
do Screen.drawRectangle(350,120,390,219); // door
do Screen.drawRectangle(292,120,332,150); // window
do Screen.setColor(true);
do Screen.drawCircle(360,170,3); // door handle
do Screen.drawLine(280,90,345,35); // roof
do Screen.drawLine(345,35,410,90); // roof
do Screen.drawCircle(140,60,30); // sun
do Screen.drawLine(140,26, 140, 6);
do Screen.drawLine(163,35,178,20);
do Screen.drawLine(174,60,194,60);
do Screen.drawLine(163,85,178,100);
do Screen.drawLine(140,94,140,114);
do Screen.drawLine(117,85,102,100);
do Screen.drawLine(106,60,86,60);
do Screen.drawLine(117,35,102,20);
return;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

63
12/String.jack Normal file
View File

@@ -0,0 +1,63 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/String.jack
/**
* Represents character strings. In addition for constructing and disposing
* strings, the class features methods for getting and setting individual
* characters of the string, for erasing the string's last character,
* for appending a character to the string's end, and more typical
* string-oriented operations.
*/
class String {
/** constructs a new empty string with a maximum length of maxLength
* and initial length of 0. */
constructor String new(int maxLength) {
}
/** Disposes this string. */
method void dispose() {
}
/** Returns the current length of this string. */
method int length() {
}
/** Returns the character at the j-th location of this string. */
method char charAt(int j) {
}
/** Sets the character at the j-th location of this string to c. */
method void setCharAt(int j, char c) {
}
/** Appends c to this string's end and returns this string. */
method String appendChar(char c) {
}
/** Erases the last character from this string. */
method void eraseLastChar() {
}
/** Returns the integer value of this string,
* until a non-digit character is detected. */
method int intValue() {
}
/** Sets this string to hold a representation of the given value. */
method void setInt(int val) {
}
/** Returns the new line character. */
function char newLine() {
}
/** Returns the backspace character. */
function char backSpace() {
}
/** Returns the double quote (") character. */
function char doubleQuote() {
}
}

83
12/StringTest/Main.jack Normal file
View File

@@ -0,0 +1,83 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/StringTest/Main.jack
/** Test program for the OS String class. */
class Main {
/** Performs various string manipulations and displays their results. */
function void main() {
var String s;
var String i;
let s = String.new(0); // a zero-capacity string should be supported
do s.dispose();
let s = String.new(6); // capacity 6, make sure that length 5 is displayed
let s = s.appendChar(97);
let s = s.appendChar(98);
let s = s.appendChar(99);
let s = s.appendChar(100);
let s = s.appendChar(101);
do Output.printString("new,appendChar: ");
do Output.printString(s); // new, appendChar: abcde
do Output.println();
let i = String.new(6);
do i.setInt(12345);
do Output.printString("setInt: ");
do Output.printString(i); // setInt: 12345
do Output.println();
do i.setInt(-32767);
do Output.printString("setInt: ");
do Output.printString(i); // setInt: -32767
do Output.println();
do Output.printString("length: ");
do Output.printInt(s.length()); // length: 5
do Output.println();
do Output.printString("charAt[2]: ");
do Output.printInt(s.charAt(2)); // charAt[2]: 99
do Output.println();
do s.setCharAt(2, 45);
do Output.printString("setCharAt(2,'-'): ");
do Output.printString(s); // setCharAt(2,'-'): ab-de
do Output.println();
do s.eraseLastChar();
do Output.printString("eraseLastChar: ");
do Output.printString(s); // eraseLastChar: ab-d
do Output.println();
let s = "456";
do Output.printString("intValue: ");
do Output.printInt(s.intValue()); // intValue: 456
do Output.println();
let s = "-32123";
do Output.printString("intValue: ");
do Output.printInt(s.intValue()); // intValue: -32123
do Output.println();
do Output.printString("backSpace: ");
do Output.printInt(String.backSpace()); // backSpace: 129
do Output.println();
do Output.printString("doubleQuote: ");
do Output.printInt(String.doubleQuote());// doubleQuote: 34
do Output.println();
do Output.printString("newLine: ");
do Output.printInt(String.newLine()); // newLine: 128
do Output.println();
do i.dispose();
do s.dispose();
return;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

27
12/Sys.jack Normal file
View File

@@ -0,0 +1,27 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Sys.jack
/**
* A library that supports various program execution services.
*/
class Sys {
/** Performs all the initializations required by the OS. */
function void init() {
}
/** Halts the program execution. */
function void halt() {
}
/** Waits approximately duration milliseconds and returns. */
function void wait(int duration) {
}
/** Displays the given error code in the form "ERR<errorCode>",
* and halts the program's execution. */
function void error(int errorCode) {
}
}

31
12/SysTest/Main.jack Normal file
View File

@@ -0,0 +1,31 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/SysTest/Main.jack
/** Test program for the OS Sys class. */
class Main {
/** Tests the wait method of the Sys class. */
function void main() {
var char key;
do Output.printString("Wait test:");
do Output.println();
do Output.printString("Press any key. After 2 seconds, another message will be printed:");
while (key = 0) {
let key = Keyboard.keyPressed();
}
while (~(key = 0)) {
let key = Keyboard.keyPressed();
}
do Sys.wait(2000);
do Output.println();
do Output.printString("Time is up. Make sure that 2 seconds elapsed.");
return;
}
}

View File

@@ -1 +0,0 @@
This project was somewhat easy, but it took a significant amount of time to bring back the concepts. It connected a ton to my discrete math and computer systems (in CS) course, and applied those concepts into creating fundamental logic gates, and extending them into (de)multiplexers and more gates. Setting up the environment was simple for me as well- I'm very comfortable in the terminal, and have configured editors for any possible file I could encounter already.

View File

@@ -1,5 +0,0 @@
Project 10 was a nice shift from the low-level system building I'd been doing- finally working with language structure and grammar. The modular design philosophy I'd been using since Project 6 carried over well. The JackTokenizer and CompilationEngine split followed the same Parser/CodeWriter pattern from my VM translator, just dealing with a much richer set of tokens and grammar rules. Building the tokenizer was actually straightforward- it's essentially just string parsing that I've done plenty of times before. The comment handling was trickier than expected though, with multi-line comments that span across lines requiring state tracking between advance() calls.
The compilation engine was where my algorithm/programming language design and computer systems (in CS, 306) courses finally clicked into place. Recursive descent parsing is just grammar rules implemented as methods that call each other- it was elegant, but only once I saw it. Each production rule maps directly to a method, and the recursive calls naturally build the parse tree (which I just so happen to be doing in CS 308, programming language design!). The XML output requirement was actually great for debugging since I could visually inspect the parse tree structure in a browser and catch parsing errors immediately. I hit some tricky edge cases with expression parsing- operator precedence, unary operators, and making sure the tokenizer advanced at exactly the right moments for complex constructs like array access and method calls.
What really struck me was how this project revealed the hidden complexity of syntax analysis- something I'd always taken for granted as a programmer. Seeing how a parser actually breaks down source code according to grammar rules, handles precedence, and builds a structured representation gave me new appreciation for what happens before compilation even starts. Again, a great compliment to 308, as I'm learning the theory there and putting it into practice here.

View File

@@ -1 +0,0 @@
Now we're starting to ramp up, and this is beginning to cause some internal conflict. Coming from computer science, and with my experience on low-power systems, I find optimization to be really important. Yet, in the ALU, I found it easiest to compute multiple values and then decide which one to keep, because you can't "build" a circuit after something is computed, rather, you have to prepare for all outcomes. Although the logic here seems Turing complete (without full analysis), it's a bit of a learning curve for me to think physically and not in terms of software.

View File

@@ -1 +0,0 @@
This project felt more aligned with the information from CSCI 306: using program counters, storing information in registers, using low/high bits to find what to address. Learning what the DFF did took a bit of reading and re-reading- still fuzzy on that, but the videos helped. The program counter was a bit confusing, as I tried to build it without a register first; once I figured out I needed to store the counter I went back to the register. The RAM was straightforward- just scaled, and I needed to split the address to propagate downwards and find which bank(s) to reference.

View File

@@ -1 +0,0 @@
This project was definitely the most difficult yet, but made sense after a while. I started with laying out the actions of what's going on functionally, turned that into pseudocode comments. Most of my time then turned into translating RISC-V style pseudocode into functional code, and debugging. Assembly makes sense, but only after a while. Documentation is kinda all over the place.

View File

@@ -1,17 +0,0 @@
I say this each time, but this one was definitely the hardest so far. Glad to be done with HDL. The Computer was easiest- just combining three parts. Memory was simple enough once I laid it out, using the textbook to figure out offsets and partitions. I'm not a fan of bit splitting (referencing like it's an array), but it's good enough to work. Partly why I'm glad to move on.
That being said, the CPU was difficult.
*extra lines for dramatic effect*
Decoding instruction type? fine.
Computing jump type? fine, eventually.
Updating the program counter? fine. easy, even.
Connecting outputs? didn't know I could just reroute outputs- until I looked at my old code and realized I doubled it anyways. Bit of an airhead moment from me, I just forced it with an or. Worked, but at what cost? (I know the cost. two or's. that's literally the cost.) ¯\_(ツ)_/¯
ALU op? Lots of variables. But I made the ALU before- it's just plugging it in correctly.
The problem was taking the instruction and turning it into something the ALU could handle. Even though I had the instruction breakdown, and the connections, I just repeatedly hit my head against a wall. It really took a lot of trial and error, but I had the majority of this all done in the first two days, and spent the rest of the time on fixing this. Eventually, I just kinda fixed it by accident? (In the words of Ned Ladd: There are three steps to solving a problem. Write down what you know, Think really hard, Write down the answer. You're at step 2.)
In actuality, I drew out diagrams, connected the bit segments to where they needed to go, unraveled the mess of drawings I did create over and over, until I actually figured it out. Then it worked. But that isn't as fun of a response.
Thank you for coming to my ted talk.

View File

@@ -1,8 +0,0 @@
Combining a reflection of 5.5 and 6 here...
I began the bunny/hare project recalling how to program with Python. I looked back at my CSCI 204 labs to find how I had worked with file I/O, and copied functions from that to start. I prefer to work in heavily object oriented, strongly typed languages with less room for experimentation, so going back to Python feels very odd. Once I got file I/O and lists working, the program was fairly straightforward.
Moving onto the assembler, I heavily utilized the template. I broke the program up into three classes: A parser, which reads the assembly commands and breaks them up into components; a symbol table, which acted as a lookup table for predefined symbols (registers, screen, keyboard etc), and a "code" class, which translates the mnemonics into their respective binary representations. Once those helpers were done, I began on the assembler. I store all the assembly that's generated into a list, which is later written to a file. Not the best implementation- more file writes would be safer, but this works for now, and lets me iterate.
I check for more commands, iterate through the commands, find their type, then either look it up or convert to binary (this is simplified, but gets the gist). once all commands are processed, I write the list to the file.
That's it! This took a bit of time, I optimized my classes a bit out of preference, but it works!

View File

@@ -1,3 +0,0 @@
Functionally, my code for Project 7 (VM to ASM) is the same as Project 6 (ASM to Hack), at least in the beginning. I wrote the program to be very class-heavy, object oriented and well structured- allowing me to bring over the Parser class. The Parser class takes all commands into a list, and allows for iteration through the list. It allows for the command type to be identified and arguments to be separated. The CodeWriter class then writes the assembly commands as strings- theyre parsed by the parser, fed into the translator which then writes the correct sequence of commands into assembly (usually more than one per vm line). The translator creates an instance of parser and code writer, and combines their functionality to write the assembly to a file. Finally, the main function handles the aggregation of it all- taking in a file, verifying arguments, parsing directory contents etc.
My process throughout this was iterative- I used my base from project 6 as a good start. Although it didnt necessarily build off of the prior project, the process was similar. I started porting the parser, mapping the commands to a lookup list. Then the CodeWriter, which actually converted the commands to their symbols. The CodeWriter took the most time- as I needed to fill in the gaps with pushing and popping from the correct places. The translator just connected the two, so that was easy. Along the way I brought over my main function, changed it to handle directories and updated its usage.

View File

@@ -1,5 +0,0 @@
Building the VM translator for Project 8 felt like a natural evolution from Project 7, much like how Project 7 built conceptually on Project 6's foundation. The modular design I started in the assembler, with clean separation between Parser and CodeWriter classes, paid off. I extended the existing VM translator by just adding new command types to the parser and corresponding translation methods to the CodeWriter. The OOP structure made this expansion surprisingly straightforward and easy.
What struck me most was how this project revealed the hidden complexity of function calls- something I'd always taken for granted as a programmer. Seeing how the stack based calling convention actually works under the hood, with its intricate back and forth of saving state, repositioning pointers, and managing return addresses, gave me a new appreciation for what compilers do behind the scenes. It reminded me of CS 315 (operating system design). The recursive Fibonacci function was cool to see, as it showed parallels between the LIFO nature of the stack and the LIFO behavior of nested function calls- further explaining what I knew about recursion.
The most challenging piece was getting the function calling protocol exactly right. The sequence of operations for `call` and `return` commands required careful attention to detail, especially managing the temporary registers and ensuring the stack frame was constructed correctly.

View File

@@ -1,3 +0,0 @@
Project 9 was a nice change of pace from the previous projects. Instead of implementing precise specifications like the assembler or VM translator, I got to be creative and build something interactive. The modular design approach I'd been using in Projects 6-8 carried over well - separate classes for Point, Food, Snake, and SnakeGame made the code clean and easy to debug. I hit several tricky issues though - the snake would leave white pixel artifacts when growing, food would sometimes spawn invisibly at screen edges, and hitting walls caused program crashes with "illegal rectangle coordinates" errors. Jack also doesn't have built-in random functions, so I had to find a random number generator online, as I didn't know where to start with making one myself. I found one using "Linear Congruential Generator" math that I didn't really understand, but it worked for spawning food in different locations. The modular design helped isolate these problems to specific classes rather than hunting through monolithic code.
The most rewarding part was seeing the entire stack work together. The Snake game runs on the CPU built in Project 5, uses the VM implemented in Projects 7-8, and gets compiled by the Jack compiler. Every keystroke travels through layers I actually understand now- from hardware input to game logic to screen output. The debugging was different too- instead of failed test cases, I had to diagnose visual glitches and gameplay behavior. Jack's limitations also forced some creative workarounds, like implementing a proper random number generator from scratch and handling the lack of color support by using outlined boxes for food instead of filled squares. It felt more like real software development with messier problems and less obvious solutions, but also more satisfying when everything finally worked smoothly.

View File

@@ -1,18 +0,0 @@
What points were the most clear to you? (List up to 3)
- Fundamentals of logic gates (or, and, not) made sense.
- Explaining how a NAND gate can make up the three fundamentals made sense.
Grading comment:
What points were the muddiest and you'd like to talk more about? (List up to 3)
- The idea of how a multiplexer functions makes sense, but its building blocks were kinda fuzzy (required external research).
- Same with a demultiplexer, but I have a better understanding now.
Grading comment:
Reflect on what you read.
Give me a sense about what is connecting to existing knowledge
-OR-
Your "ah ha!" moments
-OR-
What is hanging off by itself, not connecting.
The concepts of chapter 1 felt relatively simple. I understood logic gates and truth tables because of my prior courses, namely discrete math. The snippets of HDL and API descriptions also made a lot of sense to me, as I work on more complex API structures and took CSCI 306 with assembly covered. The idea of this course is exciting- Ive worked on every individual segment before, but never have I gone from the fundamentals to a complete product. Theres usually layers of abstraction in my projects- working with existing frameworks, or stopping at a level where I show proficiency for a class assignment.

View File

@@ -1,20 +0,0 @@
What points were the most clear to you? (List up to 3)
- Tokenization makes sense- breaking code into symbols, keywords, identifiers
- Okay, parsing follows the grammar structure naturally
- The XML output is just a way to visualize the parse tree structure
Grading comment:
What points were the muddiest and you'd like to talk more about? (List up to 3)
- Why XML output instead of just building the parse tree directly in some sort of object/other format
- The LL(0) grammar thing - seems like we're deliberately making Jack simple to avoid lookahead (tokenization again! like AI!!!)
- How do we handle operator precedence if Jack doesn't enforce it? Lots of parentheses?
Grading comment:
Reflect on what you read.
Give me a sense about what is connecting to existing knowledge
-OR-
Your "ah ha!" moments
-OR-
What is hanging off by itself, not connecting.
This chapter shows how compilers work under the hood- tokenization breaks source code into basic elements, then recursive descent parsing follows grammar rules to build a parse tree. The XML output is just a demonstration tool to show the parser understands the program structure. This connects to my discrete math course- the grammars finally have a practical application beyond theory (finally! theory into practice! I thought this day would never come.). The LL(0) grammar design makes sense from an implementation perspective, though it feels wrong compared to real languages. Jack's deliberate simplifications (mandatory keywords, no operator precedence, forced curly braces) are clearly intended to make compiler construction easier to learn, but it ends up with a clunky syntax that I definitely wouldn't want to use in practice. Still, breaking this complex topic into manageable pieces (tokenizer + parser) makes a ton of sense.

View File

@@ -1,17 +0,0 @@
What points were the most clear to you? (List up to 3)
- The concept of binary addition, and subsequent operations
- Differences between a half and full adder, and how to connect them
Grading comment:
What points were the muddiest and you'd like to talk more about? (List up to 3)
- The idea of an ALU made sense, but the concept of implementation was a little dense. I understand it now after working on the project for a bit.
Grading comment:
Reflect on what you read.
Give me a sense about what is connecting to existing knowledge
-OR-
Your "ah ha!" moments
-OR-
What is hanging off by itself, not connecting.
As with the prior chapter, this felt like review of CSCI 306- where we went over integer/binary addition, subtraction, etc. The idea of an ALU was touched on, but I feel like this is going to diverge a bit here- less in theory, more of implementation in this course. Again, Im excited to see where this goes.

View File

@@ -1,17 +0,0 @@
What points were the most clear to you? (List up to 3)
- Concept of clock cycles, separating out calculations into time units
- Flip Flops storing data
Grading comment:
What points were the muddiest and you'd like to talk more about? (List up to 3)
- How do we maintain a clock with our current system? Everything just computes instantly so far, how do we modify what we have?
Grading comment:
Reflect on what you read.
Give me a sense about what is connecting to existing knowledge
-OR-
Your "ah ha!" moments
-OR-
What is hanging off by itself, not connecting.
So my first thought- concurrency?? already? This doesnt sound good. But then I read on- starting to make sense. Clock cycles are expected, yet I thought theyd have come up with the ALU (but the ALU is simple enough). I remember building flip flops in Minecraft (not surprisingly), so that concept also makes sense. Other than that, the RAM seems to scale exponentially, but from an implementation perspective, it just seems like a bit of repetition- so that will be simple enough once the basic implementation is met. Were scaling up rapidly here, yet the concepts still somewhat remain in grasp.

View File

@@ -1,19 +0,0 @@
What points were the most clear to you? (List up to 3)
- Machine language is familiar, however the flavor is not.
- working with memory, memory vs data reg, loop/jump
Grading comment:
What points were the muddiest and you'd like to talk more about? (List up to 3)
- Back to assembly… can we not? (kidding, but also not really.)
- Input/Output- we have predefined registers out of the ram range?
- Working with the screen seems intimidating- well see how that goes. Any tips would be appreciated.
Grading comment:
Reflect on what you read.
Give me a sense about what is connecting to existing knowledge
-OR-
Your "ah ha!" moments
-OR-
What is hanging off by itself, not connecting.
As with project03, this project with assembly language is starting to overlap with CSCI 306- working with assembly. Although I didnt necessarily like that part of the course, I understand it, and Im hoping that will overlap now. The only problem I see myself facing in the near future is shedding my RISCV assembly tendencies and learning hack, which seems to have weird syntax comparatively. Otherwise, the instructions from a high level here make sense and appear to be straightforward.

View File

@@ -1,18 +0,0 @@
What points were the most clear to you? (List up to 3)
- four main sections of a CPU: ALU, registers, control, I/O.
- screen made sense, as I had to look this up before
Grading comment:
What points were the muddiest and you'd like to talk more about? (List up to 3)
- Where are we storing the ROM?
- is this OS going to have a scheduler?
Grading comment:
Reflect on what you read.
Give me a sense about what is connecting to existing knowledge
-OR-
Your "ah ha!" moments
-OR-
What is hanging off by itself, not connecting.
Starting to get a little muddy, but Im still holding on. The parts of the CPU I knew, connecting it all makes sense, but Im too used to linux and Im confusing layers of complexity. Abstracting all of the functions into sections of the CPU is whats going to hold it together, I think. Now its just taking the API spec and turning into something functional. We'll see how this goes.

View File

@@ -1,19 +0,0 @@
What points were the most clear to you? (List up to 3)
- Lots of hardcoding, but its okay here (software brain scared)
- Symbolic references seem like a fun challenge. Im sure Im the only person to say this.
- This is just translation- Instruction X equals value Y. Just a bit more complicated. Spec will help.
Grading comment:
What points were the muddiest and you'd like to talk more about? (List up to 3)
- I dont like hardcoding. Magic numbers are bad.
- Are we going to end up optimizing later? Especially since this is a low-power CPU.
Grading comment:
Reflect on what you read.
Give me a sense about what is connecting to existing knowledge
-OR-
Your "ah ha!" moments
-OR-
What is hanging off by itself, not connecting.
I feel like I say this every time- but this is where its getting good. We have the system, we have the language, now lets make the system recognize the language (kinda but not really, you get what I mean). Again calls back to CSCI 306, but we didnt write our own assembler, just explored how it worked. RISC-V, although simple, isnt as simple as this machine. Im worried about my resistance to magic numbers and hardcoding, although thatll be necessary here. I also am not so sure where to start. But thats a later problem.

View File

@@ -1,21 +0,0 @@
What points were the most clear to you? (List up to 3)
- The concept of a VM (I work with Java a ton, this made sense)
- Two-tiered architecture (translation between code and byte code, and another between byte code to machine language)
- Push and pop, the stack, eventually a heap (I guess not?)
Grading comment:
What points were the muddiest and you'd like to talk more about? (List up to 3)
- Why are we using a VM here? Isnt that inefficient? Shouldnt we be emulating something C-like instead of Java-like? Java is sloooow.
- Again, as I read more- why a VM? This is just an extra layer! Were not going for cross compatibility here, this is a weak machine!
Grading comment:
Reflect on what you read.
Give me a sense about what is connecting to existing knowledge
-OR-
Your "ah ha!" moments
-OR-
What is hanging off by itself, not connecting.
Im definitely (not) biased here. My software engineering brain has one of those rotating police sirens going off. Why a VM? Thats super inefficient here. We have a low power computer, were not optimizing for cross-platform code compatibility, were not even using a standard architecture! So why are we using this? To me, this looks like a useless intermediary step that exists just to complicate things.
That being said, learning about a VM language is a different story. And thats how Im rationalizing this seemingly bad decision. If this VM exists to teach us about programming language design, fine. But thats better left for CSCI 308.

View File

@@ -1,19 +0,0 @@
What points were the most clear to you? (List up to 3)
- Okay, so were going up a step. We made the VM turn into Hack ASM, but we need something to make the VM language files in the first place- were not writing direct to VM.
- So were translating Jack (java-ish) to VM! New syntax to learn, but its only 8 library files. That sounds doable.
- The “calling protocol” makes sense- similar to the call stack Im used to.
Grading comment:
What points were the muddiest and you'd like to talk more about? (List up to 3)
- Again- VM bad, extra obscurity! Good for education.
- how do we really define functions? Thats the library stuff I dont quite get yet.
Grading comment:
Reflect on what you read.
Give me a sense about what is connecting to existing knowledge
-OR-
Your "ah ha!" moments
-OR-
What is hanging off by itself, not connecting.
Were going up in the CS course stack! This time, a mix of 306 and 308 - computer systems, and programming language design. I understand how we are using functions now- converting a user-friendly programming language, to a vm intermediary, then compiling to assembly. This makes sense, and is exactly what I wanted to see in the course! I wanted to see this higher level connection of language to compiler to compiled- the VM step, no matter how much I disagree with it, is nice too.

View File

@@ -1,20 +0,0 @@
What points were the most clear to you? (List up to 3)
- Jack syntax is pretty straightforward- Java-ish but simplified, which makes sense
- OOP concepts translate well, even on this basic platform
- The standard library provides the building blocks we need for larger programs
Grading comment:
What points were the muddiest and you'd like to talk more about? (List up to 3)
- Memory management seems manual- are we doing our own malloc/free equivalent?
- Graphics programming at this level feels primitive…
- How do we debug Jack programs effectively without proper debugging tools?
Grading comment:
Reflect on what you read.
Give me a sense about what is connecting to existing knowledge
-OR-
Your "ah ha!" moments
-OR-
What is hanging off by itself, not connecting.
Finally! We're at the application layer- this is where it all comes together. After building everything from NAND gates to a VM, we can actually write real programs that do useful things. The Jack language feels like a stripped-down Java, which makes sense given my background. It's cool to see how OOP concepts work even on this simple platform. Im now realizing that Ive built a complete computing stack. We went from basic logic gates to writing applications with graphics and user interaction- insane when you think about it. Every layer we built is now being used - the ALU for calculations, memory for storage, the screen for output. What still bugs me is the realization that this is still pretty primitive compared to modern development. No garbage collection, limited graphics, basic I/O. But I know that's the point- I understand what's happening under the hood now. When I write programs normally, there are so many layers of abstraction I never think about.