summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuchen Pei <me@ypei.me>2018-01-17 09:02:30 +0100
committerYuchen Pei <me@ypei.me>2018-01-17 09:02:30 +0100
commit17c169707a1efc2d576e1b03d2956b0b4be4135d (patch)
treea6d0c38030f2221b2a20c7230b7e0614e160ad07
parent225da72f92b9e0b5caded3e0b85de30633af55fb (diff)
finished Math.jack
-rw-r--r--projects/12/Math.jack98
-rw-r--r--projects/12/MathTest/Main.vm162
-rw-r--r--projects/12/MathTest/Math.jack146
-rw-r--r--projects/12/MathTest/Math.vm446
-rw-r--r--projects/12/MathTest/MathTest.out2
5 files changed, 854 insertions, 0 deletions
diff --git a/projects/12/Math.jack b/projects/12/Math.jack
index a57f023..61e09fc 100644
--- a/projects/12/Math.jack
+++ b/projects/12/Math.jack
@@ -8,13 +8,33 @@
* 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);
}
/** 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.
@@ -23,6 +43,18 @@ class Math {
* the Jack expressions x*y and multiply(x,y) return the same value.
*/
function int multiply(int x, int y) {
+ var int z, res, shiftedX, i;
+ let shiftedX = x;
+ let i = 0;
+ let res = 0;
+ while ((twoToThe[i] > x) & (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.
@@ -31,17 +63,83 @@ class Math {
* 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/projects/12/MathTest/Main.vm b/projects/12/MathTest/Main.vm
new file mode 100644
index 0000000..025f20c
--- /dev/null
+++ b/projects/12/MathTest/Main.vm
@@ -0,0 +1,162 @@
+function Main.main 1
+push constant 8000
+pop local 0
+push constant 0
+push local 0
+add
+push constant 2
+push constant 3
+call Math.multiply 2
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 1
+push local 0
+add
+push constant 0
+push local 0
+add
+pop pointer 1
+push that 0
+push constant 30
+neg
+call Math.multiply 2
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 2
+push local 0
+add
+push constant 1
+push local 0
+add
+pop pointer 1
+push that 0
+push constant 100
+call Math.multiply 2
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 3
+push local 0
+add
+push constant 1
+push constant 2
+push local 0
+add
+pop pointer 1
+push that 0
+call Math.multiply 2
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 4
+push local 0
+add
+push constant 3
+push local 0
+add
+pop pointer 1
+push that 0
+push constant 0
+call Math.multiply 2
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 5
+push local 0
+add
+push constant 9
+push constant 3
+call Math.divide 2
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 6
+push local 0
+add
+push constant 18000
+neg
+push constant 6
+call Math.divide 2
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 7
+push local 0
+add
+push constant 32766
+push constant 32767
+neg
+call Math.divide 2
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 8
+push local 0
+add
+push constant 9
+call Math.sqrt 1
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 9
+push local 0
+add
+push constant 32767
+call Math.sqrt 1
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 10
+push local 0
+add
+push constant 345
+push constant 123
+call Math.min 2
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 11
+push local 0
+add
+push constant 123
+push constant 345
+neg
+call Math.max 2
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 12
+push local 0
+add
+push constant 27
+call Math.abs 1
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 13
+push local 0
+add
+push constant 32767
+neg
+call Math.abs 1
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push constant 0
+return
diff --git a/projects/12/MathTest/Math.jack b/projects/12/MathTest/Math.jack
new file mode 100644
index 0000000..6bac42e
--- /dev/null
+++ b/projects/12/MathTest/Math.jack
@@ -0,0 +1,146 @@
+// 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);
+ }
+
+ /** 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/projects/12/MathTest/Math.vm b/projects/12/MathTest/Math.vm
new file mode 100644
index 0000000..dad8ff5
--- /dev/null
+++ b/projects/12/MathTest/Math.vm
@@ -0,0 +1,446 @@
+function Math.init 2
+push constant 1
+pop local 1
+push constant 0
+pop local 0
+push constant 16
+call Array.new 1
+pop static 0
+label WHILE_EXP0
+push local 0
+push constant 16
+lt
+not
+if-goto WHILE_END0
+push local 0
+push static 0
+add
+push local 1
+pop temp 0
+pop pointer 1
+push temp 0
+pop that 0
+push local 1
+push local 1
+add
+pop local 1
+push local 0
+push constant 1
+add
+pop local 0
+goto WHILE_EXP0
+label WHILE_END0
+push constant 0
+return
+function Math.bit 0
+push argument 0
+push argument 1
+push static 0
+add
+pop pointer 1
+push that 0
+and
+push constant 0
+eq
+not
+return
+function Math.abs 0
+push argument 0
+push constant 0
+gt
+if-goto IF_TRUE0
+goto IF_FALSE0
+label IF_TRUE0
+push argument 0
+return
+goto IF_END0
+label IF_FALSE0
+push argument 0
+neg
+return
+label IF_END0
+function Math.multiply 3
+push argument 0
+pop local 1
+push constant 0
+pop local 2
+push constant 0
+pop local 0
+label WHILE_EXP0
+push local 2
+push constant 16
+lt
+not
+if-goto WHILE_END0
+push argument 1
+push local 2
+call Math.bit 2
+if-goto IF_TRUE0
+goto IF_FALSE0
+label IF_TRUE0
+push local 0
+push local 1
+add
+pop local 0
+label IF_FALSE0
+push local 1
+push local 1
+add
+pop local 1
+push local 2
+push constant 1
+add
+pop local 2
+goto WHILE_EXP0
+label WHILE_END0
+push local 0
+return
+function Math.divide 2
+push argument 0
+push constant 0
+gt
+if-goto IF_TRUE0
+goto IF_FALSE0
+label IF_TRUE0
+push argument 1
+push constant 0
+gt
+if-goto IF_TRUE1
+goto IF_FALSE1
+label IF_TRUE1
+push argument 0
+push argument 1
+call Math.divide1 2
+return
+goto IF_END1
+label IF_FALSE1
+push argument 0
+push argument 1
+neg
+call Math.divide1 2
+neg
+return
+label IF_END1
+goto IF_END0
+label IF_FALSE0
+push argument 1
+push constant 0
+gt
+if-goto IF_TRUE2
+goto IF_FALSE2
+label IF_TRUE2
+push argument 0
+neg
+push argument 1
+call Math.divide1 2
+neg
+return
+goto IF_END2
+label IF_FALSE2
+push argument 0
+neg
+push argument 1
+neg
+call Math.divide1 2
+return
+label IF_END2
+label IF_END0
+function Math.divide1 1
+push argument 1
+push constant 0
+eq
+if-goto IF_TRUE0
+goto IF_FALSE0
+label IF_TRUE0
+push constant 24
+call String.new 1
+push constant 69
+call String.appendChar 2
+push constant 114
+call String.appendChar 2
+push constant 114
+call String.appendChar 2
+push constant 111
+call String.appendChar 2
+push constant 114
+call String.appendChar 2
+push constant 58
+call String.appendChar 2
+push constant 32
+call String.appendChar 2
+push constant 100
+call String.appendChar 2
+push constant 105
+call String.appendChar 2
+push constant 118
+call String.appendChar 2
+push constant 105
+call String.appendChar 2
+push constant 115
+call String.appendChar 2
+push constant 105
+call String.appendChar 2
+push constant 111
+call String.appendChar 2
+push constant 110
+call String.appendChar 2
+push constant 32
+call String.appendChar 2
+push constant 98
+call String.appendChar 2
+push constant 121
+call String.appendChar 2
+push constant 32
+call String.appendChar 2
+push constant 122
+call String.appendChar 2
+push constant 101
+call String.appendChar 2
+push constant 114
+call String.appendChar 2
+push constant 111
+call String.appendChar 2
+push constant 46
+call String.appendChar 2
+call Output.printString 1
+pop temp 0
+push constant 0
+call Sys.error 1
+pop temp 0
+label IF_FALSE0
+push argument 1
+push argument 0
+gt
+push argument 1
+push constant 0
+lt
+or
+if-goto IF_TRUE1
+goto IF_FALSE1
+label IF_TRUE1
+push constant 0
+return
+label IF_FALSE1
+push argument 0
+push argument 1
+push constant 2
+call Math.multiply 2
+call Math.divide1 2
+pop local 0
+push argument 0
+push constant 2
+push local 0
+call Math.multiply 2
+push argument 1
+call Math.multiply 2
+sub
+push argument 1
+lt
+if-goto IF_TRUE2
+goto IF_FALSE2
+label IF_TRUE2
+push constant 2
+push local 0
+call Math.multiply 2
+return
+goto IF_END2
+label IF_FALSE2
+push constant 2
+push local 0
+call Math.multiply 2
+push constant 1
+add
+return
+label IF_END2
+function Math.length 1
+push constant 14
+pop local 0
+label WHILE_EXP0
+push local 0
+push static 0
+add
+pop pointer 1
+push that 0
+push argument 0
+gt
+not
+if-goto WHILE_END0
+push local 0
+push constant 1
+sub
+pop local 0
+goto WHILE_EXP0
+label WHILE_END0
+push local 0
+return
+function Math.sqrt 4
+push argument 0
+push constant 0
+lt
+if-goto IF_TRUE0
+goto IF_FALSE0
+label IF_TRUE0
+push constant 40
+call String.new 1
+push constant 69
+call String.appendChar 2
+push constant 114
+call String.appendChar 2
+push constant 114
+call String.appendChar 2
+push constant 111
+call String.appendChar 2
+push constant 114
+call String.appendChar 2
+push constant 58
+call String.appendChar 2
+push constant 32
+call String.appendChar 2
+push constant 115
+call String.appendChar 2
+push constant 113
+call String.appendChar 2
+push constant 117
+call String.appendChar 2
+push constant 97
+call String.appendChar 2
+push constant 114
+call String.appendChar 2
+push constant 101
+call String.appendChar 2
+push constant 32
+call String.appendChar 2
+push constant 114
+call String.appendChar 2
+push constant 111
+call String.appendChar 2
+push constant 111
+call String.appendChar 2
+push constant 116
+call String.appendChar 2
+push constant 105
+call String.appendChar 2
+push constant 110
+call String.appendChar 2
+push constant 103
+call String.appendChar 2
+push constant 32
+call String.appendChar 2
+push constant 97
+call String.appendChar 2
+push constant 32
+call String.appendChar 2
+push constant 110
+call String.appendChar 2
+push constant 101
+call String.appendChar 2
+push constant 103
+call String.appendChar 2
+push constant 97
+call String.appendChar 2
+push constant 116
+call String.appendChar 2
+push constant 105
+call String.appendChar 2
+push constant 118
+call String.appendChar 2
+push constant 101
+call String.appendChar 2
+push constant 32
+call String.appendChar 2
+push constant 110
+call String.appendChar 2
+push constant 117
+call String.appendChar 2
+push constant 109
+call String.appendChar 2
+push constant 98
+call String.appendChar 2
+push constant 101
+call String.appendChar 2
+push constant 114
+call String.appendChar 2
+push constant 46
+call String.appendChar 2
+call Output.printString 1
+pop temp 0
+push constant 0
+call Sys.error 1
+pop temp 0
+label IF_FALSE0
+push argument 0
+call Math.length 1
+push constant 2
+call Math.divide 2
+pop local 1
+push constant 0
+pop local 0
+label WHILE_EXP0
+push local 1
+push constant 0
+lt
+not
+not
+if-goto WHILE_END0
+push local 0
+push local 1
+push static 0
+add
+pop pointer 1
+push that 0
+add
+pop local 2
+push local 2
+push local 2
+call Math.multiply 2
+pop local 3
+push local 3
+push argument 0
+gt
+not
+push local 3
+push constant 0
+gt
+and
+if-goto IF_TRUE1
+goto IF_FALSE1
+label IF_TRUE1
+push local 2
+pop local 0
+label IF_FALSE1
+push local 1
+push constant 1
+sub
+pop local 1
+goto WHILE_EXP0
+label WHILE_END0
+push local 0
+return
+function Math.max 0
+push argument 0
+push argument 1
+gt
+if-goto IF_TRUE0
+goto IF_FALSE0
+label IF_TRUE0
+push argument 0
+return
+goto IF_END0
+label IF_FALSE0
+push argument 1
+return
+label IF_END0
+function Math.min 0
+push argument 0
+push argument 1
+lt
+if-goto IF_TRUE0
+goto IF_FALSE0
+label IF_TRUE0
+push argument 0
+return
+goto IF_END0
+label IF_FALSE0
+push argument 1
+return
+label IF_END0
diff --git a/projects/12/MathTest/MathTest.out b/projects/12/MathTest/MathTest.out
new file mode 100644
index 0000000..8b5a504
--- /dev/null
+++ b/projects/12/MathTest/MathTest.out
@@ -0,0 +1,2 @@
+|RAM[8000]|RAM[8001]|RAM[8002]|RAM[8003]|RAM[8004]|RAM[8005]|RAM[8006]|RAM[8007]|RAM[8008]|RAM[8009]|RAM[8010]|RAM[8011]|RAM[8012]|RAM[8013]|
+| 6 | -180 | -18000 | -18000 | 0 | 3 | -3000 | 0 | 3 | 181 | 123 | 123 | 27 | 32767 |