aboutsummaryrefslogtreecommitdiff
path: root/jackos
diff options
context:
space:
mode:
authorYuchen Pei <me@ypei.me>2018-01-20 15:41:49 +0100
committerYuchen Pei <me@ypei.me>2018-01-20 15:41:49 +0100
commitd3a0cc3a8ba6dfeb64d3faeffdeb6845b60e5840 (patch)
treed58df9ec2480e2a9ec6240f9c797f83d1a0b1056 /jackos
parent3571f998b28fbc8d9250ba04c983935f10a16c15 (diff)
rearranged the dir for github
- removed tools and pdfs - rearranged the projects dirs - added md files - other minor changes
Diffstat (limited to 'jackos')
-rw-r--r--jackos/Array.jack26
-rw-r--r--jackos/Keyboard.jack97
-rw-r--r--jackos/Math.jack158
-rw-r--r--jackos/Memory.jack72
-rw-r--r--jackos/Output.jack281
-rw-r--r--jackos/Screen.jack138
-rw-r--r--jackos/String.jack176
-rw-r--r--jackos/Sys.jack51
8 files changed, 999 insertions, 0 deletions
diff --git a/jackos/Array.jack b/jackos/Array.jack
new file mode 100644
index 0000000..343c25c
--- /dev/null
+++ b/jackos/Array.jack
@@ -0,0 +1,26 @@
+// 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) {
+ return Memory.alloc(size);
+ }
+
+ /** Disposes this array. */
+ method void dispose() {
+ do Memory.deAlloc(this);
+ return;
+ }
+}
diff --git a/jackos/Keyboard.jack b/jackos/Keyboard.jack
new file mode 100644
index 0000000..a35704a
--- /dev/null
+++ b/jackos/Keyboard.jack
@@ -0,0 +1,97 @@
+// 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() {
+ return;
+ }
+
+ /**
+ * 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() {
+ return Memory.peek(24576);
+ }
+
+ /**
+ * 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() {
+ var int key, key1;
+ let key = 0;
+ while (key = 0) {
+ let key = Memory.peek(24576);
+ }
+ let key1 = key;
+ while (key1 = key) {
+ let key1 = Memory.peek(24576);
+ }
+ if ((key > 31) & (key < 127) | (key = 128) | (key = 129)) {
+ do Output.printChar(key);
+ }
+ return key;
+ }
+
+ /**
+ * 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) {
+ var int c;
+ var String s;
+ let s = String.new(140);
+ do Output.printString(message);
+ let c = Keyboard.readChar();
+ while (~(c = 128)) {
+ if (c = 129) {
+ if (s.length() > 0) {
+ do s.eraseLastChar();
+ }
+ } else {
+ do s.appendChar(c);
+ }
+ let c = Keyboard.readChar();
+ }
+ return s;
+ }
+
+ /**
+ * 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) {
+ var String s;
+ do Output.printString(message);
+ let s = Keyboard.readLine("");
+ return s.intValue();
+ }
+}
diff --git a/jackos/Math.jack b/jackos/Math.jack
new file mode 100644
index 0000000..01bce8f
--- /dev/null
+++ b/jackos/Math.jack
@@ -0,0 +1,158 @@
+// 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.
+ * Note: Jack compilers implement multiplication and division using OS method calls.
+ */
+class Math {
+ static Array twoToThe;
+
+ /** Initializes the library. */
+ function void init() {
+ var int i, x;
+ let x = 1;
+ let i = 0;
+ let twoToThe = Array.new(16);
+ while (i < 16){
+ let twoToThe[i] = x;
+ let x = x + x;
+ let i = i + 1;
+ }
+ return;
+ }
+
+ function boolean bit(int x, int i) {
+ return ~(x & twoToThe[i] = 0);
+ }
+
+ function int sign(int x) {
+ if (x > 0) {
+ return 1;
+ } else {
+ if (x < 0) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ /** Returns the absolute value of x. */
+ function int abs(int x) {
+ if (x > 0){
+ return x;
+ } else {
+ return -x;
+ }
+ }
+
+ /** Returns the product of x and y.
+ * When a Jack compiler detects the multiplication operator '*' in the
+ * program's code, it handles it by invoking this method. In other words,
+ * the Jack expressions x*y and multiply(x,y) return the same value.
+ */
+ function int multiply(int x, int y) {
+ var int res, shiftedX, i;
+ let shiftedX = x;
+ let i = 0;
+ let res = 0;
+ //while ((~(twoToThe[i] > y)) & (i < 16)) {
+ while (i < 16) {
+ if (Math.bit(y, i)){
+ let res = res + shiftedX;
+ }
+ let shiftedX = shiftedX + shiftedX;
+ let i = i + 1;
+ }
+ return res;
+ }
+
+ /** Returns the integer part of x/y.
+ * When a Jack compiler detects the multiplication operator '/' in the
+ * program's code, it handles it by invoking this method. In other words,
+ * the Jack expressions x/y and divide(x,y) return the same value.
+ */
+ function int divide(int x, int y) {
+ var int ax, ay;
+ if (x > 0) {
+ if (y > 0) {
+ return Math.divide1(x, y);
+ } else {
+ return -Math.divide1(x, -y);
+ }
+ } else {
+ if (y > 0) {
+ return -Math.divide1(-x, y);
+ } else {
+ return Math.divide1(-x, -y);
+ }
+ }
+ }
+
+ function int divide1(int x, int y) {
+ var int q;
+ if (y = 0) {
+ do Output.printString("Error: division by zero.");
+ do Sys.error(0);
+ }
+ if ((y > x) | (y < 0)) {
+ return 0;
+ }
+ let q = Math.divide1(x, y * 2);
+ if (x - (2 * q * y) < y) {
+ return 2 * q;
+ } else {
+ return 2 * q + 1;
+ }
+ }
+
+ function int length(int x){
+ var int n;
+ let n = 14;
+ while (twoToThe[n] > x){
+ let n = n - 1;
+ }
+ return n;
+ }
+
+ /** Returns the integer part of the square root of x. */
+ function int sqrt(int x) {
+ var int y, k, z, w;
+ if (x < 0) {
+ do Output.printString("Error: square rooting a negative number.");
+ do Sys.error(0);
+ }
+ let k = Math.length(x) / 2;
+ let y = 0;
+ while (~(k < 0)) {
+ let z = y + twoToThe[k];
+ let w = z * z;
+ if ((~(w > x)) & (w > 0)) {
+ let y = z;
+ }
+ let k = k - 1;
+ }
+ return y;
+ }
+
+ /** Returns the greater number. */
+ function int max(int a, int b) {
+ if (a > b) {
+ return a;
+ } else {
+ return b;
+ }
+ }
+
+ /** Returns the smaller number. */
+ function int min(int a, int b) {
+ if (a < b) {
+ return a;
+ } else {
+ return b;
+ }
+ }
+}
diff --git a/jackos/Memory.jack b/jackos/Memory.jack
new file mode 100644
index 0000000..54e04aa
--- /dev/null
+++ b/jackos/Memory.jack
@@ -0,0 +1,72 @@
+// 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 {
+ static Array memory;
+ static Array heap;
+ static int last;
+
+ /** Initializes the class. */
+ function void init() {
+ let memory = 0;
+ let heap = 2048;
+ let heap[0] = -1;
+ let heap[1] = 14334;
+ let last = 0;
+ return;
+ }
+
+ /** Returns the RAM value at the given address. */
+ function int peek(int address) {
+ return memory[address];
+ }
+
+ /** Sets the RAM value at the given address to the given value. */
+ function void poke(int address, int value) {
+ let memory[address] = value;
+ return;
+ }
+
+ /** Finds an available RAM block of the given size and returns
+ * a reference to its base address. */
+ function int alloc(int size) {
+ var int current;
+ var int size2;
+ var int newLast;
+ let current = 0;
+ let size2 = size + 2;
+ while ((current > -1) & (heap[current + 1] < size2)) {
+ let current = heap[current];
+ }
+ if (current = -1) {
+ do String.println("Insufficient space for allocation!");
+ do Sys.error(1);
+ return -1;
+ } else {
+ let heap[current + 1] = heap[current + 1] - size2;
+ let newLast = current + heap[current + 1] + 2;
+ let heap[newLast] = heap[current];
+ let heap[current] = newLast;
+ let heap[newLast + 1] = size;
+ return heap + newLast + 2;
+ }
+ }
+
+ /** De-allocates the given object (cast as an array) by making
+ * it available for future allocations. */
+ function void deAlloc(Array o) {
+ var int oBase;
+ let oBase = o - heap - 2;
+ let heap[oBase] = -1;
+ let heap[last] = oBase;
+ let last = oBase;
+ return;
+ }
+}
diff --git a/jackos/Output.jack b/jackos/Output.jack
new file mode 100644
index 0000000..61b24de
--- /dev/null
+++ b/jackos/Output.jack
@@ -0,0 +1,281 @@
+// 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;
+ static int cursorI, cursorJ;
+
+ /** Initializes the screen, and locates the cursor at the screen's top-left. */
+ function void init() {
+ do Output.initMap();
+ do Output.moveCursor(0, 0);
+ return;
+ }
+
+ // 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,12,12,30,30,51,51,63,51,51,0,0); // A
+ 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) {
+ var int x, y;
+ let x = cursorJ * 8;
+ let y = cursorI * 11;
+ do Screen.setColor(false);
+ do Screen.drawRectangle(x, y, x + 7, y + 10);
+ let x = j * 8;
+ let y = i * 11;
+ do Screen.setColor(true);
+ do Screen.drawRectangle(x, y, x + 7, y + 10);
+ let cursorI = i;
+ let cursorJ = j;
+ return;
+ }
+
+ /** Displays the given character at the cursor location,
+ * and advances the cursor one column forward. */
+ function void printChar(char c) {
+ var int k, x, y, addr;
+ var Array cm;
+ if (c = 129) {
+ do Output.backSpace();
+ return;
+ }
+ if (cursorI = 22) {
+ if (c = 128) {
+ return;
+ }
+ if (cursorJ = 63) {
+ return;
+ }
+ }
+ if (c = 128) {
+ do Output.println();
+ return;
+ }
+ let k = 0;
+ let x = cursorJ / 2;
+ let y = cursorJ - (x * 2); // y = 0: lsb, y = 1: msb
+ let addr = cursorI * 352 + x + 16384;
+ let cm = Output.getMap(c);
+ if (cursorJ = 63) {
+ do Output.moveCursor(cursorI + 1, 0);
+ } else {
+ do Output.moveCursor(cursorI, cursorJ + 1);
+ }
+ while (k < 11) {
+ if (y = 0){
+ do Memory.poke(addr, Memory.peek(addr) & (-128) + cm[k]);
+ } else {
+ do Memory.poke(addr, Memory.peek(addr) & 255 + (cm[k] * 256));
+ }
+ let k = k + 1;
+ let addr = addr + 32;
+ }
+ return;
+ }
+
+ /** displays the given string starting at the cursor location,
+ * and advances the cursor appropriately. */
+ function void printString(String s) {
+ var int i;
+ var int n;
+ let i = 0;
+ let n = s.length();
+ while (i < n) {
+ do Output.printChar(s.charAt(i));
+ let i = i + 1;
+ }
+ return;
+ }
+
+ /** Displays the given integer starting at the cursor location,
+ * and advances the cursor appropriately. */
+ function void printInt(int i) {
+ var String s;
+ let s = String.new(6);
+ do s.setInt(i);
+ do Output.printString(s);
+ return;
+ }
+
+ /** Advances the cursor to the beginning of the next line. */
+ function void println() {
+ if (cursorI < 22) {
+ do Output.moveCursor(cursorI + 1, 0);
+ }
+ return;
+ }
+
+ /** Moves the cursor one column back. */
+ function void backSpace() {
+ if (cursorJ > 0) {
+ do Output.moveCursor(cursorI, cursorJ - 1);
+ } else {
+ do Output.moveCursor(cursorI - 1, 63);
+ }
+ return;
+ }
+}
diff --git a/jackos/Screen.jack b/jackos/Screen.jack
new file mode 100644
index 0000000..a370ab9
--- /dev/null
+++ b/jackos/Screen.jack
@@ -0,0 +1,138 @@
+// 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 {
+ static Array twoToThe;
+ static Array screen;
+ static boolean color;
+
+ /** Initializes the Screen. */
+ function void init() {
+ var int i, x;
+ let x = 1;
+ let i = 0;
+ let twoToThe = Array.new(16);
+ while (i < 16){
+ let twoToThe[i] = x;
+ let x = x + x;
+ let i = i + 1;
+ }
+ let screen = 16384;
+ let color = true;
+ return;
+ }
+
+ /** Erases the entire screen. */
+ function void clearScreen() {
+ var boolean c;
+ let c = color;
+ let color = false;
+ do Screen.drawRectangle(0, 0, 511, 255);
+ let color = c;
+ return;
+ }
+
+ /** 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) {
+ let color = b;
+ return;
+ }
+
+ /** Draws the (x,y) pixel, using the current color. */
+ function void drawPixel(int x, int y) {
+ var int addr, t;
+ if ((x < 0) | (y < 0) | (x > 511) | (y > 255)) {
+ //String.println("drawPixel: coordinates out of range!");
+ //Sys.error(2);
+ return;
+ }
+ let t = x / 16;
+ let addr = 32 * y + t;
+ if (color) {
+ let screen[addr] = screen[addr] | twoToThe[x - (t * 16)];
+ } else {
+ let screen[addr] = screen[addr] & (- (twoToThe[x - (t * 16)] + 1));
+ }
+ return;
+ }
+
+ /** 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) {
+ var int dx, dy, x, y, a, b, diff;
+ let x = x1;
+ let y = y1;
+ do Screen.drawPixel(x, y);
+ if (x1 = x2) {
+ if (y1 = y2) {
+ return;
+ } else {
+ let diff = 1;
+ }
+ } else {
+ if (y1 = y2) {
+ let diff = -1;
+ } else {
+ let diff = 0;
+ }
+ }
+ let dx = x2 - x1;
+ let dy = y2 - y1;
+ let a = Math.sign(dx);
+ let b = Math.sign(dy);
+ let dx = Math.abs(dx);
+ let dy = Math.abs(dy);
+ while (~((x = x2) & (y = y2))) {
+ if (diff < 0){
+ let x = x + a;
+ let diff = diff + dy;
+ } else {
+ let y = y + b;
+ let diff = diff - dx;
+ }
+ do Screen.drawPixel(x, y);
+ }
+ return;
+ }
+
+ /** 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) {
+ var int x;
+ if ((x1 > x2) | (y1 > y2)) {
+ return;
+ }
+ let x = x1;
+ while (~(x > x2)) {
+ do Screen.drawLine(x, y1, x, y2);
+ let x = x + 1;
+ }
+ return;
+ }
+
+ /** Draws a filled circle of radius r<=181 around (x,y), using the current color. */
+ function void drawCircle(int x, int y, int r) {
+ var int dx, dy, r2;
+ if (r > 181) {
+ do String.println("drawCircle: radius too big!");
+ do Sys.error(2);
+ return;
+ }
+ let dy = -r;
+ let r2 = r * r;
+ while (~(dy > r)) {
+ let dx = Math.sqrt(r2 - (dy * dy));
+ do Screen.drawLine(x - dx, y + dy, x + dx, y + dy);
+ let dy = dy + 1;
+ }
+ return;
+ }
+}
diff --git a/jackos/String.jack b/jackos/String.jack
new file mode 100644
index 0000000..3ef40b2
--- /dev/null
+++ b/jackos/String.jack
@@ -0,0 +1,176 @@
+// 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 {
+ field int maxLen;
+ field int len;
+ field Array s;
+
+ /** constructs a new empty string with a maximum length of maxLength
+ * and initial length of 0. */
+ constructor String new(int maxLength) {
+ if (maxLength > 0) {
+ let s = Array.new(maxLength);
+ }
+ let maxLen = maxLength;
+ let len = 0;
+ return this;
+ }
+
+ /** Disposes this string. */
+ method void dispose() {
+ if (maxLen > 0) {
+ do s.dispose();
+ }
+ do Memory.deAlloc(this);
+ return;
+ }
+
+ /** Returns the current length of this string. */
+ method int length() {
+ return len;
+ }
+
+ /** Returns the character at the j-th location of this string. */
+ method char charAt(int j) {
+ if ((j < 0) | (j + 1 > len)){
+ do Output.printString("String.charAt: index out of range!");
+ do Sys.error(5);
+ }
+ return s[j];
+ }
+
+ /** Sets the character at the j-th location of this string to c. */
+ method void setCharAt(int j, char c) {
+ if ((j < 0) | (j + 1 > len)){
+ do Output.printString("String.setCharAt: index out of range!");
+ do Sys.error(5);
+ }
+ let s[j] = c;
+ return;
+ }
+
+ /** Appends c to this string's end and returns this string. */
+ method String appendChar(char c) {
+ if (len = maxLen) {
+ do Output.printString("String.appendChar: reached max length!");
+ do Sys.error(5);
+ }
+ let s[len] = c;
+ let len = len + 1;
+ return this;
+ }
+
+ /** Erases the last character from this string. */
+ method void eraseLastChar() {
+ if (len = 0){
+ do Output.printString("String.eraseLastChar: string is already empty!");
+ do Sys.error(5);
+ }
+ let len = len - 1;
+ return;
+ }
+
+ /** Returns the integer value of this string,
+ * until a non-digit character is detected. */
+ method int intValue() {
+ var int n, i;
+ var char c;
+ var boolean neg, done;
+ let n = 0;
+ if (s[0] = 45) {
+ let i = 1;
+ let neg = true;
+ } else {
+ let i = 0;
+ let neg = false;
+ }
+ let c = s[i];
+ if ((c < 48) | (c > 57)) {
+ do Sys.error(3);
+ do Output.printString("String.intValue: the input data is not number!");
+ }
+ let done = false;
+ while ((~done) & (i < len)) {
+ let c = s[i];
+ if ((c > 47) & (c < 58)) {
+ let n = n * 10 + (c - 48);
+ } else {
+ let done = true;
+ }
+ let i = i + 1;
+ }
+ if (neg) {
+ return -n;
+ } else {
+ return n;
+ }
+
+ }
+
+ /** Sets this string to hold a representation of the given value. */
+ method void setInt(int val) { //change Output.printInt after this
+ var int x, i, y;
+ var boolean neg;
+ if (val < 0) {
+ let neg = true;
+ let len = 2;
+ } else {
+ let neg = false;
+ let len = 1;
+ }
+ let x = Math.abs(val);
+ if (x > 9999) {
+ let len = len + 4;
+ } else { if (x > 999) {
+ let len = len + 3;
+ } else { if (x > 99) {
+ let len = len + 2;
+ } else { if (x > 9) {
+ let len = len + 1;
+ }}}}
+ if (len > maxLen) {
+ do Output.printString("String.setInt: val is too big for the string!");
+ do Sys.error(5);
+ }
+ if (x = 0) {
+ do setCharAt(0, 48);
+ return;
+ }
+ if (neg) {
+ do setCharAt(0, 45);
+ }
+ let i = len - 1;
+ while (x > 0) {
+ let y = x / 10;
+ do setCharAt(i, x - (y * 10) + 48);
+ let x = y;
+ let i = i - 1;
+ }
+ return;
+ }
+
+ /** Returns the new line character. */
+ function char newLine() {
+ return 128;
+ }
+
+ /** Returns the backspace character. */
+ function char backSpace() {
+ return 129;
+ }
+
+ /** Returns the double quote (") character. */
+ function char doubleQuote() {
+ return 34;
+ }
+}
diff --git a/jackos/Sys.jack b/jackos/Sys.jack
new file mode 100644
index 0000000..53c078c
--- /dev/null
+++ b/jackos/Sys.jack
@@ -0,0 +1,51 @@
+// 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() {
+ do Keyboard.init();
+ do Math.init();
+ do Memory.init();
+ do Output.init();
+ do Screen.init();
+ do Main.main();
+ do Sys.halt();
+ return;
+ }
+
+ /** Halts the program execution. */
+ function void halt() {
+ while (true){
+ }
+ return;
+ }
+
+ /** Waits approximately duration milliseconds and returns. */
+ function void wait(int duration) {
+ var int i, j;
+ let i = 0;
+ while (i < duration){
+ let i = i + 1;
+ let j = 0;
+ while (j < 318){
+ let j = j + 1;
+ }
+ }
+ return;
+ }
+
+ /** Displays the given error code in the form "ERR<errorCode>",
+ * and halts the program's execution. */
+ function void error(int errorCode) {
+ do Output.printString("ERR");
+ do Output.printInt(errorCode);
+ return;
+ }
+}