From 646da78ea8f753a92732020349e59307f3309f6a Mon Sep 17 00:00:00 2001 From: David Souther Date: Fri, 3 Nov 2023 09:40:05 -0400 Subject: [PATCH 01/14] Added VM language --- simulator/src/languages/grammars/vm.js | 0 simulator/src/languages/grammars/vm.ohm | 52 +++++ simulator/src/languages/grammars/vm.ohm.js | 54 +++++ simulator/src/languages/vm.test.ts | 226 ++++++++++++++++++++ simulator/src/languages/vm.ts | 229 +++++++++++++++++++++ 5 files changed, 561 insertions(+) create mode 100644 simulator/src/languages/grammars/vm.js create mode 100644 simulator/src/languages/grammars/vm.ohm create mode 100644 simulator/src/languages/grammars/vm.ohm.js create mode 100644 simulator/src/languages/vm.test.ts create mode 100644 simulator/src/languages/vm.ts diff --git a/simulator/src/languages/grammars/vm.js b/simulator/src/languages/grammars/vm.js new file mode 100644 index 000000000..e69de29bb diff --git a/simulator/src/languages/grammars/vm.ohm b/simulator/src/languages/grammars/vm.ohm new file mode 100644 index 000000000..e573eea1e --- /dev/null +++ b/simulator/src/languages/grammars/vm.ohm @@ -0,0 +1,52 @@ +Vm <: Base { + Root := Vm + + Vm = VmInstruction+ + + VmInstruction = + | StackInstruction + | OpInstruction + | FunctionInstruction + | CallInstruction + | ReturnInstruction + | GotoInstruction + | LabelInstruction + + StackInstruction = (Push | Pop) MemorySegment Number + OpInstruction = Add | Sub | Neg | Lt | Gt | Eq | And | Or | Not + FunctionInstruction = Function Name Number + CallInstruction = Call Name Number + ReturnInstruction = Return + LabelInstruction = Label Name + GotoInstruction = (Goto | IfGoto) Name + + MemorySegment = Argument | Local | Static | Constant | This | That | Pointer | Temp + + Push = "push" + Pop = "pop" + Function = "function" + Call = "call" + Return = "return" + Goto = "goto" + IfGoto = "if-goto" + Label = "label" + + Argument = "argument" + Local = "local" + Static = "static" + Constant = "constant" + This = "this" + That = "that" + Pointer = "pointer" + Temp = "temp" + + Add = "add" + Sub = "sub" + Neg = "neg" + Eq = "eq" + Lt = "lt" + Gt = "gt" + And = "and" + Or = "or" + Not = "not" +} \ No newline at end of file diff --git a/simulator/src/languages/grammars/vm.ohm.js b/simulator/src/languages/grammars/vm.ohm.js new file mode 100644 index 000000000..bb18d7baf --- /dev/null +++ b/simulator/src/languages/grammars/vm.ohm.js @@ -0,0 +1,54 @@ +const vm = ` +Vm <: Base { + Root := Vm + + Vm = VmInstruction+ + + VmInstruction = + | StackInstruction + | OpInstruction + | FunctionInstruction + | CallInstruction + | ReturnInstruction + | GotoInstruction + | LabelInstruction + + StackInstruction = (Push | Pop) MemorySegment Number + OpInstruction = Add | Sub | Neg | Lt | Gt | Eq | And | Or | Not + FunctionInstruction = Function Name Number + CallInstruction = Call Name Number + ReturnInstruction = Return + LabelInstruction = Label Name + GotoInstruction = (Goto | IfGoto) Name + + MemorySegment = Argument | Local | Static | Constant | This | That | Pointer | Temp + + Push = "push" + Pop = "pop" + Function = "function" + Call = "call" + Return = "return" + Goto = "goto" + IfGoto = "if-goto" + Label = "label" + + Argument = "argument" + Local = "local" + Static = "static" + Constant = "constant" + This = "this" + That = "that" + Pointer = "pointer" + Temp = "temp" + + Add = "add" + Sub = "sub" + Neg = "neg" + Eq = "eq" + Lt = "lt" + Gt = "gt" + And = "and" + Or = "or" + Not = "not" +}`; +export default vm; diff --git a/simulator/src/languages/vm.test.ts b/simulator/src/languages/vm.test.ts new file mode 100644 index 000000000..495b227c4 --- /dev/null +++ b/simulator/src/languages/vm.test.ts @@ -0,0 +1,226 @@ +import { grammar, VM, Vm } from "./vm.js"; + +const SIMPLE_ADD = ` +push constant 7 +push constant 8 +add`; + +const SIMPLE_ADD_PARSED = { + instructions: [ + { op: "push", segment: "constant", value: 7 }, + { op: "push", segment: "constant", value: 8 }, + { op: "add" }, + ], +} satisfies Vm; + +// d = (2 - x) + (y + 9) +const FIG7_3A = ` +push constant 2 +push local 0 +sub +push local 1 +push constant 9 +add +add +pop local 2 +`; + +const FIG7_3A_PARSED = { + instructions: [ + { op: "push", segment: "constant", value: 2 }, + { op: "push", segment: "local", value: 0 }, + { op: "sub" }, + { op: "push", segment: "local", value: 1 }, + { op: "push", segment: "constant", value: 9 }, + { op: "add" }, + { op: "add" }, + { op: "pop", segment: "local", value: 2 }, + ], +} satisfies Vm; + +// (x < 7) or (y == 8) +const FIG7_3B = ` +push local 0 +push constant 7 +lt +push local 1 +push constant 8 +eq +or +`; +const FIG7_3B_PARSED = { + instructions: [ + { op: "push", segment: "local", value: 0 }, + { op: "push", segment: "constant", value: 7 }, + { op: "lt" }, + { op: "push", segment: "local", value: 1 }, + { op: "push", segment: "constant", value: 8 }, + { op: "eq" }, + { op: "or" }, + ], +} satisfies Vm; + +const FIG8_1 = ` +// returns x * y +// x = arg 0 +// y = arg 1 +// sum = local 0 +// i = local 1 +function mult 2 + push constant 0 + pop local 0 + push constant 0 + pop local 1 +label WHILE_LOOP + push local 1 + push argument 1 + lt + neg + if-goto WHILE_END + push local 0 + push argument 0 + add + pop local 0 + push local 1 + push constant 1 + add + pop local 1 + goto WHILE_LOOP +label WHILE_END + push local 0 + return +`; +const FIG8_1_PARSED = { + instructions: [ + { op: "function", name: "mult", nArgs: 2 }, + { op: "push", segment: "constant", value: 0 }, + { op: "pop", segment: "local", value: 0 }, + { op: "push", segment: "constant", value: 0 }, + { op: "pop", segment: "local", value: 1 }, + { op: "label", label: "WHILE_LOOP" }, + { op: "push", segment: "local", value: 1 }, + { op: "push", segment: "argument", value: 1 }, + { op: "lt" }, + { op: "neg" }, + { op: "if-goto", label: "WHILE_END" }, + { op: "push", segment: "local", value: 0 }, + { op: "push", segment: "argument", value: 0 }, + { op: "add" }, + { op: "pop", segment: "local", value: 0 }, + { op: "push", segment: "local", value: 1 }, + { op: "push", segment: "constant", value: 1 }, + { op: "add" }, + { op: "pop", segment: "local", value: 1 }, + { op: "goto", label: "WHILE_LOOP" }, + { op: "label", label: "WHILE_END" }, + { op: "push", segment: "local", value: 0 }, + { op: "return" }, + ], +} satisfies Vm; + +const FIG8_2 = ` +function main 0 + push constant 3 + push constant 4 + call hypot 2 + return + +function hypot 2 + push argument 0 + push argument 0 + call mult 2 + push argument 1 + push argument 1 + call mult 2 + add + call sqrt 1 + return +`; +const FIG8_2_PARSED = { + instructions: [ + { op: "function", name: "main", nArgs: 0 }, + { op: "push", segment: "constant", value: 3 }, + { op: "push", segment: "constant", value: 4 }, + { op: "call", name: "hypot", nArgs: 2 }, + { op: "return" }, + { op: "function", name: "hypot", nArgs: 2 }, + { op: "push", segment: "argument", value: 0 }, + { op: "push", segment: "argument", value: 0 }, + { op: "call", name: "mult", nArgs: 2 }, + { op: "push", segment: "argument", value: 1 }, + { op: "push", segment: "argument", value: 1 }, + { op: "call", name: "mult", nArgs: 2 }, + { op: "add" }, + { op: "call", name: "sqrt", nArgs: 1 }, + { op: "return" }, + ], +} satisfies Vm; + +const FIG8_4 = ` +function main 0 +push constant 3 +call factorial 1 +return +function factorial 1 +push argument 0 +push constant 1 +eq +if-goto BASE_CASE +push argument 0 +push argument 0 +push constant 1 +sub +call factorial 1 +call mult 2 +return +label BASE_CASE +push constant 1 +return +`; +const FIG8_4_PARSED = { + instructions: [ + { op: "function", name: "main", nArgs: 0 }, + { op: "push", segment: "constant", value: 3 }, + { op: "call", name: "factorial", nArgs: 1 }, + { op: "return" }, + { op: "function", name: "factorial", nArgs: 1 }, + { op: "push", segment: "argument", value: 0 }, + { op: "push", segment: "constant", value: 1 }, + { op: "eq" }, + { op: "if-goto", label: "BASE_CASE" }, + { op: "push", segment: "argument", value: 0 }, + { op: "push", segment: "argument", value: 0 }, + { op: "push", segment: "constant", value: 1 }, + { op: "sub" }, + { op: "call", name: "factorial", nArgs: 1 }, + { op: "call", name: "mult", nArgs: 2 }, + { op: "return" }, + { op: "label", label: "BASE_CASE" }, + { op: "push", segment: "constant", value: 1 }, + { op: "return" }, + ], +} satisfies Vm; + +test.each([ + ["Simple Add", SIMPLE_ADD, SIMPLE_ADD_PARSED], + ["Figure 7.3a", FIG7_3A, FIG7_3A_PARSED], + ["Figure 7.3b", FIG7_3B, FIG7_3B_PARSED], + ["Figure 8.1", FIG8_1, FIG8_1_PARSED], + ["Figure 8.2", FIG8_2, FIG8_2_PARSED], + ["Figure 8.4", FIG8_4, FIG8_4_PARSED], +])("VM Parser: %s", (_name, fig, parsed) => { + const match = grammar.match(fig); + expect(match).toHaveSucceeded(); + expect(VM.semantics(match).vm).toStrictEqual(parsed); +}); + +test.each([ + ["call mult", 'Line 1, col 10: expected "%B", ".", a digit, or "%X"'], + [ + "push invalid", + 'Line 1, col 6: expected "temp", "pointer", "that", "this", "constant", "static", "local", or "argument"', + ], +])("VM Parser Error: '%s'", (bad, message) => { + const match = grammar.match(bad); + expect(match).toHaveFailed(message); +}); diff --git a/simulator/src/languages/vm.ts b/simulator/src/languages/vm.ts new file mode 100644 index 000000000..585dc4f5b --- /dev/null +++ b/simulator/src/languages/vm.ts @@ -0,0 +1,229 @@ +/** Reads tst files to apply and perform test runs. */ + +import ohm from "ohm-js"; +import { baseSemantics, grammars, makeParser, Span } from "./base.js"; + +import vmGrammar from "./grammars/vm.ohm.js"; +export const grammar = ohm.grammar(vmGrammar, grammars); +export const vmSemantics = grammar.extendSemantics(baseSemantics); + +export interface Vm { + instructions: VmInstruction[]; +} + +export type VmInstruction = + | StackInstruction + | OpInstruction + | FunctionInstruction + | CallInstruction + | ReturnInstruction + | GotoInstruction + | LabelInstruction; + +export interface StackInstruction { + op: "push" | "pop"; + segment: + | "argument" + | "local" + | "static" + | "constant" + | "this" + | "that" + | "pointer" + | "temp"; + value: number; +} +export interface OpInstruction { + op: "add" | "sub" | "neg" | "lt" | "gt" | "eq" | "and" | "or" | "not"; +} +export interface FunctionInstruction { + op: "function"; + name: string; + nArgs: number; +} +export interface CallInstruction { + op: "call"; + name: string; + nArgs: number; +} +export interface ReturnInstruction { + op: "return"; +} +export interface LabelInstruction { + op: "label"; + label: string; +} +export interface GotoInstruction { + op: "goto" | "if-goto"; + label: string; +} + +vmSemantics.addAttribute< + | "push" + | "pop" + | "function" + | "call" + | "return" + | "goto" + | "if-goto" + | "label" + | "add" + | "sub" + | "neg" + | "lt" + | "gt" + | "eq" + | "and" + | "or" + | "not" +>("op", { + Push(_) { + return "push"; + }, + Pop(_) { + return "pop"; + }, + Function(_) { + return "function"; + }, + Call(_) { + return "call"; + }, + Return(_) { + return "return"; + }, + Goto(_) { + return "goto"; + }, + IfGoto(_) { + return "if-goto"; + }, + Label(_) { + return "label"; + }, + Add(_) { + return "add"; + }, + Sub(_) { + return "sub"; + }, + Neg(_) { + return "neg"; + }, + Eq(_) { + return "eq"; + }, + Lt(_) { + return "lt"; + }, + Gt(_) { + return "gt"; + }, + And(_) { + return "and"; + }, + Or(_) { + return "or"; + }, + Not(_) { + return "not"; + }, +}); + +vmSemantics.addAttribute< + | "argument" + | "local" + | "static" + | "constant" + | "this" + | "that" + | "pointer" + | "temp" +>("segment", { + Argument(_) { + return "argument"; + }, + Local(_) { + return "local"; + }, + Static(_) { + return "static"; + }, + Constant(_) { + return "constant"; + }, + This(_) { + return "this"; + }, + That(_) { + return "that"; + }, + Pointer(_) { + return "pointer"; + }, + Temp(_) { + return "temp"; + }, +}); + +vmSemantics.addAttribute("instruction", { + StackInstruction({ op }, { segment }, { value }) { + return { + op: op as "push" | "pop", + segment, + value, + }; + }, + OpInstruction({ op }) { + return { + op: op as + | "add" + | "sub" + | "neg" + | "lt" + | "gt" + | "eq" + | "and" + | "or" + | "not", + }; + }, + FunctionInstruction(_, { name }, { value: nArgs }) { + return { op: "function", name, nArgs }; + }, + CallInstruction(_, { name }, { value: nArgs }) { + return { op: "call", name, nArgs }; + }, + ReturnInstruction(_) { + return { op: "return" }; + }, + // LabelInstruction = Label Name + LabelInstruction(_, { name: label }) { + return { op: "label", label }; + }, + // GotoInstruction = (Goto | IfGoto) Name + GotoInstruction({ op }, { name: label }) { + return { op: op as "goto" | "if-goto", label }; + }, +}); + +vmSemantics.addAttribute("vm", { + Vm(lines) { + return { + instructions: lines.children.map((n) => n.instruction), + }; + }, +}); + +vmSemantics.addAttribute("root", { + Root({ vm }) { + return vm; + }, +}); + +export const VM = { + grammar: vmGrammar, + semantics: vmSemantics, + parser: grammar, + parse: makeParser(grammar, vmSemantics), +}; From b43836792a91a88ce84c7bb71d5bd8b787c987e6 Mon Sep 17 00:00:00 2001 From: David Souther Date: Fri, 3 Nov 2023 14:56:21 -0400 Subject: [PATCH 02/14] VM Simulator --- simulator/src/languages/grammars/vm.ohm | 2 +- simulator/src/languages/grammars/vm.ohm.js | 2 +- simulator/src/languages/vm.test.ts | 84 +-- simulator/src/languages/vm.ts | 10 +- simulator/src/vm/vm.test.ts | 538 ++++++++++++++++++ simulator/src/vm/vm.ts | 625 +++++++++++++++++++++ 6 files changed, 1212 insertions(+), 49 deletions(-) create mode 100644 simulator/src/vm/vm.test.ts create mode 100644 simulator/src/vm/vm.ts diff --git a/simulator/src/languages/grammars/vm.ohm b/simulator/src/languages/grammars/vm.ohm index e573eea1e..3b613d536 100644 --- a/simulator/src/languages/grammars/vm.ohm +++ b/simulator/src/languages/grammars/vm.ohm @@ -1,7 +1,7 @@ Vm <: Base { Root := Vm - Vm = VmInstruction+ + Vm = VmInstruction* VmInstruction = | StackInstruction diff --git a/simulator/src/languages/grammars/vm.ohm.js b/simulator/src/languages/grammars/vm.ohm.js index bb18d7baf..dec8fd7c5 100644 --- a/simulator/src/languages/grammars/vm.ohm.js +++ b/simulator/src/languages/grammars/vm.ohm.js @@ -2,7 +2,7 @@ const vm = ` Vm <: Base { Root := Vm - Vm = VmInstruction+ + Vm = VmInstruction* VmInstruction = | StackInstruction diff --git a/simulator/src/languages/vm.test.ts b/simulator/src/languages/vm.test.ts index 495b227c4..a18d3e3b2 100644 --- a/simulator/src/languages/vm.test.ts +++ b/simulator/src/languages/vm.test.ts @@ -7,8 +7,8 @@ add`; const SIMPLE_ADD_PARSED = { instructions: [ - { op: "push", segment: "constant", value: 7 }, - { op: "push", segment: "constant", value: 8 }, + { op: "push", segment: "constant", offset: 7 }, + { op: "push", segment: "constant", offset: 8 }, { op: "add" }, ], } satisfies Vm; @@ -27,14 +27,14 @@ pop local 2 const FIG7_3A_PARSED = { instructions: [ - { op: "push", segment: "constant", value: 2 }, - { op: "push", segment: "local", value: 0 }, + { op: "push", segment: "constant", offset: 2 }, + { op: "push", segment: "local", offset: 0 }, { op: "sub" }, - { op: "push", segment: "local", value: 1 }, - { op: "push", segment: "constant", value: 9 }, + { op: "push", segment: "local", offset: 1 }, + { op: "push", segment: "constant", offset: 9 }, { op: "add" }, { op: "add" }, - { op: "pop", segment: "local", value: 2 }, + { op: "pop", segment: "local", offset: 2 }, ], } satisfies Vm; @@ -50,11 +50,11 @@ or `; const FIG7_3B_PARSED = { instructions: [ - { op: "push", segment: "local", value: 0 }, - { op: "push", segment: "constant", value: 7 }, + { op: "push", segment: "local", offset: 0 }, + { op: "push", segment: "constant", offset: 7 }, { op: "lt" }, - { op: "push", segment: "local", value: 1 }, - { op: "push", segment: "constant", value: 8 }, + { op: "push", segment: "local", offset: 1 }, + { op: "push", segment: "constant", offset: 8 }, { op: "eq" }, { op: "or" }, ], @@ -92,28 +92,28 @@ label WHILE_END `; const FIG8_1_PARSED = { instructions: [ - { op: "function", name: "mult", nArgs: 2 }, - { op: "push", segment: "constant", value: 0 }, - { op: "pop", segment: "local", value: 0 }, - { op: "push", segment: "constant", value: 0 }, - { op: "pop", segment: "local", value: 1 }, + { op: "function", name: "mult", nVars: 2 }, + { op: "push", segment: "constant", offset: 0 }, + { op: "pop", segment: "local", offset: 0 }, + { op: "push", segment: "constant", offset: 0 }, + { op: "pop", segment: "local", offset: 1 }, { op: "label", label: "WHILE_LOOP" }, - { op: "push", segment: "local", value: 1 }, - { op: "push", segment: "argument", value: 1 }, + { op: "push", segment: "local", offset: 1 }, + { op: "push", segment: "argument", offset: 1 }, { op: "lt" }, { op: "neg" }, { op: "if-goto", label: "WHILE_END" }, - { op: "push", segment: "local", value: 0 }, - { op: "push", segment: "argument", value: 0 }, + { op: "push", segment: "local", offset: 0 }, + { op: "push", segment: "argument", offset: 0 }, { op: "add" }, - { op: "pop", segment: "local", value: 0 }, - { op: "push", segment: "local", value: 1 }, - { op: "push", segment: "constant", value: 1 }, + { op: "pop", segment: "local", offset: 0 }, + { op: "push", segment: "local", offset: 1 }, + { op: "push", segment: "constant", offset: 1 }, { op: "add" }, - { op: "pop", segment: "local", value: 1 }, + { op: "pop", segment: "local", offset: 1 }, { op: "goto", label: "WHILE_LOOP" }, { op: "label", label: "WHILE_END" }, - { op: "push", segment: "local", value: 0 }, + { op: "push", segment: "local", offset: 0 }, { op: "return" }, ], } satisfies Vm; @@ -138,17 +138,17 @@ function hypot 2 `; const FIG8_2_PARSED = { instructions: [ - { op: "function", name: "main", nArgs: 0 }, - { op: "push", segment: "constant", value: 3 }, - { op: "push", segment: "constant", value: 4 }, + { op: "function", name: "main", nVars: 0 }, + { op: "push", segment: "constant", offset: 3 }, + { op: "push", segment: "constant", offset: 4 }, { op: "call", name: "hypot", nArgs: 2 }, { op: "return" }, - { op: "function", name: "hypot", nArgs: 2 }, - { op: "push", segment: "argument", value: 0 }, - { op: "push", segment: "argument", value: 0 }, + { op: "function", name: "hypot", nVars: 2 }, + { op: "push", segment: "argument", offset: 0 }, + { op: "push", segment: "argument", offset: 0 }, { op: "call", name: "mult", nArgs: 2 }, - { op: "push", segment: "argument", value: 1 }, - { op: "push", segment: "argument", value: 1 }, + { op: "push", segment: "argument", offset: 1 }, + { op: "push", segment: "argument", offset: 1 }, { op: "call", name: "mult", nArgs: 2 }, { op: "add" }, { op: "call", name: "sqrt", nArgs: 1 }, @@ -179,24 +179,24 @@ return `; const FIG8_4_PARSED = { instructions: [ - { op: "function", name: "main", nArgs: 0 }, - { op: "push", segment: "constant", value: 3 }, + { op: "function", name: "main", nVars: 0 }, + { op: "push", segment: "constant", offset: 3 }, { op: "call", name: "factorial", nArgs: 1 }, { op: "return" }, - { op: "function", name: "factorial", nArgs: 1 }, - { op: "push", segment: "argument", value: 0 }, - { op: "push", segment: "constant", value: 1 }, + { op: "function", name: "factorial", nVars: 1 }, + { op: "push", segment: "argument", offset: 0 }, + { op: "push", segment: "constant", offset: 1 }, { op: "eq" }, { op: "if-goto", label: "BASE_CASE" }, - { op: "push", segment: "argument", value: 0 }, - { op: "push", segment: "argument", value: 0 }, - { op: "push", segment: "constant", value: 1 }, + { op: "push", segment: "argument", offset: 0 }, + { op: "push", segment: "argument", offset: 0 }, + { op: "push", segment: "constant", offset: 1 }, { op: "sub" }, { op: "call", name: "factorial", nArgs: 1 }, { op: "call", name: "mult", nArgs: 2 }, { op: "return" }, { op: "label", label: "BASE_CASE" }, - { op: "push", segment: "constant", value: 1 }, + { op: "push", segment: "constant", offset: 1 }, { op: "return" }, ], } satisfies Vm; diff --git a/simulator/src/languages/vm.ts b/simulator/src/languages/vm.ts index 585dc4f5b..df2be7fa9 100644 --- a/simulator/src/languages/vm.ts +++ b/simulator/src/languages/vm.ts @@ -1,7 +1,7 @@ /** Reads tst files to apply and perform test runs. */ import ohm from "ohm-js"; -import { baseSemantics, grammars, makeParser, Span } from "./base.js"; +import { baseSemantics, grammars, makeParser } from "./base.js"; import vmGrammar from "./grammars/vm.ohm.js"; export const grammar = ohm.grammar(vmGrammar, grammars); @@ -31,7 +31,7 @@ export interface StackInstruction { | "that" | "pointer" | "temp"; - value: number; + offset: number; } export interface OpInstruction { op: "add" | "sub" | "neg" | "lt" | "gt" | "eq" | "and" | "or" | "not"; @@ -39,7 +39,7 @@ export interface OpInstruction { export interface FunctionInstruction { op: "function"; name: string; - nArgs: number; + nVars: number; } export interface CallInstruction { op: "call"; @@ -171,7 +171,7 @@ vmSemantics.addAttribute("instruction", { return { op: op as "push" | "pop", segment, - value, + offset: value, }; }, OpInstruction({ op }) { @@ -189,7 +189,7 @@ vmSemantics.addAttribute("instruction", { }; }, FunctionInstruction(_, { name }, { value: nArgs }) { - return { op: "function", name, nArgs }; + return { op: "function", name, nVars: nArgs }; }, CallInstruction(_, { name }, { value: nArgs }) { return { op: "call", name, nArgs }; diff --git a/simulator/src/vm/vm.test.ts b/simulator/src/vm/vm.test.ts new file mode 100644 index 000000000..cc06e7a3d --- /dev/null +++ b/simulator/src/vm/vm.test.ts @@ -0,0 +1,538 @@ +import { unwrap } from "@davidsouther/jiffies/lib/esm/result.js"; +import { VM } from "../languages/vm.js"; +import { Vm } from "./vm.js"; + +test("Simple Adder VM", () => { + const vm = Vm.build([ + { op: "push", segment: "constant", offset: 7 }, + { op: "push", segment: "constant", offset: 8 }, + { op: "add" }, + ]); + + expect(vm.read([0])).toEqual([256]); + vm.step(); // push 7 + expect(vm.read([0, 256])).toEqual([257, 7]); + vm.step(); // push 8 + expect(vm.read([0, 256, 257])).toEqual([258, 7, 8]); + vm.step(); // add + expect(vm.read([0, 256, 257])).toEqual([257, 15, 8]); + vm.step(); // goto __END + expect(vm.read([0, 256])).toEqual([257, 15]); + vm.step(); // goto __END + expect(vm.read([0, 256])).toEqual([257, 15]); +}); + +const BIT_TEST = ` +push constant 57 +push constant 31 +push constant 53 +add +push constant 112 +sub +neg +and +push constant 82 +or +not +`; + +test("Bit Ops", () => { + const { instructions } = unwrap(VM.parse(BIT_TEST)); + const vm = Vm.build(instructions); + + for (let i = 0; i < 11; i++) { + vm.step(); + } + + const stack = vm.read([0, 256]); + expect(stack).toEqual([257, -91]); +}); + +const STACK_TEST = ` +push constant 17 +push constant 17 +eq +push constant 17 +push constant 16 +eq +push constant 16 +push constant 17 +eq +push constant 892 +push constant 891 +lt +push constant 891 +push constant 892 +lt +push constant 891 +push constant 891 +lt +push constant 32767 +push constant 32766 +gt +push constant 32766 +push constant 32767 +gt +push constant 32766 +push constant 32766 +gt +push constant 57 +push constant 31 +push constant 53 +add +push constant 112 +sub +neg +and +push constant 82 +or +not +`; + +test("07 / Memory Access / Stack Test", () => { + const { instructions } = unwrap(VM.parse(STACK_TEST)); + const vm = Vm.build(instructions); + + for (let i = 0; i < 38; i++) { + vm.step(); + } + + const cells = [0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265]; + const values = [266, -1, 0, 0, 0, -1, 0, -1, 0, 0, -91]; + const stack = vm.read(cells); + const actual = cells.map((a, i) => [a, stack[i]]); + const expected = cells.map((a, i) => [a, values[i]]); + expect(actual).toEqual(expected); +}); + +const BASIC_TEST = ` +push constant 10 +pop local 0 +push constant 21 +push constant 22 +pop argument 2 +pop argument 1 +push constant 36 +pop this 6 +push constant 42 +push constant 45 +pop that 5 +pop that 2 +push constant 510 +pop temp 6 +push local 0 +push that 5 +add +push argument 1 +sub +push this 6 +push this 6 +add +sub +push temp 6 +add +`; + +test("07 / Memory Access / Basic Test", () => { + const { instructions } = unwrap(VM.parse(BASIC_TEST)); + const vm = Vm.build(instructions); + + vm.write([ + [0, 256], + [1, 300], + [2, 400], + [3, 3000], + [4, 3010], + ]); + + for (let i = 0; i < 25; i++) { + vm.step(); + } + + const test = vm.read([256, 300, 401, 402, 3006, 3012, 3015, 11]); + expect(test).toEqual([472, 10, 21, 22, 36, 42, 45, 510]); +}); + +const POINTER_TEST = ` +push constant 3030 +pop pointer 0 +push constant 3040 +pop pointer 1 +push constant 32 +pop this 2 +push constant 46 +pop that 6 +push pointer 0 +push pointer 1 +add +push this 2 +sub +push that 6 +add +`; + +test("07 / Memory Access / Pointer Test", () => { + const { instructions } = unwrap(VM.parse(POINTER_TEST)); + const vm = Vm.build(instructions); + + vm.write([ + [0, 256], + [1, 300], + [2, 400], + [3, 3000], + [4, 3010], + ]); + + for (let i = 0; i < 16; i++) { + vm.step(); + } + + const test = vm.read([256, 3, 4, 3032, 3046]); + expect(test).toEqual([6084, 3030, 3040, 32, 46]); +}); + +const LOOP_TEST = ` +push constant 0 +pop local 0 // initializes sum = 0 +label LOOP_START +push argument 0 +push local 0 +add +pop local 0 // sum = sum + counter +push argument 0 +push constant 1 +sub +pop argument 0 // counter-- +push argument 0 +if-goto LOOP_START // If counter != 0, goto LOOP_START +push local 0 +`; + +test("08 / Program Flow / Basic Loop", () => { + const { instructions } = unwrap(VM.parse(LOOP_TEST)); + const vm = Vm.build(instructions); + + vm.write([ + [0, 256], + [1, 300], + [2, 400], + [400, 3], + ]); + + for (let i = 0; i < 26; i++) { + vm.step(); + } + + const test = vm.read([0, 256]); + expect(test).toEqual([257, 6]); +}); + +const FIBONACCI_SERIES = ` +push argument 1 +pop pointer 1 // that = argument[1] + +push constant 0 +pop that 0 // first element in the series = 0 +push constant 1 +pop that 1 // second element in the series = 1 + +push argument 0 +push constant 2 +sub +pop argument 0 // num_of_elements -= 2 (first 2 elements are set) + +label MAIN_LOOP_START + +push argument 0 +if-goto COMPUTE_ELEMENT // if num_of_elements > 0, goto COMPUTE_ELEMENT +goto END_PROGRAM // otherwise, goto END_PROGRAM + +label COMPUTE_ELEMENT + +push that 0 +push that 1 +add +pop that 2 // that[2] = that[0] + that[1] + +push pointer 1 +push constant 1 +add +pop pointer 1 // that += 1 + +push argument 0 +push constant 1 +sub +pop argument 0 // num_of_elements-- + +goto MAIN_LOOP_START + +label END_PROGRAM +`; + +test("08 / Program Flow / Fibonacci Series", () => { + const { instructions } = unwrap(VM.parse(FIBONACCI_SERIES)); + const vm = Vm.build(instructions); + + vm.write([ + [0, 256], + [1, 300], + [2, 400], + [400, 6], + [401, 3000], + ]); + + for (let i = 0; i < 1000; i++) { + vm.step(); + } + + const test = vm.read([3000, 3001, 3002, 3003, 3004, 3005]); + expect(test).toEqual([0, 1, 1, 2, 3, 5]); +}); + +const SIMPLE_FUNCTION = ` +// __implicit + push constant 3 + push constant 4 + call mult 2 + +// returns x * y as sum i = 0 to y x +// x = arg 0 +// y = arg 1 +// sum = local 0 +// i = local 1 +function mult 2 +label WHILE_LOOP + push local 1 + push argument 1 + lt + not + if-goto WHILE_END + push local 0 + push argument 0 + add + pop local 0 + push local 1 + push constant 1 + add + pop local 1 + goto WHILE_LOOP +label WHILE_END + push local 0 + return +`; + +test("08 / Simple Function / Simple Function", () => { + const { instructions } = unwrap(VM.parse(SIMPLE_FUNCTION)); + const vm = Vm.build(instructions); + + vm.write([]); + + for (let i = 0; i < 100; i++) { + vm.step(); + } + + const test = vm.read([0, 256]); + expect(test).toEqual([257, 12]); +}); + +const NESTED_FUNCTION = ` +// Sys.vm for NestedCall test. + +// Sys.init() +// +// Calls Sys.main() and stores return value in temp 1. +// Does not return. (Enters infinite loop.) + +function Sys.init 0 +push constant 4000 // test THIS and THAT context save +pop pointer 0 +push constant 5000 +pop pointer 1 +call Sys.main 0 +pop temp 1 +label LOOP +goto LOOP + +// Sys.main() +// +// Sets locals 1, 2 and 3, leaving locals 0 and 4 unchanged to test +// default local initialization to 0. (RAM set to -1 by test setup.) +// Calls Sys.add12(123) and stores return value (135) in temp 0. +// Returns local 0 + local 1 + local 2 + local 3 + local 4 (456) to confirm +// that locals were not mangled by function call. + +function Sys.main 5 +push constant 4001 +pop pointer 0 +push constant 5001 +pop pointer 1 +push constant 200 +pop local 1 +push constant 40 +pop local 2 +push constant 6 +pop local 3 +push constant 123 +call Sys.add12 1 +pop temp 0 +push local 0 +push local 1 +push local 2 +push local 3 +push local 4 +add +add +add +add +return + +// Sys.add12(int n) +// +// Returns n+12. + +function Sys.add12 0 +push constant 4002 +pop pointer 0 +push constant 5002 +pop pointer 1 +push argument 0 +push constant 12 +add +return +`; + +test("08 / Functions / Nested Function", () => { + const { instructions } = unwrap(VM.parse(NESTED_FUNCTION)); + const vm = Vm.build(instructions); + + const init: [number, number][] = [ + [3, -3], + [4, -4], + [5, -1], + [6, -1], + [257, -1], + [258, -2], + [259, -3], + [260, -4], + ]; + + for (let i = 261; i < 300; i++) { + init.push([i, -1]); + } + + vm.write(init); + + for (let i = 0; i < 1000; i++) { + vm.step(); + } + + const test = vm.read([0, 1, 2, 3, 4, 5, 6]); + expect(test).toEqual([261, 261, 256, 4000, 5000, 135, 246]); +}); + +const FIB_MAIN = ` +function Main.fibonacci 0 +push argument 0 +push constant 2 +lt // checks if n<2 +if-goto IF_TRUE +goto IF_FALSE +label IF_TRUE // if n<2, return n +push argument 0 +return +label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) +push argument 0 +push constant 2 +sub +call Main.fibonacci 1 // computes fib(n-2) +push argument 0 +push constant 1 +sub +call Main.fibonacci 1 // computes fib(n-1) +add // returns fib(n-1) + fib(n-2) +return +`; + +const FIB_SYS = ` +function Sys.init 0 +push constant 4 +call Main.fibonacci 1 // computes the 4'th fibonacci element +label WHILE +goto WHILE // loops infinitely +`; + +test("08 / Functions / Fib", () => { + const { instructions } = unwrap(VM.parse(FIB_MAIN + FIB_SYS)); + const vm = Vm.build(instructions); + + vm.write([]); + + for (let i = 0; i < 1000; i++) { + vm.step(); + } + + const test = vm.read([0, 261]); + expect(test).toEqual([262, 3]); +}); + +const STATIC_CLASS_1 = `function Class1.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class1.get 0 +push static 0 +push static 1 +sub +return +`; +const STATIC_CLASS_2 = `function Class2.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class2.get 0 +push static 0 +push static 1 +sub +return +`; + +const STATIC_SYS = `function Sys.init 0 +push constant 6 +push constant 8 +call Class1.set 2 +pop temp 0 // Dumps the return value +push constant 23 +push constant 15 +call Class2.set 2 +pop temp 0 // Dumps the return value +call Class1.get 0 +call Class2.get 0 +label WHILE +goto WHILE +`; + +test("08 / Functions / Static", () => { + const { instructions } = unwrap( + VM.parse([STATIC_CLASS_1, STATIC_CLASS_2, STATIC_SYS].join("\n")) + ); + const vm = Vm.build(instructions); + + vm.write([]); + + for (let i = 0; i < 1000; i++) { + vm.step(); + } + + const test = vm.read([0, 261, 262]); + expect(test).toEqual([263, -2, 8]); +}); diff --git a/simulator/src/vm/vm.ts b/simulator/src/vm/vm.ts new file mode 100644 index 000000000..859cdd042 --- /dev/null +++ b/simulator/src/vm/vm.ts @@ -0,0 +1,625 @@ +import { RAM } from "../cpu/memory.js"; +import { FunctionInstruction, VmInstruction } from "../languages/vm.js"; + +const SP = 0; +const LCL = 1; +const ARG = 2; +const THIS = 3; +const THAT = 4; + +export class VmMemory extends RAM { + strict = true; + get SP(): number { + return this.get(SP); + } + get LCL(): number { + return this.get(LCL); + } + get ARG(): number { + return this.get(ARG); + } + get THIS(): number { + return this.get(THIS); + } + get THAT(): number { + return this.get(THAT); + } + + get state() { + const temps = []; + for (let i = 5; i < 13; i++) { + temps.push(this.get(i)); + } + const internal = []; + for (let i = 13; i < 16; i++) { + internal.push(i); + } + return { + ["0: SP"]: this.SP, + ["1: LCL"]: this.LCL, + ["2: ARG"]: this.ARG, + ["3: THIS"]: this.THIS, + ["4: THAT"]: this.THAT, + TEMPS: temps, + VM: internal, + }; + } + + get statics() { + const statics = []; + for (let i = 16; i < 256; i++) { + statics.push(this.get(i)); + } + return statics; + } + + get frame() { + // Arg0 Arg1... RET LCL ARG THIS THAT [SP] + const args = []; + for (let i = this.ARG; i < this.LCL - 5; i++) { + args.push(this.get(i)); + } + const locals = []; + for (let i = this.LCL; i < this.SP; i++) { + locals.push(this.get(i)); + } + const _this = []; + for (let i = 0; i < 5; i++) { + _this.push(this.this(i)); + } + return { + args, + locals, + this: _this, + }; + } + + constructor() { + super(); + this.set(SP, 256); + } + + baseSegment( + segment: + | "argument" + | "local" + | "static" + | "constant" + | "this" + | "that" + | "pointer" + | "temp", + offset: number + ): number { + switch (segment) { + case "argument": + return this.ARG + offset; + case "constant": + return offset; + case "local": + return this.LCL + offset; + case "pointer": + return this.pointer(offset); + case "static": + return 16 + offset; + case "temp": + return 5 + offset; + case "that": + return this.THAT + offset; + case "this": + return this.THIS + offset; + } + } + + getSegment( + segment: + | "argument" + | "local" + | "static" + | "constant" + | "this" + | "that" + | "pointer" + | "temp", + offset: number + ): number { + if (segment === "constant") return offset; + const base = this.baseSegment(segment, offset); + return this.get(base); + } + setSegment( + segment: + | "argument" + | "local" + | "static" + | "constant" + | "this" + | "that" + | "pointer" + | "temp", + offset: number, + value: number + ) { + const base = this.baseSegment(segment, offset); + this.set(base, value); + } + + argument(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + return this.get(this.ARG + offset); + } + local(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + return this.get(this.LCL + offset); + } + static(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + if (this.strict && offset > 255 - 16) + throw new Error(`Cannot access statics beyond 239: ${offset}`); + return this.get(16 + offset); + } + constant(offset: number): number { + return offset; + } + this(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + return this.get(this.THIS + offset); + } + that(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + return this.get(this.THAT + offset); + } + pointer(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + if (this.strict && offset > 1) + throw new Error( + `pointer out of bounds access (pointer can be 0 for this, 1 for that, but got ${offset}` + ); + return offset === 0 ? THIS : THAT; + } + temp(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + if (this.strict && offset > 7) + throw new Error( + `Temp out of bounds access (temp can be 0 to 7, but got ${offset}` + ); + return this.get(5 + offset); + } + + push(value: number) { + const sp = this.SP; + this.set(sp, value); + this.set(0, sp + 1); + } + pop(): number { + if (this.strict && this.SP === 256) + throw new Error(`Cannot pop the stack below 256 in strict mode`); + this.set(0, this.SP - 1); + const value = this.get(this.SP); + return value; + } + // Stack frame, from figure 8.3, is: + // [ARG] Arg0 Arg1... RET LCL ARG THIS THAT [LCL] Local0 Local1... [SP] + pushFrame(ret: number, nArgs: number, nLocals: number) { + const arg = this.SP - nArgs; + let sp = this.SP + 5; + this.set(sp - 5, ret); + this.set(sp - 4, this.LCL); + this.set(sp - 3, this.ARG); + this.set(sp - 2, this.THIS); + this.set(sp - 1, this.THAT); + + this.set(ARG, arg); + this.set(LCL, sp); + + // Technically this happens in the function, but the VM will handle it for free + for (let i = 0; i < nLocals; i++) { + this.set(sp, 0); + sp += 1; + } + this.set(SP, sp); + } + popFrame(): number { + const frame = this.LCL; + const ret = this.get(frame - 5); + const value = this.pop(); + this.set(this.ARG, value); + this.set(SP, this.ARG + 1); + this.set(THAT, this.get(frame - 1)); + this.set(THIS, this.get(frame - 2)); + this.set(ARG, this.get(frame - 3)); + this.set(LCL, this.get(frame - 4)); + return ret; + } + + binOp(fn: (a: number, b: number) => number) { + const a = this.get(this.SP - 2); + const b = this.get(this.SP - 1); + const v = fn(a, b) & 0xffff; + this.set(this.SP - 2, v); + this.set(SP, this.SP - 1); + } + unOp(fn: (a: number) => number) { + const a = this.get(this.SP - 1); + const v = fn(a) & 0xffff; + this.set(this.SP - 1, v); + } + comp(fn: (a: number, b: number) => boolean) { + this.binOp((a, b) => (fn(a, b) ? -1 : 0)); + } +} + +export type VmOperation = + | StackOperation + | OpOperation + | CallOperation + | ReturnOperation + | GotoOperation + | LabelOperation; + +export interface StackOperation { + op: "push" | "pop"; + segment: + | "argument" + | "local" + | "static" + | "constant" + | "this" + | "that" + | "pointer" + | "temp"; + offset: number; +} +export interface OpOperation { + op: "add" | "sub" | "neg" | "lt" | "gt" | "eq" | "and" | "or" | "not"; +} +export interface CallOperation { + op: "call"; + name: string; + nArgs: number; +} +export interface ReturnOperation { + op: "return"; +} +export interface LabelOperation { + op: "label"; + label: string; +} +export interface GotoOperation { + op: "goto" | "if-goto"; + label: string; +} + +export type VmFunctions = Record; +export interface VmFunction { + name: string; + nVars: number; + labels: Record; + operations: VmOperation[]; +} + +interface VmFunctionInvocation { + function: string; + op: number; +} + +const BOOTSTRAP: VmFunction = { + name: "__bootstrap", + nVars: 0, + labels: {}, + operations: [{ op: "call", name: "Sys.init", nArgs: 0 }], +}; + +export class Vm { + private memory = new VmMemory(); + private functionMap: Record = { + [BOOTSTRAP.name]: BOOTSTRAP, + }; + private executionStack: VmFunctionInvocation[] = [ + { function: BOOTSTRAP.name, op: 0 }, + ]; + private staticCount = 0; + private statics: Record = {}; + private registerStatic(fnName: string, offset: number): number { + const fileName = fnName.split(".")[0]; + const statics = this.statics[fileName] ?? []; + this.statics[fileName] = statics; + const static_ = statics[offset] ?? this.staticCount++; + statics[offset] = static_; + return static_; + } + + private registerStatics() { + for (const fn of Object.values(this.functionMap)) { + for (const op of fn.operations) { + if ( + ["push", "pop"].includes(op.op) && + (op as { segment: string }).segment === "static" + ) { + (op as { offset: number }).offset = this.registerStatic( + fn.name, + (op as { offset: number }).offset + ); + } + } + } + } + + static build(instructions: VmInstruction[]): Vm { + const vm = new Vm(); + + if (instructions[0]?.op !== "function") { + instructions.unshift({ op: "function", name: "__implicit", nVars: 0 }); + } + + let i = 0; + while (i < instructions.length) { + const [fn, i_] = this.buildFunction(instructions, i); + if (vm.functionMap[fn.name]) + throw new Error(`VM Already has a function named ${fn.name}`); + if (fn.name === "__implicit") { + fn.labels["__END"] = fn.operations.length; + fn.operations.push({ op: "label", label: "__END" }); + fn.operations.push({ op: "goto", label: "__END" }); + } + vm.functionMap[fn.name] = fn; + i = i_; + } + + if (!vm.functionMap["Sys.init"]) { + if (vm.functionMap["main"]) { + // Inject a Sys.init + vm.functionMap["Sys.init"] = { + name: "Sys.init", + labels: { END: 1 }, + nVars: 0, + operations: [ + { op: "call", name: "main", nArgs: 0 }, + { op: "goto", label: "END" }, + ], + }; + } else if (vm.functionMap["__implicit"]) { + // Use __implicit instead of __bootstrap + vm.executionStack = [{ function: "__implicit", op: 0 }]; + } else { + throw new Error("Could not determine an entry point for VM"); + } + } + + vm.registerStatics(); + return vm; + } + + private static buildFunction( + instructions: VmInstruction[], + i: number + ): [VmFunction, number] { + if (instructions[i].op !== "function") + throw new Error( + "Only call buildFunction at the initial Function instruction" + ); + const fn: VmFunction = { + name: (instructions[i] as FunctionInstruction).name, + nVars: (instructions[i] as FunctionInstruction).nVars, + labels: {}, + operations: [], + }; + + i += 1; + instructions: while (i < instructions.length) { + switch (instructions[i].op) { + case "function": + break instructions; + case "add": + case "sub": + case "neg": + case "and": + case "or": + case "not": + case "gt": + case "lt": + case "eq": + fn.operations.push({ + op: instructions[i].op as + | "add" + | "sub" + | "neg" + | "lt" + | "gt" + | "eq" + | "and" + | "or" + | "not", + }); + break; + case "push": + case "pop": + fn.operations.push({ + op: instructions[i].op as "push" | "pop", + segment: ( + instructions[i] as { + segment: + | "argument" + | "local" + | "static" + | "constant" + | "this" + | "that" + | "pointer" + | "temp"; + } + ).segment, + offset: (instructions[i] as { offset: number }).offset, + }); + break; + case "call": + fn.operations.push({ + op: "call", + name: (instructions[i] as { name: string }).name, + nArgs: (instructions[i] as { nArgs: number }).nArgs, + }); + break; + case "goto": + case "if-goto": + fn.operations.push({ + op: instructions[i].op as "goto" | "if-goto", + label: (instructions[i] as { label: string }).label, + }); + break; + case "label": { + const { label } = instructions[i] as { label: string }; + if (fn.labels[label]) + throw new Error( + `Cannot redeclare label ${label} in function ${fn.name} (previously at ${fn.labels[label]})` + ); + fn.labels[label] = fn.operations.length; + fn.operations.push({ op: "label", label }); + break; + } + case "return": { + fn.operations.push({ op: "return" }); + break; + } + } + + i += 1; + } + + return [fn, i]; + } + + get invocation() { + const invocation = this.executionStack.at(-1); + if (invocation === undefined) throw new Error("Empty execution stack!"); + return invocation; + } + + get currentFunction() { + const fn = this.functionMap[this.invocation.function]; + if (fn === undefined) + throw new Error( + `Executing undefined function ${this.invocation.function}` + ); + return fn; + } + + get operation() { + if (this.invocation.op > this.currentFunction.operations.length) + throw new Error( + `Current operation step beyond end of function operations (${this.invocation.op} > ${this.currentFunction.operations.length})` + ); + + return this.currentFunction.operations[this.invocation.op]; + } + + step() { + const operation = this.operation ?? { op: "return" }; // Implicit return if the function doesn't end on its own. + switch (operation.op) { + case "push": { + const value = this.memory.getSegment( + operation.segment, + operation.offset + ); + this.memory.push(value); + break; + } + case "pop": { + const value = this.memory.pop(); + this.memory.setSegment(operation.segment, operation.offset, value); + break; + } + case "add": { + this.memory.binOp((a, b) => a + b); + break; + } + case "sub": { + this.memory.binOp((a, b) => a - b); + break; + } + case "neg": { + // neg by flipping the sign bit + this.memory.unOp((a) => -a); + break; + } + case "and": { + this.memory.binOp((a, b) => a & b); + break; + } + case "or": { + this.memory.binOp((a, b) => a | b); + break; + } + case "not": { + this.memory.unOp((a) => ~a); + break; + } + case "eq": { + this.memory.comp((a, b) => a === b); + break; + } + case "lt": { + this.memory.comp((a, b) => a < b); + break; + } + case "gt": { + this.memory.comp((a, b) => a > b); + break; + } + case "goto": { + this.goto(operation.label); + break; + } + case "if-goto": { + const check = this.memory.pop(); + if (check != 0) { + this.goto(operation.label); + } + break; + } + case "call": { + const fnName = operation.name; + const fn = this.functionMap[fnName]; + if (!fn) throw new Error(`Calling unknown function ${fnName}`); + this.memory.pushFrame(this.invocation.op, operation.nArgs, fn.nVars); + this.executionStack.push({ function: fnName, op: -1 }); + break; + } + case "return": { + this.executionStack.pop(); + const ret = this.memory.popFrame(); + this.invocation.op = ret; + break; + } + case "label": { + // noop + break; + } + } + this.invocation.op += 1; + } + + private goto(label: string) { + if (this.currentFunction.labels[label] === undefined) + throw new Error( + `Attempting GOTO to unknown label ${label} in ${this.currentFunction.name}` + ); + this.invocation.op = this.currentFunction.labels[label]; + } + + write(addresses: [number, number][]) { + addresses.map(([address, value]) => { + this.memory.set(address, value); + }); + } + + read(addresses: number[]): number[] { + return addresses.map((address) => this.memory.get(address)); + } +} From e1b82165b94ffd957c43e29a0fe6b70772bae2fd Mon Sep 17 00:00:00 2001 From: David Souther Date: Sat, 11 Nov 2023 22:43:50 -0500 Subject: [PATCH 03/14] Extracted vm to vm and memory files --- simulator/src/languages/asm.ts | 80 ++++++++- simulator/src/vm/memory.ts | 225 +++++++++++++++++++++++++ simulator/src/vm/vm.ts | 297 +++------------------------------ 3 files changed, 330 insertions(+), 272 deletions(-) create mode 100644 simulator/src/vm/memory.ts diff --git a/simulator/src/languages/asm.ts b/simulator/src/languages/asm.ts index 578bbfc17..427ae7de0 100644 --- a/simulator/src/languages/asm.ts +++ b/simulator/src/languages/asm.ts @@ -147,12 +147,37 @@ asmSemantics.addAttribute("instruction", { }, }); +export type Pointer = + | "R0" + | "R1" + | "R2" + | "R3" + | "R4" + | "R5" + | "R6" + | "R7" + | "R8" + | "R9" + | "R10" + | "R11" + | "R12" + | "R13" + | "R14" + | "R15" + | "SP" + | "LCL" + | "ARG" + | "THIS" + | "THAT" + | "SCREEN" + | "KBD"; + export function fillLabel( asm: Asm, symbolCallback?: (name: string, value: number, isVar: boolean) => void ) { let nextLabel = 16; - const symbols = new Map([ + const symbols = new Map([ ["R0", 0], ["R1", 1], ["R2", 2], @@ -218,7 +243,27 @@ export function fillLabel( unfilled.forEach(transmuteAInstruction); } -export function translateInstruction(inst: AsmInstruction) { +function writeCInst(inst: AsmCInstruction): string { + return ( + (inst.store ? `${ASSIGN.op[inst.store]}=` : "") + + COMMANDS.op[inst.op] + + (inst.jump ? `;${JUMP.op[inst.jump]}` : "") + ); +} + +export const AsmToString = (inst: AsmInstruction | string): string => { + if (typeof inst === "string") return inst; + switch (inst.type) { + case "A": + return isALabelInstruction(inst) ? `@${inst.label}` : `@${inst.value}`; + case "L": + return `(${inst.label})`; + case "C": + return writeCInst(inst); + } +}; + +export function translateInstruction(inst: AsmInstruction): number | undefined { if (inst.type === "A") { if (isALabelInstruction(inst)) { throw new Error(`ASM Emitting unfilled A instruction`); @@ -242,6 +287,33 @@ export function emit(asm: Asm): number[] { .filter((op): op is number => op !== undefined); } +const A = (source: string | number): AsmAInstruction => + typeof source === "string" + ? { type: "A", label: source } + : { type: "A", value: source }; +const C = ( + assign: ASSIGN_ASM, + op: COMMANDS_ASM, + jmp?: JUMP_ASM +): AsmCInstruction => { + const isM = assign.includes("M") || op.includes("M"); + const inst: AsmCInstruction = { + type: "C", + op: COMMANDS.asm[op], + isM, + }; + if (jmp) inst.jump = JUMP.asm[jmp]; + if (assign) inst.store = ASSIGN.asm[assign]; + return inst; +}; +const AC = ( + source: string | number, + assign: ASSIGN_ASM, + op: COMMANDS_ASM, + jmp?: JUMP_ASM +) => [A(source), C(assign, op, jmp)]; +const L = (label: string): AsmLabelInstruction => ({ type: "L", label }); + export const ASM = { grammar: asmGrammar, semantics: asmSemantics, @@ -251,4 +323,8 @@ export const ASM = { fillLabel, emit, }, + A, + C, + AC, + L, }; diff --git a/simulator/src/vm/memory.ts b/simulator/src/vm/memory.ts new file mode 100644 index 000000000..d444bf66a --- /dev/null +++ b/simulator/src/vm/memory.ts @@ -0,0 +1,225 @@ +import { RAM } from "../cpu/memory.js"; +import { Segment } from "./vm.js"; + +export const SP = 0; +export const LCL = 1; +export const ARG = 2; +export const THIS = 3; +export const THAT = 4; +export const TEMP = 5; +export const STATIC = 16; + +export class VmMemory extends RAM { + strict = true; + get SP(): number { + return this.get(SP); + } + get LCL(): number { + return this.get(LCL); + } + get ARG(): number { + return this.get(ARG); + } + get THIS(): number { + return this.get(THIS); + } + get THAT(): number { + return this.get(THAT); + } + + get state() { + const temps = []; + for (let i = 5; i < 13; i++) { + temps.push(this.get(i)); + } + const internal = []; + for (let i = 13; i < 16; i++) { + internal.push(i); + } + return { + ["0: SP"]: this.SP, + ["1: LCL"]: this.LCL, + ["2: ARG"]: this.ARG, + ["3: THIS"]: this.THIS, + ["4: THAT"]: this.THAT, + TEMPS: temps, + VM: internal, + }; + } + + get statics() { + const statics = []; + for (let i = 16; i < 256; i++) { + statics.push(this.get(i)); + } + return statics; + } + + get frame() { + // Arg0 Arg1... RET LCL ARG THIS THAT [SP] + const args = []; + for (let i = this.ARG; i < this.LCL - 5; i++) { + args.push(this.get(i)); + } + const locals = []; + for (let i = this.LCL; i < this.SP; i++) { + locals.push(this.get(i)); + } + const _this = []; + for (let i = 0; i < 5; i++) { + _this.push(this.this(i)); + } + return { + args, + locals, + this: _this, + }; + } + + constructor() { + super(); + this.set(SP, 256); + } + + baseSegment(segment: Segment, offset: number): number { + switch (segment) { + case "argument": + return this.ARG + offset; + case "constant": + return offset; + case "local": + return this.LCL + offset; + case "pointer": + return this.pointer(offset); + case "static": + return 16 + offset; + case "temp": + return 5 + offset; + case "that": + return this.THAT + offset; + case "this": + return this.THIS + offset; + } + } + + getSegment(segment: Segment, offset: number): number { + if (segment === "constant") return offset; + const base = this.baseSegment(segment, offset); + return this.get(base); + } + setSegment(segment: Segment, offset: number, value: number) { + const base = this.baseSegment(segment, offset); + this.set(base, value); + } + + argument(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + return this.get(this.ARG + offset); + } + local(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + return this.get(this.LCL + offset); + } + static(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + if (this.strict && offset > 255 - 16) + throw new Error(`Cannot access statics beyond 239: ${offset}`); + return this.get(16 + offset); + } + constant(offset: number): number { + return offset; + } + this(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + return this.get(this.THIS + offset); + } + that(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + return this.get(this.THAT + offset); + } + pointer(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + if (this.strict && offset > 1) + throw new Error( + `pointer out of bounds access (pointer can be 0 for this, 1 for that, but got ${offset}` + ); + return offset === 0 ? THIS : THAT; + } + temp(offset: number): number { + if (this.strict && offset < 0) + throw new Error(`Cannot access negative offsets: ${offset}`); + if (this.strict && offset > 7) + throw new Error( + `Temp out of bounds access (temp can be 0 to 7, but got ${offset}` + ); + return this.get(5 + offset); + } + + push(value: number) { + const sp = this.SP; + this.set(sp, value); + this.set(0, sp + 1); + } + pop(): number { + if (this.strict && this.SP === 256) + throw new Error(`Cannot pop the stack below 256 in strict mode`); + this.set(0, this.SP - 1); + const value = this.get(this.SP); + return value; + } + // Stack frame, from figure 8.3, is: + // [ARG] Arg0 Arg1... RET LCL ARG THIS THAT [LCL] Local0 Local1... [SP] + pushFrame(ret: number, nArgs: number, nLocals: number) { + const arg = this.SP - nArgs; + let sp = this.SP + 5; + this.set(sp - 5, ret); + this.set(sp - 4, this.LCL); + this.set(sp - 3, this.ARG); + this.set(sp - 2, this.THIS); + this.set(sp - 1, this.THAT); + + this.set(ARG, arg); + this.set(LCL, sp); + + // Technically this happens in the function, but the VM will handle it for free + for (let i = 0; i < nLocals; i++) { + this.set(sp, 0); + sp += 1; + } + this.set(SP, sp); + } + popFrame(): number { + const frame = this.LCL; + const ret = this.get(frame - 5); + const value = this.pop(); + this.set(this.ARG, value); + this.set(SP, this.ARG + 1); + this.set(THAT, this.get(frame - 1)); + this.set(THIS, this.get(frame - 2)); + this.set(ARG, this.get(frame - 3)); + this.set(LCL, this.get(frame - 4)); + return ret; + } + + binOp(fn: (a: number, b: number) => number) { + const a = this.get(this.SP - 2); + const b = this.get(this.SP - 1); + const v = fn(a, b) & 0xffff; + this.set(this.SP - 2, v); + this.set(SP, this.SP - 1); + } + unOp(fn: (a: number) => number) { + const a = this.get(this.SP - 1); + const v = fn(a) & 0xffff; + this.set(this.SP - 1, v); + } + comp(fn: (a: number, b: number) => boolean) { + this.binOp((a, b) => (fn(a, b) ? -1 : 0)); + } +} diff --git a/simulator/src/vm/vm.ts b/simulator/src/vm/vm.ts index 859cdd042..df4d1f160 100644 --- a/simulator/src/vm/vm.ts +++ b/simulator/src/vm/vm.ts @@ -1,260 +1,6 @@ -import { RAM } from "../cpu/memory.js"; import { FunctionInstruction, VmInstruction } from "../languages/vm.js"; - -const SP = 0; -const LCL = 1; -const ARG = 2; -const THIS = 3; -const THAT = 4; - -export class VmMemory extends RAM { - strict = true; - get SP(): number { - return this.get(SP); - } - get LCL(): number { - return this.get(LCL); - } - get ARG(): number { - return this.get(ARG); - } - get THIS(): number { - return this.get(THIS); - } - get THAT(): number { - return this.get(THAT); - } - - get state() { - const temps = []; - for (let i = 5; i < 13; i++) { - temps.push(this.get(i)); - } - const internal = []; - for (let i = 13; i < 16; i++) { - internal.push(i); - } - return { - ["0: SP"]: this.SP, - ["1: LCL"]: this.LCL, - ["2: ARG"]: this.ARG, - ["3: THIS"]: this.THIS, - ["4: THAT"]: this.THAT, - TEMPS: temps, - VM: internal, - }; - } - - get statics() { - const statics = []; - for (let i = 16; i < 256; i++) { - statics.push(this.get(i)); - } - return statics; - } - - get frame() { - // Arg0 Arg1... RET LCL ARG THIS THAT [SP] - const args = []; - for (let i = this.ARG; i < this.LCL - 5; i++) { - args.push(this.get(i)); - } - const locals = []; - for (let i = this.LCL; i < this.SP; i++) { - locals.push(this.get(i)); - } - const _this = []; - for (let i = 0; i < 5; i++) { - _this.push(this.this(i)); - } - return { - args, - locals, - this: _this, - }; - } - - constructor() { - super(); - this.set(SP, 256); - } - - baseSegment( - segment: - | "argument" - | "local" - | "static" - | "constant" - | "this" - | "that" - | "pointer" - | "temp", - offset: number - ): number { - switch (segment) { - case "argument": - return this.ARG + offset; - case "constant": - return offset; - case "local": - return this.LCL + offset; - case "pointer": - return this.pointer(offset); - case "static": - return 16 + offset; - case "temp": - return 5 + offset; - case "that": - return this.THAT + offset; - case "this": - return this.THIS + offset; - } - } - - getSegment( - segment: - | "argument" - | "local" - | "static" - | "constant" - | "this" - | "that" - | "pointer" - | "temp", - offset: number - ): number { - if (segment === "constant") return offset; - const base = this.baseSegment(segment, offset); - return this.get(base); - } - setSegment( - segment: - | "argument" - | "local" - | "static" - | "constant" - | "this" - | "that" - | "pointer" - | "temp", - offset: number, - value: number - ) { - const base = this.baseSegment(segment, offset); - this.set(base, value); - } - - argument(offset: number): number { - if (this.strict && offset < 0) - throw new Error(`Cannot access negative offsets: ${offset}`); - return this.get(this.ARG + offset); - } - local(offset: number): number { - if (this.strict && offset < 0) - throw new Error(`Cannot access negative offsets: ${offset}`); - return this.get(this.LCL + offset); - } - static(offset: number): number { - if (this.strict && offset < 0) - throw new Error(`Cannot access negative offsets: ${offset}`); - if (this.strict && offset > 255 - 16) - throw new Error(`Cannot access statics beyond 239: ${offset}`); - return this.get(16 + offset); - } - constant(offset: number): number { - return offset; - } - this(offset: number): number { - if (this.strict && offset < 0) - throw new Error(`Cannot access negative offsets: ${offset}`); - return this.get(this.THIS + offset); - } - that(offset: number): number { - if (this.strict && offset < 0) - throw new Error(`Cannot access negative offsets: ${offset}`); - return this.get(this.THAT + offset); - } - pointer(offset: number): number { - if (this.strict && offset < 0) - throw new Error(`Cannot access negative offsets: ${offset}`); - if (this.strict && offset > 1) - throw new Error( - `pointer out of bounds access (pointer can be 0 for this, 1 for that, but got ${offset}` - ); - return offset === 0 ? THIS : THAT; - } - temp(offset: number): number { - if (this.strict && offset < 0) - throw new Error(`Cannot access negative offsets: ${offset}`); - if (this.strict && offset > 7) - throw new Error( - `Temp out of bounds access (temp can be 0 to 7, but got ${offset}` - ); - return this.get(5 + offset); - } - - push(value: number) { - const sp = this.SP; - this.set(sp, value); - this.set(0, sp + 1); - } - pop(): number { - if (this.strict && this.SP === 256) - throw new Error(`Cannot pop the stack below 256 in strict mode`); - this.set(0, this.SP - 1); - const value = this.get(this.SP); - return value; - } - // Stack frame, from figure 8.3, is: - // [ARG] Arg0 Arg1... RET LCL ARG THIS THAT [LCL] Local0 Local1... [SP] - pushFrame(ret: number, nArgs: number, nLocals: number) { - const arg = this.SP - nArgs; - let sp = this.SP + 5; - this.set(sp - 5, ret); - this.set(sp - 4, this.LCL); - this.set(sp - 3, this.ARG); - this.set(sp - 2, this.THIS); - this.set(sp - 1, this.THAT); - - this.set(ARG, arg); - this.set(LCL, sp); - - // Technically this happens in the function, but the VM will handle it for free - for (let i = 0; i < nLocals; i++) { - this.set(sp, 0); - sp += 1; - } - this.set(SP, sp); - } - popFrame(): number { - const frame = this.LCL; - const ret = this.get(frame - 5); - const value = this.pop(); - this.set(this.ARG, value); - this.set(SP, this.ARG + 1); - this.set(THAT, this.get(frame - 1)); - this.set(THIS, this.get(frame - 2)); - this.set(ARG, this.get(frame - 3)); - this.set(LCL, this.get(frame - 4)); - return ret; - } - - binOp(fn: (a: number, b: number) => number) { - const a = this.get(this.SP - 2); - const b = this.get(this.SP - 1); - const v = fn(a, b) & 0xffff; - this.set(this.SP - 2, v); - this.set(SP, this.SP - 1); - } - unOp(fn: (a: number) => number) { - const a = this.get(this.SP - 1); - const v = fn(a) & 0xffff; - this.set(this.SP - 1, v); - } - comp(fn: (a: number, b: number) => boolean) { - this.binOp((a, b) => (fn(a, b) ? -1 : 0)); - } -} +import { VmCompiler } from "./compiler.js"; +import { VmMemory } from "./memory.js"; export type VmOperation = | StackOperation @@ -264,21 +10,28 @@ export type VmOperation = | GotoOperation | LabelOperation; +export type Segment = + | "argument" + | "local" + | "static" + | "constant" + | "this" + | "that" + | "pointer" + | "temp"; + +export type BinOp = "add" | "sub" | "and" | "or"; +export type CmpOp = "lt" | "gt" | "eq"; +export type UnOp = "neg" | "not"; +export type Op = BinOp | CmpOp | UnOp; + export interface StackOperation { op: "push" | "pop"; - segment: - | "argument" - | "local" - | "static" - | "constant" - | "this" - | "that" - | "pointer" - | "temp"; + segment: Segment; offset: number; } export interface OpOperation { - op: "add" | "sub" | "neg" | "lt" | "gt" | "eq" | "and" | "or" | "not"; + op: Op; } export interface CallOperation { op: "call"; @@ -318,15 +71,15 @@ const BOOTSTRAP: VmFunction = { }; export class Vm { - private memory = new VmMemory(); - private functionMap: Record = { + protected memory = new VmMemory(); + protected functionMap: Record = { [BOOTSTRAP.name]: BOOTSTRAP, }; - private executionStack: VmFunctionInvocation[] = [ + protected executionStack: VmFunctionInvocation[] = [ { function: BOOTSTRAP.name, op: 0 }, ]; private staticCount = 0; - private statics: Record = {}; + protected statics: Record = {}; private registerStatic(fnName: string, offset: number): number { const fileName = fnName.split(".")[0]; const statics = this.statics[fileName] ?? []; @@ -622,4 +375,8 @@ export class Vm { read(addresses: number[]): number[] { return addresses.map((address) => this.memory.get(address)); } + + compiler(): VmCompiler { + return new VmCompiler(this.functionMap); + } } From 5a0ecaa319814f57865e96a6e5c77ad2bd66050e Mon Sep 17 00:00:00 2001 From: David Souther Date: Sat, 11 Nov 2023 11:21:00 -0500 Subject: [PATCH 04/14] Started VM store & page VM Page --- components/src/stores/chip.store.ts | 2 +- components/src/stores/cpu.store.ts | 18 +- components/src/stores/imm_memory.ts | 20 + components/src/stores/vm.store.ts | 125 ++++ package-lock.json | 28 + projects/src/samples/vm.ts | 178 +++++ simulator/package.json | 1 + simulator/src/chip/builtins/all.test.ts | 2 +- simulator/src/cpu/memory.ts | 4 + simulator/src/output.test.ts | 3 +- simulator/src/output.ts | 2 +- simulator/src/projects/all.test.ts | 2 +- simulator/src/projects/runner.ts | 2 +- simulator/src/test/builder.ts | 104 +++ .../src/{tst.test.ts => test/chiptst.test.ts} | 18 +- simulator/src/test/chiptst.ts | 115 +++ simulator/src/test/cputst.ts | 120 ++++ simulator/src/test/instruction.ts | 227 ++++++ simulator/src/test/tst.ts | 112 +++ simulator/src/test/vmtst.ts | 80 +++ simulator/src/testing/mult.ts | 23 + simulator/src/tst.ts | 675 ------------------ simulator/src/vm/memory.ts | 45 +- simulator/src/vm/vm.test.ts | 232 +----- simulator/src/vm/vm.ts | 89 ++- tsconfig.base.json | 2 +- web/src/App.tsx | 33 +- web/src/ErrorBoundary.tsx | 60 ++ web/src/pages/vm.tsx | 180 ++++- web/src/urls.tsx | 3 + 30 files changed, 1556 insertions(+), 949 deletions(-) create mode 100644 components/src/stores/imm_memory.ts create mode 100644 components/src/stores/vm.store.ts create mode 100644 projects/src/samples/vm.ts create mode 100644 simulator/src/test/builder.ts rename simulator/src/{tst.test.ts => test/chiptst.test.ts} (94%) create mode 100644 simulator/src/test/chiptst.ts create mode 100644 simulator/src/test/cputst.ts create mode 100644 simulator/src/test/instruction.ts create mode 100644 simulator/src/test/tst.ts create mode 100644 simulator/src/test/vmtst.ts delete mode 100644 simulator/src/tst.ts create mode 100644 web/src/ErrorBoundary.tsx diff --git a/components/src/stores/chip.store.ts b/components/src/stores/chip.store.ts index 8630d0ef2..e2829f0c2 100644 --- a/components/src/stores/chip.store.ts +++ b/components/src/stores/chip.store.ts @@ -24,7 +24,7 @@ import { CHIP_PROJECTS, ChipProjects, } from "@nand2tetris/projects/index.js"; -import { ChipTest } from "@nand2tetris/simulator/tst.js"; +import { ChipTest } from "@nand2tetris/simulator/test/chiptst.js"; import { ImmPin, reducePins } from "../pinout.js"; import { useImmerReducer } from "../react.js"; diff --git a/components/src/stores/cpu.store.ts b/components/src/stores/cpu.store.ts index a4ad8d1cb..7b3d3ed7d 100644 --- a/components/src/stores/cpu.store.ts +++ b/components/src/stores/cpu.store.ts @@ -5,16 +5,16 @@ import { MemoryAdapter, MemoryKeyboard, ROM, - SubMemory, } from "@nand2tetris/simulator/cpu/memory.js"; import { Span } from "@nand2tetris/simulator/languages/base.js"; import { TST } from "@nand2tetris/simulator/languages/tst.js"; import { HACK } from "@nand2tetris/simulator/testing/mult.js"; -import { CPUTest } from "@nand2tetris/simulator/tst.js"; +import { CPUTest } from "@nand2tetris/simulator/test/cputst.js"; import { Dispatch, MutableRefObject, useContext, useMemo, useRef } from "react"; import { compare } from "../compare.js"; import { useImmerReducer } from "../react.js"; import { BaseContext } from "./base.context.js"; +import { ImmMemory } from "./imm_memory.js"; function makeTst() { return `repeat { @@ -44,20 +44,6 @@ export interface CpuPageState { test: CPUTestSim; } -class ImmMemory extends SubMemory { - constructor( - parent: MemoryAdapter, - private dispatch: MutableRefObject - ) { - super(parent, parent.size, 0); - } - - override async load(fs: FileSystem, path: string): Promise { - await super.load(fs, path); - this.dispatch.current({ action: "update" }); - } -} - function reduceCPUTest( cpuTest: CPUTest, dispatch: MutableRefObject diff --git a/components/src/stores/imm_memory.ts b/components/src/stores/imm_memory.ts new file mode 100644 index 000000000..a1edf1e6b --- /dev/null +++ b/components/src/stores/imm_memory.ts @@ -0,0 +1,20 @@ +import { FileSystem } from "@davidsouther/jiffies/lib/esm/fs.js"; +import { MemoryAdapter, SubMemory } from "@nand2tetris/simulator/cpu/memory.js"; +import { MutableRefObject } from "react"; + +export class ImmMemory< + Action extends { action: "update" }, + Dispatch extends (a: Action) => void +> extends SubMemory { + constructor( + parent: MemoryAdapter, + private dispatch: MutableRefObject + ) { + super(parent, parent.size, 0); + } + + override async load(fs: FileSystem, path: string): Promise { + await super.load(fs, path); + this.dispatch.current({ action: "update" } as Action); + } +} diff --git a/components/src/stores/vm.store.ts b/components/src/stores/vm.store.ts new file mode 100644 index 000000000..92d2dfdd9 --- /dev/null +++ b/components/src/stores/vm.store.ts @@ -0,0 +1,125 @@ +import { FileSystem } from "@davidsouther/jiffies/lib/esm/fs.js"; +// import { VM as multVM } from "@nand2tetris/simulator/testing/mult.js"; +import { FIBONACCI } from "@nand2tetris/projects/samples/vm.js"; +import { Dispatch, MutableRefObject, useContext, useMemo, useRef } from "react"; +import { BaseContext } from "./base.context.js"; +import { useImmerReducer } from "../react.js"; +import { + KeyboardAdapter, + MemoryAdapter, + MemoryKeyboard, +} from "@nand2tetris/simulator/cpu/memory.js"; +import { VMTest } from "@nand2tetris/simulator/test/vmtst.js"; +import { VM, VmInstruction } from "@nand2tetris/simulator/languages/vm.js"; +import { ImmMemory } from "./imm_memory.js"; +import { unwrap } from "@davidsouther/jiffies/lib/esm/result.js"; +import { Frame, Vm } from "@nand2tetris/simulator/vm/vm.js"; +import { Span } from "@nand2tetris/simulator/languages/base.js"; + +export interface VmSim { + RAM: MemoryAdapter; + Screen: MemoryAdapter; + Keyboard: KeyboardAdapter; + Stack: Frame[]; + Prog: VmInstruction[]; + highlight: number; +} + +export interface VMTestSim { + useTest: boolean; + highlight: Span | undefined; +} + +export interface VmPageState { + vm: VmSim; + controls: ControlsState; + test: VMTestSim; +} + +export interface ControlsState { + runningTest: boolean; + error: string; +} + +export type VmStoreDispatch = Dispatch<{ + action: keyof ReturnType["reducers"]; + payload?: unknown; +}>; + +function reduceVMTest( + vmTest: VMTest, + dispatch: MutableRefObject +): VmSim { + const RAM = new ImmMemory(vmTest.vm.RAM, dispatch); + const Screen = new ImmMemory(vmTest.vm.Screen, dispatch); + const Keyboard = new MemoryKeyboard( + new ImmMemory(vmTest.vm.Keyboard, dispatch) + ); + + return { + Keyboard, + RAM, + Screen, + Stack: vmTest.vm.vmStack(), + Prog: vmTest.vm.program, + highlight: -1, + }; +} + +export function makeVmStore( + fs: FileSystem, + setStatus: (status: string) => void, + storage: Record, + dispatch: MutableRefObject +) { + const parsed = unwrap(VM.parse(FIBONACCI)); + const vm = unwrap(Vm.build(parsed.instructions)); + const test = new VMTest().with(vm); + let useTest = true; + const reducers = { + update(state: VmPageState) { + state.vm = reduceVMTest(test, dispatch); + state.test.useTest = useTest; + }, + }; + const initialState: VmPageState = { + vm: reduceVMTest(test, dispatch), + controls: { + error: "", + runningTest: false, + }, + test: { + useTest, + highlight: undefined, + }, + }; + const actions = { + step() { + vm.step(); + }, + reset() { + //todo + }, + toggleUseTest() { + useTest = !useTest; + }, + }; + + return { initialState, reducers, actions }; +} + +export function useVmPageStore() { + const { fs, setStatus, storage } = useContext(BaseContext); + + const dispatch = useRef(() => undefined); + + const { initialState, reducers, actions } = useMemo( + () => makeVmStore(fs, setStatus, storage, dispatch), + [fs, setStatus, storage, dispatch] + ); + + const [state, dispatcher] = useImmerReducer(reducers, initialState); + dispatch.current = dispatcher; + + return { state, dispatch, actions }; +} diff --git a/package-lock.json b/package-lock.json index ddc513856..17d4b3da6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21437,6 +21437,11 @@ "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", "dev": true }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -23047,6 +23052,7 @@ "@davidsouther/jiffies": "^2.0.6", "@nand2tetris/projects": "^1.0.0", "@nand2tetris/runner": "^1.0.0", + "@types/node": "^20.9.0", "ohm-js": "^16.6.0", "rxjs": "^7.8.0" }, @@ -23069,6 +23075,14 @@ "pretty-format": "^29.0.0" } }, + "simulator/node_modules/@types/node": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", + "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, "simulator/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -25528,6 +25542,7 @@ "@nand2tetris/projects": "^1.0.0", "@nand2tetris/runner": "^1.0.0", "@types/jest": "^29.1.2", + "@types/node": "^20.9.0", "babel-jest": "^29.3.1", "jest": "^29.3.1", "jest-ts-webcompat-resolver": "^1.0.0", @@ -25546,6 +25561,14 @@ "pretty-format": "^29.0.0" } }, + "@types/node": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", + "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", + "requires": { + "undici-types": "~5.26.4" + } + }, "ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -38921,6 +38944,11 @@ "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", "dev": true }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", diff --git a/projects/src/samples/vm.ts b/projects/src/samples/vm.ts new file mode 100644 index 000000000..5b07cea14 --- /dev/null +++ b/projects/src/samples/vm.ts @@ -0,0 +1,178 @@ +export const SIMPLE_FUNCTION = ` +// __implicit + push constant 3 + push constant 4 + call mult 2 + +// returns x * y as sum i = 0 to y x +// x = arg 0 +// y = arg 1 +// sum = local 0 +// i = local 1 +function mult 2 +label WHILE_LOOP + push local 1 + push argument 1 + lt + not + if-goto WHILE_END + push local 0 + push argument 0 + add + pop local 0 + push local 1 + push constant 1 + add + pop local 1 + goto WHILE_LOOP +label WHILE_END + push local 0 + return +`; + +export const NESTED_FUNCTION = ` +// Sys.vm for NestedCall test. + +// Sys.init() +// +// Calls Sys.main() and stores return value in temp 1. +// Does not return. (Enters infinite loop.) + +function Sys.init 0 +push constant 4000 // test THIS and THAT context save +pop pointer 0 +push constant 5000 +pop pointer 1 +call Sys.main 0 +pop temp 1 +label LOOP +goto LOOP + +// Sys.main() +// +// Sets locals 1, 2 and 3, leaving locals 0 and 4 unchanged to test +// default local initialization to 0. (RAM set to -1 by test setup.) +// Calls Sys.add12(123) and stores return value (135) in temp 0. +// Returns local 0 + local 1 + local 2 + local 3 + local 4 (456) to confirm +// that locals were not mangled by function call. + +function Sys.main 5 +push constant 4001 +pop pointer 0 +push constant 5001 +pop pointer 1 +push constant 200 +pop local 1 +push constant 40 +pop local 2 +push constant 6 +pop local 3 +push constant 123 +call Sys.add12 1 +pop temp 0 +push local 0 +push local 1 +push local 2 +push local 3 +push local 4 +add +add +add +add +return + +// Sys.add12(int n) +// +// Returns n+12. + +function Sys.add12 0 +push constant 4002 +pop pointer 0 +push constant 5002 +pop pointer 1 +push argument 0 +push constant 12 +add +return +`; + +export const FIB_MAIN = ` +function Main.fibonacci 0 +push argument 0 +push constant 2 +lt // checks if n<2 +if-goto IF_TRUE +goto IF_FALSE +label IF_TRUE // if n<2, return n +push argument 0 +return +label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) +push argument 0 +push constant 2 +sub +call Main.fibonacci 1 // computes fib(n-2) +push argument 0 +push constant 1 +sub +call Main.fibonacci 1 // computes fib(n-1) +add // returns fib(n-1) + fib(n-2) +return +`; + +export const FIB_SYS = ` +function Sys.init 0 +push constant 4 +call Main.fibonacci 1 // computes the 4'th fibonacci element +label WHILE +goto WHILE // loops infinitely +`; + +export const FIBONACCI = FIB_MAIN + FIB_SYS; + +export const STATIC_CLASS_1 = `function Class1.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class1.get 0 +push static 0 +push static 1 +sub +return +`; +export const STATIC_CLASS_2 = `function Class2.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class2.get 0 +push static 0 +push static 1 +sub +return +`; + +export const STATIC_SYS = `function Sys.init 0 +push constant 6 +push constant 8 +call Class1.set 2 +pop temp 0 // Dumps the return value +push constant 23 +push constant 15 +call Class2.set 2 +pop temp 0 // Dumps the return value +call Class1.get 0 +call Class2.get 0 +label WHILE +goto WHILE +`; + +export const STATIC = STATIC_CLASS_1 + STATIC_CLASS_2 + STATIC_SYS; diff --git a/simulator/package.json b/simulator/package.json index 79482bb38..d7ecd46fd 100644 --- a/simulator/package.json +++ b/simulator/package.json @@ -21,6 +21,7 @@ "@davidsouther/jiffies": "^2.0.6", "@nand2tetris/projects": "^1.0.0", "@nand2tetris/runner": "^1.0.0", + "@types/node": "^20.9.0", "ohm-js": "^16.6.0", "rxjs": "^7.8.0" }, diff --git a/simulator/src/chip/builtins/all.test.ts b/simulator/src/chip/builtins/all.test.ts index e5b743414..f3b67e9c1 100644 --- a/simulator/src/chip/builtins/all.test.ts +++ b/simulator/src/chip/builtins/all.test.ts @@ -9,9 +9,9 @@ import { Tst, TST } from "../../languages/tst.js"; import { ChipProjects, CHIP_PROJECTS } from "@nand2tetris/projects/index.js"; import { Max } from "@nand2tetris/projects/samples/hack.js"; import { compare } from "../../compare.js"; -import { ChipTest } from "../../tst.js"; import { build } from "../builder.js"; import { Chip } from "../chip.js"; +import { ChipTest } from "../../test/chiptst.js"; const SKIP = new Set(["Computer"]); diff --git a/simulator/src/cpu/memory.ts b/simulator/src/cpu/memory.ts index d05fa920a..39268a07d 100644 --- a/simulator/src/cpu/memory.ts +++ b/simulator/src/cpu/memory.ts @@ -3,6 +3,7 @@ import { FileSystem } from "@davidsouther/jiffies/lib/esm/fs.js"; import { op } from "../util/asm.js"; import { int10, int16, int2 } from "../util/twos.js"; import { load } from "../fs.js"; +import { Screen } from "../chip/builtins/computer/computer.js"; export const FORMATS = ["bin", "dec", "hex", "asm"]; export type Format = typeof FORMATS[number]; @@ -204,6 +205,9 @@ export class ROM extends Memory { } export class RAM extends Memory { + keyboard = new SubMemory(this, 1, KEYBOARD_OFFSET); + screen = new SubMemory(this, SCREEN_SIZE, SCREEN_OFFSET); + // 4k main memory, 2k screen memory, 1 keyboard // static readonly SIZE = 0x4000 + 0x2000 + 0x0001; static readonly SIZE = 0x8000; diff --git a/simulator/src/output.test.ts b/simulator/src/output.test.ts index 4573c56c0..a7b62c40a 100644 --- a/simulator/src/output.test.ts +++ b/simulator/src/output.test.ts @@ -1,6 +1,7 @@ import { cleanState } from "@davidsouther/jiffies/lib/esm/scope/state.js"; import { Output } from "./output.js"; -import { Test, TestOutputInstruction } from "./tst.js"; +import { Test } from "./test/tst.js"; +import { TestOutputInstruction } from "./test/instruction.js"; class OutputTest extends Test { private readonly vars: Map; diff --git a/simulator/src/output.ts b/simulator/src/output.ts index cdc5f1161..93d579c17 100644 --- a/simulator/src/output.ts +++ b/simulator/src/output.ts @@ -1,6 +1,6 @@ import { assert } from "@davidsouther/jiffies/lib/esm/assert.js"; import { bin, dec, hex } from "./util/twos.js"; -import { Test } from "./tst.js"; +import { Test } from "./test/tst.js"; export class Output { private readonly fmt: "B" | "X" | "D" | "S"; diff --git a/simulator/src/projects/all.test.ts b/simulator/src/projects/all.test.ts index 36c7bbb5f..4927b8ae1 100644 --- a/simulator/src/projects/all.test.ts +++ b/simulator/src/projects/all.test.ts @@ -10,7 +10,6 @@ import { Asm, ASM } from "../languages/asm.js"; import { Cmp, CMP } from "../languages/cmp.js"; import { HDL, HdlParse } from "../languages/hdl.js"; import { Tst, TST } from "../languages/tst.js"; -import { ChipTest } from "../tst.js"; import { ChipProjects, ASM_PROJECTS, @@ -22,6 +21,7 @@ import { FILES as ASM_FILES, } from "@nand2tetris/projects/samples/project_06/index.js"; import { Max } from "@nand2tetris/projects/samples/hack.js"; +import { ChipTest } from "../test/chiptst.js"; const PROJECTS = new Set(["01", "03"]); const SKIP = new Set([]); diff --git a/simulator/src/projects/runner.ts b/simulator/src/projects/runner.ts index 494c5e3dd..144bc91d6 100644 --- a/simulator/src/projects/runner.ts +++ b/simulator/src/projects/runner.ts @@ -11,9 +11,9 @@ import type { Runner, RunResult } from "@nand2tetris/runner/types.js"; import { HDL, HdlParse } from "../languages/hdl.js"; import { Tst, TST } from "../languages/tst.js"; import { build as buildChip } from "../chip/builder.js"; -import { ChipTest } from "../tst.js"; import { ParseError } from "../languages/base.js"; import { Chip } from "../chip/chip.js"; +import { ChipTest } from "../test/chiptst.js"; export interface AssignmentFiles extends Assignment { hdl: string; diff --git a/simulator/src/test/builder.ts b/simulator/src/test/builder.ts new file mode 100644 index 000000000..ebd948922 --- /dev/null +++ b/simulator/src/test/builder.ts @@ -0,0 +1,104 @@ +import { checkExhaustive } from "@davidsouther/jiffies/lib/esm/assert.js"; +import { + Tst, + TstLineStatement, + TstOperation, + TstStatement, + TstWhileStatement, +} from "../languages/tst.js"; +import { + TestEvalInstruction, + TestTickInstruction, + TestTockInstruction, +} from "./chiptst.js"; +import { + Condition, + TestClearEchoInstruction, + TestCompoundInstruction, + TestEchoInstruction, + TestLoadROMInstruction, + TestOutputInstruction, + TestOutputListInstruction, + TestRepeatInstruction, + TestSetInstruction, + TestWhileInstruction, +} from "./instruction.js"; +import { Test } from "./tst.js"; +import { TestTickTockInstruction } from "./cputst.js"; + +function isTstLineStatment(line: TstStatement): line is TstLineStatement { + return (line as TstLineStatement).ops !== undefined; +} + +function isTstWhileStatement(line: TstStatement): line is TstWhileStatement { + return (line as TstWhileStatement).condition !== undefined; +} + +function makeLineStatement(line: TstLineStatement) { + const statement = new TestCompoundInstruction(); + statement.span = line.span; + for (const op of line.ops) { + const inst = makeInstruction(op); + if (inst !== undefined) statement.addInstruction(inst); + } + return statement; +} + +function makeInstruction(inst: TstOperation) { + const { op } = inst; + switch (op) { + case "tick": + return new TestTickInstruction(); + case "tock": + return new TestTockInstruction(); + case "ticktock": + return new TestTickTockInstruction(); + case "eval": + return new TestEvalInstruction(); + case "output": + return new TestOutputInstruction(); + case "set": + return new TestSetInstruction(inst.id, inst.value, inst.index); + case "output-list": + return new TestOutputListInstruction(inst.spec); + case "echo": + return new TestEchoInstruction(inst.message); + case "clear-echo": + return new TestClearEchoInstruction(); + case "loadRom": + return new TestLoadROMInstruction(inst.file); + case "load": + case "output-file": + case "compare-to": + return undefined; + default: + checkExhaustive(op, `Unknown tst operation ${op}`); + } +} + +export function fill(test: T, tst: Tst): T { + for (const line of tst.lines) { + if (isTstLineStatment(line)) { + test.addInstruction(makeLineStatement(line)); + } else { + const repeat = isTstWhileStatement(line) + ? new TestWhileInstruction( + new Condition( + line.condition.left, + line.condition.right, + line.condition.op + ) + ) + : new TestRepeatInstruction(line.count); + repeat.span = line.span; + test.addInstruction(repeat); + for (const statement of line.statements) { + repeat.addInstruction(makeLineStatement(statement)); + } + } + } + + test.reset(); + + return test; +} diff --git a/simulator/src/tst.test.ts b/simulator/src/test/chiptst.test.ts similarity index 94% rename from simulator/src/tst.test.ts rename to simulator/src/test/chiptst.test.ts index 73fef78af..d06bfd8f3 100644 --- a/simulator/src/tst.test.ts +++ b/simulator/src/test/chiptst.test.ts @@ -1,18 +1,20 @@ -import { TstRepeat } from "./languages/tst.js"; -import { Computer } from "./chip/builtins/computer/computer.js"; -import { Nand } from "./chip/builtins/logic/nand.js"; -import { Output } from "./output.js"; +import { TstRepeat } from "../languages/tst.js"; +import { Computer } from "../chip/builtins/computer/computer.js"; +import { Nand } from "../chip/builtins/logic/nand.js"; +import { Output } from "../output.js"; import { ChipTest, - TestSetInstruction, TestEvalInstruction, - TestOutputInstruction, TestTickInstruction, TestTockInstruction, +} from "./chiptst.js"; +import { TestCompoundInstruction, -} from "./tst.js"; + TestOutputInstruction, + TestSetInstruction, +} from "./instruction.js"; -describe("Simulator Test", () => { +describe("Chip Test", () => { describe("Builtins", () => { it("can set Memory", async () => { const computer = new Computer(); diff --git a/simulator/src/test/chiptst.ts b/simulator/src/test/chiptst.ts new file mode 100644 index 000000000..616b7ddf3 --- /dev/null +++ b/simulator/src/test/chiptst.ts @@ -0,0 +1,115 @@ +import { Bus, Chip, HIGH, Low, LOW } from "../chip/chip.js"; +import { Clock } from "../chip/clock.js"; +import { Tst } from "../languages/tst.js"; +import { fill } from "./builder.js"; +import { TestInstruction } from "./instruction.js"; +import { Test } from "./tst.js"; + +export class ChipTest extends Test { + private chip: Chip = new Low(); + get chipId(): number { + return this.chip.id; + } + + private clock = Clock.get(); + + static from(tst: Tst): ChipTest { + const test = new ChipTest(); + return fill(test, tst); + } + + with(chip: Chip): this { + this.chip = chip; + return this; + } + + hasVar(variable: string | number): boolean { + if (variable === "time") { + return true; + } + variable = `${variable}`; + // Look up built-in chip state variables + return this.chip.hasIn(variable) || this.chip.hasOut(variable); + } + + getVar(variable: string | number, offset?: number): number | string { + variable = `${variable}`; + if (variable === "time") { + return this.clock.toString(); + } + const pin = this.chip.get(variable, offset); + if (!pin) return 0; + return pin instanceof Bus ? pin.busVoltage : pin.voltage(); + } + + setVar(variable: string, value: number, offset?: number): void { + // Look up built-in chip state variables + const pinOrBus = this.chip.get(variable, offset); + if (pinOrBus instanceof Bus) { + pinOrBus.busVoltage = value; + } else { + pinOrBus?.pull(value === 0 ? LOW : HIGH); + } + } + + eval(): void { + this.chip.eval(); + } + + tick(): void { + this.chip.eval(); + this.clock.tick(); + } + + tock(): void { + this.chip.eval(); + this.clock.tock(); + } + + override async load(filename: string) { + await this.chip.load(this.fs, filename); + } + + override async run() { + this.clock.reset(); + await super.run(); + } +} + +export interface ChipTestInstruction extends TestInstruction { + _chipTestInstruction_: true; + do(test: ChipTest): void | Promise; +} + +export class TestEvalInstruction implements ChipTestInstruction { + readonly _chipTestInstruction_ = true; + do(test: ChipTest) { + test.eval(); + } + + *steps() { + yield this; + } +} + +export class TestTickInstruction implements ChipTestInstruction { + readonly _chipTestInstruction_ = true; + do(test: ChipTest) { + test.tick(); + } + + *steps() { + yield this; + } +} + +export class TestTockInstruction implements ChipTestInstruction { + readonly _chipTestInstruction_ = true; + do(test: ChipTest) { + test.tock(); + } + + *steps() { + yield this; + } +} diff --git a/simulator/src/test/cputst.ts b/simulator/src/test/cputst.ts new file mode 100644 index 000000000..74541e281 --- /dev/null +++ b/simulator/src/test/cputst.ts @@ -0,0 +1,120 @@ +import { ROM } from "../cpu/memory.js"; +import { CPU } from "../cpu/cpu.js"; +import { Test } from "./tst.js"; +import { Tst } from "../languages/tst.js"; +import { TestInstruction } from "./instruction.js"; +import { fill } from "./builder.js"; + +export class CPUTest extends Test { + readonly cpu: CPU; + private ticks = 0; + + static from(tst: Tst, rom?: ROM): CPUTest { + const test = new CPUTest(rom); + return fill(test, tst); + } + + constructor(rom: ROM = new ROM(new Int16Array())) { + super(); + this.cpu = new CPU({ ROM: rom }); + this.reset(); + } + + override reset(): this { + super.reset(); + this.cpu.reset(); + this.ticks = 0; + return this; + } + + hasVar(variable: string | number): boolean { + if (typeof variable === "number") { + return false; + } + // A: Current value of the address register (unsigned 15-bit); + // D: Current value of the data register (16-bit); + // PC: Current value of the Program Counter (unsigned 15-bit); + // RAM[i]: Current value of RAM location i (16-bit); + // time: Number of time units (also called clock cycles, or ticktocks) that elapsed since the simulation started (a read-only system variable). + if ( + variable === "A" || + variable === "D" || + variable === "PC" || + variable === "time" || + variable.startsWith("RAM") + ) { + return true; + } + return false; + } + + getVar(variable: string | number, offset?: number): number { + switch (variable) { + case "A": + return this.cpu.A; + case "D": + return this.cpu.D; + case "PC": + return this.cpu.PC; + case "time": + return this.ticks; + case "RAM": + // Exact RAM with offset + return offset === undefined ? 0 : this.cpu.RAM.get(offset); + } + if (typeof variable === "number") return 0; + if (variable.startsWith("RAM")) { + // RAM with implicit offset, EG: RAM[123] + const num = Number(variable.substring(4, variable.length - 1)); + return this.cpu.RAM.get(num); + } + return 0; + } + + setVar(variable: string, value: number, index?: number): void { + // A: Current value of the address register (unsigned 15-bit); + // D: Current value of the data register (16-bit); + // PC: Current value of the Program Counter (unsigned 15-bit); + // RAM[i]: Current value of RAM location i (16-bit); + switch (variable) { + case "A": + this.cpu.setA(value); + break; + case "D": + this.cpu.setD(value); + break; + case "PC": + this.cpu.setPC(value); + break; + case "RAM": + this.cpu.RAM.set(index ?? 0, value); + break; + } + return; + } + + ticktock(): void { + this.ticks += 1; + this.cpu.tick(); + } + + override async load(filename: string): Promise { + await this.cpu.ROM.load(this.fs, filename); + } +} + +export interface CPUTestInstruction extends TestInstruction { + _cpuTestInstruction_: true; + do(test: CPUTest): void | Promise; +} + +export class TestTickTockInstruction implements CPUTestInstruction { + readonly _cpuTestInstruction_ = true; + do(test: CPUTest) { + test.ticktock(); + } + + *steps() { + yield this; + } +} diff --git a/simulator/src/test/instruction.ts b/simulator/src/test/instruction.ts new file mode 100644 index 000000000..812d8adbb --- /dev/null +++ b/simulator/src/test/instruction.ts @@ -0,0 +1,227 @@ +import { Span } from "../languages/base.js"; +import { TstOutputSpec } from "../languages/tst.js"; +import { Output } from "../output.js"; +import { Test } from "./tst.js"; + +export interface TestInstruction { + span?: Span; + do(test: Test): void; + steps(test: Test): IterableIterator; +} + +export class TestSetInstruction implements TestInstruction { + constructor( + private variable: string, + private value: number, + private index?: number | undefined + ) {} + + do(test: Test) { + test.setVar(this.variable, this.value, this.index); + } + + *steps() { + yield this; + } +} + +export class TestOutputInstruction implements TestInstruction { + do(test: Test) { + test.output(); + } + + *steps() { + yield this; + } +} + +export class TestOutputListInstruction implements TestInstruction { + private outputs: Output[] = []; + + constructor(specs: TstOutputSpec[] = []) { + for (const spec of specs) { + this.addOutput(spec); + } + } + + addOutput(inst: TstOutputSpec) { + this.outputs.push( + new Output( + inst.id, + inst.style, + inst.width, + inst.lpad, + inst.rpad, + inst.builtin, + inst.address + ) + ); + } + + do(test: Test) { + test.outputList(this.outputs); + test.header(); + } + + *steps() { + yield this; + } +} + +export class TestCompoundInstruction implements TestInstruction { + protected readonly instructions: TestInstruction[] = []; + span?: Span; + + addInstruction(instruction: TestInstruction) { + this.instructions.push(instruction); + } + + do(test: Test): void { + for (const instruction of this.instructions) { + instruction.do(test); + } + } + + *steps(_test: Test): Generator { + yield this; + } +} + +export class TestRepeatInstruction extends TestCompoundInstruction { + constructor(public readonly repeat: number) { + super(); + } + + override do() { + return undefined; + } + + private *innerSteps(test: Test): Generator { + for (const instruction of this.instructions) { + yield* instruction.steps(test) as Generator; + } + } + + override *steps(test: Test): Generator { + if (this.repeat === -1) { + yield this; + while (true) { + yield* this.innerSteps(test); + } + } else { + for (let i = 0; i < this.repeat; i++) { + yield this; + yield* this.innerSteps(test); + } + } + } +} + +export class Condition { + constructor( + public readonly x: string | number, + public readonly y: string | number, + public readonly op: "<" | "<=" | "=" | ">=" | ">" | "<>" + ) {} + + check(test: Test): boolean { + const x = test.hasVar(this.x) ? test.getVar(this.x) : this.x; + const y = test.hasVar(this.y) ? test.getVar(this.y) : this.y; + + if (typeof x === "string" || typeof y === "string") { + switch (this.op) { + case "=": + return `${x}` === `${y}`; + case "<>": + return `${x}` !== `${y}`; + } + } else { + switch (this.op) { + case "<": + return x < y; + case "<=": + return x <= y; + case ">": + return x > y; + case ">=": + return x >= y; + case "=": + return x === y; + case "<>": + return x !== y; + } + } + return false; + } +} + +export class TestWhileInstruction extends TestCompoundInstruction { + constructor(public readonly condition: Condition) { + super(); + } + + override *steps(test: Test): Generator { + while (this.condition.check(test)) { + yield this; + for (const instruction of this.instructions) { + yield* instruction.steps(test) as Generator; + } + } + } +} + +export class TestEchoInstruction implements TestInstruction { + constructor(public readonly content: string) {} + do(test: Test) { + test.echo(this.content); + } + + *steps() { + yield this; + } +} + +export class TestClearEchoInstruction implements TestInstruction { + do(test: Test) { + test.clearEcho(); + } + + *steps() { + yield this; + } +} + +export class TestLoadROMInstruction implements TestInstruction { + constructor(readonly file: string) {} + async do(test: Test) { + test.fs.pushd("/samples"); + await test.load(this.file); + test.fs.popd(); + } + + *steps() { + yield this; + } +} + +export class TestBreakpointInstruction implements TestInstruction { + constructor(readonly variable: string, readonly value: number) {} + + do(test: Test) { + test.addBreakpoint(this.variable, this.value); + } + + *steps() { + yield this; + } +} + +export class TestClearBreakpointsInstruction implements TestInstruction { + do(test: Test) { + test.clearBreakpoints(); + } + + *steps() { + yield this; + } +} diff --git a/simulator/src/test/tst.ts b/simulator/src/test/tst.ts new file mode 100644 index 000000000..bec1a626e --- /dev/null +++ b/simulator/src/test/tst.ts @@ -0,0 +1,112 @@ +import { assertExists } from "@davidsouther/jiffies/lib/esm/assert.js"; +import { FileSystem } from "@davidsouther/jiffies/lib/esm/fs.js"; +import { Output } from "../output.js"; +import { TestInstruction } from "./instruction.js"; + +export abstract class Test { + protected readonly instructions: (IS | TestInstruction)[] = []; + protected _outputList: Output[] = []; + protected _log = ""; + fs: FileSystem = new FileSystem(); + + setFileSystem(fs: FileSystem): this { + this.fs = fs; + return this; + } + + echo(_content: string) { + return undefined; + } + clearEcho() { + return undefined; + } + + async load(_filename: string): Promise { + return undefined; + } + async compareTo(_filename: string): Promise { + return undefined; + } + outputFile(_filename: string): void { + return undefined; + } + outputList(outputs: Output[]): void { + this._outputList = outputs; + } + + addInstruction(instruction: IS | TestInstruction): void { + this.instructions.push(instruction); + } + + reset(): this { + this._steps = (function* (test) { + for (const instruction of test.instructions) { + yield* instruction.steps(test); + } + })(this); + this._step = this._steps.next(); + this._step; //? + this._log = ""; + return this; + } + + private _steps!: IterableIterator; + private _step!: IteratorResult; + + get steps(): Iterator { + if (this._steps === undefined) { + this.reset(); + this._steps = assertExists(this._steps, "Reset did not initialize steps"); + this._step = assertExists(this._step, "Reset did not find first step"); + } + return this._steps; + } + + get currentStep(): IS | TestInstruction | undefined { + return this._step?.value; + } + + get done(): boolean { + return this._step?.done ?? false; + } + + step() { + if (!this._step.done) { + this._step.value.do(this); + this._step = this.steps.next(); + return false; + } + return true; + } + + async run() { + this.reset(); + while (!(await this.step())); + } + + protected readonly breakpoints: Map = new Map(); + addBreakpoint(variable: string, value: number) { + this.breakpoints.set(variable, value); + } + clearBreakpoints() { + this.breakpoints.clear(); + } + + output() { + const values = this._outputList.map((output) => output.print(this)); + this._log += `|${values.join("|")}|\n`; + } + + header() { + const values = this._outputList.map((output) => output.header(this)); + this._log += `|${values.join("|")}|\n`; + } + + log() { + return this._log; + } + + abstract hasVar(variable: string | number): boolean; + abstract getVar(variable: string | number, offset?: number): number | string; + abstract setVar(variable: string, value: number, offset?: number): void; +} diff --git a/simulator/src/test/vmtst.ts b/simulator/src/test/vmtst.ts new file mode 100644 index 000000000..318c1a7c6 --- /dev/null +++ b/simulator/src/test/vmtst.ts @@ -0,0 +1,80 @@ +import { RAM } from "../cpu/memory.js"; +import { Vm } from "../vm/vm.js"; +import { TestInstruction } from "./instruction.js"; +import { Test } from "./tst.js"; + +export class VMTest extends Test { + vm: Vm = new Vm(); + + with(vm: Vm) { + this.vm = vm; + return this; + } + + hasVar(variable: string | number, index?: number): boolean { + if (typeof variable !== "string") { + index = variable; + variable = "RAM"; + } + if ( + variable === "RAM" && + index !== undefined && + index > 0 && + index < RAM.SIZE + ) { + return true; + } + return false; + } + + getVar(variable: string | number, index?: number): number { + if (typeof variable !== "string") { + index = variable; + variable = "RAM"; + } + if ( + variable === "RAM" && + index !== undefined && + index > 0 && + index < RAM.SIZE + ) { + return this.vm.RAM.get(index); + } + return 0; + } + + setVar(variable: string, value: number, index?: number): void { + if (typeof variable !== "string") { + index = variable; + variable = "RAM"; + } + if ( + variable === "RAM" && + index !== undefined && + index > 0 && + index < RAM.SIZE + ) { + this.vm.RAM.set(index, value); + } + } + + vmstep(): void { + this.vm.step(); + } +} + +export interface VMTestInstruction extends TestInstruction { + _vmTestInstruction_: true; + do(test: VMTest): void | Promise; +} + +export class TestVMStepInstruction implements VMTestInstruction { + readonly _vmTestInstruction_ = true; + do(test: VMTest) { + test.vmstep(); + } + + *steps() { + yield this; + } +} diff --git a/simulator/src/testing/mult.ts b/simulator/src/testing/mult.ts index 73a799d58..f33b481da 100644 --- a/simulator/src/testing/mult.ts +++ b/simulator/src/testing/mult.ts @@ -4,6 +4,29 @@ while (R0 > 0) { R0 = R0 - 1 }`; +export const VM = ` +(_loop_start) + push constant 0 + push arg 0 + eq + jump-eq _loop_end + + push arg 1 + push local 0 + add + pop local 0 + + push arg 0 + push constant 1 + sub + pop arg 0 + + jump _loop_start + +(_loop_end) + jump loop_end +`; + export const ASM = ` @R2 M=0 diff --git a/simulator/src/tst.ts b/simulator/src/tst.ts deleted file mode 100644 index c3978a457..000000000 --- a/simulator/src/tst.ts +++ /dev/null @@ -1,675 +0,0 @@ -import { - assertExists, - checkExhaustive, -} from "@davidsouther/jiffies/lib/esm/assert.js"; -import { FileSystem } from "@davidsouther/jiffies/lib/esm/fs.js"; -import { Span } from "./languages/base.js"; -import { - Tst, - TstLineStatement, - TstOperation, - TstOutputSpec, - TstStatement, - TstWhileStatement, -} from "./languages/tst.js"; -import { Bus, Chip, HIGH, Low, LOW } from "./chip/chip.js"; -import { Clock } from "./chip/clock.js"; -import { Output } from "./output.js"; -import { ROM } from "./cpu/memory.js"; -import { CPU } from "./cpu/cpu.js"; - -export abstract class Test { - protected readonly instructions: (IS | TestInstruction)[] = []; - protected _outputList: Output[] = []; - protected _log = ""; - fs: FileSystem = new FileSystem(); - - setFileSystem(fs: FileSystem): this { - this.fs = fs; - return this; - } - - echo(_content: string) { - return undefined; - } - clearEcho() { - return undefined; - } - - async load(_filename: string): Promise { - return undefined; - } - async compareTo(_filename: string): Promise { - return undefined; - } - outputFile(_filename: string): void { - return undefined; - } - outputList(outputs: Output[]): void { - this._outputList = outputs; - } - - addInstruction(instruction: IS | TestInstruction): void { - this.instructions.push(instruction); - } - - reset(): this { - this._steps = (function* (test) { - for (const instruction of test.instructions) { - yield* instruction.steps(test); - } - })(this); - this._step = this._steps.next(); - this._step; //? - this._log = ""; - return this; - } - - private _steps!: IterableIterator; - private _step!: IteratorResult; - - get steps(): Iterator { - if (this._steps === undefined) { - this.reset(); - this._steps = assertExists(this._steps, "Reset did not initialize steps"); - this._step = assertExists(this._step, "Reset did not find first step"); - } - return this._steps; - } - - get currentStep(): IS | TestInstruction | undefined { - return this._step?.value; - } - - get done(): boolean { - return this._step?.done ?? false; - } - - step() { - if (!this._step.done) { - this._step.value.do(this); - this._step = this.steps.next(); - return false; - } - return true; - } - - async run() { - this.reset(); - while (!(await this.step())); - } - - protected readonly breakpoints: Map = new Map(); - addBreakpoint(variable: string, value: number) { - this.breakpoints.set(variable, value); - } - clearBreakpoints() { - this.breakpoints.clear(); - } - - output() { - const values = this._outputList.map((output) => output.print(this)); - this._log += `|${values.join("|")}|\n`; - } - - header() { - const values = this._outputList.map((output) => output.header(this)); - this._log += `|${values.join("|")}|\n`; - } - - log() { - return this._log; - } - - abstract hasVar(variable: string | number): boolean; - abstract getVar(variable: string | number, offset?: number): number | string; - abstract setVar(variable: string, value: number, offset?: number): void; -} - -function isTstLineStatment(line: TstStatement): line is TstLineStatement { - return (line as TstLineStatement).ops !== undefined; -} - -function isTstWhileStatement(line: TstStatement): line is TstWhileStatement { - return (line as TstWhileStatement).condition !== undefined; -} - -function makeLineStatement(line: TstLineStatement) { - const statement = new TestCompoundInstruction(); - statement.span = line.span; - for (const op of line.ops) { - const inst = makeInstruction(op); - if (inst !== undefined) statement.addInstruction(inst); - } - return statement; -} - -function makeInstruction(inst: TstOperation) { - const { op } = inst; - switch (op) { - case "tick": - return new TestTickInstruction(); - case "tock": - return new TestTockInstruction(); - case "ticktock": - return new TestTickTockInstruction(); - case "eval": - return new TestEvalInstruction(); - case "output": - return new TestOutputInstruction(); - case "set": - return new TestSetInstruction(inst.id, inst.value, inst.index); - case "output-list": - return new TestOutputListInstruction(inst.spec); - case "echo": - return new TestEchoInstruction(inst.message); - case "clear-echo": - return new TestClearEchoInstruction(); - case "loadRom": - return new TestLoadROMInstruction(inst.file); - case "load": - case "output-file": - case "compare-to": - return undefined; - default: - checkExhaustive(op, `Unknown tst operation ${op}`); - } -} - -function fill(test: T, tst: Tst): T { - for (const line of tst.lines) { - if (isTstLineStatment(line)) { - test.addInstruction(makeLineStatement(line)); - } else { - const repeat = isTstWhileStatement(line) - ? new TestWhileInstruction( - new Condition( - line.condition.left, - line.condition.right, - line.condition.op - ) - ) - : new TestRepeatInstruction(line.count); - repeat.span = line.span; - test.addInstruction(repeat); - for (const statement of line.statements) { - repeat.addInstruction(makeLineStatement(statement)); - } - } - } - - test.reset(); - - return test; -} - -export class ChipTest extends Test { - private chip: Chip = new Low(); - get chipId(): number { - return this.chip.id; - } - - private clock = Clock.get(); - - static from(tst: Tst): ChipTest { - const test = new ChipTest(); - return fill(test, tst); - } - - with(chip: Chip): this { - this.chip = chip; - return this; - } - - hasVar(variable: string | number): boolean { - if (variable === "time") { - return true; - } - variable = `${variable}`; - // Look up built-in chip state variables - return this.chip.hasIn(variable) || this.chip.hasOut(variable); - } - - getVar(variable: string | number, offset?: number): number | string { - variable = `${variable}`; - if (variable === "time") { - return this.clock.toString(); - } - const pin = this.chip.get(variable, offset); - if (!pin) return 0; - return pin instanceof Bus ? pin.busVoltage : pin.voltage(); - } - - setVar(variable: string, value: number, offset?: number): void { - // Look up built-in chip state variables - const pinOrBus = this.chip.get(variable, offset); - if (pinOrBus instanceof Bus) { - pinOrBus.busVoltage = value; - } else { - pinOrBus?.pull(value === 0 ? LOW : HIGH); - } - } - - eval(): void { - this.chip.eval(); - } - - tick(): void { - this.chip.eval(); - this.clock.tick(); - } - - tock(): void { - this.chip.eval(); - this.clock.tock(); - } - - override async load(filename: string) { - await this.chip.load(this.fs, filename); - } - - override async run() { - this.clock.reset(); - await super.run(); - } -} - -export class CPUTest extends Test { - readonly cpu: CPU; - private ticks = 0; - - static from(tst: Tst, rom?: ROM): CPUTest { - const test = new CPUTest(rom); - return fill(test, tst); - } - - constructor(rom: ROM = new ROM(new Int16Array())) { - super(); - this.cpu = new CPU({ ROM: rom }); - this.reset(); - } - - override reset(): this { - super.reset(); - this.cpu.reset(); - this.ticks = 0; - return this; - } - - hasVar(variable: string | number): boolean { - if (typeof variable === "number") { - return false; - } - // A: Current value of the address register (unsigned 15-bit); - // D: Current value of the data register (16-bit); - // PC: Current value of the Program Counter (unsigned 15-bit); - // RAM[i]: Current value of RAM location i (16-bit); - // time: Number of time units (also called clock cycles, or ticktocks) that elapsed since the simulation started (a read-only system variable). - if ( - variable === "A" || - variable === "D" || - variable === "PC" || - variable === "time" || - variable.startsWith("RAM") - ) { - return true; - } - return false; - } - - getVar(variable: string | number, offset?: number): number { - switch (variable) { - case "A": - return this.cpu.A; - case "D": - return this.cpu.D; - case "PC": - return this.cpu.PC; - case "time": - return this.ticks; - case "RAM": - return offset === undefined ? 0 : this.cpu.RAM.get(offset); - } - if (typeof variable === "number") return 0; - return 0; - } - - setVar(variable: string, value: number, index?: number): void { - // A: Current value of the address register (unsigned 15-bit); - // D: Current value of the data register (16-bit); - // PC: Current value of the Program Counter (unsigned 15-bit); - // RAM[i]: Current value of RAM location i (16-bit); - switch (variable) { - case "A": - this.cpu.setA(value); - break; - case "D": - this.cpu.setD(value); - break; - case "PC": - this.cpu.setPC(value); - break; - case "RAM": - this.cpu.RAM.set(index ?? 0, value); - break; - } - return; - } - - ticktock(): void { - this.ticks += 1; - this.cpu.tick(); - } - - override async load(filename: string): Promise { - await this.cpu.ROM.load(this.fs, filename); - } -} - -export class VMTest extends Test { - hasVar(_variable: string | number): boolean { - return false; - } - getVar(_variable: string | number): number { - return 0; - } - setVar(_variable: string, _value: number): void { - return undefined; - } - vmstep(): void { - return undefined; - } -} - -export interface TestInstruction { - span?: Span; - do(test: Test): void; - steps(test: Test): IterableIterator; -} - -export class TestSetInstruction implements TestInstruction { - constructor( - private variable: string, - private value: number, - private index?: number | undefined - ) {} - - do(test: Test) { - test.setVar(this.variable, this.value, this.index); - } - - *steps() { - yield this; - } -} - -export class TestOutputInstruction implements TestInstruction { - do(test: Test) { - test.output(); - } - - *steps() { - yield this; - } -} - -export class TestOutputListInstruction implements TestInstruction { - private outputs: Output[] = []; - - constructor(specs: TstOutputSpec[] = []) { - for (const spec of specs) { - this.addOutput(spec); - } - } - - addOutput(inst: TstOutputSpec) { - this.outputs.push( - new Output( - inst.id, - inst.style, - inst.width, - inst.lpad, - inst.rpad, - inst.builtin, - inst.address - ) - ); - } - - do(test: Test) { - test.outputList(this.outputs); - test.header(); - } - - *steps() { - yield this; - } -} - -export class TestCompoundInstruction implements TestInstruction { - protected readonly instructions: TestInstruction[] = []; - span?: Span; - - addInstruction(instruction: TestInstruction) { - this.instructions.push(instruction); - } - - do(test: Test): void { - for (const instruction of this.instructions) { - instruction.do(test); - } - } - - *steps(_test: Test): Generator { - yield this; - } -} - -export class TestRepeatInstruction extends TestCompoundInstruction { - constructor(public readonly repeat: number) { - super(); - } - - override do() { - return undefined; - } - - private *innerSteps(test: Test) { - for (const instruction of this.instructions) { - yield* instruction.steps(test); - } - } - - override *steps(test: Test) { - if (this.repeat === -1) { - yield this; - while (true) { - yield* this.innerSteps(test); - } - } else { - for (let i = 0; i < this.repeat; i++) { - yield this; - yield* this.innerSteps(test); - } - } - } -} - -export class Condition { - constructor( - public readonly x: string | number, - public readonly y: string | number, - public readonly op: "<" | "<=" | "=" | ">=" | ">" | "<>" - ) {} - - check(test: Test): boolean { - const x = test.hasVar(this.x) ? test.getVar(this.x) : this.x; - const y = test.hasVar(this.y) ? test.getVar(this.y) : this.y; - - if (typeof x === "string" || typeof y === "string") { - switch (this.op) { - case "=": - return `${x}` === `${y}`; - case "<>": - return `${x}` !== `${y}`; - } - } else { - switch (this.op) { - case "<": - return x < y; - case "<=": - return x <= y; - case ">": - return x > y; - case ">=": - return x >= y; - case "=": - return x === y; - case "<>": - return x !== y; - } - } - return false; - } -} - -export class TestWhileInstruction extends TestCompoundInstruction { - constructor(public readonly condition: Condition) { - super(); - } - - override *steps(test: Test) { - while (this.condition.check(test)) { - yield this; - for (const instruction of this.instructions) { - yield* instruction.steps(test); - } - } - } -} - -export class TestEchoInstruction implements TestInstruction { - constructor(public readonly content: string) {} - do(test: Test) { - test.echo(this.content); - } - - *steps() { - yield this; - } -} - -export class TestClearEchoInstruction implements TestInstruction { - do(test: Test) { - test.clearEcho(); - } - - *steps() { - yield this; - } -} - -export class TestLoadROMInstruction implements TestInstruction { - constructor(readonly file: string) {} - async do(test: Test) { - test.fs.pushd("/test"); - await test.load(this.file); - test.fs.popd(); - } - - *steps() { - yield this; - } -} - -export class TestBreakpointInstruction implements TestInstruction { - constructor(readonly variable: string, readonly value: number) {} - - do(test: Test) { - test.addBreakpoint(this.variable, this.value); - } - - *steps() { - yield this; - } -} - -export class TestClearBreakpointsInstruction implements TestInstruction { - do(test: Test) { - test.clearBreakpoints(); - } - - *steps() { - yield this; - } -} - -export interface ChipTestInstruction extends TestInstruction { - _chipTestInstruction_: true; - do(test: ChipTest): void | Promise; -} - -export class TestEvalInstruction implements ChipTestInstruction { - readonly _chipTestInstruction_ = true; - do(test: ChipTest) { - test.eval(); - } - - *steps() { - yield this; - } -} - -export class TestTickInstruction implements ChipTestInstruction { - readonly _chipTestInstruction_ = true; - do(test: ChipTest) { - test.tick(); - } - - *steps() { - yield this; - } -} - -export class TestTockInstruction implements ChipTestInstruction { - readonly _chipTestInstruction_ = true; - do(test: ChipTest) { - test.tock(); - } - - *steps() { - yield this; - } -} - -export interface CPUTestInstruction extends TestInstruction { - _cpuTestInstruction_: true; - do(test: CPUTest): void | Promise; -} - -export class TestTickTockInstruction implements CPUTestInstruction { - readonly _cpuTestInstruction_ = true; - do(test: CPUTest) { - test.ticktock(); - } - - *steps() { - yield this; - } -} - -export interface VMTestInstruction extends TestInstruction { - _vmTestInstruction_: true; - do(test: VMTest): void | Promise; -} - -export class TestVMStepInstruction implements VMTestInstruction { - readonly _vmTestInstruction_ = true; - do(test: VMTest) { - test.vmstep(); - } - - *steps() { - yield this; - } -} diff --git a/simulator/src/vm/memory.ts b/simulator/src/vm/memory.ts index d444bf66a..a7c606ea2 100644 --- a/simulator/src/vm/memory.ts +++ b/simulator/src/vm/memory.ts @@ -1,5 +1,5 @@ -import { RAM } from "../cpu/memory.js"; -import { Segment } from "./vm.js"; +import { RAM, SubMemory } from "../cpu/memory.js"; +import { Frame, Segment } from "./vm.js"; export const SP = 0; export const LCL = 1; @@ -175,25 +175,28 @@ export class VmMemory extends RAM { } // Stack frame, from figure 8.3, is: // [ARG] Arg0 Arg1... RET LCL ARG THIS THAT [LCL] Local0 Local1... [SP] - pushFrame(ret: number, nArgs: number, nLocals: number) { - const arg = this.SP - nArgs; - let sp = this.SP + 5; - this.set(sp - 5, ret); - this.set(sp - 4, this.LCL); - this.set(sp - 3, this.ARG); - this.set(sp - 2, this.THIS); - this.set(sp - 1, this.THAT); + pushFrame(ret: number, nArgs: number, nLocals: number): number { + const base = this.SP; + const arg = base - nArgs; + this.set(base, ret); + this.set(base + 1, this.LCL); + this.set(base + 2, this.ARG); + this.set(base + 3, this.THIS); + this.set(base + 4, this.THAT); this.set(ARG, arg); - this.set(LCL, sp); + this.set(LCL, base); + let sp = base + 5; // Technically this happens in the function, but the VM will handle it for free for (let i = 0; i < nLocals; i++) { this.set(sp, 0); sp += 1; } this.set(SP, sp); + return base; } + popFrame(): number { const frame = this.LCL; const ret = this.get(frame - 5); @@ -207,6 +210,26 @@ export class VmMemory extends RAM { return ret; } + getFrame( + base: number, // The address of the frame, the RET address + argN: number, // The number of arguments to this frame + localN: number, // The number of locals in this frame + thisN: number, // The number of items in `this` + thatN: number // the number of items in `that` + ): Frame { + return { + args: new SubMemory(this, argN, base - argN), + locals: new SubMemory(this, localN, base - localN), + stack: { + RET: this.get(base), + LCL: this.get(base + 1), + ARG: this.get(base + 2), + THIS: this.get(base + 3), + THAT: this.get(base + 4), + }, + }; + } + binOp(fn: (a: number, b: number) => number) { const a = this.get(this.SP - 2); const b = this.get(this.SP - 1); diff --git a/simulator/src/vm/vm.test.ts b/simulator/src/vm/vm.test.ts index cc06e7a3d..c3a153fd7 100644 --- a/simulator/src/vm/vm.test.ts +++ b/simulator/src/vm/vm.test.ts @@ -1,13 +1,21 @@ import { unwrap } from "@davidsouther/jiffies/lib/esm/result.js"; import { VM } from "../languages/vm.js"; import { Vm } from "./vm.js"; +import { + FIBONACCI, + NESTED_FUNCTION, + SIMPLE_FUNCTION, + STATIC, +} from "@nand2tetris/projects/samples/vm.js"; test("Simple Adder VM", () => { - const vm = Vm.build([ - { op: "push", segment: "constant", offset: 7 }, - { op: "push", segment: "constant", offset: 8 }, - { op: "add" }, - ]); + const vm = unwrap( + Vm.build([ + { op: "push", segment: "constant", offset: 7 }, + { op: "push", segment: "constant", offset: 8 }, + { op: "add" }, + ]) + ); expect(vm.read([0])).toEqual([256]); vm.step(); // push 7 @@ -38,7 +46,7 @@ not test("Bit Ops", () => { const { instructions } = unwrap(VM.parse(BIT_TEST)); - const vm = Vm.build(instructions); + const vm = unwrap(Vm.build(instructions)); for (let i = 0; i < 11; i++) { vm.step(); @@ -91,7 +99,7 @@ not test("07 / Memory Access / Stack Test", () => { const { instructions } = unwrap(VM.parse(STACK_TEST)); - const vm = Vm.build(instructions); + const vm = unwrap(Vm.build(instructions)); for (let i = 0; i < 38; i++) { vm.step(); @@ -135,7 +143,7 @@ add test("07 / Memory Access / Basic Test", () => { const { instructions } = unwrap(VM.parse(BASIC_TEST)); - const vm = Vm.build(instructions); + const vm = unwrap(Vm.build(instructions)); vm.write([ [0, 256], @@ -173,7 +181,7 @@ add test("07 / Memory Access / Pointer Test", () => { const { instructions } = unwrap(VM.parse(POINTER_TEST)); - const vm = Vm.build(instructions); + const vm = unwrap(Vm.build(instructions)); vm.write([ [0, 256], @@ -210,7 +218,7 @@ push local 0 test("08 / Program Flow / Basic Loop", () => { const { instructions } = unwrap(VM.parse(LOOP_TEST)); - const vm = Vm.build(instructions); + const vm = unwrap(Vm.build(instructions)); vm.write([ [0, 256], @@ -271,7 +279,7 @@ label END_PROGRAM test("08 / Program Flow / Fibonacci Series", () => { const { instructions } = unwrap(VM.parse(FIBONACCI_SERIES)); - const vm = Vm.build(instructions); + const vm = unwrap(Vm.build(instructions)); vm.write([ [0, 256], @@ -289,41 +297,9 @@ test("08 / Program Flow / Fibonacci Series", () => { expect(test).toEqual([0, 1, 1, 2, 3, 5]); }); -const SIMPLE_FUNCTION = ` -// __implicit - push constant 3 - push constant 4 - call mult 2 - -// returns x * y as sum i = 0 to y x -// x = arg 0 -// y = arg 1 -// sum = local 0 -// i = local 1 -function mult 2 -label WHILE_LOOP - push local 1 - push argument 1 - lt - not - if-goto WHILE_END - push local 0 - push argument 0 - add - pop local 0 - push local 1 - push constant 1 - add - pop local 1 - goto WHILE_LOOP -label WHILE_END - push local 0 - return -`; - test("08 / Simple Function / Simple Function", () => { const { instructions } = unwrap(VM.parse(SIMPLE_FUNCTION)); - const vm = Vm.build(instructions); + const vm = unwrap(Vm.build(instructions)); vm.write([]); @@ -335,75 +311,9 @@ test("08 / Simple Function / Simple Function", () => { expect(test).toEqual([257, 12]); }); -const NESTED_FUNCTION = ` -// Sys.vm for NestedCall test. - -// Sys.init() -// -// Calls Sys.main() and stores return value in temp 1. -// Does not return. (Enters infinite loop.) - -function Sys.init 0 -push constant 4000 // test THIS and THAT context save -pop pointer 0 -push constant 5000 -pop pointer 1 -call Sys.main 0 -pop temp 1 -label LOOP -goto LOOP - -// Sys.main() -// -// Sets locals 1, 2 and 3, leaving locals 0 and 4 unchanged to test -// default local initialization to 0. (RAM set to -1 by test setup.) -// Calls Sys.add12(123) and stores return value (135) in temp 0. -// Returns local 0 + local 1 + local 2 + local 3 + local 4 (456) to confirm -// that locals were not mangled by function call. - -function Sys.main 5 -push constant 4001 -pop pointer 0 -push constant 5001 -pop pointer 1 -push constant 200 -pop local 1 -push constant 40 -pop local 2 -push constant 6 -pop local 3 -push constant 123 -call Sys.add12 1 -pop temp 0 -push local 0 -push local 1 -push local 2 -push local 3 -push local 4 -add -add -add -add -return - -// Sys.add12(int n) -// -// Returns n+12. - -function Sys.add12 0 -push constant 4002 -pop pointer 0 -push constant 5002 -pop pointer 1 -push argument 0 -push constant 12 -add -return -`; - test("08 / Functions / Nested Function", () => { const { instructions } = unwrap(VM.parse(NESTED_FUNCTION)); - const vm = Vm.build(instructions); + const vm = unwrap(Vm.build(instructions)); const init: [number, number][] = [ [3, -3], @@ -430,42 +340,9 @@ test("08 / Functions / Nested Function", () => { expect(test).toEqual([261, 261, 256, 4000, 5000, 135, 246]); }); -const FIB_MAIN = ` -function Main.fibonacci 0 -push argument 0 -push constant 2 -lt // checks if n<2 -if-goto IF_TRUE -goto IF_FALSE -label IF_TRUE // if n<2, return n -push argument 0 -return -label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) -push argument 0 -push constant 2 -sub -call Main.fibonacci 1 // computes fib(n-2) -push argument 0 -push constant 1 -sub -call Main.fibonacci 1 // computes fib(n-1) -add // returns fib(n-1) + fib(n-2) -return -`; - -const FIB_SYS = ` -function Sys.init 0 -push constant 4 -call Main.fibonacci 1 // computes the 4'th fibonacci element -label WHILE -goto WHILE // loops infinitely -`; - test("08 / Functions / Fib", () => { - const { instructions } = unwrap(VM.parse(FIB_MAIN + FIB_SYS)); - const vm = Vm.build(instructions); - - vm.write([]); + const { instructions } = unwrap(VM.parse(FIBONACCI)); + const vm = unwrap(Vm.build(instructions)); for (let i = 0; i < 1000; i++) { vm.step(); @@ -475,59 +352,9 @@ test("08 / Functions / Fib", () => { expect(test).toEqual([262, 3]); }); -const STATIC_CLASS_1 = `function Class1.set 0 -push argument 0 -pop static 0 -push argument 1 -pop static 1 -push constant 0 -return - -// Returns static[0] - static[1]. -function Class1.get 0 -push static 0 -push static 1 -sub -return -`; -const STATIC_CLASS_2 = `function Class2.set 0 -push argument 0 -pop static 0 -push argument 1 -pop static 1 -push constant 0 -return - -// Returns static[0] - static[1]. -function Class2.get 0 -push static 0 -push static 1 -sub -return -`; - -const STATIC_SYS = `function Sys.init 0 -push constant 6 -push constant 8 -call Class1.set 2 -pop temp 0 // Dumps the return value -push constant 23 -push constant 15 -call Class2.set 2 -pop temp 0 // Dumps the return value -call Class1.get 0 -call Class2.get 0 -label WHILE -goto WHILE -`; - test("08 / Functions / Static", () => { - const { instructions } = unwrap( - VM.parse([STATIC_CLASS_1, STATIC_CLASS_2, STATIC_SYS].join("\n")) - ); - const vm = Vm.build(instructions); - - vm.write([]); + const { instructions } = unwrap(VM.parse(STATIC)); + const vm = unwrap(Vm.build(instructions)); for (let i = 0; i < 1000; i++) { vm.step(); @@ -536,3 +363,12 @@ test("08 / Functions / Static", () => { const test = vm.read([0, 261, 262]); expect(test).toEqual([263, -2, 8]); }); + +describe("debug frame views", () => { + test("top frame", () => { + const { instructions } = unwrap(VM.parse(FIBONACCI)); + const vm = unwrap(Vm.build(instructions)); + + expect(vm.vmStack().length).toBe(1); + }); +}); diff --git a/simulator/src/vm/vm.ts b/simulator/src/vm/vm.ts index df4d1f160..e9ca3e0f9 100644 --- a/simulator/src/vm/vm.ts +++ b/simulator/src/vm/vm.ts @@ -1,6 +1,14 @@ +import { + Err, + Ok, + Result, + isErr, + unwrap, +} from "@davidsouther/jiffies/lib/esm/result.js"; import { FunctionInstruction, VmInstruction } from "../languages/vm.js"; import { VmCompiler } from "./compiler.js"; import { VmMemory } from "./memory.js"; +import { MemoryAdapter, RAM } from "../cpu/memory.js"; export type VmOperation = | StackOperation @@ -50,6 +58,19 @@ export interface GotoOperation { label: string; } +export interface Frame { + fn?: VmFunction; + locals: MemoryAdapter; + args: MemoryAdapter; + stack: { + RET: number; + ARG: number; + LCL: number; + THIS: number; + THAT: number; + }; +} + export type VmFunctions = Record; export interface VmFunction { name: string; @@ -61,6 +82,8 @@ export interface VmFunction { interface VmFunctionInvocation { function: string; op: number; + base: number; + nArgs: number; } const BOOTSTRAP: VmFunction = { @@ -76,8 +99,9 @@ export class Vm { [BOOTSTRAP.name]: BOOTSTRAP, }; protected executionStack: VmFunctionInvocation[] = [ - { function: BOOTSTRAP.name, op: 0 }, + { function: BOOTSTRAP.name, op: 0, base: 256, nArgs: 0 }, ]; + program: VmInstruction[] = []; private staticCount = 0; protected statics: Record = {}; private registerStatic(fnName: string, offset: number): number { @@ -105,8 +129,9 @@ export class Vm { } } - static build(instructions: VmInstruction[]): Vm { + static build(instructions: VmInstruction[]): Result { const vm = new Vm(); + vm.program = instructions; if (instructions[0]?.op !== "function") { instructions.unshift({ op: "function", name: "__implicit", nVars: 0 }); @@ -114,7 +139,10 @@ export class Vm { let i = 0; while (i < instructions.length) { - const [fn, i_] = this.buildFunction(instructions, i); + const buildFn = this.buildFunction(instructions, i); + if (isErr(buildFn)) + return Err(new Error("Failed to build VM", { cause: Err(buildFn) })); + const [fn, i_] = unwrap(buildFn); if (vm.functionMap[fn.name]) throw new Error(`VM Already has a function named ${fn.name}`); if (fn.name === "__implicit") { @@ -140,23 +168,25 @@ export class Vm { }; } else if (vm.functionMap["__implicit"]) { // Use __implicit instead of __bootstrap - vm.executionStack = [{ function: "__implicit", op: 0 }]; + vm.executionStack = [ + { function: "__implicit", op: 0, base: 256, nArgs: 0 }, + ]; } else { - throw new Error("Could not determine an entry point for VM"); + return Err(Error("Could not determine an entry point for VM")); } } vm.registerStatics(); - return vm; + return Ok(vm); } private static buildFunction( instructions: VmInstruction[], i: number - ): [VmFunction, number] { + ): Result<[VmFunction, number]> { if (instructions[i].op !== "function") - throw new Error( - "Only call buildFunction at the initial Function instruction" + return Err( + Error("Only call buildFunction at the initial Function instruction") ); const fn: VmFunction = { name: (instructions[i] as FunctionInstruction).name, @@ -245,7 +275,18 @@ export class Vm { i += 1; } - return [fn, i]; + return Ok([fn, i]); + } + + get RAM(): RAM { + return this.memory; + } + + get Keyboard(): MemoryAdapter { + return this.memory.keyboard; + } + get Screen(): MemoryAdapter { + return this.memory.screen; } get invocation() { @@ -340,8 +381,17 @@ export class Vm { const fnName = operation.name; const fn = this.functionMap[fnName]; if (!fn) throw new Error(`Calling unknown function ${fnName}`); - this.memory.pushFrame(this.invocation.op, operation.nArgs, fn.nVars); - this.executionStack.push({ function: fnName, op: -1 }); + const base = this.memory.pushFrame( + this.invocation.op, + operation.nArgs, + fn.nVars + ); + this.executionStack.push({ + function: fnName, + op: -1, + nArgs: operation.nArgs, + base, + }); break; } case "return": { @@ -379,4 +429,19 @@ export class Vm { compiler(): VmCompiler { return new VmCompiler(this.functionMap); } + + vmStack(): Frame[] { + return this.executionStack.map((invocation) => { + const fn = this.functionMap[invocation.function]; + const frame = this.memory.getFrame( + invocation.base, + invocation.nArgs, + fn.nVars, + 0, + 0 + ); + frame.fn = fn; + return frame; + }); + } } diff --git a/tsconfig.base.json b/tsconfig.base.json index 11366daac..9c6ece3db 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -4,7 +4,7 @@ "composite": true, // Assume browser environment & esm - "lib": ["es2021", "DOM", "DOM.Iterable"], + "lib": ["es2022", "DOM", "DOM.Iterable"], "target": "es2022", "module": "ESNext", "moduleResolution": "node", diff --git a/web/src/App.tsx b/web/src/App.tsx index 2d3417a0d..a4aa9d9c6 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -30,6 +30,7 @@ import "./pico/flex.scss"; import "./pico/pico.scss"; import "./pico/tooltip.scss"; import { TrackingBanner } from "./tracking"; +import { ErrorBoundary, RenderError } from "./ErrorBoundary"; i18n.load("en", messages.messages); i18n.load("en-PL", plMessages.messages); @@ -69,21 +70,23 @@ function App() {
- Loading...}> - - - } - /> - {Object.values(urls).map(({ href, target }) => ( - - ))} - - + + Loading...}> + + + } + /> + {Object.values(urls).map(({ href, target }) => ( + + ))} + + +
diff --git a/web/src/ErrorBoundary.tsx b/web/src/ErrorBoundary.tsx new file mode 100644 index 000000000..541c5830e --- /dev/null +++ b/web/src/ErrorBoundary.tsx @@ -0,0 +1,60 @@ +import { Component, PropsWithChildren, ReactElement } from "react"; + +type ErrorBoundaryProps = PropsWithChildren & { + fallback: (_: { error?: Error }) => ReactElement; +}; + +export class ErrorBoundary extends Component< + ErrorBoundaryProps, + { hasError: boolean; error?: Error } +> { + constructor(props: ErrorBoundaryProps) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError(error: unknown) { + // Update state so the next render will show the fallback UI. + return { + hasError: true, + error, + }; + } + + override render() { + if (this.state.hasError) { + // You can render any custom fallback UI + return this.props.fallback({ + error: this.state.error, + }); + } + + return this.props.children; + } +} + +export const RenderError = ({ error }: { error?: Error }) => + error ? ( +
+

+ {error.name ?? "Error"}: {error.message} +

+ {error.stack && ( +
+          {error.stack}
+        
+ )} + {error.cause ? ( + <> +
+ Caused by +
+ + + ) : ( + <> + )} +
+ ) : ( +

Unknown Error

+ ); diff --git a/web/src/pages/vm.tsx b/web/src/pages/vm.tsx index 20b302be6..89ec6af7e 100644 --- a/web/src/pages/vm.tsx +++ b/web/src/pages/vm.tsx @@ -1,9 +1,175 @@ -const VM = () => ( -
-
-

VM

-
-
-); +import * as VMLang from "@nand2tetris/simulator/languages/vm.js"; +import { Keyboard } from "@nand2tetris/components/chips/keyboard.js"; +import { MemoryBlock } from "@nand2tetris/components/chips/memory.js"; +import { Screen } from "@nand2tetris/components/chips/screen.js"; +import { useVmPageStore } from "@nand2tetris/components/stores/vm.store.js"; +import { Timer } from "@nand2tetris/simulator/timer.js"; +import { useEffect, useRef, useState } from "react"; +import { Panel } from "../shell/panel"; +import { TestPanel } from "../shell/test_panel"; + +const VM = () => { + const { state, actions, dispatch } = useVmPageStore(); + + const [tst, setTst] = useState("repeat {\n\tticktock;\n}"); + const [out, setOut] = useState(""); + const [cmp, setCmp] = useState(""); + + const runner = useRef(); + useEffect(() => { + runner.current = new (class ChipTimer extends Timer { + override tick() { + actions.step(); + return false; + } + + override finishFrame() { + dispatch.current({ action: "update" }); + } + + override reset() { + actions.reset(); + } + + override toggle() { + dispatch.current({ action: "update" }); + } + })(); + + return () => { + runner.current?.stop(); + }; + }, [actions, dispatch]); + + return ( +
+ +
+ + + + + + + + + + {state.vm.Prog.map((inst, key) => + VMInstructionRow({ inst, key }) + )} + +
InstTargetVal
+
+
+ +
+ +
+ + +
+ {state.vm.Stack.map((frame, i) => ( +
+
+

+ Function + {frame.fn?.name ?? "Unknown Function"} +

+
+
+ {frame.args.size > 0 ? ( + + ) : ( +

No Args

+ )} + {frame.locals.size > 0 ? ( + + ) : ( +

No Locals

+ )} +
+
+ ))} +
+
+ +
+ ); +}; export default VM; + +export function VMInstructionRow({ + inst, + key, +}: { + inst: VMLang.VmInstruction; + key: number; +}) { + switch (inst.op) { + case "add": + case "and": + case "eq": + case "gt": + case "lt": + case "neg": + case "not": + case "or": + case "sub": + case "return": + return ( + + {inst.op} + + + ); + + case "if-goto": + case "label": + case "goto": + return ( + + {inst.op} + {inst.label} + + ); + case "function": + case "call": + return ( + + {inst.op} + {inst.name} + {inst.op === "call" ? inst.nArgs : inst.nVars} + + ); + case "pop": + case "push": + return ( + + {inst.op} + {inst.segment} + {inst.offset} + + ); + default: + return ( + + Unknown + + ); + } +} diff --git a/web/src/urls.tsx b/web/src/urls.tsx index ae6c20d62..c0e79d8be 100644 --- a/web/src/urls.tsx +++ b/web/src/urls.tsx @@ -5,6 +5,7 @@ const Chip = lazy(() => import("./pages/chip")); const CPU = lazy(() => import("./pages/cpu")); const ASM = lazy(() => import("./pages/asm")); const BITMAP = lazy(() => import("./pages/bitmap")); +const VM = lazy(() => import("./pages/vm")); const Util = lazy(() => import("./pages/util")); const Guide = lazy(() => import("./pages/user_guide")); const About = lazy(() => import("./pages/about")); @@ -15,6 +16,7 @@ export const TOOLS: Record = { chip: "Hardware Simulator", cpu: "CPU Emulator", asm: "Assembler", + VM: "VM Emulator", bitmap: "Bitmap Editor", }; @@ -56,6 +58,7 @@ const URLs = { icon: "menu_book", target: , }, + vm: { href: "/vm", link: `VM`, icon: "computer", target: }, about: { href: "/about", tooltip: t`About`, icon: "info", target: }, }; From ef5833f0b05db9c31a2d20d1b19f2fa8397b4bbc Mon Sep 17 00:00:00 2001 From: David Souther Date: Sun, 12 Nov 2023 09:22:25 -0500 Subject: [PATCH 05/14] Add text frame debugger and corrected errors in __bootstrap init --- simulator/src/cpu/memory.ts | 19 +++- simulator/src/vm/memory.ts | 43 +++++--- simulator/src/vm/vm.test.ts | 4 +- simulator/src/vm/vm.ts | 205 +++++++++++++++++++++++++++++------- 4 files changed, 210 insertions(+), 61 deletions(-) diff --git a/simulator/src/cpu/memory.ts b/simulator/src/cpu/memory.ts index 39268a07d..a230f701e 100644 --- a/simulator/src/cpu/memory.ts +++ b/simulator/src/cpu/memory.ts @@ -3,7 +3,6 @@ import { FileSystem } from "@davidsouther/jiffies/lib/esm/fs.js"; import { op } from "../util/asm.js"; import { int10, int16, int2 } from "../util/twos.js"; import { load } from "../fs.js"; -import { Screen } from "../chip/builtins/computer/computer.js"; export const FORMATS = ["bin", "dec", "hex", "asm"]; export type Format = typeof FORMATS[number]; @@ -28,6 +27,7 @@ export interface MemoryAdapter { start?: number, end?: number ): Iterable; + [Symbol.iterator](): Iterable; } export interface KeyboardAdapter { @@ -118,11 +118,15 @@ export class Memory implements MemoryAdapter { start = 0, end = this.size ): Iterable { - assert(start < end); + assert(start <= end); for (let i = start; i < end; i++) { yield fn(i, this.get(i)); } } + + [Symbol.iterator](): Iterable { + return this.map((_, v) => v); + } } export class SubMemory implements MemoryAdapter { @@ -168,12 +172,17 @@ export class SubMemory implements MemoryAdapter { range(start?: number, end?: number): number[] { return this.parent.range(start, end); } + map( fn: (index: number, value: number) => T, - start?: number, - end?: number + start = 0, + end: number = this.size ): Iterable { - return this.parent.map(fn, start, end); + return this.parent.map(fn, start + this.offset, end + this.offset); + } + + [Symbol.iterator](): Iterable { + return this.map((_, v) => v); } } diff --git a/simulator/src/vm/memory.ts b/simulator/src/vm/memory.ts index a7c606ea2..8e3555bee 100644 --- a/simulator/src/vm/memory.ts +++ b/simulator/src/vm/memory.ts @@ -1,5 +1,5 @@ -import { RAM, SubMemory } from "../cpu/memory.js"; -import { Frame, Segment } from "./vm.js"; +import { RAM } from "../cpu/memory.js"; +import { VmFrame, Segment } from "./vm.js"; export const SP = 0; export const LCL = 1; @@ -185,15 +185,14 @@ export class VmMemory extends RAM { this.set(base + 4, this.THAT); this.set(ARG, arg); - this.set(LCL, base); + this.set(LCL, base + 5); - let sp = base + 5; + const sp = base + 5; // Technically this happens in the function, but the VM will handle it for free for (let i = 0; i < nLocals; i++) { - this.set(sp, 0); - sp += 1; + this.set(sp + 1, 0); } - this.set(SP, sp); + this.set(SP, sp + nLocals); return base; } @@ -215,17 +214,29 @@ export class VmMemory extends RAM { argN: number, // The number of arguments to this frame localN: number, // The number of locals in this frame thisN: number, // The number of items in `this` - thatN: number // the number of items in `that` - ): Frame { + thatN: number, // the number of items in `that` + nextFrame: number + ): VmFrame { + const arg = base - argN; + const lcl = base + 5; + const stk = lcl + localN; + const stackN = nextFrame - stk; + const args = [...this.map((_, v) => v, arg, arg + argN)]; + const locals = [...this.map((_, v) => v, lcl, lcl + localN)]; + const stack = [...this.map((_, v) => v, stk, stk + stackN)]; + // [arg, argN, args]; //? + // [lcl, localN, locals]; //? + // [stk, stackN, stack]; //? return { - args: new SubMemory(this, argN, base - argN), - locals: new SubMemory(this, localN, base - localN), - stack: { + args: { base: arg, count: argN, values: args }, + locals: { base: lcl, count: localN, values: locals }, + stack: { base: stk, count: stackN, values: stack }, + frame: { RET: this.get(base), - LCL: this.get(base + 1), - ARG: this.get(base + 2), - THIS: this.get(base + 3), - THAT: this.get(base + 4), + LCL: this.LCL, + ARG: this.ARG, + THIS: this.THIS, + THAT: this.THAT, }, }; } diff --git a/simulator/src/vm/vm.test.ts b/simulator/src/vm/vm.test.ts index c3a153fd7..da3cdc54d 100644 --- a/simulator/src/vm/vm.test.ts +++ b/simulator/src/vm/vm.test.ts @@ -307,6 +307,8 @@ test("08 / Simple Function / Simple Function", () => { vm.step(); } + vm.program; //? + const test = vm.read([0, 256]); expect(test).toEqual([257, 12]); }); @@ -337,7 +339,7 @@ test("08 / Functions / Nested Function", () => { } const test = vm.read([0, 1, 2, 3, 4, 5, 6]); - expect(test).toEqual([261, 261, 256, 4000, 5000, 135, 246]); + expect(test).toEqual([261, 261, 256, 4000, 5000, 135, 244]); }); test("08 / Functions / Fib", () => { diff --git a/simulator/src/vm/vm.ts b/simulator/src/vm/vm.ts index e9ca3e0f9..5c7a64cca 100644 --- a/simulator/src/vm/vm.ts +++ b/simulator/src/vm/vm.ts @@ -6,11 +6,11 @@ import { unwrap, } from "@davidsouther/jiffies/lib/esm/result.js"; import { FunctionInstruction, VmInstruction } from "../languages/vm.js"; -import { VmCompiler } from "./compiler.js"; import { VmMemory } from "./memory.js"; import { MemoryAdapter, RAM } from "../cpu/memory.js"; export type VmOperation = + | FunctionOperation | StackOperation | OpOperation | CallOperation @@ -33,6 +33,12 @@ export type CmpOp = "lt" | "gt" | "eq"; export type UnOp = "neg" | "not"; export type Op = BinOp | CmpOp | UnOp; +export interface FunctionOperation { + op: "function"; + name: string; + nVars: number; +} + export interface StackOperation { op: "push" | "pop"; segment: Segment; @@ -58,11 +64,18 @@ export interface GotoOperation { label: string; } -export interface Frame { +interface VmFrameValues { + base: number; + count: number; + values: number[]; +} + +export interface VmFrame { fn?: VmFunction; - locals: MemoryAdapter; - args: MemoryAdapter; - stack: { + locals: VmFrameValues; + args: VmFrameValues; + stack: VmFrameValues; + frame: { RET: number; ARG: number; LCL: number; @@ -77,20 +90,28 @@ export interface VmFunction { nVars: number; labels: Record; operations: VmOperation[]; + opBase: number; } interface VmFunctionInvocation { function: string; - op: number; - base: number; + // The current operation offset in the function + opPtr: number; + // Base address of the frame in memory + frameBase: number; + // The number of args the function was called with nArgs: number; } const BOOTSTRAP: VmFunction = { name: "__bootstrap", nVars: 0, + opBase: 0, labels: {}, - operations: [{ op: "call", name: "Sys.init", nArgs: 0 }], + operations: [ + { op: "function", name: "__bootstrap", nVars: 0 }, + { op: "call", name: "Sys.init", nArgs: 0 }, + ], }; export class Vm { @@ -99,11 +120,15 @@ export class Vm { [BOOTSTRAP.name]: BOOTSTRAP, }; protected executionStack: VmFunctionInvocation[] = [ - { function: BOOTSTRAP.name, op: 0, base: 256, nArgs: 0 }, + { function: BOOTSTRAP.name, opPtr: 1, frameBase: 256, nArgs: 0 }, ]; - program: VmInstruction[] = []; + + functions: VmFunction[] = []; + program: VmOperation[] = []; + private staticCount = 0; protected statics: Record = {}; + private registerStatic(fnName: string, offset: number): number { const fileName = fnName.split(".")[0]; const statics = this.statics[fileName] ?? []; @@ -131,7 +156,6 @@ export class Vm { static build(instructions: VmInstruction[]): Result { const vm = new Vm(); - vm.program = instructions; if (instructions[0]?.op !== "function") { instructions.unshift({ op: "function", name: "__implicit", nVars: 0 }); @@ -161,6 +185,7 @@ export class Vm { name: "Sys.init", labels: { END: 1 }, nVars: 0, + opBase: 0, operations: [ { op: "call", name: "main", nArgs: 0 }, { op: "goto", label: "END" }, @@ -169,14 +194,30 @@ export class Vm { } else if (vm.functionMap["__implicit"]) { // Use __implicit instead of __bootstrap vm.executionStack = [ - { function: "__implicit", op: 0, base: 256, nArgs: 0 }, + { function: "__implicit", opPtr: 1, frameBase: 256, nArgs: 0 }, ]; + delete vm.functionMap["__bootstrap"]; } else { return Err(Error("Could not determine an entry point for VM")); } } vm.registerStatics(); + + vm.functions = Object.values(vm.functionMap); + vm.functions.sort((a, b) => { + if (a.name === "__implicit" || a.name === "__bootstrap") return -1; + if (b.name === "__implicit" || b.name === "__bootstrap") return 1; + return a.name.localeCompare(b.name); + }); + + let offset = 0; + vm.program = vm.functions.reduce((prog, fn) => { + fn.opBase = offset; + offset += fn.operations.length; + return prog.concat(fn.operations); + }, [] as VmOperation[]); + return Ok(vm); } @@ -188,11 +229,13 @@ export class Vm { return Err( Error("Only call buildFunction at the initial Function instruction") ); + const { name, nVars } = instructions[i] as FunctionInstruction; const fn: VmFunction = { - name: (instructions[i] as FunctionInstruction).name, - nVars: (instructions[i] as FunctionInstruction).nVars, + name, + nVars, labels: {}, - operations: [], + operations: [{ op: "function", name, nVars }], + opBase: 0, }; i += 1; @@ -305,12 +348,12 @@ export class Vm { } get operation() { - if (this.invocation.op > this.currentFunction.operations.length) + if (this.invocation.opPtr > this.currentFunction.operations.length) throw new Error( - `Current operation step beyond end of function operations (${this.invocation.op} > ${this.currentFunction.operations.length})` + `Current operation step beyond end of function operations (${this.invocation.opPtr} > ${this.currentFunction.operations.length})` ); - return this.currentFunction.operations[this.invocation.op]; + return this.currentFunction.operations[this.invocation.opPtr]; } step() { @@ -382,22 +425,22 @@ export class Vm { const fn = this.functionMap[fnName]; if (!fn) throw new Error(`Calling unknown function ${fnName}`); const base = this.memory.pushFrame( - this.invocation.op, + this.invocation.opPtr, operation.nArgs, fn.nVars ); this.executionStack.push({ function: fnName, - op: -1, + opPtr: 0, nArgs: operation.nArgs, - base, + frameBase: base, }); break; } case "return": { this.executionStack.pop(); const ret = this.memory.popFrame(); - this.invocation.op = ret; + this.invocation.opPtr = ret; break; } case "label": { @@ -405,7 +448,7 @@ export class Vm { break; } } - this.invocation.op += 1; + this.invocation.opPtr += 1; } private goto(label: string) { @@ -413,7 +456,7 @@ export class Vm { throw new Error( `Attempting GOTO to unknown label ${label} in ${this.currentFunction.name}` ); - this.invocation.op = this.currentFunction.labels[label]; + this.invocation.opPtr = this.currentFunction.labels[label]; } write(addresses: [number, number][]) { @@ -426,22 +469,106 @@ export class Vm { return addresses.map((address) => this.memory.get(address)); } - compiler(): VmCompiler { - return new VmCompiler(this.functionMap); + vmStack(): VmFrame[] { + return this.executionStack.map((invocation, i) => { + const next = this.executionStack[i + 1]; + const end = next ? next.frameBase - next.nArgs : this.memory.get(0); + return this.makeFrame(invocation, end); + }); } - vmStack(): Frame[] { - return this.executionStack.map((invocation) => { - const fn = this.functionMap[invocation.function]; - const frame = this.memory.getFrame( - invocation.base, - invocation.nArgs, - fn.nVars, - 0, - 0 - ); - frame.fn = fn; - return frame; - }); + makeFrame(invocation = this.invocation, nextFrame: number): VmFrame { + const fn = this.functionMap[invocation.function]; + if (["__implicit", "__bootstrap"].includes(fn.name)) { + // top most frame is "special" + const stackN = this.memory.get(0) - 256; + return { + fn, + args: { base: 256, count: 0, values: [] }, + locals: { base: 256, count: 0, values: [] }, + stack: { + base: 256, + count: stackN, + values: [...this.memory.map((_, v) => v, 256, 256 + stackN)], + }, + frame: { + ARG: 0, + LCL: 0, + RET: 0, + THAT: 0, + THIS: 0, + }, + }; + } + const frame = this.memory.getFrame( + invocation.frameBase, + invocation.nArgs, + fn.nVars, + 0, + 0, + nextFrame + ); + frame.fn = fn; + return frame; + } + + writeDebug(): string { + const line = this.currentFunction.opBase + this.invocation.opPtr; + const from = Math.max(line - 5, 0); + const to = Math.min(line + 3, this.program.length); + const lines = this.program.slice(from, to); + const prog = lines + .map((op, i) => `${i === line - from ? "->" : " "} ${writeOp(op)}`) + .join("\n"); + const frame = this.vmStack().at(-1); + if (frame) { + return prog + "\n\n" + writeFrame(frame); + } + return prog; + } +} + +export function writeFrame(frame: VmFrame): string { + return [ + `Frame: ${frame.fn?.name ?? "Unknown Fn"} ARG:${frame.frame.ARG} LCL:${ + frame.frame.LCL + }`, + `Args: ${writeFrameValues(frame.args)}`, + `Lcls: ${writeFrameValues(frame.locals)}`, + `Stck: ${writeFrameValues(frame.stack)}`, + ].join("\n"); +} + +function writeFrameValues(fv: VmFrameValues): string { + return `[${fv.base};${fv.count}][${fv.values.join(", ")}]`; +} + +function writeOp(op: VmOperation): string { + switch (op.op) { + case "add": + case "and": + case "sub": + case "eq": + case "gt": + case "lt": + case "neg": + case "not": + case "or": + case "return": + return ` ${op.op}`; + case "goto": + return ` ${op.op} ${op.label}`; + case "if-goto": + return ` ${op.op} ${op.label}`; + case "label": + return `${op.op} ${op.label}`; + case "call": + return ` ${op.op} ${op.name} ${op.nArgs}`; + case "function": + return `${op.op} ${op.name} ${op.nVars}`; + case "pop": + return ` ${op.op} ${op.segment} ${op.offset}`; + case "push": + return ` ${op.op} ${op.segment} ${op.offset}`; } } From 02672c8f940b65cee61907baa2200842b2bb4769 Mon Sep 17 00:00:00 2001 From: David Souther Date: Sun, 12 Nov 2023 10:18:38 -0500 Subject: [PATCH 06/14] Show stack and highlighted line in VM page --- components/src/stores/vm.store.ts | 9 ++++--- simulator/src/vm/vm.ts | 16 +++++++++--- web/src/pages/vm.scss | 7 ++++++ web/src/pages/vm.tsx | 42 ++++++++++++++++++------------- web/src/pico/pico.scss | 3 +-- 5 files changed, 50 insertions(+), 27 deletions(-) create mode 100644 web/src/pages/vm.scss diff --git a/components/src/stores/vm.store.ts b/components/src/stores/vm.store.ts index 92d2dfdd9..3c22eab5b 100644 --- a/components/src/stores/vm.store.ts +++ b/components/src/stores/vm.store.ts @@ -13,14 +13,14 @@ import { VMTest } from "@nand2tetris/simulator/test/vmtst.js"; import { VM, VmInstruction } from "@nand2tetris/simulator/languages/vm.js"; import { ImmMemory } from "./imm_memory.js"; import { unwrap } from "@davidsouther/jiffies/lib/esm/result.js"; -import { Frame, Vm } from "@nand2tetris/simulator/vm/vm.js"; +import { VmFrame, Vm } from "@nand2tetris/simulator/vm/vm.js"; import { Span } from "@nand2tetris/simulator/languages/base.js"; export interface VmSim { RAM: MemoryAdapter; Screen: MemoryAdapter; Keyboard: KeyboardAdapter; - Stack: Frame[]; + Stack: VmFrame[]; Prog: VmInstruction[]; highlight: number; } @@ -55,14 +55,15 @@ function reduceVMTest( const Keyboard = new MemoryKeyboard( new ImmMemory(vmTest.vm.Keyboard, dispatch) ); + const highlight = vmTest.vm.derivedLine(); return { Keyboard, RAM, Screen, - Stack: vmTest.vm.vmStack(), + Stack: vmTest.vm.vmStack().reverse(), Prog: vmTest.vm.program, - highlight: -1, + highlight, }; } diff --git a/simulator/src/vm/vm.ts b/simulator/src/vm/vm.ts index 5c7a64cca..970af1b9f 100644 --- a/simulator/src/vm/vm.ts +++ b/simulator/src/vm/vm.ts @@ -481,15 +481,19 @@ export class Vm { const fn = this.functionMap[invocation.function]; if (["__implicit", "__bootstrap"].includes(fn.name)) { // top most frame is "special" - const stackN = this.memory.get(0) - 256; + const frameBase = 256; + const nextFrame = this.executionStack[1]; + const frameEnd = nextFrame + ? nextFrame.frameBase - nextFrame.nArgs + : this.memory.get(0); return { fn, args: { base: 256, count: 0, values: [] }, locals: { base: 256, count: 0, values: [] }, stack: { base: 256, - count: stackN, - values: [...this.memory.map((_, v) => v, 256, 256 + stackN)], + count: frameEnd - frameBase, + values: [...this.memory.map((_, v) => v, frameBase, frameEnd)], }, frame: { ARG: 0, @@ -512,8 +516,12 @@ export class Vm { return frame; } + derivedLine(): number { + return this.currentFunction.opBase + this.invocation.opPtr; + } + writeDebug(): string { - const line = this.currentFunction.opBase + this.invocation.opPtr; + const line = this.derivedLine(); const from = Math.max(line - 5, 0); const to = Math.min(line + 3, this.program.length); const lines = this.program.slice(from, to); diff --git a/web/src/pages/vm.scss b/web/src/pages/vm.scss new file mode 100644 index 000000000..09ea42359 --- /dev/null +++ b/web/src/pages/vm.scss @@ -0,0 +1,7 @@ +tbody { + font-family: var(--font-family-monospace); +} + +tr.highlight { + background-color: antiquewhite; +} diff --git a/web/src/pages/vm.tsx b/web/src/pages/vm.tsx index 89ec6af7e..45a9e32f3 100644 --- a/web/src/pages/vm.tsx +++ b/web/src/pages/vm.tsx @@ -1,12 +1,12 @@ import * as VMLang from "@nand2tetris/simulator/languages/vm.js"; import { Keyboard } from "@nand2tetris/components/chips/keyboard.js"; -import { MemoryBlock } from "@nand2tetris/components/chips/memory.js"; import { Screen } from "@nand2tetris/components/chips/screen.js"; import { useVmPageStore } from "@nand2tetris/components/stores/vm.store.js"; import { Timer } from "@nand2tetris/simulator/timer.js"; import { useEffect, useRef, useState } from "react"; import { Panel } from "../shell/panel"; import { TestPanel } from "../shell/test_panel"; +import "./vm.scss"; const VM = () => { const { state, actions, dispatch } = useVmPageStore(); @@ -55,7 +55,11 @@ const VM = () => { {state.vm.Prog.map((inst, key) => - VMInstructionRow({ inst, key }) + VMInstructionRow({ + inst, + key, + highlighted: key === state.vm.highlight, + }) )} @@ -85,16 +89,18 @@ const VM = () => {
- {frame.args.size > 0 ? ( - - ) : ( -

No Args

- )} - {frame.locals.size > 0 ? ( - - ) : ( -

No Locals

- )} +

+ Args: + [{frame.args.values.join(", ")}] +

+

+ Locals: + [{frame.locals.values.join(", ")}] +

+

+ Stack: + [{frame.stack.values.join(", ")}] +

))} @@ -116,9 +122,11 @@ export default VM; export function VMInstructionRow({ inst, key, + highlighted, }: { inst: VMLang.VmInstruction; key: number; + highlighted: boolean; }) { switch (inst.op) { case "add": @@ -132,7 +140,7 @@ export function VMInstructionRow({ case "sub": case "return": return ( - + {inst.op} @@ -142,7 +150,7 @@ export function VMInstructionRow({ case "label": case "goto": return ( - + {inst.op} {inst.label} @@ -150,7 +158,7 @@ export function VMInstructionRow({ case "function": case "call": return ( - + {inst.op} {inst.name} {inst.op === "call" ? inst.nArgs : inst.nVars} @@ -159,7 +167,7 @@ export function VMInstructionRow({ case "pop": case "push": return ( - + {inst.op} {inst.segment} {inst.offset} @@ -167,7 +175,7 @@ export function VMInstructionRow({ ); default: return ( - + Unknown ); diff --git a/web/src/pico/pico.scss b/web/src/pico/pico.scss index c059fdfc0..46cd0902a 100644 --- a/web/src/pico/pico.scss +++ b/web/src/pico/pico.scss @@ -150,8 +150,7 @@ } } - nav ol, - nav ul { + nav :is(ol, ul) { margin-right: 0; } From 982a16a3c4143eeceeb3e00c7b1e21b95e0fa52e Mon Sep 17 00:00:00 2001 From: David Souther Date: Sun, 12 Nov 2023 10:46:19 -0500 Subject: [PATCH 07/14] Use consistent "Page" style --- components/src/stores/vm.store.ts | 15 ++++-- simulator/src/vm/vm.ts | 79 ++++++++++++++++++++----------- web/src/pages/chip.scss | 16 +------ web/src/pages/chip.tsx | 2 +- web/src/pages/cpu.scss | 12 +---- web/src/pages/cpu.tsx | 2 +- web/src/pages/page.scss | 17 +++++++ web/src/pages/vm.scss | 14 ++++-- web/src/pages/vm.tsx | 7 ++- 9 files changed, 97 insertions(+), 67 deletions(-) create mode 100644 web/src/pages/page.scss diff --git a/components/src/stores/vm.store.ts b/components/src/stores/vm.store.ts index 3c22eab5b..0a4192a91 100644 --- a/components/src/stores/vm.store.ts +++ b/components/src/stores/vm.store.ts @@ -76,11 +76,12 @@ export function makeVmStore( const parsed = unwrap(VM.parse(FIBONACCI)); const vm = unwrap(Vm.build(parsed.instructions)); const test = new VMTest().with(vm); - let useTest = true; + let useTest = false; const reducers = { update(state: VmPageState) { state.vm = reduceVMTest(test, dispatch); state.test.useTest = useTest; + state.test.highlight = test.currentStep?.span; }, }; const initialState: VmPageState = { @@ -96,13 +97,21 @@ export function makeVmStore( }; const actions = { step() { - vm.step(); + if (useTest) { + test.step(); + } else { + vm.step(); + } + dispatch.current({ action: "update" }); }, reset() { - //todo + test.reset(); + vm.reset(); + dispatch.current({ action: "update" }); }, toggleUseTest() { useTest = !useTest; + dispatch.current({ action: "update" }); }, }; diff --git a/simulator/src/vm/vm.ts b/simulator/src/vm/vm.ts index 970af1b9f..78038f9b9 100644 --- a/simulator/src/vm/vm.ts +++ b/simulator/src/vm/vm.ts @@ -103,6 +103,14 @@ interface VmFunctionInvocation { nArgs: number; } +const IMPLICIT: VmFunction = { + name: "__implicit", + nVars: 0, + opBase: 0, + labels: {}, + operations: [{ op: "function", name: "__implicit", nVars: 0 }], +}; + const BOOTSTRAP: VmFunction = { name: "__bootstrap", nVars: 0, @@ -114,14 +122,27 @@ const BOOTSTRAP: VmFunction = { ], }; +const END_LABEL = "__END"; +const SYS_INIT: VmFunction = { + name: "Sys.init", + labels: { END: 1 }, + nVars: 0, + opBase: 0, + operations: [ + { op: "call", name: "main", nArgs: 0 }, + { op: "label", label: END_LABEL }, + { op: "goto", label: END_LABEL }, + ], +}; + +const INITIAL_FNS = [BOOTSTRAP.name, IMPLICIT.name]; + export class Vm { protected memory = new VmMemory(); protected functionMap: Record = { [BOOTSTRAP.name]: BOOTSTRAP, }; - protected executionStack: VmFunctionInvocation[] = [ - { function: BOOTSTRAP.name, opPtr: 1, frameBase: 256, nArgs: 0 }, - ]; + protected executionStack: VmFunctionInvocation[] = []; functions: VmFunction[] = []; program: VmOperation[] = []; @@ -158,45 +179,30 @@ export class Vm { const vm = new Vm(); if (instructions[0]?.op !== "function") { - instructions.unshift({ op: "function", name: "__implicit", nVars: 0 }); + instructions.unshift({ op: "function", name: IMPLICIT.name, nVars: 0 }); } let i = 0; while (i < instructions.length) { const buildFn = this.buildFunction(instructions, i); + if (isErr(buildFn)) return Err(new Error("Failed to build VM", { cause: Err(buildFn) })); const [fn, i_] = unwrap(buildFn); if (vm.functionMap[fn.name]) throw new Error(`VM Already has a function named ${fn.name}`); - if (fn.name === "__implicit") { - fn.labels["__END"] = fn.operations.length; - fn.operations.push({ op: "label", label: "__END" }); - fn.operations.push({ op: "goto", label: "__END" }); - } + vm.functionMap[fn.name] = fn; i = i_; } - if (!vm.functionMap["Sys.init"]) { + if (!vm.functionMap[SYS_INIT.name]) { if (vm.functionMap["main"]) { // Inject a Sys.init - vm.functionMap["Sys.init"] = { - name: "Sys.init", - labels: { END: 1 }, - nVars: 0, - opBase: 0, - operations: [ - { op: "call", name: "main", nArgs: 0 }, - { op: "goto", label: "END" }, - ], - }; - } else if (vm.functionMap["__implicit"]) { + vm.functionMap[SYS_INIT.name] = SYS_INIT; + } else if (vm.functionMap[IMPLICIT.name]) { // Use __implicit instead of __bootstrap - vm.executionStack = [ - { function: "__implicit", opPtr: 1, frameBase: 256, nArgs: 0 }, - ]; - delete vm.functionMap["__bootstrap"]; + delete vm.functionMap[BOOTSTRAP.name]; } else { return Err(Error("Could not determine an entry point for VM")); } @@ -206,8 +212,8 @@ export class Vm { vm.functions = Object.values(vm.functionMap); vm.functions.sort((a, b) => { - if (a.name === "__implicit" || a.name === "__bootstrap") return -1; - if (b.name === "__implicit" || b.name === "__bootstrap") return 1; + if (INITIAL_FNS.includes(a.name)) return -1; + if (INITIAL_FNS.includes(b.name)) return 1; return a.name.localeCompare(b.name); }); @@ -218,6 +224,7 @@ export class Vm { return prog.concat(fn.operations); }, [] as VmOperation[]); + vm.reset(); return Ok(vm); } @@ -229,6 +236,7 @@ export class Vm { return Err( Error("Only call buildFunction at the initial Function instruction") ); + const { name, nVars } = instructions[i] as FunctionInstruction; const fn: VmFunction = { name, @@ -318,6 +326,12 @@ export class Vm { i += 1; } + if (fn.name === IMPLICIT.name) { + fn.labels[END_LABEL] = fn.operations.length; + fn.operations.push({ op: "label", label: END_LABEL }); + fn.operations.push({ op: "goto", label: END_LABEL }); + } + return Ok([fn, i]); } @@ -356,6 +370,17 @@ export class Vm { return this.currentFunction.operations[this.invocation.opPtr]; } + reset() { + const bootstrap = this.functionMap[BOOTSTRAP.name] + ? BOOTSTRAP.name + : "__implicit"; + this.executionStack = [ + { function: bootstrap, opPtr: 1, frameBase: 256, nArgs: 0 }, + ]; + this.memory.reset(); + this.memory.set(0, 256); + } + step() { const operation = this.operation ?? { op: "return" }; // Implicit return if the function doesn't end on its own. switch (operation.op) { diff --git a/web/src/pages/chip.scss b/web/src/pages/chip.scss index 6f4f659b8..54338c26b 100644 --- a/web/src/pages/chip.scss +++ b/web/src/pages/chip.scss @@ -1,20 +1,6 @@ -@use "../pico/button-group.scss"; -@use "../shell/tab.scss"; +@use "./page.scss"; .ChipPage { - h2 { - margin: 0 var(--nav-element-spacing-horizontal); - } - - --screen-size: calc(512px + calc(var(--block-spacing-horizontal) * 5)); - - height: 100%; - - grid-template-rows: 1fr; - grid-template-columns: 1fr var(--screen-size) 1fr; - margin: 0px; - gap: 0; - grid-template-areas: "hdl prt tst"; ._hdl_panel { diff --git a/web/src/pages/chip.tsx b/web/src/pages/chip.tsx index 1de0e6875..40eb01738 100644 --- a/web/src/pages/chip.tsx +++ b/web/src/pages/chip.tsx @@ -434,7 +434,7 @@ export const Chip = () => { ); return ( -
+
{hdlPanel} {pinsPanel} {testPanel} diff --git a/web/src/pages/cpu.scss b/web/src/pages/cpu.scss index 0eb4517a9..69333a6ad 100644 --- a/web/src/pages/cpu.scss +++ b/web/src/pages/cpu.scss @@ -1,16 +1,6 @@ -@use "../pico/button-group.scss"; -@use "../shell/tab.scss"; +@use "./page.scss"; .CpuPage { - --screen-size: calc( - 512px + calc(calc(var(--block-spacing-horizontal) * 5)) / 2 - ); - - height: 100%; - - margin: 0px; - gap: 0; - grid-template-areas: "ROM RAM" "IO IO" "test test"; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr 1fr; diff --git a/web/src/pages/cpu.tsx b/web/src/pages/cpu.tsx index a1c6f7dde..92b460749 100644 --- a/web/src/pages/cpu.tsx +++ b/web/src/pages/cpu.tsx @@ -122,7 +122,7 @@ export const CPU = () => { }; return ( -
+
{ const { state, actions, dispatch } = useVmPageStore(); - const [tst, setTst] = useState("repeat {\n\tticktock;\n}"); + const [tst, setTst] = useState("repeat {\n\tvmstep;\n}"); const [out, setOut] = useState(""); const [cmp, setCmp] = useState(""); @@ -42,7 +42,7 @@ const VM = () => { }, [actions, dispatch]); return ( -
+
@@ -108,8 +108,7 @@ const VM = () => { From e68d3e76987bb140a5b8a873c3c474016f9c4549 Mon Sep 17 00:00:00 2001 From: David Souther Date: Sun, 12 Nov 2023 11:24:43 -0500 Subject: [PATCH 08/14] Add VM Projects --- projects/src/index.ts | 23 ++ projects/src/project_05/make_samples.sh | 14 + projects/src/project_07/11_simple_add.ts | 57 ++++ projects/src/project_07/12_stack_test.ts | 105 ++++++ projects/src/project_07/21_basic_test.ts | 95 ++++++ projects/src/project_07/22_pointer_test.ts | 71 ++++ projects/src/project_07/23_static_test.ts | 65 ++++ .../MemoryAccess/BasicTest/BasicTest.cmp | 2 + .../MemoryAccess/BasicTest/BasicTest.hdl_tst | 25 ++ .../MemoryAccess/BasicTest/BasicTest.vm | 31 ++ .../MemoryAccess/BasicTest/BasicTest.vm_tst | 25 ++ .../MemoryAccess/PointerTest/PointerTest.cmp | 2 + .../PointerTest/PointerTest.hdl_tst | 20 ++ .../MemoryAccess/PointerTest/PointerTest.vm | 22 ++ .../PointerTest/PointerTest.vm_tst | 20 ++ .../MemoryAccess/StaticTest/StaticTest.cmp | 2 + .../StaticTest/StaticTest.hdl_tst | 17 + .../MemoryAccess/StaticTest/StaticTest.vm | 17 + .../MemoryAccess/StaticTest/StaticTest.vm_tst | 17 + .../StackArithmetic/SimpleAdd/SimpleAdd.cmp | 2 + .../SimpleAdd/SimpleAdd.hdl_tst | 17 + .../StackArithmetic/SimpleAdd/SimpleAdd.vm | 9 + .../SimpleAdd/SimpleAdd.vm_tst | 17 + .../StackArithmetic/StackTest/StackTest.cmp | 4 + .../StackTest/StackTest.hdl_tst | 22 ++ .../StackArithmetic/StackTest/StackTest.vm | 45 +++ .../StackTest/StackTest.vm_tst | 22 ++ projects/src/project_07/index.ts | 45 +++ projects/src/project_08/11_basic_loop.ts | 76 +++++ .../src/project_08/12_fibonacci_series.ts | 107 ++++++ projects/src/project_08/20_simple_function.ts | 88 +++++ projects/src/project_08/21_nested_call.ts | 212 ++++++++++++ .../src/project_08/22_fibonacci_element.ts | 94 ++++++ projects/src/project_08/23_statics_test.ts | 108 +++++++ .../FibonacciElement/FibonacciElement.cmp | 2 + .../FibonacciElement/FibonacciElement.hdl_tst | 18 ++ .../FibonacciElement/FibonacciElement.vm | 45 +++ .../FibonacciElement/FibonacciElement.vm_tst | 17 + .../FunctionCalls/FibonacciElement/Main.vm | 30 ++ .../FunctionCalls/FibonacciElement/Sys.vm | 15 + .../FunctionCalls/NestedCall/NestedCall.cmp | 2 + .../NestedCall/NestedCall.hdl_tst | 65 ++++ .../FunctionCalls/NestedCall/NestedCall.html | 196 +++++++++++ .../FunctionCalls/NestedCall/NestedCall.vm | 63 ++++ .../NestedCall/NestedCall.vm_tst | 70 ++++ .../NestedCall/NestedCallStack.html | 306 ++++++++++++++++++ .../SimpleFunction/SimpleFunction.cmp | 2 + .../SimpleFunction/SimpleFunction.hdl_tst | 29 ++ .../SimpleFunction/SimpleFunction.vm | 16 + .../SimpleFunction/SimpleFunction.vm_tst | 29 ++ .../FunctionCalls/StaticsTest/Class1.vm | 20 ++ .../FunctionCalls/StaticsTest/Class2.vm | 20 ++ .../FunctionCalls/StaticsTest/StaticsTest.cmp | 2 + .../StaticsTest/StaticsTest.hdl_tst | 17 + .../FunctionCalls/StaticsTest/StaticsTest.vm | 60 ++++ .../StaticsTest/StaticsTest.vm_tst | 17 + .../FunctionCalls/StaticsTest/Sys.vm | 20 ++ .../ProgramFlow/BasicLoop/BasicLoop.cmp | 2 + .../ProgramFlow/BasicLoop/BasicLoop.hdl_tst | 20 ++ .../ProgramFlow/BasicLoop/BasicLoop.vm | 22 ++ .../ProgramFlow/BasicLoop/BasicLoop.vm_tst | 20 ++ .../FibonacciSeries/FibonacciSeries.cmp | 2 + .../FibonacciSeries/FibonacciSeries.hdl_tst | 22 ++ .../FibonacciSeries/FibonacciSeries.vm | 49 +++ .../FibonacciSeries/FibonacciSeries.vm_tst | 22 ++ projects/src/project_08/index.ts | 52 +++ simulator/src/test/vmtst.test.ts | 0 67 files changed, 2770 insertions(+) create mode 100644 projects/src/project_05/make_samples.sh create mode 100644 projects/src/project_07/11_simple_add.ts create mode 100644 projects/src/project_07/12_stack_test.ts create mode 100644 projects/src/project_07/21_basic_test.ts create mode 100644 projects/src/project_07/22_pointer_test.ts create mode 100644 projects/src/project_07/23_static_test.ts create mode 100644 projects/src/project_07/MemoryAccess/BasicTest/BasicTest.cmp create mode 100644 projects/src/project_07/MemoryAccess/BasicTest/BasicTest.hdl_tst create mode 100644 projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm create mode 100644 projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm_tst create mode 100644 projects/src/project_07/MemoryAccess/PointerTest/PointerTest.cmp create mode 100644 projects/src/project_07/MemoryAccess/PointerTest/PointerTest.hdl_tst create mode 100644 projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm create mode 100644 projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm_tst create mode 100644 projects/src/project_07/MemoryAccess/StaticTest/StaticTest.cmp create mode 100644 projects/src/project_07/MemoryAccess/StaticTest/StaticTest.hdl_tst create mode 100644 projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm create mode 100644 projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm_tst create mode 100644 projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.cmp create mode 100644 projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.hdl_tst create mode 100644 projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm create mode 100644 projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm_tst create mode 100644 projects/src/project_07/StackArithmetic/StackTest/StackTest.cmp create mode 100644 projects/src/project_07/StackArithmetic/StackTest/StackTest.hdl_tst create mode 100644 projects/src/project_07/StackArithmetic/StackTest/StackTest.vm create mode 100644 projects/src/project_07/StackArithmetic/StackTest/StackTest.vm_tst create mode 100644 projects/src/project_07/index.ts create mode 100644 projects/src/project_08/11_basic_loop.ts create mode 100644 projects/src/project_08/12_fibonacci_series.ts create mode 100644 projects/src/project_08/20_simple_function.ts create mode 100644 projects/src/project_08/21_nested_call.ts create mode 100644 projects/src/project_08/22_fibonacci_element.ts create mode 100644 projects/src/project_08/23_statics_test.ts create mode 100644 projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.cmp create mode 100644 projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.hdl_tst create mode 100644 projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm create mode 100644 projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm_tst create mode 100644 projects/src/project_08/FunctionCalls/FibonacciElement/Main.vm create mode 100644 projects/src/project_08/FunctionCalls/FibonacciElement/Sys.vm create mode 100644 projects/src/project_08/FunctionCalls/NestedCall/NestedCall.cmp create mode 100644 projects/src/project_08/FunctionCalls/NestedCall/NestedCall.hdl_tst create mode 100644 projects/src/project_08/FunctionCalls/NestedCall/NestedCall.html create mode 100644 projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm create mode 100644 projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm_tst create mode 100644 projects/src/project_08/FunctionCalls/NestedCall/NestedCallStack.html create mode 100644 projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.cmp create mode 100644 projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.hdl_tst create mode 100644 projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm create mode 100644 projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm_tst create mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/Class1.vm create mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/Class2.vm create mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.cmp create mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.hdl_tst create mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm create mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm_tst create mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/Sys.vm create mode 100644 projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.cmp create mode 100644 projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.hdl_tst create mode 100644 projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm create mode 100644 projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm_tst create mode 100644 projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.cmp create mode 100644 projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.hdl_tst create mode 100644 projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm create mode 100644 projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm_tst create mode 100644 projects/src/project_08/index.ts create mode 100644 simulator/src/test/vmtst.test.ts diff --git a/projects/src/index.ts b/projects/src/index.ts index 665f81445..b0a5de4cd 100644 --- a/projects/src/index.ts +++ b/projects/src/index.ts @@ -5,6 +5,8 @@ import * as project_02 from "./project_02/index.js"; import * as project_03 from "./project_03/index.js"; import * as project_04 from "./project_04/index.js"; import * as project_05 from "./project_05/index.js"; +import * as project_07 from "./project_07/index.js"; +import * as project_08 from "./project_08/index.js"; /** * Duplicated for web from node:path. @@ -32,6 +34,11 @@ export const ChipProjects = { "05": project_05, }; +export const VmProjets = { + "07": project_07, + "08": project_08, +}; + let reset = false; export const resetFiles = async (fs: FileSystem) => { if (reset) return; // React will double-render a call to resetFiles in useEffect. @@ -41,6 +48,8 @@ export const resetFiles = async (fs: FileSystem) => { await project_03.resetFiles(fs); await project_04.resetFiles(fs); await project_05.resetFiles(fs); + await project_07.resetFiles(fs); + await project_08.resetFiles(fs); reset = false; }; @@ -102,9 +111,23 @@ export const ASM_PROJECTS: Record<"06", string[]> = { "06": ["Add", "Max", "Rectangle", "Pong"], }; +export const VM_PROJECTS: Record<"07" | "08", string[]> = { + "07": ["SimpleAdd", "StackTest", "MemoryTest", "PointerTest", "StaticTest"], + "08": [ + "BasicLoop", + "FibonacciSeries", + "SimpleFunction", + "NestedCall", + "FibonacciElement", + "StaticsTest", + ], +}; + export const Assignments = { ...project_01.CHIPS, ...project_02.CHIPS, ...project_03.CHIPS, ...project_05.CHIPS, + ...project_07.VMS, + ...project_08.VMS, }; diff --git a/projects/src/project_05/make_samples.sh b/projects/src/project_05/make_samples.sh new file mode 100644 index 000000000..bd2b4e398 --- /dev/null +++ b/projects/src/project_05/make_samples.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# write FileName.ts varname SourceFile + +function write () { + echo -n "export const $2 = \`" >> $1 + cat $3 >> $1 + echo "\`;\n\n" >> $1 +} + +# write_all ts_name ProjName +function write_all() { + for e in vm vm_tst hdl_tst cmp ; do write $1 $e $2.$e ; done +} \ No newline at end of file diff --git a/projects/src/project_07/11_simple_add.ts b/projects/src/project_07/11_simple_add.ts new file mode 100644 index 000000000..3f3450bcb --- /dev/null +++ b/projects/src/project_07/11_simple_add.ts @@ -0,0 +1,57 @@ +export const vm = `// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.vm + +// Pushes and adds two constants. +push constant 7 +push constant 8 +add +`; + + +export const vm_tst = `// 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/07/StackArithmetic/SimpleAdd/SimpleAddVME.tst + +load SimpleAdd.vm, +output-file SimpleAdd.out, +compare-to SimpleAdd.cmp, +output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; + +set RAM[0] 256, // initializes the stack pointer + +repeat 3 { // SimpleAdd.vm has 3 instructions + vmstep; +} + +output; // the stack pointer and the stack base +`; + + +export const hdl_tst = `// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.tst + +load SimpleAdd.asm, +output-file SimpleAdd.out, +compare-to SimpleAdd.cmp, +output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; + +set RAM[0] 256, // initializes the stack pointer + +repeat 60 { // enough cycles to complete the execution + ticktock; +} + +output; // the stack pointer and the stack base +`; + + +export const cmp = `| RAM[0] | RAM[256] | +| 257 | 15 | +`; + + diff --git a/projects/src/project_07/12_stack_test.ts b/projects/src/project_07/12_stack_test.ts new file mode 100644 index 000000000..67fac0133 --- /dev/null +++ b/projects/src/project_07/12_stack_test.ts @@ -0,0 +1,105 @@ +export const vm = `// 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/07/StackArithmetic/StackTest/StackTest.vm + +// Executes a sequence of arithmetic and logical operations +// on the stack. +push constant 17 +push constant 17 +eq +push constant 17 +push constant 16 +eq +push constant 16 +push constant 17 +eq +push constant 892 +push constant 891 +lt +push constant 891 +push constant 892 +lt +push constant 891 +push constant 891 +lt +push constant 32767 +push constant 32766 +gt +push constant 32766 +push constant 32767 +gt +push constant 32766 +push constant 32766 +gt +push constant 57 +push constant 31 +push constant 53 +add +push constant 112 +sub +neg +and +push constant 82 +or +not +`; + + +export const vm_tst = `// 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/07/StackArithmetic/StackTest/StackTestVME.tst + +load StackTest.vm, +output-file StackTest.out, +compare-to StackTest.cmp, +output-list RAM[0]%D2.6.2 + RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; + +set RAM[0] 256, // initializes the stack pointer + +repeat 38 { // StackTest.vm consists of 38 instructions + vmstep; +} + +// outputs the stack pointer (RAM[0]) and +// the stack contents: RAM[256]-RAM[265] +output; +output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; +output; +`; + + +export const hdl_tst = `// 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/07/StackArithmetic/StackTest/StackTest.tst + +load StackTest.asm, +output-file StackTest.out, +compare-to StackTest.cmp, +output-list RAM[0]%D2.6.2 + RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; + +set RAM[0] 256, // initializes the stack pointer + +repeat 1000 { // enough cycles to complete the execution + ticktock; +} + +// outputs the stack pointer (RAM[0]) and +// the stack contents: RAM[256]-RAM[265] +output; +output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; +output; +`; + + +export const cmp = `| RAM[0] | RAM[256] | RAM[257] | RAM[258] | RAM[259] | RAM[260] | +| 266 | -1 | 0 | 0 | 0 | -1 | +| RAM[261] | RAM[262] | RAM[263] | RAM[264] | RAM[265] | +| 0 | -1 | 0 | 0 | -91 | +`; + + diff --git a/projects/src/project_07/21_basic_test.ts b/projects/src/project_07/21_basic_test.ts new file mode 100644 index 000000000..cccc46ac2 --- /dev/null +++ b/projects/src/project_07/21_basic_test.ts @@ -0,0 +1,95 @@ +export const vm = `// 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/07/MemoryAccess/BasicTest/BasicTest.vm + +// Executes pop and push commands using the virtual memory segments. +push constant 10 +pop local 0 +push constant 21 +push constant 22 +pop argument 2 +pop argument 1 +push constant 36 +pop this 6 +push constant 42 +push constant 45 +pop that 5 +pop that 2 +push constant 510 +pop temp 6 +push local 0 +push that 5 +add +push argument 1 +sub +push this 6 +push this 6 +add +sub +push temp 6 +add +`; + + +export const vm_tst = `// 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/07/MemoryAccess/BasicTest/BasicTestVME.tst + +load BasicTest.vm, +output-file BasicTest.out, +compare-to BasicTest.cmp, +output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 + RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 + RAM[3015]%D1.6.1 RAM[11]%D1.6.1; + +set sp 256, // stack pointer +set local 300, // base address of the local segment +set argument 400, // base address of the argument segment +set this 3000, // base address of the this segment +set that 3010, // base address of the that segment + +repeat 25 { // BasicTest.vm has 25 instructions + vmstep; +} + +// Outputs the stack base and some values +// from the tested memory segments +output; +`; + + +export const hdl_tst = `// 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/07/MemoryAccess/BasicTest/BasicTest.tst + +load BasicTest.asm, +output-file BasicTest.out, +compare-to BasicTest.cmp, +output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 + RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 + RAM[3015]%D1.6.1 RAM[11]%D1.6.1; + +set RAM[0] 256, // stack pointer +set RAM[1] 300, // base address of the local segment +set RAM[2] 400, // base address of the argument segment +set RAM[3] 3000, // base address of the this segment +set RAM[4] 3010, // base address of the that segment + +repeat 600 { // enough cycles to complete the execution + ticktock; +} + +// Outputs the stack base and some values +// from the tested memory segments +output; +`; + + +export const cmp = `|RAM[256]|RAM[300]|RAM[401]|RAM[402]|RAM[3006|RAM[3012|RAM[3015|RAM[11] | +| 472 | 10 | 21 | 22 | 36 | 42 | 45 | 510 | +`; + + diff --git a/projects/src/project_07/22_pointer_test.ts b/projects/src/project_07/22_pointer_test.ts new file mode 100644 index 000000000..694fea4f2 --- /dev/null +++ b/projects/src/project_07/22_pointer_test.ts @@ -0,0 +1,71 @@ +export const vm = `// 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/07/MemoryAccess/PointerTest/PointerTest.vm + +// Executes pop and push commands using the +// pointer, this, and that segments. +push constant 3030 +pop pointer 0 +push constant 3040 +pop pointer 1 +push constant 32 +pop this 2 +push constant 46 +pop that 6 +push pointer 0 +push pointer 1 +add +push this 2 +sub +push that 6 +add +`; + +export const vm_tst = `// 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/07/MemoryAccess/PointerTest/PointerTestVME.tst + +load PointerTest.vm, +output-file PointerTest.out, +compare-to PointerTest.cmp, +output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 + RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; + +set RAM[0] 256, // initializes the stack pointer + +repeat 15 { // PointerTest.vm has 15 instructions + vmstep; +} + +// outputs the stack base, this, that, and +// some values from the the this and that segments +output; +`; + +export const hdl_tst = `// 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/07/MemoryAccess/PointerTest/PointerTest.tst + +load PointerTest.asm, +output-file PointerTest.out, +compare-to PointerTest.cmp, +output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 + RAM[4]%D1.6.1 RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; + +set RAM[0] 256, // initializes the stack pointer + +repeat 450 { // enough cycles to complete the execution + ticktock; +} + +// outputs the stack base, this, that, and +// some values from the the this and that segments +output; +`; + +export const cmp = `|RAM[256]| RAM[3] | RAM[4] |RAM[3032|RAM[3046| +| 6084 | 3030 | 3040 | 32 | 46 | +`; diff --git a/projects/src/project_07/23_static_test.ts b/projects/src/project_07/23_static_test.ts new file mode 100644 index 000000000..8e38cc975 --- /dev/null +++ b/projects/src/project_07/23_static_test.ts @@ -0,0 +1,65 @@ +export const vm = `// 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/07/MemoryAccess/StaticTest/StaticTest.vm + +// Executes pop and push commands using the static segment. +push constant 111 +push constant 333 +push constant 888 +pop static 8 +pop static 3 +pop static 1 +push static 3 +push static 1 +sub +push static 8 +add +`; + + +export const vm_tst = `// 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/07/MemoryAccess/StaticTest/StaticTestVME.tst + +load StaticTest.vm, +output-file StaticTest.out, +compare-to StaticTest.cmp, +output-list RAM[256]%D1.6.1; + +set sp 256, // initializes the stack pointer + +repeat 11 { // StaticTest.vm has 11 instructions + vmstep; +} + +output; // the stack base +`; + + +export const hdl_tst = `// 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/07/MemoryAccess/StaticTest/StaticTest.tst + +load StaticTest.asm, +output-file StaticTest.out, +compare-to StaticTest.cmp, +output-list RAM[256]%D1.6.1; + +set RAM[0] 256, // initializes the stack pointer + +repeat 200 { // enough cycles to complete the execution + ticktock; +} + +output; // the stack base +`; + + +export const cmp = `|RAM[256]| +| 1110 | +`; + + diff --git a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.cmp b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.cmp new file mode 100644 index 000000000..538454bde --- /dev/null +++ b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.cmp @@ -0,0 +1,2 @@ +|RAM[256]|RAM[300]|RAM[401]|RAM[402]|RAM[3006|RAM[3012|RAM[3015|RAM[11] | +| 472 | 10 | 21 | 22 | 36 | 42 | 45 | 510 | diff --git a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.hdl_tst b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.hdl_tst new file mode 100644 index 000000000..fa6d9a6f9 --- /dev/null +++ b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.hdl_tst @@ -0,0 +1,25 @@ +// 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/07/MemoryAccess/BasicTest/BasicTest.tst + +load BasicTest.asm, +output-file BasicTest.out, +compare-to BasicTest.cmp, +output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 + RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 + RAM[3015]%D1.6.1 RAM[11]%D1.6.1; + +set RAM[0] 256, // stack pointer +set RAM[1] 300, // base address of the local segment +set RAM[2] 400, // base address of the argument segment +set RAM[3] 3000, // base address of the this segment +set RAM[4] 3010, // base address of the that segment + +repeat 600 { // enough cycles to complete the execution + ticktock; +} + +// Outputs the stack base and some values +// from the tested memory segments +output; diff --git a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm new file mode 100644 index 000000000..b2f93431c --- /dev/null +++ b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm @@ -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/07/MemoryAccess/BasicTest/BasicTest.vm + +// Executes pop and push commands using the virtual memory segments. +push constant 10 +pop local 0 +push constant 21 +push constant 22 +pop argument 2 +pop argument 1 +push constant 36 +pop this 6 +push constant 42 +push constant 45 +pop that 5 +pop that 2 +push constant 510 +pop temp 6 +push local 0 +push that 5 +add +push argument 1 +sub +push this 6 +push this 6 +add +sub +push temp 6 +add diff --git a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm_tst b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm_tst new file mode 100644 index 000000000..24e909069 --- /dev/null +++ b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm_tst @@ -0,0 +1,25 @@ +// 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/07/MemoryAccess/BasicTest/BasicTestVME.tst + +load BasicTest.vm, +output-file BasicTest.out, +compare-to BasicTest.cmp, +output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 + RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 + RAM[3015]%D1.6.1 RAM[11]%D1.6.1; + +set sp 256, // stack pointer +set local 300, // base address of the local segment +set argument 400, // base address of the argument segment +set this 3000, // base address of the this segment +set that 3010, // base address of the that segment + +repeat 25 { // BasicTest.vm has 25 instructions + vmstep; +} + +// Outputs the stack base and some values +// from the tested memory segments +output; diff --git a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.cmp b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.cmp new file mode 100644 index 000000000..b59fa97ce --- /dev/null +++ b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.cmp @@ -0,0 +1,2 @@ +|RAM[256]| RAM[3] | RAM[4] |RAM[3032|RAM[3046| +| 6084 | 3030 | 3040 | 32 | 46 | diff --git a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.hdl_tst b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.hdl_tst new file mode 100644 index 000000000..cd5515dce --- /dev/null +++ b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.hdl_tst @@ -0,0 +1,20 @@ +// 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/07/MemoryAccess/PointerTest/PointerTest.tst + +load PointerTest.asm, +output-file PointerTest.out, +compare-to PointerTest.cmp, +output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 + RAM[4]%D1.6.1 RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; + +set RAM[0] 256, // initializes the stack pointer + +repeat 450 { // enough cycles to complete the execution + ticktock; +} + +// outputs the stack base, this, that, and +// some values from the the this and that segments +output; diff --git a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm new file mode 100644 index 000000000..5b0a109a5 --- /dev/null +++ b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm @@ -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/07/MemoryAccess/PointerTest/PointerTest.vm + +// Executes pop and push commands using the +// pointer, this, and that segments. +push constant 3030 +pop pointer 0 +push constant 3040 +pop pointer 1 +push constant 32 +pop this 2 +push constant 46 +pop that 6 +push pointer 0 +push pointer 1 +add +push this 2 +sub +push that 6 +add diff --git a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm_tst b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm_tst new file mode 100644 index 000000000..1b395c2c6 --- /dev/null +++ b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm_tst @@ -0,0 +1,20 @@ +// 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/07/MemoryAccess/PointerTest/PointerTestVME.tst + +load PointerTest.vm, +output-file PointerTest.out, +compare-to PointerTest.cmp, +output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 + RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; + +set RAM[0] 256, // initializes the stack pointer + +repeat 15 { // PointerTest.vm has 15 instructions + vmstep; +} + +// outputs the stack base, this, that, and +// some values from the the this and that segments +output; diff --git a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.cmp b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.cmp new file mode 100644 index 000000000..29f4bf032 --- /dev/null +++ b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.cmp @@ -0,0 +1,2 @@ +|RAM[256]| +| 1110 | diff --git a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.hdl_tst b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.hdl_tst new file mode 100644 index 000000000..1f23d6681 --- /dev/null +++ b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.hdl_tst @@ -0,0 +1,17 @@ +// 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/07/MemoryAccess/StaticTest/StaticTest.tst + +load StaticTest.asm, +output-file StaticTest.out, +compare-to StaticTest.cmp, +output-list RAM[256]%D1.6.1; + +set RAM[0] 256, // initializes the stack pointer + +repeat 200 { // enough cycles to complete the execution + ticktock; +} + +output; // the stack base diff --git a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm new file mode 100644 index 000000000..65b4f6f75 --- /dev/null +++ b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm @@ -0,0 +1,17 @@ +// 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/07/MemoryAccess/StaticTest/StaticTest.vm + +// Executes pop and push commands using the static segment. +push constant 111 +push constant 333 +push constant 888 +pop static 8 +pop static 3 +pop static 1 +push static 3 +push static 1 +sub +push static 8 +add diff --git a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm_tst b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm_tst new file mode 100644 index 000000000..52882a486 --- /dev/null +++ b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm_tst @@ -0,0 +1,17 @@ +// 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/07/MemoryAccess/StaticTest/StaticTestVME.tst + +load StaticTest.vm, +output-file StaticTest.out, +compare-to StaticTest.cmp, +output-list RAM[256]%D1.6.1; + +set sp 256, // initializes the stack pointer + +repeat 11 { // StaticTest.vm has 11 instructions + vmstep; +} + +output; // the stack base diff --git a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.cmp b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.cmp new file mode 100644 index 000000000..7a3585b9a --- /dev/null +++ b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.cmp @@ -0,0 +1,2 @@ +| RAM[0] | RAM[256] | +| 257 | 15 | diff --git a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.hdl_tst b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.hdl_tst new file mode 100644 index 000000000..02dece306 --- /dev/null +++ b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.hdl_tst @@ -0,0 +1,17 @@ +// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.tst + +load SimpleAdd.asm, +output-file SimpleAdd.out, +compare-to SimpleAdd.cmp, +output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; + +set RAM[0] 256, // initializes the stack pointer + +repeat 60 { // enough cycles to complete the execution + ticktock; +} + +output; // the stack pointer and the stack base diff --git a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm new file mode 100644 index 000000000..cfd4ee9c2 --- /dev/null +++ b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm @@ -0,0 +1,9 @@ +// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.vm + +// Pushes and adds two constants. +push constant 7 +push constant 8 +add diff --git a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm_tst b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm_tst new file mode 100644 index 000000000..5010f4ff4 --- /dev/null +++ b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm_tst @@ -0,0 +1,17 @@ +// 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/07/StackArithmetic/SimpleAdd/SimpleAddVME.tst + +load SimpleAdd.vm, +output-file SimpleAdd.out, +compare-to SimpleAdd.cmp, +output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; + +set RAM[0] 256, // initializes the stack pointer + +repeat 3 { // SimpleAdd.vm has 3 instructions + vmstep; +} + +output; // the stack pointer and the stack base diff --git a/projects/src/project_07/StackArithmetic/StackTest/StackTest.cmp b/projects/src/project_07/StackArithmetic/StackTest/StackTest.cmp new file mode 100644 index 000000000..f90fa1b7d --- /dev/null +++ b/projects/src/project_07/StackArithmetic/StackTest/StackTest.cmp @@ -0,0 +1,4 @@ +| RAM[0] | RAM[256] | RAM[257] | RAM[258] | RAM[259] | RAM[260] | +| 266 | -1 | 0 | 0 | 0 | -1 | +| RAM[261] | RAM[262] | RAM[263] | RAM[264] | RAM[265] | +| 0 | -1 | 0 | 0 | -91 | diff --git a/projects/src/project_07/StackArithmetic/StackTest/StackTest.hdl_tst b/projects/src/project_07/StackArithmetic/StackTest/StackTest.hdl_tst new file mode 100644 index 000000000..f9c539675 --- /dev/null +++ b/projects/src/project_07/StackArithmetic/StackTest/StackTest.hdl_tst @@ -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/07/StackArithmetic/StackTest/StackTest.tst + +load StackTest.asm, +output-file StackTest.out, +compare-to StackTest.cmp, +output-list RAM[0]%D2.6.2 + RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; + +set RAM[0] 256, // initializes the stack pointer + +repeat 1000 { // enough cycles to complete the execution + ticktock; +} + +// outputs the stack pointer (RAM[0]) and +// the stack contents: RAM[256]-RAM[265] +output; +output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; +output; diff --git a/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm b/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm new file mode 100644 index 000000000..bfe78e06f --- /dev/null +++ b/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm @@ -0,0 +1,45 @@ +// 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/07/StackArithmetic/StackTest/StackTest.vm + +// Executes a sequence of arithmetic and logical operations +// on the stack. +push constant 17 +push constant 17 +eq +push constant 17 +push constant 16 +eq +push constant 16 +push constant 17 +eq +push constant 892 +push constant 891 +lt +push constant 891 +push constant 892 +lt +push constant 891 +push constant 891 +lt +push constant 32767 +push constant 32766 +gt +push constant 32766 +push constant 32767 +gt +push constant 32766 +push constant 32766 +gt +push constant 57 +push constant 31 +push constant 53 +add +push constant 112 +sub +neg +and +push constant 82 +or +not diff --git a/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm_tst b/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm_tst new file mode 100644 index 000000000..b66bd054f --- /dev/null +++ b/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm_tst @@ -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/07/StackArithmetic/StackTest/StackTestVME.tst + +load StackTest.vm, +output-file StackTest.out, +compare-to StackTest.cmp, +output-list RAM[0]%D2.6.2 + RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; + +set RAM[0] 256, // initializes the stack pointer + +repeat 38 { // StackTest.vm consists of 38 instructions + vmstep; +} + +// outputs the stack pointer (RAM[0]) and +// the stack contents: RAM[256]-RAM[265] +output; +output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; +output; diff --git a/projects/src/project_07/index.ts b/projects/src/project_07/index.ts new file mode 100644 index 000000000..592f10bcb --- /dev/null +++ b/projects/src/project_07/index.ts @@ -0,0 +1,45 @@ +import { FileSystem, reset } from "@davidsouther/jiffies/lib/esm/fs.js"; +import * as simple_add from "./11_simple_add.js"; +import * as stack_test from "./12_stack_test.js"; +import * as memory_test from "./21_basic_test.js"; +import * as pointer_test from "./22_pointer_test.js"; +import * as static_test from "./23_static_test.js"; + +export const VMS = { + SimpleAdd: { + "SimpleAdd.vm": simple_add.vm, + "SimpleAdd.vm_tst": simple_add.vm_tst, + "SimpleAdd.cmp": simple_add.cmp, + "SimpleAdd.tst": simple_add.hdl_tst, + }, + StackTest: { + "StackTest.vm": stack_test.vm, + "StackTest.vm_tst": stack_test.vm_tst, + "StackTest.cmp": stack_test.cmp, + "StackTest.tst": stack_test.hdl_tst, + }, + MemoryTest: { + "MemoryTest.vm": memory_test.vm, + "MemoryTest.vm_tst": memory_test.vm_tst, + "MemoryTest.cmp": memory_test.cmp, + "MemoryTest.tst": memory_test.hdl_tst, + }, + PointerTest: { + "PointerTest.vm": pointer_test.vm, + "PointerTest.vm_tst": pointer_test.vm_tst, + "PointerTest.cmp": pointer_test.cmp, + "PointerTest.tst": pointer_test.hdl_tst, + }, + StaticTest: { + "StaticTest.vm": static_test.vm, + "StaticTest.vm_tst": static_test.vm_tst, + "StaticTest.cmp": static_test.cmp, + "StaticTest.tst": static_test.hdl_tst, + }, +}; + +export async function resetFiles(fs: FileSystem): Promise { + await fs.pushd("/projects/07"); + await reset(fs, VMS); + await fs.popd(); +} diff --git a/projects/src/project_08/11_basic_loop.ts b/projects/src/project_08/11_basic_loop.ts new file mode 100644 index 000000000..f841f018c --- /dev/null +++ b/projects/src/project_08/11_basic_loop.ts @@ -0,0 +1,76 @@ +export const vm = `// 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/08/ProgramFlow/BasicLoop/BasicLoop.vm + +// Computes the sum 1 + 2 + ... + argument[0] and pushes the +// result onto the stack. Argument[0] is initialized by the test +// script before this code starts running. +push constant 0 +pop local 0 // initializes sum = 0 +label LOOP_START +push argument 0 +push local 0 +add +pop local 0 // sum = sum + counter +push argument 0 +push constant 1 +sub +pop argument 0 // counter-- +push argument 0 +if-goto LOOP_START // If counter != 0, goto LOOP_START +push local 0 +`; + + +export const vm_tst = `// 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/08/ProgramFlow/BasicLoop/BasicLoopVME.tst + +load BasicLoop.vm, +output-file BasicLoop.out, +compare-to BasicLoop.cmp, +output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; + +set sp 256, +set local 300, +set argument 400, +set argument[0] 3, + +repeat 33 { + vmstep; +} + +output; +`; + + +export const hdl_tst = `// 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/08/ProgramFlow/BasicLoop/BasicLoop.tst + +load BasicLoop.asm, +output-file BasicLoop.out, +compare-to BasicLoop.cmp, +output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; + +set RAM[0] 256, +set RAM[1] 300, +set RAM[2] 400, +set RAM[400] 3, + +repeat 600 { + ticktock; +} + +output; +`; + + +export const cmp = `| RAM[0] |RAM[256]| +| 257 | 6 | +`; + + diff --git a/projects/src/project_08/12_fibonacci_series.ts b/projects/src/project_08/12_fibonacci_series.ts new file mode 100644 index 000000000..868f7ec2f --- /dev/null +++ b/projects/src/project_08/12_fibonacci_series.ts @@ -0,0 +1,107 @@ +export const vm = `// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm + +// Puts the first argument[0] elements of the Fibonacci series +// in the memory, starting in the address given in argument[1]. +// Argument[0] and argument[1] are initialized by the test script +// before this code starts running. + +push argument 1 +pop pointer 1 // that = argument[1] + +push constant 0 +pop that 0 // first element in the series = 0 +push constant 1 +pop that 1 // second element in the series = 1 + +push argument 0 +push constant 2 +sub +pop argument 0 // num_of_elements -= 2 (first 2 elements are set) + +label MAIN_LOOP_START + +push argument 0 +if-goto COMPUTE_ELEMENT // if num_of_elements > 0, goto COMPUTE_ELEMENT +goto END_PROGRAM // otherwise, goto END_PROGRAM + +label COMPUTE_ELEMENT + +push that 0 +push that 1 +add +pop that 2 // that[2] = that[0] + that[1] + +push pointer 1 +push constant 1 +add +pop pointer 1 // that += 1 + +push argument 0 +push constant 1 +sub +pop argument 0 // num_of_elements-- + +goto MAIN_LOOP_START + +label END_PROGRAM +`; + + +export const vm_tst = `// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeriesVME.tst + +load FibonacciSeries.vm, +output-file FibonacciSeries.out, +compare-to FibonacciSeries.cmp, +output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 + RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; + +set sp 256, +set local 300, +set argument 400, +set argument[0] 6, +set argument[1] 3000, + +repeat 73 { + vmstep; +} + +output; +`; + + +export const hdl_tst = `// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.tst + +load FibonacciSeries.asm, +output-file FibonacciSeries.out, +compare-to FibonacciSeries.cmp, +output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 + RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; + +set RAM[0] 256, +set RAM[1] 300, +set RAM[2] 400, +set RAM[400] 6, +set RAM[401] 3000, + +repeat 1100 { + ticktock; +} + +output; +`; + + +export const cmp = `|RAM[3000]|RAM[3001]|RAM[3002]|RAM[3003]|RAM[3004]|RAM[3005]| +| 0 | 1 | 1 | 2 | 3 | 5 | +`; + + diff --git a/projects/src/project_08/20_simple_function.ts b/projects/src/project_08/20_simple_function.ts new file mode 100644 index 000000000..0d7e32603 --- /dev/null +++ b/projects/src/project_08/20_simple_function.ts @@ -0,0 +1,88 @@ +export const vm = `// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.vm + +// Performs a simple calculation and returns the result. +function SimpleFunction.test 2 +push local 0 +push local 1 +add +not +push argument 0 +add +push argument 1 +sub +return +`; + + +export const vm_tst = `// 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/08/FunctionCalls/SimpleFunction/SimpleFunctionVME.tst + +load SimpleFunction.vm, +output-file SimpleFunction.out, +compare-to SimpleFunction.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 + RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; + +set sp 317, +set local 317, +set argument 310, +set this 3000, +set that 4000, +set argument[0] 1234, +set argument[1] 37, +set argument[2] 9, +set argument[3] 305, +set argument[4] 300, +set argument[5] 3010, +set argument[6] 4010, + +repeat 10 { + vmstep; +} + +output; +`; + + +export const hdl_tst = `// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.tst + +load SimpleFunction.asm, +output-file SimpleFunction.out, +compare-to SimpleFunction.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 + RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; + +set RAM[0] 317, +set RAM[1] 317, +set RAM[2] 310, +set RAM[3] 3000, +set RAM[4] 4000, +set RAM[310] 1234, +set RAM[311] 37, +set RAM[312] 1000, +set RAM[313] 305, +set RAM[314] 300, +set RAM[315] 3010, +set RAM[316] 4010, + +repeat 300 { + ticktock; +} + +output; +`; + + +export const cmp = `| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] |RAM[310]| +| 311 | 305 | 300 | 3010 | 4010 | 1196 | +`; + + diff --git a/projects/src/project_08/21_nested_call.ts b/projects/src/project_08/21_nested_call.ts new file mode 100644 index 000000000..1420c8d90 --- /dev/null +++ b/projects/src/project_08/21_nested_call.ts @@ -0,0 +1,212 @@ +export const vm = `// Sys.vm for NestedCall test. + +// Sys.init() +// +// Calls Sys.main() and stores return value in temp 1. +// Does not return. (Enters infinite loop.) + +function Sys.init 0 +push constant 4000 // test THIS and THAT context save +pop pointer 0 +push constant 5000 +pop pointer 1 +call Sys.main 0 +pop temp 1 +label LOOP +goto LOOP + +// Sys.main() +// +// Sets locals 1, 2 and 3, leaving locals 0 and 4 unchanged to test +// default local initialization to 0. (RAM set to -1 by test setup.) +// Calls Sys.add12(123) and stores return value (135) in temp 0. +// Returns local 0 + local 1 + local 2 + local 3 + local 4 (456) to confirm +// that locals were not mangled by function call. + +function Sys.main 5 +push constant 4001 +pop pointer 0 +push constant 5001 +pop pointer 1 +push constant 200 +pop local 1 +push constant 40 +pop local 2 +push constant 6 +pop local 3 +push constant 123 +call Sys.add12 1 +pop temp 0 +push local 0 +push local 1 +push local 2 +push local 3 +push local 4 +add +add +add +add +return + +// Sys.add12(int n) +// +// Returns n+12. + +function Sys.add12 0 +push constant 4002 +pop pointer 0 +push constant 5002 +pop pointer 1 +push argument 0 +push constant 12 +add +return +`; + + +export const vm_tst = `// Test file for NestedCall test. + +load Sys.vm, +output-file NestedCall.out, +compare-to NestedCall.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; + +set RAM[0] 261, +set RAM[1] 261, +set RAM[2] 256, +set RAM[3] -3, +set RAM[4] -4, +set RAM[5] -1, // test results +set RAM[6] -1, +set RAM[256] 1234, // fake stack frame from call Sys.init +set RAM[257] -1, +set RAM[258] -2, +set RAM[259] -3, +set RAM[260] -4, + +set RAM[261] -1, // Initialize stack to check for local segment +set RAM[262] -1, // being cleared to zero. +set RAM[263] -1, +set RAM[264] -1, +set RAM[265] -1, +set RAM[266] -1, +set RAM[267] -1, +set RAM[268] -1, +set RAM[269] -1, +set RAM[270] -1, +set RAM[271] -1, +set RAM[272] -1, +set RAM[273] -1, +set RAM[274] -1, +set RAM[275] -1, +set RAM[276] -1, +set RAM[277] -1, +set RAM[278] -1, +set RAM[279] -1, +set RAM[280] -1, +set RAM[281] -1, +set RAM[282] -1, +set RAM[283] -1, +set RAM[284] -1, +set RAM[285] -1, +set RAM[286] -1, +set RAM[287] -1, +set RAM[288] -1, +set RAM[289] -1, +set RAM[290] -1, +set RAM[291] -1, +set RAM[292] -1, +set RAM[293] -1, +set RAM[294] -1, +set RAM[295] -1, +set RAM[296] -1, +set RAM[297] -1, +set RAM[298] -1, +set RAM[299] -1, + +set sp 261, +set local 261, +set argument 256, +set this 3000, +set that 4000; + +repeat 50 { + vmstep; +} +output; +`; + + +export const hdl_tst = `// Test file for NestedCall test. + +load NestedCall.asm, +output-file NestedCall.out, +compare-to NestedCall.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; + +set RAM[0] 261, +set RAM[1] 261, +set RAM[2] 256, +set RAM[3] -3, +set RAM[4] -4, +set RAM[5] -1, // test results +set RAM[6] -1, +set RAM[256] 1234, // fake stack frame from call Sys.init +set RAM[257] -1, +set RAM[258] -2, +set RAM[259] -3, +set RAM[260] -4, + +set RAM[261] -1, // Initialize stack to check for local segment +set RAM[262] -1, // being cleared to zero. +set RAM[263] -1, +set RAM[264] -1, +set RAM[265] -1, +set RAM[266] -1, +set RAM[267] -1, +set RAM[268] -1, +set RAM[269] -1, +set RAM[270] -1, +set RAM[271] -1, +set RAM[272] -1, +set RAM[273] -1, +set RAM[274] -1, +set RAM[275] -1, +set RAM[276] -1, +set RAM[277] -1, +set RAM[278] -1, +set RAM[279] -1, +set RAM[280] -1, +set RAM[281] -1, +set RAM[282] -1, +set RAM[283] -1, +set RAM[284] -1, +set RAM[285] -1, +set RAM[286] -1, +set RAM[287] -1, +set RAM[288] -1, +set RAM[289] -1, +set RAM[290] -1, +set RAM[291] -1, +set RAM[292] -1, +set RAM[293] -1, +set RAM[294] -1, +set RAM[295] -1, +set RAM[296] -1, +set RAM[297] -1, +set RAM[298] -1, +set RAM[299] -1, + +repeat 4000 { + ticktock; +} + +output; +`; + + +export const cmp = `| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] | RAM[5] | RAM[6] | +| 261 | 261 | 256 | 4000 | 5000 | 135 | 246 | +`; + + diff --git a/projects/src/project_08/22_fibonacci_element.ts b/projects/src/project_08/22_fibonacci_element.ts new file mode 100644 index 000000000..aced2390b --- /dev/null +++ b/projects/src/project_08/22_fibonacci_element.ts @@ -0,0 +1,94 @@ +export const vm = `// 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/08/FunctionCalls/FibonacciElement/Main.vm + +// Computes the n'th element of the Fibonacci series, recursively. +// n is given in argument[0]. Called by the Sys.init function +// (part of the Sys.vm file), which also pushes the argument[0] +// parameter before this code starts running. + +function Main.fibonacci 0 +push argument 0 +push constant 2 +lt // checks if n<2 +if-goto IF_TRUE +goto IF_FALSE +label IF_TRUE // if n<2, return n +push argument 0 +return +label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) +push argument 0 +push constant 2 +sub +call Main.fibonacci 1 // computes fib(n-2) +push argument 0 +push constant 1 +sub +call Main.fibonacci 1 // computes fib(n-1) +add // returns fib(n-1) + fib(n-2) +return +// 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/08/FunctionCalls/FibonacciElement/Sys.vm + +// Pushes a constant, say n, onto the stack, and calls the Main.fibonacii +// function, which computes the n'th element of the Fibonacci series. +// Note that by convention, the Sys.init function is called "automatically" +// by the bootstrap code. + +function Sys.init 0 +push constant 4 +call Main.fibonacci 1 // computes the 4'th fibonacci element +label WHILE +goto WHILE // loops infinitely +`; + + +export const vm_tst = `// 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/08/FunctionCalls/FibonacciElement/FibonacciElementVME.tst + +load, // Load all the VM files from the current directory +output-file FibonacciElement.out, +compare-to FibonacciElement.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; + +set sp 261, + +repeat 110 { + vmstep; +} + +output; +`; + + +export const hdl_tst = `// 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/08/FunctionCalls/FibonacciElement/FibonacciElement.tst + +// FibonacciElement.asm results from translating both Main.vm and Sys.vm into +// a single assembly program, stored in the file FibonacciElement.asm. + +load FibonacciElement.asm, +output-file FibonacciElement.out, +compare-to FibonacciElement.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; + +repeat 6000 { + ticktock; +} + +output; +`; + + +export const cmp = `| RAM[0] |RAM[261]| +| 262 | 3 | +`; + + diff --git a/projects/src/project_08/23_statics_test.ts b/projects/src/project_08/23_statics_test.ts new file mode 100644 index 000000000..39306095c --- /dev/null +++ b/projects/src/project_08/23_statics_test.ts @@ -0,0 +1,108 @@ +export const vm = `// 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/08/FunctionCalls/StaticsTest/Class1.vm + +// Stores two supplied arguments in static[0] and static[1]. +function Class1.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class1.get 0 +push static 0 +push static 1 +sub +return +// 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/08/FunctionCalls/StaticsTest/Class2.vm + +// Stores two supplied arguments in static[0] and static[1]. +function Class2.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class2.get 0 +push static 0 +push static 1 +sub +return +// 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/08/FunctionCalls/StaticsTest/Sys.vm + +// Tests that different functions, stored in two different +// class files, manipulate the static segment correctly. +function Sys.init 0 +push constant 6 +push constant 8 +call Class1.set 2 +pop temp 0 // Dumps the return value +push constant 23 +push constant 15 +call Class2.set 2 +pop temp 0 // Dumps the return value +call Class1.get 0 +call Class2.get 0 +label WHILE +goto WHILE +`; + + +export const vm_tst = `// 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/08/FunctionCalls/StaticsTest/StaticsTestVME.tst + +load, // loads all the VM files from the current directory. +output-file StaticsTest.out, +compare-to StaticsTest.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; + +set sp 261, + +repeat 36 { + vmstep; +} + +output; +`; + + +export const hdl_tst = `// 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/08/FunctionCalls/StaticsTest/StaticsTest.tst + +load StaticsTest.asm, +output-file StaticsTest.out, +compare-to StaticsTest.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; + +set RAM[0] 256, + +repeat 2500 { + ticktock; +} + +output; +`; + + +export const cmp = `| RAM[0] |RAM[261]|RAM[262]| +| 263 | -2 | 8 | +`; + + diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.cmp b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.cmp new file mode 100644 index 000000000..d66783468 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.cmp @@ -0,0 +1,2 @@ +| RAM[0] |RAM[261]| +| 262 | 3 | diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.hdl_tst b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.hdl_tst new file mode 100644 index 000000000..1f907b1da --- /dev/null +++ b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.hdl_tst @@ -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/08/FunctionCalls/FibonacciElement/FibonacciElement.tst + +// FibonacciElement.asm results from translating both Main.vm and Sys.vm into +// a single assembly program, stored in the file FibonacciElement.asm. + +load FibonacciElement.asm, +output-file FibonacciElement.out, +compare-to FibonacciElement.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; + +repeat 6000 { + ticktock; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm new file mode 100644 index 000000000..ead925d64 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm @@ -0,0 +1,45 @@ +// 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/08/FunctionCalls/FibonacciElement/Main.vm + +// Computes the n'th element of the Fibonacci series, recursively. +// n is given in argument[0]. Called by the Sys.init function +// (part of the Sys.vm file), which also pushes the argument[0] +// parameter before this code starts running. + +function Main.fibonacci 0 +push argument 0 +push constant 2 +lt // checks if n<2 +if-goto IF_TRUE +goto IF_FALSE +label IF_TRUE // if n<2, return n +push argument 0 +return +label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) +push argument 0 +push constant 2 +sub +call Main.fibonacci 1 // computes fib(n-2) +push argument 0 +push constant 1 +sub +call Main.fibonacci 1 // computes fib(n-1) +add // returns fib(n-1) + fib(n-2) +return +// 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/08/FunctionCalls/FibonacciElement/Sys.vm + +// Pushes a constant, say n, onto the stack, and calls the Main.fibonacii +// function, which computes the n'th element of the Fibonacci series. +// Note that by convention, the Sys.init function is called "automatically" +// by the bootstrap code. + +function Sys.init 0 +push constant 4 +call Main.fibonacci 1 // computes the 4'th fibonacci element +label WHILE +goto WHILE // loops infinitely diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm_tst b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm_tst new file mode 100644 index 000000000..87c092086 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm_tst @@ -0,0 +1,17 @@ +// 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/08/FunctionCalls/FibonacciElement/FibonacciElementVME.tst + +load, // Load all the VM files from the current directory +output-file FibonacciElement.out, +compare-to FibonacciElement.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; + +set sp 261, + +repeat 110 { + vmstep; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/Main.vm b/projects/src/project_08/FunctionCalls/FibonacciElement/Main.vm new file mode 100644 index 000000000..55e5ad217 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/FibonacciElement/Main.vm @@ -0,0 +1,30 @@ +// 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/08/FunctionCalls/FibonacciElement/Main.vm + +// Computes the n'th element of the Fibonacci series, recursively. +// n is given in argument[0]. Called by the Sys.init function +// (part of the Sys.vm file), which also pushes the argument[0] +// parameter before this code starts running. + +function Main.fibonacci 0 +push argument 0 +push constant 2 +lt // checks if n<2 +if-goto IF_TRUE +goto IF_FALSE +label IF_TRUE // if n<2, return n +push argument 0 +return +label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) +push argument 0 +push constant 2 +sub +call Main.fibonacci 1 // computes fib(n-2) +push argument 0 +push constant 1 +sub +call Main.fibonacci 1 // computes fib(n-1) +add // returns fib(n-1) + fib(n-2) +return diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/Sys.vm b/projects/src/project_08/FunctionCalls/FibonacciElement/Sys.vm new file mode 100644 index 000000000..f3965c97a --- /dev/null +++ b/projects/src/project_08/FunctionCalls/FibonacciElement/Sys.vm @@ -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/08/FunctionCalls/FibonacciElement/Sys.vm + +// Pushes a constant, say n, onto the stack, and calls the Main.fibonacii +// function, which computes the n'th element of the Fibonacci series. +// Note that by convention, the Sys.init function is called "automatically" +// by the bootstrap code. + +function Sys.init 0 +push constant 4 +call Main.fibonacci 1 // computes the 4'th fibonacci element +label WHILE +goto WHILE // loops infinitely diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.cmp b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.cmp new file mode 100644 index 000000000..9200202e6 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.cmp @@ -0,0 +1,2 @@ +| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] | RAM[5] | RAM[6] | +| 261 | 261 | 256 | 4000 | 5000 | 135 | 246 | diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.hdl_tst b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.hdl_tst new file mode 100644 index 000000000..70e5523cd --- /dev/null +++ b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.hdl_tst @@ -0,0 +1,65 @@ +// Test file for NestedCall test. + +load NestedCall.asm, +output-file NestedCall.out, +compare-to NestedCall.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; + +set RAM[0] 261, +set RAM[1] 261, +set RAM[2] 256, +set RAM[3] -3, +set RAM[4] -4, +set RAM[5] -1, // test results +set RAM[6] -1, +set RAM[256] 1234, // fake stack frame from call Sys.init +set RAM[257] -1, +set RAM[258] -2, +set RAM[259] -3, +set RAM[260] -4, + +set RAM[261] -1, // Initialize stack to check for local segment +set RAM[262] -1, // being cleared to zero. +set RAM[263] -1, +set RAM[264] -1, +set RAM[265] -1, +set RAM[266] -1, +set RAM[267] -1, +set RAM[268] -1, +set RAM[269] -1, +set RAM[270] -1, +set RAM[271] -1, +set RAM[272] -1, +set RAM[273] -1, +set RAM[274] -1, +set RAM[275] -1, +set RAM[276] -1, +set RAM[277] -1, +set RAM[278] -1, +set RAM[279] -1, +set RAM[280] -1, +set RAM[281] -1, +set RAM[282] -1, +set RAM[283] -1, +set RAM[284] -1, +set RAM[285] -1, +set RAM[286] -1, +set RAM[287] -1, +set RAM[288] -1, +set RAM[289] -1, +set RAM[290] -1, +set RAM[291] -1, +set RAM[292] -1, +set RAM[293] -1, +set RAM[294] -1, +set RAM[295] -1, +set RAM[296] -1, +set RAM[297] -1, +set RAM[298] -1, +set RAM[299] -1, + +repeat 4000 { + ticktock; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.html b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.html new file mode 100644 index 000000000..0d8534dbb --- /dev/null +++ b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.html @@ -0,0 +1,196 @@ + + + + + NestedCall.tst — Nand2Tetris Calling Convention Test + + + + +

Synopsis

+NestedCall.tst is an intermediate test (in terms of complexity) intended to be used between the SimpleFunction and +FibonacciElement tests. It may be useful when SimpleFunction passes but FibonacciElement fails or crashes. NestedCall also +tests several requirements of the Function Calling Protocol that are not verified by the other +supplied tests. NestedCall can be used with or without the VM bootstrap code. +

+NestedCallVME.tst runs the same test on the VM Emulator. +

+The NestedCall tests and supporting documentation were written by Mark Armbrust. + + +

Test Structure

+

Startup

+NestedCall is implemented entirely within the Sys.vm file. The first function in Sys.vm is +Sys.init(). This allows it to be used before the bootstrap code has been added to the VM Translator +since there will be no file processing order issues. +

+NestedCall loads NestedCall.asm, sets up the stack to simulate the bootstrap's call to Sys.init(), then +begins execution at the beginning of NestedCall.asm. If the bootstrap is not present, the program begins +running with Sys.init() since it is the first function in Sys.vm. +

+If NestedCall.asm includes the bootstrap, the bootstrap will (re)initialize the stack and call Sys.init(), +so the test should see the same environment either way it gets to Sys.init(). +

+The test setup also initializes the LCL, ARG, THIS and THAT pointers to -1, -2, -3 and -4. + +

Sys.init()

+ +THIS and THAT are set to known values so that context save and restore can be tested. +

+Sys.init() calls Sys.main() and stores the return value in temp 1. This tests call to and +return from a function with no arguments. + +

Sys.main()

+Sys.main() allocates 5 local variables. It sets local 1, local 2 and +local 3. local 0 and local 4 are intentionally not set. +

+THIS and THAT are changed so that context save and restore can be tested. +

+Sys.main() calls Sys.add12(123) and stores the return value in temp 0. This tests call to and +return from a function with arguments. +

+After Sys.add12() returns, Sys.main() sums local 0 through local 4 and returns the +result. This tests that the local segment was properly allocated on the stack and that the local +variables were not overwritten by the call to Sys.main(). It also tests that local 0 and +local 4 were properly initialized to 0. + +

Sys.add12()

+ +THIS and THAT are set to known values so that context save and restore can be tested. +

+Returns argument 0 plus 12. + + +

Test Coverage

+ +

+Functions with no arguments return to correct RIP (Return Instruction Point) with correct return value on stack.
+This can fail if the RIP is not correctly pushed on the stack by the calling code, or if the returning +code does not store the RIP in a temporary register before overwriting it with the return value. + +

+Functions with arguments return to correct RIP with correct return value on stack.
+This can fail if it is assumed that ARG points to the RIP. + +

+Functions with local variables allocate space on the stack for the local variables.
+This can fail if the function prologue is not written or if the SP is not updated after zeroing +the local variables. + +

+All local variables are initialized to 0.
+Common errors are to forget this completely, or for the zeroing loop to be off by one. + +

+THIS and THAT are correctly retained across function calls. Looking ahead, in Project 9 you will be asked to write a simple computer game in the high-level Jack language. You can run your game (following compilation) on the supplied VM Emulator. But, if you choose to translate the VM code that the compiler generates using your VM Translator, then code like +"push THIS, push THAT ... pop THIS, pop THAT" can cause some interesting failures! + + +

Debugging

+These comments assume that your VM translator has passed the SimpleFunction test. +

+If RAM[0] is incorrect, you have a stack skew. More data was pushed onto the stack by +call than was popped by return, or vice versa. See debugging with +breakpoints later in this section. +

+If one or more of RAM[1] through RAM[4] is incorrect, the LCL, +ARG, THIS and THAT pointers are not being correctly saved or restored. +Most likely problem is when they are being saved; the SimpleFunction test verified that +return restored them correctly. +

+If RAM[5] is incorrect there may be a problem with setting up the ARG pointer. +

+If RAM[4] is incorrect and RAM[5] is correct, there may be a problem with +allocation or initialization of local variables. + +

Debugging with breakpoints

+ +To find tough bugs you can use the "breakpoint" facility in the CPU Emulator (red flag button). +You can use breakpoints to have you program stop when it gets to a particular RAM address. For +example:
+ • load the NestedCall.tst file,
+ • set a PC breakpoint at the ROM address for (Sys.main),
+ • hit the run button.
+When the CPU Emulator stops at the breakpoint you can inspect the RAM to check the stack and pointers values. +(If the breakpoint isn't hit, you will need to to single-step debug through +your calling code to see why it didn't get there.) +

+Other useful places to set breakpoints are the entry points to the other functions and at the +first and final instructions generated for return commands. +

+NestedCallStack.html shows the expected stack values at various points +during the test. + +

Finding ROM address in your ASM code

+It is not easy to find the ROM locations where you want to set breakpoints, because there is no +one-to-one correspondence between the ASM file line numbers and the ROM addresses. This is made even more +difficult because the supplied CPU Emulator does not display the (LABELS) in its ROM panel. +

+There are two things that you can do to make this easier. +

+

Modify your assembler to generate a listing file.
+A listing file shows all the ASM source lines, including comments, as well as the ROM addresses and +the values of the labels and the instructions. For example, here is a snippet of a listing file generated by an assembler written by Mark Armbrust: +
+   20    16      @i      // i -= 1
+   21  FC88      M=M-1
+             
+   22  FC10      D=M     // if i > 0
+   23     6      @LOOP
+   24  E301      D;JGT   //      goto LOOP
+             
+   25        (STOP)
+   25    25      @STOP
+   26  EA87      0;JMP
+
+Data Symbols
+
+   16 D  i
+
+Code Symbols
+
+    6 C  LOOP
+   17 C  SKIP
+   25 C  STOP
+
+For the Nand2Tetris environment, it is most useful to list the ROM addresses and A-instruction +values in decimal. In the above snippet, the C-instruction values are +listed in hexadecimal. +

+The list file is generated during pass 2 of the Assembler, parallel to generating the .hack file. To +make it easier to handle blank and comment only lines, Mark has Parser.commandType() return +NO_COMMAND for source lines with no command. Mark also added Parser.sourceLine() that returns the +unmodified source line. +

+

Have your VM Translator write the VM source lines as comments in the ASM output.
+For example: +
+    // label LOOP
+(Sys.init$LOOP)
+    // goto LOOP
+@Sys.init$LOOP
+0;JMP
+    //
+    // // Sys.main()
+    // 
+    // // Sets locals 1, 2 and 3, leaving locals 0 and 4 unchanged to test
+    // // default local initialization to 0.  (RAM set to -1 by test setup.)
+    // // Calls Sys.add12(123) and stores return value (135) in temp 0.
+    // // Returns local 0 + local 1 + local 2 + local 3 + local 4 (456) to confirm
+    // // that locals were not mangled by function call.
+    // 
+    // function Sys.main 5
+(Sys.main)
+@5
+D=-A
+($3)
+@SP
+
+Note that comments in the VM source become double comments. Looking ahead, in Project 11 you will be asked to write a compiler for the Jack language. If your compiler will write the Jack source lines as comments in the +generated VM files, this convention will be quite useful. + + + \ No newline at end of file diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm new file mode 100644 index 000000000..8b0b003d0 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm @@ -0,0 +1,63 @@ +// Sys.vm for NestedCall test. + +// Sys.init() +// +// Calls Sys.main() and stores return value in temp 1. +// Does not return. (Enters infinite loop.) + +function Sys.init 0 +push constant 4000 // test THIS and THAT context save +pop pointer 0 +push constant 5000 +pop pointer 1 +call Sys.main 0 +pop temp 1 +label LOOP +goto LOOP + +// Sys.main() +// +// Sets locals 1, 2 and 3, leaving locals 0 and 4 unchanged to test +// default local initialization to 0. (RAM set to -1 by test setup.) +// Calls Sys.add12(123) and stores return value (135) in temp 0. +// Returns local 0 + local 1 + local 2 + local 3 + local 4 (456) to confirm +// that locals were not mangled by function call. + +function Sys.main 5 +push constant 4001 +pop pointer 0 +push constant 5001 +pop pointer 1 +push constant 200 +pop local 1 +push constant 40 +pop local 2 +push constant 6 +pop local 3 +push constant 123 +call Sys.add12 1 +pop temp 0 +push local 0 +push local 1 +push local 2 +push local 3 +push local 4 +add +add +add +add +return + +// Sys.add12(int n) +// +// Returns n+12. + +function Sys.add12 0 +push constant 4002 +pop pointer 0 +push constant 5002 +pop pointer 1 +push argument 0 +push constant 12 +add +return diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm_tst b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm_tst new file mode 100644 index 000000000..2c689b870 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm_tst @@ -0,0 +1,70 @@ +// Test file for NestedCall test. + +load Sys.vm, +output-file NestedCall.out, +compare-to NestedCall.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; + +set RAM[0] 261, +set RAM[1] 261, +set RAM[2] 256, +set RAM[3] -3, +set RAM[4] -4, +set RAM[5] -1, // test results +set RAM[6] -1, +set RAM[256] 1234, // fake stack frame from call Sys.init +set RAM[257] -1, +set RAM[258] -2, +set RAM[259] -3, +set RAM[260] -4, + +set RAM[261] -1, // Initialize stack to check for local segment +set RAM[262] -1, // being cleared to zero. +set RAM[263] -1, +set RAM[264] -1, +set RAM[265] -1, +set RAM[266] -1, +set RAM[267] -1, +set RAM[268] -1, +set RAM[269] -1, +set RAM[270] -1, +set RAM[271] -1, +set RAM[272] -1, +set RAM[273] -1, +set RAM[274] -1, +set RAM[275] -1, +set RAM[276] -1, +set RAM[277] -1, +set RAM[278] -1, +set RAM[279] -1, +set RAM[280] -1, +set RAM[281] -1, +set RAM[282] -1, +set RAM[283] -1, +set RAM[284] -1, +set RAM[285] -1, +set RAM[286] -1, +set RAM[287] -1, +set RAM[288] -1, +set RAM[289] -1, +set RAM[290] -1, +set RAM[291] -1, +set RAM[292] -1, +set RAM[293] -1, +set RAM[294] -1, +set RAM[295] -1, +set RAM[296] -1, +set RAM[297] -1, +set RAM[298] -1, +set RAM[299] -1, + +set sp 261, +set local 261, +set argument 256, +set this 3000, +set that 4000; + +repeat 50 { + vmstep; +} +output; diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCallStack.html b/projects/src/project_08/FunctionCalls/NestedCall/NestedCallStack.html new file mode 100644 index 000000000..70582b6f2 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/NestedCall/NestedCallStack.html @@ -0,0 +1,306 @@ + + + + + NestedCall.tst — Stack Frames + + + + +
+ + +
+ + + + + + + + + + + +
Bootstrap init
Pointers
0256SP
1-1LCL
2-2ARG
3-3THIS
4-4THAT
Stack
256???←SP

+ This is how my boot­strap code initial­izes the pointers before calling Sys.init(). +

+ Setting the LCL, ARG, THIS and THAT point­ers to known illegal values helps identify + when a pointer is used before it is initial­ized. +

+ (If you are running the NestedCall test with­out boot­strap code, you will not see this state.)

+
+ + + + + + + + + + + + + + + + +
Entry to Sys.init()
Pointers
0261SP
1261LCL
2256ARG
3-3THIS
4-4THAT
Stack
256*Return IP←ARG
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261???←LCL, SP

+ This is how NestedCall.tst initial­izes the pointers and stack. This is what RAM looks + like after my boot­strap calls Sys.init(). +

+ (If your VM trans­lation includes the boot­strap, the -1 through -4 values may be + different if your boot­strap initial­izes them.)

+
+ + + + + + + + + + + + + + + + + + + + +
Entry to Sys.main()
Pointers
0266SP
1266LCL
2261ARG
34000THIS
45000THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
266???←LCL, SP
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
After Sys.main() prologue
Pointers
0271SP
1266LCL
2261ARG
34000THIS
45000THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0←LCL
2670local 1
2680local 2
2690local 3
2700local 4
271???←SP

+ The function prologue is the assembly language code generated for the + "function" VM command. +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Entry to Sys.add12(123)
Pointers
0277SP
1277LCL
2271ARG
34001THIS
45001THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0
267200local 1
26840local 2
2696local 3
2700local 4
271123argument 0←ARG
272*Return IP
273266Saved LCLSys.add12
274261Saved ARG frame
2754001Saved THIS
2765001Saved THAT
277???←LCL, SP
+
+ +

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Before Sys.add12() return
Pointers
0278SP
1277LCL
2271ARG
34002THIS
45002THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0
267200local 1
26840local 2
2696local 3
2700local 4
271123argument 0←ARG
272*Return IP
273266Saved LCLSys.add12
274261Saved ARG frame
2754001Saved THIS
2765001Saved THAT
277135Return value←LCL
278???←SP
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
After Sys.add12() return
Pointers
0272SP
1266LCL
2261ARG
34001THIS
45001THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0←LCL
267200local 1
26840local 2
2696local 3
2700local 4
271135Return value
272???←SP
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Before Sys.main() return
Pointers
0272SP
1266LCL
2261ARG
34001THIS
45001THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0←LCL
267200local 1
26840local 2
2696local 3
2700local 4
271246Return value
272???←SP
+
+ + + + + + + + + + + + + + + + +
After Sys.main() return
Pointers
0262SP
1261LCL
2256ARG
34000THIS
45000THAT
Stack
256*Return IP←ARG
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261246Return value←LCL
262???←SP
+
+ + + + + + + + + + + + + + + +
In Sys.init() halt loop
Pointers
0261SP
1261LCL
2256ARG
34000THIS
45000THAT
Stack
256*Return IP←ARG
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261???←LCL, SP
+
+ + + \ No newline at end of file diff --git a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.cmp b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.cmp new file mode 100644 index 000000000..c3ea911de --- /dev/null +++ b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.cmp @@ -0,0 +1,2 @@ +| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] |RAM[310]| +| 311 | 305 | 300 | 3010 | 4010 | 1196 | diff --git a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.hdl_tst b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.hdl_tst new file mode 100644 index 000000000..c7b590562 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.hdl_tst @@ -0,0 +1,29 @@ +// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.tst + +load SimpleFunction.asm, +output-file SimpleFunction.out, +compare-to SimpleFunction.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 + RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; + +set RAM[0] 317, +set RAM[1] 317, +set RAM[2] 310, +set RAM[3] 3000, +set RAM[4] 4000, +set RAM[310] 1234, +set RAM[311] 37, +set RAM[312] 1000, +set RAM[313] 305, +set RAM[314] 300, +set RAM[315] 3010, +set RAM[316] 4010, + +repeat 300 { + ticktock; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm new file mode 100644 index 000000000..d64a34ff4 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm @@ -0,0 +1,16 @@ +// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.vm + +// Performs a simple calculation and returns the result. +function SimpleFunction.test 2 +push local 0 +push local 1 +add +not +push argument 0 +add +push argument 1 +sub +return diff --git a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm_tst b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm_tst new file mode 100644 index 000000000..c9267ee4d --- /dev/null +++ b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm_tst @@ -0,0 +1,29 @@ +// 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/08/FunctionCalls/SimpleFunction/SimpleFunctionVME.tst + +load SimpleFunction.vm, +output-file SimpleFunction.out, +compare-to SimpleFunction.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 + RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; + +set sp 317, +set local 317, +set argument 310, +set this 3000, +set that 4000, +set argument[0] 1234, +set argument[1] 37, +set argument[2] 9, +set argument[3] 305, +set argument[4] 300, +set argument[5] 3010, +set argument[6] 4010, + +repeat 10 { + vmstep; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/Class1.vm b/projects/src/project_08/FunctionCalls/StaticsTest/Class1.vm new file mode 100644 index 000000000..c4635377e --- /dev/null +++ b/projects/src/project_08/FunctionCalls/StaticsTest/Class1.vm @@ -0,0 +1,20 @@ +// 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/08/FunctionCalls/StaticsTest/Class1.vm + +// Stores two supplied arguments in static[0] and static[1]. +function Class1.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class1.get 0 +push static 0 +push static 1 +sub +return diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/Class2.vm b/projects/src/project_08/FunctionCalls/StaticsTest/Class2.vm new file mode 100644 index 000000000..94f294668 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/StaticsTest/Class2.vm @@ -0,0 +1,20 @@ +// 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/08/FunctionCalls/StaticsTest/Class2.vm + +// Stores two supplied arguments in static[0] and static[1]. +function Class2.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class2.get 0 +push static 0 +push static 1 +sub +return diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.cmp b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.cmp new file mode 100644 index 000000000..5589f1ec2 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.cmp @@ -0,0 +1,2 @@ +| RAM[0] |RAM[261]|RAM[262]| +| 263 | -2 | 8 | diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.hdl_tst b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.hdl_tst new file mode 100644 index 000000000..1b9194ed9 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.hdl_tst @@ -0,0 +1,17 @@ +// 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/08/FunctionCalls/StaticsTest/StaticsTest.tst + +load StaticsTest.asm, +output-file StaticsTest.out, +compare-to StaticsTest.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; + +set RAM[0] 256, + +repeat 2500 { + ticktock; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm new file mode 100644 index 000000000..394e4e975 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm @@ -0,0 +1,60 @@ +// 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/08/FunctionCalls/StaticsTest/Class1.vm + +// Stores two supplied arguments in static[0] and static[1]. +function Class1.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class1.get 0 +push static 0 +push static 1 +sub +return +// 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/08/FunctionCalls/StaticsTest/Class2.vm + +// Stores two supplied arguments in static[0] and static[1]. +function Class2.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class2.get 0 +push static 0 +push static 1 +sub +return +// 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/08/FunctionCalls/StaticsTest/Sys.vm + +// Tests that different functions, stored in two different +// class files, manipulate the static segment correctly. +function Sys.init 0 +push constant 6 +push constant 8 +call Class1.set 2 +pop temp 0 // Dumps the return value +push constant 23 +push constant 15 +call Class2.set 2 +pop temp 0 // Dumps the return value +call Class1.get 0 +call Class2.get 0 +label WHILE +goto WHILE diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm_tst b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm_tst new file mode 100644 index 000000000..130ba66b8 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm_tst @@ -0,0 +1,17 @@ +// 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/08/FunctionCalls/StaticsTest/StaticsTestVME.tst + +load, // loads all the VM files from the current directory. +output-file StaticsTest.out, +compare-to StaticsTest.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; + +set sp 261, + +repeat 36 { + vmstep; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/Sys.vm b/projects/src/project_08/FunctionCalls/StaticsTest/Sys.vm new file mode 100644 index 000000000..370832264 --- /dev/null +++ b/projects/src/project_08/FunctionCalls/StaticsTest/Sys.vm @@ -0,0 +1,20 @@ +// 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/08/FunctionCalls/StaticsTest/Sys.vm + +// Tests that different functions, stored in two different +// class files, manipulate the static segment correctly. +function Sys.init 0 +push constant 6 +push constant 8 +call Class1.set 2 +pop temp 0 // Dumps the return value +push constant 23 +push constant 15 +call Class2.set 2 +pop temp 0 // Dumps the return value +call Class1.get 0 +call Class2.get 0 +label WHILE +goto WHILE diff --git a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.cmp b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.cmp new file mode 100644 index 000000000..00d35d2a9 --- /dev/null +++ b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.cmp @@ -0,0 +1,2 @@ +| RAM[0] |RAM[256]| +| 257 | 6 | diff --git a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.hdl_tst b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.hdl_tst new file mode 100644 index 000000000..50ca11885 --- /dev/null +++ b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.hdl_tst @@ -0,0 +1,20 @@ +// 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/08/ProgramFlow/BasicLoop/BasicLoop.tst + +load BasicLoop.asm, +output-file BasicLoop.out, +compare-to BasicLoop.cmp, +output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; + +set RAM[0] 256, +set RAM[1] 300, +set RAM[2] 400, +set RAM[400] 3, + +repeat 600 { + ticktock; +} + +output; diff --git a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm new file mode 100644 index 000000000..dc5a92f5f --- /dev/null +++ b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm @@ -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/08/ProgramFlow/BasicLoop/BasicLoop.vm + +// Computes the sum 1 + 2 + ... + argument[0] and pushes the +// result onto the stack. Argument[0] is initialized by the test +// script before this code starts running. +push constant 0 +pop local 0 // initializes sum = 0 +label LOOP_START +push argument 0 +push local 0 +add +pop local 0 // sum = sum + counter +push argument 0 +push constant 1 +sub +pop argument 0 // counter-- +push argument 0 +if-goto LOOP_START // If counter != 0, goto LOOP_START +push local 0 diff --git a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm_tst b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm_tst new file mode 100644 index 000000000..237fdff53 --- /dev/null +++ b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm_tst @@ -0,0 +1,20 @@ +// 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/08/ProgramFlow/BasicLoop/BasicLoopVME.tst + +load BasicLoop.vm, +output-file BasicLoop.out, +compare-to BasicLoop.cmp, +output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; + +set sp 256, +set local 300, +set argument 400, +set argument[0] 3, + +repeat 33 { + vmstep; +} + +output; diff --git a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.cmp b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.cmp new file mode 100644 index 000000000..c262a4b6b --- /dev/null +++ b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.cmp @@ -0,0 +1,2 @@ +|RAM[3000]|RAM[3001]|RAM[3002]|RAM[3003]|RAM[3004]|RAM[3005]| +| 0 | 1 | 1 | 2 | 3 | 5 | diff --git a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.hdl_tst b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.hdl_tst new file mode 100644 index 000000000..07df2b925 --- /dev/null +++ b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.hdl_tst @@ -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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.tst + +load FibonacciSeries.asm, +output-file FibonacciSeries.out, +compare-to FibonacciSeries.cmp, +output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 + RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; + +set RAM[0] 256, +set RAM[1] 300, +set RAM[2] 400, +set RAM[400] 6, +set RAM[401] 3000, + +repeat 1100 { + ticktock; +} + +output; diff --git a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm new file mode 100644 index 000000000..6a643b6fd --- /dev/null +++ b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm @@ -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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm + +// Puts the first argument[0] elements of the Fibonacci series +// in the memory, starting in the address given in argument[1]. +// Argument[0] and argument[1] are initialized by the test script +// before this code starts running. + +push argument 1 +pop pointer 1 // that = argument[1] + +push constant 0 +pop that 0 // first element in the series = 0 +push constant 1 +pop that 1 // second element in the series = 1 + +push argument 0 +push constant 2 +sub +pop argument 0 // num_of_elements -= 2 (first 2 elements are set) + +label MAIN_LOOP_START + +push argument 0 +if-goto COMPUTE_ELEMENT // if num_of_elements > 0, goto COMPUTE_ELEMENT +goto END_PROGRAM // otherwise, goto END_PROGRAM + +label COMPUTE_ELEMENT + +push that 0 +push that 1 +add +pop that 2 // that[2] = that[0] + that[1] + +push pointer 1 +push constant 1 +add +pop pointer 1 // that += 1 + +push argument 0 +push constant 1 +sub +pop argument 0 // num_of_elements-- + +goto MAIN_LOOP_START + +label END_PROGRAM diff --git a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm_tst b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm_tst new file mode 100644 index 000000000..243f31bd6 --- /dev/null +++ b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm_tst @@ -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/08/ProgramFlow/FibonacciSeries/FibonacciSeriesVME.tst + +load FibonacciSeries.vm, +output-file FibonacciSeries.out, +compare-to FibonacciSeries.cmp, +output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 + RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; + +set sp 256, +set local 300, +set argument 400, +set argument[0] 6, +set argument[1] 3000, + +repeat 73 { + vmstep; +} + +output; diff --git a/projects/src/project_08/index.ts b/projects/src/project_08/index.ts new file mode 100644 index 000000000..a8dd00bfe --- /dev/null +++ b/projects/src/project_08/index.ts @@ -0,0 +1,52 @@ +import { FileSystem, reset } from "@davidsouther/jiffies/lib/esm/fs.js"; +import * as basic_loop from "./11_basic_loop.js"; +import * as fibonacci_series from "./12_fibonacci_series.js"; +import * as simple_function from "./20_simple_function.js"; +import * as nested_call from "./21_nested_call.js"; +import * as fibonacci_element from "./22_fibonacci_element.js"; +import * as statics_test from "./23_statics_test.js"; + +export const VMS = { + BasicLoop: { + "BasicLoop.vm": basic_loop.vm, + "BasicLoop.vm_tst": basic_loop.vm_tst, + "BasicLoop.cmp": basic_loop.cmp, + "BasicLoop.tst": basic_loop.hdl_tst, + }, + FibonacciSeries: { + "FibonacciSeries.vm": fibonacci_series.vm, + "FibonacciSeries.vm_tst": fibonacci_series.vm_tst, + "FibonacciSeries.cmp": fibonacci_series.cmp, + "FibonacciSeries.tst": fibonacci_series.hdl_tst, + }, + SimpleFunction: { + "SimpleFunction.vm": simple_function.vm, + "SimpleFunction.vm_tst": simple_function.vm_tst, + "SimpleFunction.cmp": simple_function.cmp, + "SimpleFunction.tst": simple_function.hdl_tst, + }, + NestedCall: { + "NestedCall.vm": nested_call.vm, + "NestedCall.vm_tst": nested_call.vm_tst, + "NestedCall.cmp": nested_call.cmp, + "NestedCall.tst": nested_call.hdl_tst, + }, + FibonacciElement: { + "FibonacciElement.vm": fibonacci_element.vm, + "FibonacciElement.vm_tst": fibonacci_element.vm_tst, + "FibonacciElement.cmp": fibonacci_element.cmp, + "FibonacciElement.tst": fibonacci_element.hdl_tst, + }, + StaticsTest: { + "StaticsTest.vm": statics_test.vm, + "StaticsTest.vm_tst": statics_test.vm_tst, + "StaticsTest.cmp": statics_test.cmp, + "StaticsTest.tst": statics_test.hdl_tst, + }, +}; + +export async function resetFiles(fs: FileSystem): Promise { + await fs.pushd("/projects/08"); + await reset(fs, VMS); + await fs.popd(); +} diff --git a/simulator/src/test/vmtst.test.ts b/simulator/src/test/vmtst.test.ts new file mode 100644 index 000000000..e69de29bb From 9e1aaf0aca7e8c7aeacdaea020af0c3a29fe9d98 Mon Sep 17 00:00:00 2001 From: David Souther Date: Sun, 12 Nov 2023 15:18:22 -0500 Subject: [PATCH 09/14] Normalized line endings and fixed ; on ending SET blocks in VM tests --- projects/src/index.ts | 4 +- projects/src/project_07/11_simple_add.ts | 89 ++- projects/src/project_07/12_stack_test.ts | 185 +++--- projects/src/project_07/21_basic_test.ts | 165 +++-- projects/src/project_07/22_pointer_test.ts | 142 ++-- projects/src/project_07/23_static_test.ts | 103 ++- .../MemoryAccess/BasicTest/BasicTest.cmp | 4 +- .../MemoryAccess/BasicTest/BasicTest.hdl_tst | 50 +- .../MemoryAccess/BasicTest/BasicTest.vm | 62 +- .../MemoryAccess/BasicTest/BasicTest.vm_tst | 50 +- .../MemoryAccess/PointerTest/PointerTest.cmp | 4 +- .../PointerTest/PointerTest.hdl_tst | 40 +- .../MemoryAccess/PointerTest/PointerTest.vm | 44 +- .../PointerTest/PointerTest.vm_tst | 40 +- .../MemoryAccess/StaticTest/StaticTest.cmp | 4 +- .../StaticTest/StaticTest.hdl_tst | 34 +- .../MemoryAccess/StaticTest/StaticTest.vm | 34 +- .../MemoryAccess/StaticTest/StaticTest.vm_tst | 34 +- .../StackArithmetic/SimpleAdd/SimpleAdd.cmp | 4 +- .../SimpleAdd/SimpleAdd.hdl_tst | 34 +- .../StackArithmetic/SimpleAdd/SimpleAdd.vm | 18 +- .../SimpleAdd/SimpleAdd.vm_tst | 34 +- .../StackArithmetic/StackTest/StackTest.cmp | 8 +- .../StackTest/StackTest.hdl_tst | 44 +- .../StackArithmetic/StackTest/StackTest.vm | 90 +-- .../StackTest/StackTest.vm_tst | 44 +- projects/src/project_07/index.ts | 12 +- projects/src/project_08/11_basic_loop.ts | 127 ++-- .../src/project_08/12_fibonacci_series.ts | 189 +++--- projects/src/project_08/20_simple_function.ts | 151 +++-- projects/src/project_08/21_nested_call.ts | 399 ++++++------ .../src/project_08/22_fibonacci_element.ts | 163 +++-- projects/src/project_08/23_statics_test.ts | 191 +++--- .../FibonacciElement/FibonacciElement.cmp | 4 +- .../FibonacciElement/FibonacciElement.hdl_tst | 36 +- .../FibonacciElement/FibonacciElement.vm | 90 +-- .../FibonacciElement/FibonacciElement.vm_tst | 34 +- .../FunctionCalls/FibonacciElement/Main.vm | 60 +- .../FunctionCalls/FibonacciElement/Sys.vm | 30 +- .../FunctionCalls/NestedCall/NestedCall.cmp | 4 +- .../NestedCall/NestedCall.hdl_tst | 130 ++-- .../FunctionCalls/NestedCall/NestedCall.vm | 126 ++-- .../NestedCall/NestedCall.vm_tst | 140 ++-- .../NestedCall/NestedCallStack.html | 610 +++++++++--------- .../SimpleFunction/SimpleFunction.cmp | 4 +- .../SimpleFunction/SimpleFunction.hdl_tst | 58 +- .../SimpleFunction/SimpleFunction.vm | 32 +- .../SimpleFunction/SimpleFunction.vm_tst | 58 +- .../FunctionCalls/StaticsTest/Class1.vm | 40 +- .../FunctionCalls/StaticsTest/Class2.vm | 40 +- .../FunctionCalls/StaticsTest/StaticsTest.cmp | 4 +- .../StaticsTest/StaticsTest.hdl_tst | 34 +- .../FunctionCalls/StaticsTest/StaticsTest.vm | 120 ++-- .../StaticsTest/StaticsTest.vm_tst | 34 +- .../FunctionCalls/StaticsTest/Sys.vm | 40 +- .../ProgramFlow/BasicLoop/BasicLoop.cmp | 4 +- .../ProgramFlow/BasicLoop/BasicLoop.hdl_tst | 40 +- .../ProgramFlow/BasicLoop/BasicLoop.vm | 44 +- .../ProgramFlow/BasicLoop/BasicLoop.vm_tst | 40 +- .../FibonacciSeries/FibonacciSeries.cmp | 4 +- .../FibonacciSeries/FibonacciSeries.hdl_tst | 44 +- .../FibonacciSeries/FibonacciSeries.vm | 98 +-- .../FibonacciSeries/FibonacciSeries.vm_tst | 44 +- projects/src/project_08/index.ts | 2 +- 64 files changed, 2296 insertions(+), 2348 deletions(-) diff --git a/projects/src/index.ts b/projects/src/index.ts index b0a5de4cd..ab2bd7e51 100644 --- a/projects/src/index.ts +++ b/projects/src/index.ts @@ -34,7 +34,7 @@ export const ChipProjects = { "05": project_05, }; -export const VmProjets = { +export const VmProjects = { "07": project_07, "08": project_08, }; @@ -112,7 +112,7 @@ export const ASM_PROJECTS: Record<"06", string[]> = { }; export const VM_PROJECTS: Record<"07" | "08", string[]> = { - "07": ["SimpleAdd", "StackTest", "MemoryTest", "PointerTest", "StaticTest"], + "07": ["SimpleAdd", "StackTest", "BasicTest", "PointerTest", "StaticTest"], "08": [ "BasicLoop", "FibonacciSeries", diff --git a/projects/src/project_07/11_simple_add.ts b/projects/src/project_07/11_simple_add.ts index 3f3450bcb..9b842cc11 100644 --- a/projects/src/project_07/11_simple_add.ts +++ b/projects/src/project_07/11_simple_add.ts @@ -1,57 +1,52 @@ -export const vm = `// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.vm - -// Pushes and adds two constants. -push constant 7 -push constant 8 -add +export const vm = `// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.vm + +// Pushes and adds two constants. +push constant 7 +push constant 8 +add `; +export const vm_tst = `// 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/07/StackArithmetic/SimpleAdd/SimpleAddVME.tst -export const vm_tst = `// 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/07/StackArithmetic/SimpleAdd/SimpleAddVME.tst - -load SimpleAdd.vm, -output-file SimpleAdd.out, -compare-to SimpleAdd.cmp, -output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; - -set RAM[0] 256, // initializes the stack pointer - -repeat 3 { // SimpleAdd.vm has 3 instructions - vmstep; -} - -output; // the stack pointer and the stack base -`; +load SimpleAdd.vm, +output-file SimpleAdd.out, +compare-to SimpleAdd.cmp, +output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; + +set RAM[0] 256; // initializes the stack pointer +repeat 3 { // SimpleAdd.vm has 3 instructions + vmstep; +} -export const hdl_tst = `// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.tst - -load SimpleAdd.asm, -output-file SimpleAdd.out, -compare-to SimpleAdd.cmp, -output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; - -set RAM[0] 256, // initializes the stack pointer - -repeat 60 { // enough cycles to complete the execution - ticktock; -} - -output; // the stack pointer and the stack base +output; // the stack pointer and the stack base `; +export const hdl_tst = `// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.tst -export const cmp = `| RAM[0] | RAM[256] | -| 257 | 15 | -`; +load SimpleAdd.asm, +output-file SimpleAdd.out, +compare-to SimpleAdd.cmp, +output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; + +set RAM[0] 256; // initializes the stack pointer +repeat 60 { // enough cycles to complete the execution + ticktock; +} +output; // the stack pointer and the stack base +`; + +export const cmp = `| RAM[0] | RAM[256] | +| 257 | 15 | +`; diff --git a/projects/src/project_07/12_stack_test.ts b/projects/src/project_07/12_stack_test.ts index 67fac0133..4c1812fce 100644 --- a/projects/src/project_07/12_stack_test.ts +++ b/projects/src/project_07/12_stack_test.ts @@ -1,105 +1,100 @@ -export const vm = `// 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/07/StackArithmetic/StackTest/StackTest.vm - -// Executes a sequence of arithmetic and logical operations -// on the stack. -push constant 17 -push constant 17 -eq -push constant 17 -push constant 16 -eq -push constant 16 -push constant 17 -eq -push constant 892 -push constant 891 -lt -push constant 891 -push constant 892 -lt -push constant 891 -push constant 891 -lt -push constant 32767 -push constant 32766 -gt -push constant 32766 -push constant 32767 -gt -push constant 32766 -push constant 32766 -gt -push constant 57 -push constant 31 -push constant 53 -add -push constant 112 -sub -neg -and -push constant 82 -or -not +export const vm = `// 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/07/StackArithmetic/StackTest/StackTest.vm + +// Executes a sequence of arithmetic and logical operations +// on the stack. +push constant 17 +push constant 17 +eq +push constant 17 +push constant 16 +eq +push constant 16 +push constant 17 +eq +push constant 892 +push constant 891 +lt +push constant 891 +push constant 892 +lt +push constant 891 +push constant 891 +lt +push constant 32767 +push constant 32766 +gt +push constant 32766 +push constant 32767 +gt +push constant 32766 +push constant 32766 +gt +push constant 57 +push constant 31 +push constant 53 +add +push constant 112 +sub +neg +and +push constant 82 +or +not `; +export const vm_tst = `// 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/07/StackArithmetic/StackTest/StackTestVME.tst -export const vm_tst = `// 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/07/StackArithmetic/StackTest/StackTestVME.tst - -load StackTest.vm, -output-file StackTest.out, -compare-to StackTest.cmp, -output-list RAM[0]%D2.6.2 - RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; - -set RAM[0] 256, // initializes the stack pointer - -repeat 38 { // StackTest.vm consists of 38 instructions - vmstep; -} - -// outputs the stack pointer (RAM[0]) and -// the stack contents: RAM[256]-RAM[265] -output; -output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; -output; -`; +load StackTest.vm, +output-file StackTest.out, +compare-to StackTest.cmp, +output-list RAM[0]%D2.6.2 + RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; +set RAM[0] 256; // initializes the stack pointer -export const hdl_tst = `// 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/07/StackArithmetic/StackTest/StackTest.tst - -load StackTest.asm, -output-file StackTest.out, -compare-to StackTest.cmp, -output-list RAM[0]%D2.6.2 - RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; - -set RAM[0] 256, // initializes the stack pointer - -repeat 1000 { // enough cycles to complete the execution - ticktock; -} - -// outputs the stack pointer (RAM[0]) and -// the stack contents: RAM[256]-RAM[265] -output; -output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; -output; +repeat 38 { // StackTest.vm consists of 38 instructions + vmstep; +} + +// outputs the stack pointer (RAM[0]) and +// the stack contents: RAM[256]-RAM[265] +output; +output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; +output; `; +export const hdl_tst = `// 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/07/StackArithmetic/StackTest/StackTest.tst -export const cmp = `| RAM[0] | RAM[256] | RAM[257] | RAM[258] | RAM[259] | RAM[260] | -| 266 | -1 | 0 | 0 | 0 | -1 | -| RAM[261] | RAM[262] | RAM[263] | RAM[264] | RAM[265] | -| 0 | -1 | 0 | 0 | -91 | -`; +load StackTest.asm, +output-file StackTest.out, +compare-to StackTest.cmp, +output-list RAM[0]%D2.6.2 + RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; +set RAM[0] 256, // initializes the stack pointer +repeat 1000 { // enough cycles to complete the execution + ticktock; +} + +// outputs the stack pointer (RAM[0]) and +// the stack contents: RAM[256]-RAM[265] +output; +output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; +output; +`; + +export const cmp = `| RAM[0] | RAM[256] | RAM[257] | RAM[258] | RAM[259] | RAM[260] | +| 266 | -1 | 0 | 0 | 0 | -1 | +| RAM[261] | RAM[262] | RAM[263] | RAM[264] | RAM[265] | +| 0 | -1 | 0 | 0 | -91 | +`; diff --git a/projects/src/project_07/21_basic_test.ts b/projects/src/project_07/21_basic_test.ts index cccc46ac2..86b57ece1 100644 --- a/projects/src/project_07/21_basic_test.ts +++ b/projects/src/project_07/21_basic_test.ts @@ -1,95 +1,90 @@ -export const vm = `// 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/07/MemoryAccess/BasicTest/BasicTest.vm - -// Executes pop and push commands using the virtual memory segments. -push constant 10 -pop local 0 -push constant 21 -push constant 22 -pop argument 2 -pop argument 1 -push constant 36 -pop this 6 -push constant 42 -push constant 45 -pop that 5 -pop that 2 -push constant 510 -pop temp 6 -push local 0 -push that 5 -add -push argument 1 -sub -push this 6 -push this 6 -add -sub -push temp 6 -add +export const vm = `// 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/07/MemoryAccess/BasicTest/BasicTest.vm + +// Executes pop and push commands using the virtual memory segments. +push constant 10 +pop local 0 +push constant 21 +push constant 22 +pop argument 2 +pop argument 1 +push constant 36 +pop this 6 +push constant 42 +push constant 45 +pop that 5 +pop that 2 +push constant 510 +pop temp 6 +push local 0 +push that 5 +add +push argument 1 +sub +push this 6 +push this 6 +add +sub +push temp 6 +add `; +export const vm_tst = `// 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/07/MemoryAccess/BasicTest/BasicTestVME.tst -export const vm_tst = `// 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/07/MemoryAccess/BasicTest/BasicTestVME.tst - -load BasicTest.vm, -output-file BasicTest.out, -compare-to BasicTest.cmp, -output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 - RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 - RAM[3015]%D1.6.1 RAM[11]%D1.6.1; - -set sp 256, // stack pointer -set local 300, // base address of the local segment -set argument 400, // base address of the argument segment -set this 3000, // base address of the this segment -set that 3010, // base address of the that segment - -repeat 25 { // BasicTest.vm has 25 instructions - vmstep; -} - -// Outputs the stack base and some values -// from the tested memory segments -output; -`; +load BasicTest.vm, +output-file BasicTest.out, +compare-to BasicTest.cmp, +output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 + RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 + RAM[3015]%D1.6.1 RAM[11]%D1.6.1; +set sp 256, // stack pointer +set local 300, // base address of the local segment +set argument 400, // base address of the argument segment +set this 3000, // base address of the this segment +set that 3010; // base address of the that segment -export const hdl_tst = `// 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/07/MemoryAccess/BasicTest/BasicTest.tst - -load BasicTest.asm, -output-file BasicTest.out, -compare-to BasicTest.cmp, -output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 - RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 - RAM[3015]%D1.6.1 RAM[11]%D1.6.1; - -set RAM[0] 256, // stack pointer -set RAM[1] 300, // base address of the local segment -set RAM[2] 400, // base address of the argument segment -set RAM[3] 3000, // base address of the this segment -set RAM[4] 3010, // base address of the that segment - -repeat 600 { // enough cycles to complete the execution - ticktock; -} - -// Outputs the stack base and some values -// from the tested memory segments -output; +repeat 25 { // BasicTest.vm has 25 instructions + vmstep; +} + +// Outputs the stack base and some values +// from the tested memory segments +output; `; +export const hdl_tst = `// 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/07/MemoryAccess/BasicTest/BasicTest.tst -export const cmp = `|RAM[256]|RAM[300]|RAM[401]|RAM[402]|RAM[3006|RAM[3012|RAM[3015|RAM[11] | -| 472 | 10 | 21 | 22 | 36 | 42 | 45 | 510 | -`; +load BasicTest.asm, +output-file BasicTest.out, +compare-to BasicTest.cmp, +output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 + RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 + RAM[3015]%D1.6.1 RAM[11]%D1.6.1; +set RAM[0] 256, // stack pointer +set RAM[1] 300, // base address of the local segment +set RAM[2] 400, // base address of the argument segment +set RAM[3] 3000, // base address of the this segment +set RAM[4] 3010; // base address of the that segment +repeat 600 { // enough cycles to complete the execution + ticktock; +} + +// Outputs the stack base and some values +// from the tested memory segments +output; +`; + +export const cmp = `|RAM[256]|RAM[300]|RAM[401]|RAM[402]|RAM[3006|RAM[3012|RAM[3015|RAM[11] | +| 472 | 10 | 21 | 22 | 36 | 42 | 45 | 510 | +`; diff --git a/projects/src/project_07/22_pointer_test.ts b/projects/src/project_07/22_pointer_test.ts index 694fea4f2..a7c46981d 100644 --- a/projects/src/project_07/22_pointer_test.ts +++ b/projects/src/project_07/22_pointer_test.ts @@ -1,71 +1,71 @@ -export const vm = `// 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/07/MemoryAccess/PointerTest/PointerTest.vm - -// Executes pop and push commands using the -// pointer, this, and that segments. -push constant 3030 -pop pointer 0 -push constant 3040 -pop pointer 1 -push constant 32 -pop this 2 -push constant 46 -pop that 6 -push pointer 0 -push pointer 1 -add -push this 2 -sub -push that 6 -add -`; - -export const vm_tst = `// 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/07/MemoryAccess/PointerTest/PointerTestVME.tst - -load PointerTest.vm, -output-file PointerTest.out, -compare-to PointerTest.cmp, -output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 - RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; - -set RAM[0] 256, // initializes the stack pointer - -repeat 15 { // PointerTest.vm has 15 instructions - vmstep; -} - -// outputs the stack base, this, that, and -// some values from the the this and that segments -output; -`; - -export const hdl_tst = `// 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/07/MemoryAccess/PointerTest/PointerTest.tst - -load PointerTest.asm, -output-file PointerTest.out, -compare-to PointerTest.cmp, -output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 - RAM[4]%D1.6.1 RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; - -set RAM[0] 256, // initializes the stack pointer - -repeat 450 { // enough cycles to complete the execution - ticktock; -} - -// outputs the stack base, this, that, and -// some values from the the this and that segments -output; -`; - -export const cmp = `|RAM[256]| RAM[3] | RAM[4] |RAM[3032|RAM[3046| -| 6084 | 3030 | 3040 | 32 | 46 | -`; +export const vm = `// 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/07/MemoryAccess/PointerTest/PointerTest.vm + +// Executes pop and push commands using the +// pointer, this, and that segments. +push constant 3030 +pop pointer 0 +push constant 3040 +pop pointer 1 +push constant 32 +pop this 2 +push constant 46 +pop that 6 +push pointer 0 +push pointer 1 +add +push this 2 +sub +push that 6 +add +`; + +export const vm_tst = `// 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/07/MemoryAccess/PointerTest/PointerTestVME.tst + +load PointerTest.vm, +output-file PointerTest.out, +compare-to PointerTest.cmp, +output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 + RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; + +set RAM[0] 256; // initializes the stack pointer + +repeat 15 { // PointerTest.vm has 15 instructions + vmstep; +} + +// outputs the stack base, this, that, and +// some values from the the this and that segments +output; +`; + +export const hdl_tst = `// 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/07/MemoryAccess/PointerTest/PointerTest.tst + +load PointerTest.asm, +output-file PointerTest.out, +compare-to PointerTest.cmp, +output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 + RAM[4]%D1.6.1 RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; + +set RAM[0] 256; // initializes the stack pointer + +repeat 450 { // enough cycles to complete the execution + ticktock; +} + +// outputs the stack base, this, that, and +// some values from the the this and that segments +output; +`; + +export const cmp = `|RAM[256]| RAM[3] | RAM[4] |RAM[3032|RAM[3046| +| 6084 | 3030 | 3040 | 32 | 46 | +`; diff --git a/projects/src/project_07/23_static_test.ts b/projects/src/project_07/23_static_test.ts index 8e38cc975..0733d811d 100644 --- a/projects/src/project_07/23_static_test.ts +++ b/projects/src/project_07/23_static_test.ts @@ -1,65 +1,58 @@ -export const vm = `// 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/07/MemoryAccess/StaticTest/StaticTest.vm - -// Executes pop and push commands using the static segment. -push constant 111 -push constant 333 -push constant 888 -pop static 8 -pop static 3 -pop static 1 -push static 3 -push static 1 -sub -push static 8 -add +export const vm = `// 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/07/MemoryAccess/StaticTest/StaticTest.vm + +// Executes pop and push commands using the static segment. +push constant 111 +push constant 333 +push constant 888 +pop static 8 +pop static 3 +pop static 1 +push static 3 +push static 1 +sub +push static 8 +add `; +export const vm_tst = `// 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/07/MemoryAccess/StaticTest/StaticTestVME.tst -export const vm_tst = `// 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/07/MemoryAccess/StaticTest/StaticTestVME.tst - -load StaticTest.vm, -output-file StaticTest.out, -compare-to StaticTest.cmp, -output-list RAM[256]%D1.6.1; - -set sp 256, // initializes the stack pointer - -repeat 11 { // StaticTest.vm has 11 instructions - vmstep; -} - -output; // the stack base -`; +load StaticTest.vm, +output-file StaticTest.out, +compare-to StaticTest.cmp, +output-list RAM[256]%D1.6.1; +repeat 11 { // StaticTest.vm has 11 instructions + vmstep; +} -export const hdl_tst = `// 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/07/MemoryAccess/StaticTest/StaticTest.tst - -load StaticTest.asm, -output-file StaticTest.out, -compare-to StaticTest.cmp, -output-list RAM[256]%D1.6.1; - -set RAM[0] 256, // initializes the stack pointer - -repeat 200 { // enough cycles to complete the execution - ticktock; -} - -output; // the stack base +output; // the stack base `; +export const hdl_tst = `// 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/07/MemoryAccess/StaticTest/StaticTest.tst -export const cmp = `|RAM[256]| -| 1110 | -`; +load StaticTest.asm, +output-file StaticTest.out, +compare-to StaticTest.cmp, +output-list RAM[256]%D1.6.1; + +set RAM[0] 256; // initializes the stack pointer +repeat 200 { // enough cycles to complete the execution + ticktock; +} +output; // the stack base +`; + +export const cmp = `|RAM[256]| +| 1110 | +`; diff --git a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.cmp b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.cmp index 538454bde..85c19a7c7 100644 --- a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.cmp +++ b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.cmp @@ -1,2 +1,2 @@ -|RAM[256]|RAM[300]|RAM[401]|RAM[402]|RAM[3006|RAM[3012|RAM[3015|RAM[11] | -| 472 | 10 | 21 | 22 | 36 | 42 | 45 | 510 | +|RAM[256]|RAM[300]|RAM[401]|RAM[402]|RAM[3006|RAM[3012|RAM[3015|RAM[11] | +| 472 | 10 | 21 | 22 | 36 | 42 | 45 | 510 | diff --git a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.hdl_tst b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.hdl_tst index fa6d9a6f9..9fb626ed1 100644 --- a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.hdl_tst +++ b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.hdl_tst @@ -1,25 +1,25 @@ -// 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/07/MemoryAccess/BasicTest/BasicTest.tst - -load BasicTest.asm, -output-file BasicTest.out, -compare-to BasicTest.cmp, -output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 - RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 - RAM[3015]%D1.6.1 RAM[11]%D1.6.1; - -set RAM[0] 256, // stack pointer -set RAM[1] 300, // base address of the local segment -set RAM[2] 400, // base address of the argument segment -set RAM[3] 3000, // base address of the this segment -set RAM[4] 3010, // base address of the that segment - -repeat 600 { // enough cycles to complete the execution - ticktock; -} - -// Outputs the stack base and some values -// from the tested memory segments -output; +// 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/07/MemoryAccess/BasicTest/BasicTest.tst + +load BasicTest.asm, +output-file BasicTest.out, +compare-to BasicTest.cmp, +output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 + RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 + RAM[3015]%D1.6.1 RAM[11]%D1.6.1; + +set RAM[0] 256, // stack pointer +set RAM[1] 300, // base address of the local segment +set RAM[2] 400, // base address of the argument segment +set RAM[3] 3000, // base address of the this segment +set RAM[4] 3010; // base address of the that segment + +repeat 600 { // enough cycles to complete the execution + ticktock; +} + +// Outputs the stack base and some values +// from the tested memory segments +output; diff --git a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm index b2f93431c..6fd45231f 100644 --- a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm +++ b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm @@ -1,31 +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/07/MemoryAccess/BasicTest/BasicTest.vm - -// Executes pop and push commands using the virtual memory segments. -push constant 10 -pop local 0 -push constant 21 -push constant 22 -pop argument 2 -pop argument 1 -push constant 36 -pop this 6 -push constant 42 -push constant 45 -pop that 5 -pop that 2 -push constant 510 -pop temp 6 -push local 0 -push that 5 -add -push argument 1 -sub -push this 6 -push this 6 -add -sub -push temp 6 -add +// 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/07/MemoryAccess/BasicTest/BasicTest.vm + +// Executes pop and push commands using the virtual memory segments. +push constant 10 +pop local 0 +push constant 21 +push constant 22 +pop argument 2 +pop argument 1 +push constant 36 +pop this 6 +push constant 42 +push constant 45 +pop that 5 +pop that 2 +push constant 510 +pop temp 6 +push local 0 +push that 5 +add +push argument 1 +sub +push this 6 +push this 6 +add +sub +push temp 6 +add diff --git a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm_tst b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm_tst index 24e909069..784403077 100644 --- a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm_tst +++ b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm_tst @@ -1,25 +1,25 @@ -// 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/07/MemoryAccess/BasicTest/BasicTestVME.tst - -load BasicTest.vm, -output-file BasicTest.out, -compare-to BasicTest.cmp, -output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 - RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 - RAM[3015]%D1.6.1 RAM[11]%D1.6.1; - -set sp 256, // stack pointer -set local 300, // base address of the local segment -set argument 400, // base address of the argument segment -set this 3000, // base address of the this segment -set that 3010, // base address of the that segment - -repeat 25 { // BasicTest.vm has 25 instructions - vmstep; -} - -// Outputs the stack base and some values -// from the tested memory segments -output; +// 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/07/MemoryAccess/BasicTest/BasicTestVME.tst + +load BasicTest.vm, +output-file BasicTest.out, +compare-to BasicTest.cmp, +output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 + RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 + RAM[3015]%D1.6.1 RAM[11]%D1.6.1; + +set sp 256, // stack pointer +set local 300, // base address of the local segment +set argument 400, // base address of the argument segment +set this 3000, // base address of the this segment +set that 3010; // base address of the that segment + +repeat 25 { // BasicTest.vm has 25 instructions + vmstep; +} + +// Outputs the stack base and some values +// from the tested memory segments +output; diff --git a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.cmp b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.cmp index b59fa97ce..5d62de88b 100644 --- a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.cmp +++ b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.cmp @@ -1,2 +1,2 @@ -|RAM[256]| RAM[3] | RAM[4] |RAM[3032|RAM[3046| -| 6084 | 3030 | 3040 | 32 | 46 | +|RAM[256]| RAM[3] | RAM[4] |RAM[3032|RAM[3046| +| 6084 | 3030 | 3040 | 32 | 46 | diff --git a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.hdl_tst b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.hdl_tst index cd5515dce..177993270 100644 --- a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.hdl_tst +++ b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.hdl_tst @@ -1,20 +1,20 @@ -// 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/07/MemoryAccess/PointerTest/PointerTest.tst - -load PointerTest.asm, -output-file PointerTest.out, -compare-to PointerTest.cmp, -output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 - RAM[4]%D1.6.1 RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; - -set RAM[0] 256, // initializes the stack pointer - -repeat 450 { // enough cycles to complete the execution - ticktock; -} - -// outputs the stack base, this, that, and -// some values from the the this and that segments -output; +// 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/07/MemoryAccess/PointerTest/PointerTest.tst + +load PointerTest.asm, +output-file PointerTest.out, +compare-to PointerTest.cmp, +output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 + RAM[4]%D1.6.1 RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; + +set RAM[0] 256; // initializes the stack pointer + +repeat 450 { // enough cycles to complete the execution + ticktock; +} + +// outputs the stack base, this, that, and +// some values from the the this and that segments +output; diff --git a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm index 5b0a109a5..a6086d90a 100644 --- a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm +++ b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm @@ -1,22 +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/07/MemoryAccess/PointerTest/PointerTest.vm - -// Executes pop and push commands using the -// pointer, this, and that segments. -push constant 3030 -pop pointer 0 -push constant 3040 -pop pointer 1 -push constant 32 -pop this 2 -push constant 46 -pop that 6 -push pointer 0 -push pointer 1 -add -push this 2 -sub -push that 6 -add +// 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/07/MemoryAccess/PointerTest/PointerTest.vm + +// Executes pop and push commands using the +// pointer, this, and that segments. +push constant 3030 +pop pointer 0 +push constant 3040 +pop pointer 1 +push constant 32 +pop this 2 +push constant 46 +pop that 6 +push pointer 0 +push pointer 1 +add +push this 2 +sub +push that 6 +add diff --git a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm_tst b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm_tst index 1b395c2c6..de288ae08 100644 --- a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm_tst +++ b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm_tst @@ -1,20 +1,20 @@ -// 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/07/MemoryAccess/PointerTest/PointerTestVME.tst - -load PointerTest.vm, -output-file PointerTest.out, -compare-to PointerTest.cmp, -output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 - RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; - -set RAM[0] 256, // initializes the stack pointer - -repeat 15 { // PointerTest.vm has 15 instructions - vmstep; -} - -// outputs the stack base, this, that, and -// some values from the the this and that segments -output; +// 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/07/MemoryAccess/PointerTest/PointerTestVME.tst + +load PointerTest.vm, +output-file PointerTest.out, +compare-to PointerTest.cmp, +output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 + RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; + +set RAM[0] 256; // initializes the stack pointer + +repeat 15 { // PointerTest.vm has 15 instructions + vmstep; +} + +// outputs the stack base, this, that, and +// some values from the the this and that segments +output; diff --git a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.cmp b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.cmp index 29f4bf032..2bc908bd9 100644 --- a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.cmp +++ b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.cmp @@ -1,2 +1,2 @@ -|RAM[256]| -| 1110 | +|RAM[256]| +| 1110 | diff --git a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.hdl_tst b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.hdl_tst index 1f23d6681..7c9eb1d96 100644 --- a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.hdl_tst +++ b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.hdl_tst @@ -1,17 +1,17 @@ -// 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/07/MemoryAccess/StaticTest/StaticTest.tst - -load StaticTest.asm, -output-file StaticTest.out, -compare-to StaticTest.cmp, -output-list RAM[256]%D1.6.1; - -set RAM[0] 256, // initializes the stack pointer - -repeat 200 { // enough cycles to complete the execution - ticktock; -} - -output; // the stack base +// 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/07/MemoryAccess/StaticTest/StaticTest.tst + +load StaticTest.asm, +output-file StaticTest.out, +compare-to StaticTest.cmp, +output-list RAM[256]%D1.6.1; + +set RAM[0] 256; // initializes the stack pointer + +repeat 200 { // enough cycles to complete the execution + ticktock; +} + +output; // the stack base diff --git a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm index 65b4f6f75..e24584bf9 100644 --- a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm +++ b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm @@ -1,17 +1,17 @@ -// 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/07/MemoryAccess/StaticTest/StaticTest.vm - -// Executes pop and push commands using the static segment. -push constant 111 -push constant 333 -push constant 888 -pop static 8 -pop static 3 -pop static 1 -push static 3 -push static 1 -sub -push static 8 -add +// 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/07/MemoryAccess/StaticTest/StaticTest.vm + +// Executes pop and push commands using the static segment. +push constant 111 +push constant 333 +push constant 888 +pop static 8 +pop static 3 +pop static 1 +push static 3 +push static 1 +sub +push static 8 +add diff --git a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm_tst b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm_tst index 52882a486..2d8c38b15 100644 --- a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm_tst +++ b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm_tst @@ -1,17 +1,17 @@ -// 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/07/MemoryAccess/StaticTest/StaticTestVME.tst - -load StaticTest.vm, -output-file StaticTest.out, -compare-to StaticTest.cmp, -output-list RAM[256]%D1.6.1; - -set sp 256, // initializes the stack pointer - -repeat 11 { // StaticTest.vm has 11 instructions - vmstep; -} - -output; // the stack base +// 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/07/MemoryAccess/StaticTest/StaticTestVME.tst + +load StaticTest.vm, +output-file StaticTest.out, +compare-to StaticTest.cmp, +output-list RAM[256]%D1.6.1; + +set sp 256; // initializes the stack pointer + +repeat 11 { // StaticTest.vm has 11 instructions + vmstep; +} + +output; // the stack base diff --git a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.cmp b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.cmp index 7a3585b9a..6b3b20e52 100644 --- a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.cmp +++ b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.cmp @@ -1,2 +1,2 @@ -| RAM[0] | RAM[256] | -| 257 | 15 | +| RAM[0] | RAM[256] | +| 257 | 15 | diff --git a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.hdl_tst b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.hdl_tst index 02dece306..92b54b7d2 100644 --- a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.hdl_tst +++ b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.hdl_tst @@ -1,17 +1,17 @@ -// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.tst - -load SimpleAdd.asm, -output-file SimpleAdd.out, -compare-to SimpleAdd.cmp, -output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; - -set RAM[0] 256, // initializes the stack pointer - -repeat 60 { // enough cycles to complete the execution - ticktock; -} - -output; // the stack pointer and the stack base +// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.tst + +load SimpleAdd.asm, +output-file SimpleAdd.out, +compare-to SimpleAdd.cmp, +output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; + +set RAM[0] 256; // initializes the stack pointer + +repeat 60 { // enough cycles to complete the execution + ticktock; +} + +output; // the stack pointer and the stack base diff --git a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm index cfd4ee9c2..d80d9fa76 100644 --- a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm +++ b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm @@ -1,9 +1,9 @@ -// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.vm - -// Pushes and adds two constants. -push constant 7 -push constant 8 -add +// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.vm + +// Pushes and adds two constants. +push constant 7 +push constant 8 +add diff --git a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm_tst b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm_tst index 5010f4ff4..71464350e 100644 --- a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm_tst +++ b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm_tst @@ -1,17 +1,17 @@ -// 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/07/StackArithmetic/SimpleAdd/SimpleAddVME.tst - -load SimpleAdd.vm, -output-file SimpleAdd.out, -compare-to SimpleAdd.cmp, -output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; - -set RAM[0] 256, // initializes the stack pointer - -repeat 3 { // SimpleAdd.vm has 3 instructions - vmstep; -} - -output; // the stack pointer and the stack base +// 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/07/StackArithmetic/SimpleAdd/SimpleAddVME.tst + +load SimpleAdd.vm, +output-file SimpleAdd.out, +compare-to SimpleAdd.cmp, +output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; + +set RAM[0] 256; // initializes the stack pointer + +repeat 3 { // SimpleAdd.vm has 3 instructions + vmstep; +} + +output; // the stack pointer and the stack base diff --git a/projects/src/project_07/StackArithmetic/StackTest/StackTest.cmp b/projects/src/project_07/StackArithmetic/StackTest/StackTest.cmp index f90fa1b7d..cb182ec10 100644 --- a/projects/src/project_07/StackArithmetic/StackTest/StackTest.cmp +++ b/projects/src/project_07/StackArithmetic/StackTest/StackTest.cmp @@ -1,4 +1,4 @@ -| RAM[0] | RAM[256] | RAM[257] | RAM[258] | RAM[259] | RAM[260] | -| 266 | -1 | 0 | 0 | 0 | -1 | -| RAM[261] | RAM[262] | RAM[263] | RAM[264] | RAM[265] | -| 0 | -1 | 0 | 0 | -91 | +| RAM[0] | RAM[256] | RAM[257] | RAM[258] | RAM[259] | RAM[260] | +| 266 | -1 | 0 | 0 | 0 | -1 | +| RAM[261] | RAM[262] | RAM[263] | RAM[264] | RAM[265] | +| 0 | -1 | 0 | 0 | -91 | diff --git a/projects/src/project_07/StackArithmetic/StackTest/StackTest.hdl_tst b/projects/src/project_07/StackArithmetic/StackTest/StackTest.hdl_tst index f9c539675..d70adce72 100644 --- a/projects/src/project_07/StackArithmetic/StackTest/StackTest.hdl_tst +++ b/projects/src/project_07/StackArithmetic/StackTest/StackTest.hdl_tst @@ -1,22 +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/07/StackArithmetic/StackTest/StackTest.tst - -load StackTest.asm, -output-file StackTest.out, -compare-to StackTest.cmp, -output-list RAM[0]%D2.6.2 - RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; - -set RAM[0] 256, // initializes the stack pointer - -repeat 1000 { // enough cycles to complete the execution - ticktock; -} - -// outputs the stack pointer (RAM[0]) and -// the stack contents: RAM[256]-RAM[265] -output; -output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; -output; +// 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/07/StackArithmetic/StackTest/StackTest.tst + +load StackTest.asm, +output-file StackTest.out, +compare-to StackTest.cmp, +output-list RAM[0]%D2.6.2 + RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; + +set RAM[0] 256; // initializes the stack pointer + +repeat 1000 { // enough cycles to complete the execution + ticktock; +} + +// outputs the stack pointer (RAM[0]) and +// the stack contents: RAM[256]-RAM[265] +output; +output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; +output; diff --git a/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm b/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm index bfe78e06f..c4181789e 100644 --- a/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm +++ b/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm @@ -1,45 +1,45 @@ -// 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/07/StackArithmetic/StackTest/StackTest.vm - -// Executes a sequence of arithmetic and logical operations -// on the stack. -push constant 17 -push constant 17 -eq -push constant 17 -push constant 16 -eq -push constant 16 -push constant 17 -eq -push constant 892 -push constant 891 -lt -push constant 891 -push constant 892 -lt -push constant 891 -push constant 891 -lt -push constant 32767 -push constant 32766 -gt -push constant 32766 -push constant 32767 -gt -push constant 32766 -push constant 32766 -gt -push constant 57 -push constant 31 -push constant 53 -add -push constant 112 -sub -neg -and -push constant 82 -or -not +// 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/07/StackArithmetic/StackTest/StackTest.vm + +// Executes a sequence of arithmetic and logical operations +// on the stack. +push constant 17 +push constant 17 +eq +push constant 17 +push constant 16 +eq +push constant 16 +push constant 17 +eq +push constant 892 +push constant 891 +lt +push constant 891 +push constant 892 +lt +push constant 891 +push constant 891 +lt +push constant 32767 +push constant 32766 +gt +push constant 32766 +push constant 32767 +gt +push constant 32766 +push constant 32766 +gt +push constant 57 +push constant 31 +push constant 53 +add +push constant 112 +sub +neg +and +push constant 82 +or +not diff --git a/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm_tst b/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm_tst index b66bd054f..e25f32911 100644 --- a/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm_tst +++ b/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm_tst @@ -1,22 +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/07/StackArithmetic/StackTest/StackTestVME.tst - -load StackTest.vm, -output-file StackTest.out, -compare-to StackTest.cmp, -output-list RAM[0]%D2.6.2 - RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; - -set RAM[0] 256, // initializes the stack pointer - -repeat 38 { // StackTest.vm consists of 38 instructions - vmstep; -} - -// outputs the stack pointer (RAM[0]) and -// the stack contents: RAM[256]-RAM[265] -output; -output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; -output; +// 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/07/StackArithmetic/StackTest/StackTestVME.tst + +load StackTest.vm, +output-file StackTest.out, +compare-to StackTest.cmp, +output-list RAM[0]%D2.6.2 + RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; + +set RAM[0] 256; // initializes the stack pointer + +repeat 38 { // StackTest.vm consists of 38 instructions + vmstep; +} + +// outputs the stack pointer (RAM[0]) and +// the stack contents: RAM[256]-RAM[265] +output; +output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; +output; diff --git a/projects/src/project_07/index.ts b/projects/src/project_07/index.ts index 592f10bcb..753ee838f 100644 --- a/projects/src/project_07/index.ts +++ b/projects/src/project_07/index.ts @@ -1,7 +1,7 @@ import { FileSystem, reset } from "@davidsouther/jiffies/lib/esm/fs.js"; import * as simple_add from "./11_simple_add.js"; import * as stack_test from "./12_stack_test.js"; -import * as memory_test from "./21_basic_test.js"; +import * as basic_test from "./21_basic_test.js"; import * as pointer_test from "./22_pointer_test.js"; import * as static_test from "./23_static_test.js"; @@ -18,11 +18,11 @@ export const VMS = { "StackTest.cmp": stack_test.cmp, "StackTest.tst": stack_test.hdl_tst, }, - MemoryTest: { - "MemoryTest.vm": memory_test.vm, - "MemoryTest.vm_tst": memory_test.vm_tst, - "MemoryTest.cmp": memory_test.cmp, - "MemoryTest.tst": memory_test.hdl_tst, + BasicTest: { + "BasicTest.vm": basic_test.vm, + "BasicTest.vm_tst": basic_test.vm_tst, + "BasicTest.cmp": basic_test.cmp, + "BasicTest.tst": basic_test.hdl_tst, }, PointerTest: { "PointerTest.vm": pointer_test.vm, diff --git a/projects/src/project_08/11_basic_loop.ts b/projects/src/project_08/11_basic_loop.ts index f841f018c..53e02962a 100644 --- a/projects/src/project_08/11_basic_loop.ts +++ b/projects/src/project_08/11_basic_loop.ts @@ -1,76 +1,71 @@ -export const vm = `// 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/08/ProgramFlow/BasicLoop/BasicLoop.vm - -// Computes the sum 1 + 2 + ... + argument[0] and pushes the -// result onto the stack. Argument[0] is initialized by the test -// script before this code starts running. -push constant 0 -pop local 0 // initializes sum = 0 -label LOOP_START -push argument 0 -push local 0 -add -pop local 0 // sum = sum + counter -push argument 0 -push constant 1 -sub -pop argument 0 // counter-- -push argument 0 -if-goto LOOP_START // If counter != 0, goto LOOP_START -push local 0 +export const vm = `// 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/08/ProgramFlow/BasicLoop/BasicLoop.vm + +// Computes the sum 1 + 2 + ... + argument[0] and pushes the +// result onto the stack. Argument[0] is initialized by the test +// script before this code starts running. +push constant 0 +pop local 0 // initializes sum = 0 +label LOOP_START +push argument 0 +push local 0 +add +pop local 0 // sum = sum + counter +push argument 0 +push constant 1 +sub +pop argument 0 // counter-- +push argument 0 +if-goto LOOP_START // If counter != 0, goto LOOP_START +push local 0 `; +export const vm_tst = `// 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/08/ProgramFlow/BasicLoop/BasicLoopVME.tst -export const vm_tst = `// 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/08/ProgramFlow/BasicLoop/BasicLoopVME.tst - -load BasicLoop.vm, -output-file BasicLoop.out, -compare-to BasicLoop.cmp, -output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; - -set sp 256, -set local 300, -set argument 400, -set argument[0] 3, - -repeat 33 { - vmstep; -} - -output; -`; +load BasicLoop.vm, +output-file BasicLoop.out, +compare-to BasicLoop.cmp, +output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; +set sp 256, +set local 300, +set argument 400, +set argument[0] 3; -export const hdl_tst = `// 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/08/ProgramFlow/BasicLoop/BasicLoop.tst - -load BasicLoop.asm, -output-file BasicLoop.out, -compare-to BasicLoop.cmp, -output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; - -set RAM[0] 256, -set RAM[1] 300, -set RAM[2] 400, -set RAM[400] 3, - -repeat 600 { - ticktock; -} - -output; +repeat 33 { + vmstep; +} + +output; `; +export const hdl_tst = `// 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/08/ProgramFlow/BasicLoop/BasicLoop.tst -export const cmp = `| RAM[0] |RAM[256]| -| 257 | 6 | -`; +load BasicLoop.asm, +output-file BasicLoop.out, +compare-to BasicLoop.cmp, +output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; +set RAM[0] 256, +set RAM[1] 300, +set RAM[2] 400, +set RAM[400] 3; +repeat 600 { + ticktock; +} + +output; +`; + +export const cmp = `| RAM[0] |RAM[256]| +| 257 | 6 | +`; diff --git a/projects/src/project_08/12_fibonacci_series.ts b/projects/src/project_08/12_fibonacci_series.ts index 868f7ec2f..c95d7c679 100644 --- a/projects/src/project_08/12_fibonacci_series.ts +++ b/projects/src/project_08/12_fibonacci_series.ts @@ -1,107 +1,102 @@ -export const vm = `// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm - -// Puts the first argument[0] elements of the Fibonacci series -// in the memory, starting in the address given in argument[1]. -// Argument[0] and argument[1] are initialized by the test script -// before this code starts running. - -push argument 1 -pop pointer 1 // that = argument[1] - -push constant 0 -pop that 0 // first element in the series = 0 -push constant 1 -pop that 1 // second element in the series = 1 - -push argument 0 -push constant 2 -sub -pop argument 0 // num_of_elements -= 2 (first 2 elements are set) - -label MAIN_LOOP_START - -push argument 0 -if-goto COMPUTE_ELEMENT // if num_of_elements > 0, goto COMPUTE_ELEMENT -goto END_PROGRAM // otherwise, goto END_PROGRAM - -label COMPUTE_ELEMENT - -push that 0 -push that 1 -add -pop that 2 // that[2] = that[0] + that[1] - -push pointer 1 -push constant 1 -add -pop pointer 1 // that += 1 - -push argument 0 -push constant 1 -sub -pop argument 0 // num_of_elements-- - -goto MAIN_LOOP_START - -label END_PROGRAM -`; +export const vm = `// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm +// Puts the first argument[0] elements of the Fibonacci series +// in the memory, starting in the address given in argument[1]. +// Argument[0] and argument[1] are initialized by the test script +// before this code starts running. -export const vm_tst = `// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeriesVME.tst - -load FibonacciSeries.vm, -output-file FibonacciSeries.out, -compare-to FibonacciSeries.cmp, -output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 - RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; - -set sp 256, -set local 300, -set argument 400, -set argument[0] 6, -set argument[1] 3000, - -repeat 73 { - vmstep; -} - -output; -`; +push argument 1 +pop pointer 1 // that = argument[1] + +push constant 0 +pop that 0 // first element in the series = 0 +push constant 1 +pop that 1 // second element in the series = 1 + +push argument 0 +push constant 2 +sub +pop argument 0 // num_of_elements -= 2 (first 2 elements are set) + +label MAIN_LOOP_START + +push argument 0 +if-goto COMPUTE_ELEMENT // if num_of_elements > 0, goto COMPUTE_ELEMENT +goto END_PROGRAM // otherwise, goto END_PROGRAM + +label COMPUTE_ELEMENT + +push that 0 +push that 1 +add +pop that 2 // that[2] = that[0] + that[1] + +push pointer 1 +push constant 1 +add +pop pointer 1 // that += 1 + +push argument 0 +push constant 1 +sub +pop argument 0 // num_of_elements-- +goto MAIN_LOOP_START -export const hdl_tst = `// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.tst - -load FibonacciSeries.asm, -output-file FibonacciSeries.out, -compare-to FibonacciSeries.cmp, -output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 - RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; - -set RAM[0] 256, -set RAM[1] 300, -set RAM[2] 400, -set RAM[400] 6, -set RAM[401] 3000, - -repeat 1100 { - ticktock; -} - -output; +label END_PROGRAM `; +export const vm_tst = `// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeriesVME.tst -export const cmp = `|RAM[3000]|RAM[3001]|RAM[3002]|RAM[3003]|RAM[3004]|RAM[3005]| -| 0 | 1 | 1 | 2 | 3 | 5 | +load FibonacciSeries.vm, +output-file FibonacciSeries.out, +compare-to FibonacciSeries.cmp, +output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 + RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; + +set sp 256, +set local 300, +set argument 400, +set argument[0] 6, +set argument[1] 3000; + +repeat 73 { + vmstep; +} + +output; `; +export const hdl_tst = `// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.tst + +load FibonacciSeries.asm, +output-file FibonacciSeries.out, +compare-to FibonacciSeries.cmp, +output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 + RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; + +set RAM[0] 256, +set RAM[1] 300, +set RAM[2] 400, +set RAM[400] 6, +set RAM[401] 3000, +repeat 1100 { + ticktock; +} + +output; +`; + +export const cmp = `|RAM[3000]|RAM[3001]|RAM[3002]|RAM[3003]|RAM[3004]|RAM[3005]| +| 0 | 1 | 1 | 2 | 3 | 5 | +`; diff --git a/projects/src/project_08/20_simple_function.ts b/projects/src/project_08/20_simple_function.ts index 0d7e32603..bec658bc0 100644 --- a/projects/src/project_08/20_simple_function.ts +++ b/projects/src/project_08/20_simple_function.ts @@ -1,88 +1,83 @@ -export const vm = `// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.vm - -// Performs a simple calculation and returns the result. -function SimpleFunction.test 2 -push local 0 -push local 1 -add -not -push argument 0 -add -push argument 1 -sub -return +export const vm = `// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.vm + +// Performs a simple calculation and returns the result. +function SimpleFunction.test 2 +push local 0 +push local 1 +add +not +push argument 0 +add +push argument 1 +sub +return `; +export const vm_tst = `// 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/08/FunctionCalls/SimpleFunction/SimpleFunctionVME.tst -export const vm_tst = `// 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/08/FunctionCalls/SimpleFunction/SimpleFunctionVME.tst - -load SimpleFunction.vm, -output-file SimpleFunction.out, -compare-to SimpleFunction.cmp, -output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 - RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; - -set sp 317, -set local 317, -set argument 310, -set this 3000, -set that 4000, -set argument[0] 1234, -set argument[1] 37, -set argument[2] 9, -set argument[3] 305, -set argument[4] 300, -set argument[5] 3010, -set argument[6] 4010, - -repeat 10 { - vmstep; -} - -output; -`; +load SimpleFunction.vm, +output-file SimpleFunction.out, +compare-to SimpleFunction.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 + RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; +set sp 317, +set local 317, +set argument 310, +set this 3000, +set that 4000, +set argument[0] 1234, +set argument[1] 37, +set argument[2] 9, +set argument[3] 305, +set argument[4] 300, +set argument[5] 3010, +set argument[6] 4010; -export const hdl_tst = `// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.tst - -load SimpleFunction.asm, -output-file SimpleFunction.out, -compare-to SimpleFunction.cmp, -output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 - RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; - -set RAM[0] 317, -set RAM[1] 317, -set RAM[2] 310, -set RAM[3] 3000, -set RAM[4] 4000, -set RAM[310] 1234, -set RAM[311] 37, -set RAM[312] 1000, -set RAM[313] 305, -set RAM[314] 300, -set RAM[315] 3010, -set RAM[316] 4010, - -repeat 300 { - ticktock; -} - -output; +repeat 10 { + vmstep; +} + +output; `; +export const hdl_tst = `// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.tst -export const cmp = `| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] |RAM[310]| -| 311 | 305 | 300 | 3010 | 4010 | 1196 | -`; +load SimpleFunction.asm, +output-file SimpleFunction.out, +compare-to SimpleFunction.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 + RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; +set RAM[0] 317, +set RAM[1] 317, +set RAM[2] 310, +set RAM[3] 3000, +set RAM[4] 4000, +set RAM[310] 1234, +set RAM[311] 37, +set RAM[312] 1000, +set RAM[313] 305, +set RAM[314] 300, +set RAM[315] 3010, +set RAM[316] 4010, +repeat 300 { + ticktock; +} + +output; +`; + +export const cmp = `| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] |RAM[310]| +| 311 | 305 | 300 | 3010 | 4010 | 1196 | +`; diff --git a/projects/src/project_08/21_nested_call.ts b/projects/src/project_08/21_nested_call.ts index 1420c8d90..8f408966c 100644 --- a/projects/src/project_08/21_nested_call.ts +++ b/projects/src/project_08/21_nested_call.ts @@ -1,212 +1,207 @@ -export const vm = `// Sys.vm for NestedCall test. - -// Sys.init() -// -// Calls Sys.main() and stores return value in temp 1. -// Does not return. (Enters infinite loop.) - -function Sys.init 0 -push constant 4000 // test THIS and THAT context save -pop pointer 0 -push constant 5000 -pop pointer 1 -call Sys.main 0 -pop temp 1 -label LOOP -goto LOOP - -// Sys.main() -// -// Sets locals 1, 2 and 3, leaving locals 0 and 4 unchanged to test -// default local initialization to 0. (RAM set to -1 by test setup.) -// Calls Sys.add12(123) and stores return value (135) in temp 0. -// Returns local 0 + local 1 + local 2 + local 3 + local 4 (456) to confirm -// that locals were not mangled by function call. - -function Sys.main 5 -push constant 4001 -pop pointer 0 -push constant 5001 -pop pointer 1 -push constant 200 -pop local 1 -push constant 40 -pop local 2 -push constant 6 -pop local 3 -push constant 123 -call Sys.add12 1 -pop temp 0 -push local 0 -push local 1 -push local 2 -push local 3 -push local 4 -add -add -add -add -return - -// Sys.add12(int n) -// -// Returns n+12. - -function Sys.add12 0 -push constant 4002 -pop pointer 0 -push constant 5002 -pop pointer 1 -push argument 0 -push constant 12 -add -return -`; +export const vm = `// Sys.vm for NestedCall test. +// Sys.init() +// +// Calls Sys.main() and stores return value in temp 1. +// Does not return. (Enters infinite loop.) -export const vm_tst = `// Test file for NestedCall test. - -load Sys.vm, -output-file NestedCall.out, -compare-to NestedCall.cmp, -output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; - -set RAM[0] 261, -set RAM[1] 261, -set RAM[2] 256, -set RAM[3] -3, -set RAM[4] -4, -set RAM[5] -1, // test results -set RAM[6] -1, -set RAM[256] 1234, // fake stack frame from call Sys.init -set RAM[257] -1, -set RAM[258] -2, -set RAM[259] -3, -set RAM[260] -4, - -set RAM[261] -1, // Initialize stack to check for local segment -set RAM[262] -1, // being cleared to zero. -set RAM[263] -1, -set RAM[264] -1, -set RAM[265] -1, -set RAM[266] -1, -set RAM[267] -1, -set RAM[268] -1, -set RAM[269] -1, -set RAM[270] -1, -set RAM[271] -1, -set RAM[272] -1, -set RAM[273] -1, -set RAM[274] -1, -set RAM[275] -1, -set RAM[276] -1, -set RAM[277] -1, -set RAM[278] -1, -set RAM[279] -1, -set RAM[280] -1, -set RAM[281] -1, -set RAM[282] -1, -set RAM[283] -1, -set RAM[284] -1, -set RAM[285] -1, -set RAM[286] -1, -set RAM[287] -1, -set RAM[288] -1, -set RAM[289] -1, -set RAM[290] -1, -set RAM[291] -1, -set RAM[292] -1, -set RAM[293] -1, -set RAM[294] -1, -set RAM[295] -1, -set RAM[296] -1, -set RAM[297] -1, -set RAM[298] -1, -set RAM[299] -1, - -set sp 261, -set local 261, -set argument 256, -set this 3000, -set that 4000; - -repeat 50 { - vmstep; -} -output; -`; +function Sys.init 0 +push constant 4000 // test THIS and THAT context save +pop pointer 0 +push constant 5000 +pop pointer 1 +call Sys.main 0 +pop temp 1 +label LOOP +goto LOOP + +// Sys.main() +// +// Sets locals 1, 2 and 3, leaving locals 0 and 4 unchanged to test +// default local initialization to 0. (RAM set to -1 by test setup.) +// Calls Sys.add12(123) and stores return value (135) in temp 0. +// Returns local 0 + local 1 + local 2 + local 3 + local 4 (456) to confirm +// that locals were not mangled by function call. + +function Sys.main 5 +push constant 4001 +pop pointer 0 +push constant 5001 +pop pointer 1 +push constant 200 +pop local 1 +push constant 40 +pop local 2 +push constant 6 +pop local 3 +push constant 123 +call Sys.add12 1 +pop temp 0 +push local 0 +push local 1 +push local 2 +push local 3 +push local 4 +add +add +add +add +return +// Sys.add12(int n) +// +// Returns n+12. -export const hdl_tst = `// Test file for NestedCall test. - -load NestedCall.asm, -output-file NestedCall.out, -compare-to NestedCall.cmp, -output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; - -set RAM[0] 261, -set RAM[1] 261, -set RAM[2] 256, -set RAM[3] -3, -set RAM[4] -4, -set RAM[5] -1, // test results -set RAM[6] -1, -set RAM[256] 1234, // fake stack frame from call Sys.init -set RAM[257] -1, -set RAM[258] -2, -set RAM[259] -3, -set RAM[260] -4, - -set RAM[261] -1, // Initialize stack to check for local segment -set RAM[262] -1, // being cleared to zero. -set RAM[263] -1, -set RAM[264] -1, -set RAM[265] -1, -set RAM[266] -1, -set RAM[267] -1, -set RAM[268] -1, -set RAM[269] -1, -set RAM[270] -1, -set RAM[271] -1, -set RAM[272] -1, -set RAM[273] -1, -set RAM[274] -1, -set RAM[275] -1, -set RAM[276] -1, -set RAM[277] -1, -set RAM[278] -1, -set RAM[279] -1, -set RAM[280] -1, -set RAM[281] -1, -set RAM[282] -1, -set RAM[283] -1, -set RAM[284] -1, -set RAM[285] -1, -set RAM[286] -1, -set RAM[287] -1, -set RAM[288] -1, -set RAM[289] -1, -set RAM[290] -1, -set RAM[291] -1, -set RAM[292] -1, -set RAM[293] -1, -set RAM[294] -1, -set RAM[295] -1, -set RAM[296] -1, -set RAM[297] -1, -set RAM[298] -1, -set RAM[299] -1, - -repeat 4000 { - ticktock; -} - -output; +function Sys.add12 0 +push constant 4002 +pop pointer 0 +push constant 5002 +pop pointer 1 +push argument 0 +push constant 12 +add +return `; +export const vm_tst = `// Test file for NestedCall test. + +load Sys.vm, +output-file NestedCall.out, +compare-to NestedCall.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; + +set RAM[0] 261, +set RAM[1] 261, +set RAM[2] 256, +set RAM[3] -3, +set RAM[4] -4, +set RAM[5] -1, // test results +set RAM[6] -1, +set RAM[256] 1234, // fake stack frame from call Sys.init +set RAM[257] -1, +set RAM[258] -2, +set RAM[259] -3, +set RAM[260] -4, + +set RAM[261] -1, // Initialize stack to check for local segment +set RAM[262] -1, // being cleared to zero. +set RAM[263] -1, +set RAM[264] -1, +set RAM[265] -1, +set RAM[266] -1, +set RAM[267] -1, +set RAM[268] -1, +set RAM[269] -1, +set RAM[270] -1, +set RAM[271] -1, +set RAM[272] -1, +set RAM[273] -1, +set RAM[274] -1, +set RAM[275] -1, +set RAM[276] -1, +set RAM[277] -1, +set RAM[278] -1, +set RAM[279] -1, +set RAM[280] -1, +set RAM[281] -1, +set RAM[282] -1, +set RAM[283] -1, +set RAM[284] -1, +set RAM[285] -1, +set RAM[286] -1, +set RAM[287] -1, +set RAM[288] -1, +set RAM[289] -1, +set RAM[290] -1, +set RAM[291] -1, +set RAM[292] -1, +set RAM[293] -1, +set RAM[294] -1, +set RAM[295] -1, +set RAM[296] -1, +set RAM[297] -1, +set RAM[298] -1, +set RAM[299] -1, + +set sp 261, +set local 261, +set argument 256, +set this 3000, +set that 4000; -export const cmp = `| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] | RAM[5] | RAM[6] | -| 261 | 261 | 256 | 4000 | 5000 | 135 | 246 | +repeat 50 { + vmstep; +} +output; `; +export const hdl_tst = `// Test file for NestedCall test. +load NestedCall.asm, +output-file NestedCall.out, +compare-to NestedCall.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; + +set RAM[0] 261, +set RAM[1] 261, +set RAM[2] 256, +set RAM[3] -3, +set RAM[4] -4, +set RAM[5] -1, // test results +set RAM[6] -1, +set RAM[256] 1234, // fake stack frame from call Sys.init +set RAM[257] -1, +set RAM[258] -2, +set RAM[259] -3, +set RAM[260] -4, + +set RAM[261] -1, // Initialize stack to check for local segment +set RAM[262] -1, // being cleared to zero. +set RAM[263] -1, +set RAM[264] -1, +set RAM[265] -1, +set RAM[266] -1, +set RAM[267] -1, +set RAM[268] -1, +set RAM[269] -1, +set RAM[270] -1, +set RAM[271] -1, +set RAM[272] -1, +set RAM[273] -1, +set RAM[274] -1, +set RAM[275] -1, +set RAM[276] -1, +set RAM[277] -1, +set RAM[278] -1, +set RAM[279] -1, +set RAM[280] -1, +set RAM[281] -1, +set RAM[282] -1, +set RAM[283] -1, +set RAM[284] -1, +set RAM[285] -1, +set RAM[286] -1, +set RAM[287] -1, +set RAM[288] -1, +set RAM[289] -1, +set RAM[290] -1, +set RAM[291] -1, +set RAM[292] -1, +set RAM[293] -1, +set RAM[294] -1, +set RAM[295] -1, +set RAM[296] -1, +set RAM[297] -1, +set RAM[298] -1, +set RAM[299] -1; + +repeat 4000 { + ticktock; +} + +output; +`; + +export const cmp = `| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] | RAM[5] | RAM[6] | +| 261 | 261 | 256 | 4000 | 5000 | 135 | 246 | +`; diff --git a/projects/src/project_08/22_fibonacci_element.ts b/projects/src/project_08/22_fibonacci_element.ts index aced2390b..b241c423a 100644 --- a/projects/src/project_08/22_fibonacci_element.ts +++ b/projects/src/project_08/22_fibonacci_element.ts @@ -1,94 +1,89 @@ -export const vm = `// 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/08/FunctionCalls/FibonacciElement/Main.vm - -// Computes the n'th element of the Fibonacci series, recursively. -// n is given in argument[0]. Called by the Sys.init function -// (part of the Sys.vm file), which also pushes the argument[0] -// parameter before this code starts running. - -function Main.fibonacci 0 -push argument 0 -push constant 2 -lt // checks if n<2 -if-goto IF_TRUE -goto IF_FALSE -label IF_TRUE // if n<2, return n -push argument 0 -return -label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) -push argument 0 -push constant 2 -sub -call Main.fibonacci 1 // computes fib(n-2) -push argument 0 -push constant 1 -sub -call Main.fibonacci 1 // computes fib(n-1) -add // returns fib(n-1) + fib(n-2) -return -// 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/08/FunctionCalls/FibonacciElement/Sys.vm - -// Pushes a constant, say n, onto the stack, and calls the Main.fibonacii -// function, which computes the n'th element of the Fibonacci series. -// Note that by convention, the Sys.init function is called "automatically" -// by the bootstrap code. - -function Sys.init 0 -push constant 4 -call Main.fibonacci 1 // computes the 4'th fibonacci element -label WHILE -goto WHILE // loops infinitely -`; +export const vm = `// 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/08/FunctionCalls/FibonacciElement/Main.vm +// Computes the n'th element of the Fibonacci series, recursively. +// n is given in argument[0]. Called by the Sys.init function +// (part of the Sys.vm file), which also pushes the argument[0] +// parameter before this code starts running. -export const vm_tst = `// 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/08/FunctionCalls/FibonacciElement/FibonacciElementVME.tst - -load, // Load all the VM files from the current directory -output-file FibonacciElement.out, -compare-to FibonacciElement.cmp, -output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; - -set sp 261, - -repeat 110 { - vmstep; -} - -output; -`; +function Main.fibonacci 0 +push argument 0 +push constant 2 +lt // checks if n<2 +if-goto IF_TRUE +goto IF_FALSE +label IF_TRUE // if n<2, return n +push argument 0 +return +label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) +push argument 0 +push constant 2 +sub +call Main.fibonacci 1 // computes fib(n-2) +push argument 0 +push constant 1 +sub +call Main.fibonacci 1 // computes fib(n-1) +add // returns fib(n-1) + fib(n-2) +return +// 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/08/FunctionCalls/FibonacciElement/Sys.vm +// Pushes a constant, say n, onto the stack, and calls the Main.fibonacii +// function, which computes the n'th element of the Fibonacci series. +// Note that by convention, the Sys.init function is called "automatically" +// by the bootstrap code. -export const hdl_tst = `// 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/08/FunctionCalls/FibonacciElement/FibonacciElement.tst - -// FibonacciElement.asm results from translating both Main.vm and Sys.vm into -// a single assembly program, stored in the file FibonacciElement.asm. - -load FibonacciElement.asm, -output-file FibonacciElement.out, -compare-to FibonacciElement.cmp, -output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; - -repeat 6000 { - ticktock; -} - -output; +function Sys.init 0 +push constant 4 +call Main.fibonacci 1 // computes the 4'th fibonacci element +label WHILE +goto WHILE // loops infinitely `; +export const vm_tst = `// 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/08/FunctionCalls/FibonacciElement/FibonacciElementVME.tst + +load, // Load all the VM files from the current directory +output-file FibonacciElement.out, +compare-to FibonacciElement.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; -export const cmp = `| RAM[0] |RAM[261]| -| 262 | 3 | +set sp 261; + +repeat 110 { + vmstep; +} + +output; `; +export const hdl_tst = `// 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/08/FunctionCalls/FibonacciElement/FibonacciElement.tst + +// FibonacciElement.asm results from translating both Main.vm and Sys.vm into +// a single assembly program, stored in the file FibonacciElement.asm. +load FibonacciElement.asm, +output-file FibonacciElement.out, +compare-to FibonacciElement.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; + +repeat 6000 { + ticktock; +} + +output; +`; + +export const cmp = `| RAM[0] |RAM[261]| +| 262 | 3 | +`; diff --git a/projects/src/project_08/23_statics_test.ts b/projects/src/project_08/23_statics_test.ts index 39306095c..38886d94c 100644 --- a/projects/src/project_08/23_statics_test.ts +++ b/projects/src/project_08/23_statics_test.ts @@ -1,108 +1,103 @@ -export const vm = `// 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/08/FunctionCalls/StaticsTest/Class1.vm - -// Stores two supplied arguments in static[0] and static[1]. -function Class1.set 0 -push argument 0 -pop static 0 -push argument 1 -pop static 1 -push constant 0 -return - -// Returns static[0] - static[1]. -function Class1.get 0 -push static 0 -push static 1 -sub -return -// 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/08/FunctionCalls/StaticsTest/Class2.vm - -// Stores two supplied arguments in static[0] and static[1]. -function Class2.set 0 -push argument 0 -pop static 0 -push argument 1 -pop static 1 -push constant 0 -return - -// Returns static[0] - static[1]. -function Class2.get 0 -push static 0 -push static 1 -sub -return -// 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/08/FunctionCalls/StaticsTest/Sys.vm - -// Tests that different functions, stored in two different -// class files, manipulate the static segment correctly. -function Sys.init 0 -push constant 6 -push constant 8 -call Class1.set 2 -pop temp 0 // Dumps the return value -push constant 23 -push constant 15 -call Class2.set 2 -pop temp 0 // Dumps the return value -call Class1.get 0 -call Class2.get 0 -label WHILE -goto WHILE -`; +export const vm = `// 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/08/FunctionCalls/StaticsTest/Class1.vm +// Stores two supplied arguments in static[0] and static[1]. +function Class1.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return -export const vm_tst = `// 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/08/FunctionCalls/StaticsTest/StaticsTestVME.tst - -load, // loads all the VM files from the current directory. -output-file StaticsTest.out, -compare-to StaticsTest.cmp, -output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; - -set sp 261, - -repeat 36 { - vmstep; -} - -output; -`; +// Returns static[0] - static[1]. +function Class1.get 0 +push static 0 +push static 1 +sub +return +// 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/08/FunctionCalls/StaticsTest/Class2.vm + +// Stores two supplied arguments in static[0] and static[1]. +function Class2.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return +// Returns static[0] - static[1]. +function Class2.get 0 +push static 0 +push static 1 +sub +return +// 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/08/FunctionCalls/StaticsTest/Sys.vm -export const hdl_tst = `// 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/08/FunctionCalls/StaticsTest/StaticsTest.tst - -load StaticsTest.asm, -output-file StaticsTest.out, -compare-to StaticsTest.cmp, -output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; - -set RAM[0] 256, - -repeat 2500 { - ticktock; -} - -output; +// Tests that different functions, stored in two different +// class files, manipulate the static segment correctly. +function Sys.init 0 +push constant 6 +push constant 8 +call Class1.set 2 +pop temp 0 // Dumps the return value +push constant 23 +push constant 15 +call Class2.set 2 +pop temp 0 // Dumps the return value +call Class1.get 0 +call Class2.get 0 +label WHILE +goto WHILE `; +export const vm_tst = `// 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/08/FunctionCalls/StaticsTest/StaticsTestVME.tst + +load, // loads all the VM files from the current directory. +output-file StaticsTest.out, +compare-to StaticsTest.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; + +set sp 261; + +repeat 36 { + vmstep; +} -export const cmp = `| RAM[0] |RAM[261]|RAM[262]| -| 263 | -2 | 8 | +output; `; +export const hdl_tst = `// 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/08/FunctionCalls/StaticsTest/StaticsTest.tst +load StaticsTest.asm, +output-file StaticsTest.out, +compare-to StaticsTest.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; + +set RAM[0] 256; + +repeat 2500 { + ticktock; +} + +output; +`; + +export const cmp = `| RAM[0] |RAM[261]|RAM[262]| +| 263 | -2 | 8 | +`; diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.cmp b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.cmp index d66783468..fdf5e2df3 100644 --- a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.cmp +++ b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.cmp @@ -1,2 +1,2 @@ -| RAM[0] |RAM[261]| -| 262 | 3 | +| RAM[0] |RAM[261]| +| 262 | 3 | diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.hdl_tst b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.hdl_tst index 1f907b1da..6478bdcdd 100644 --- a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.hdl_tst +++ b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.hdl_tst @@ -1,18 +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/08/FunctionCalls/FibonacciElement/FibonacciElement.tst - -// FibonacciElement.asm results from translating both Main.vm and Sys.vm into -// a single assembly program, stored in the file FibonacciElement.asm. - -load FibonacciElement.asm, -output-file FibonacciElement.out, -compare-to FibonacciElement.cmp, -output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; - -repeat 6000 { - ticktock; -} - -output; +// 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/08/FunctionCalls/FibonacciElement/FibonacciElement.tst + +// FibonacciElement.asm results from translating both Main.vm and Sys.vm into +// a single assembly program, stored in the file FibonacciElement.asm. + +load FibonacciElement.asm, +output-file FibonacciElement.out, +compare-to FibonacciElement.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; + +repeat 6000 { + ticktock; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm index ead925d64..b10ac3576 100644 --- a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm +++ b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm @@ -1,45 +1,45 @@ -// 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/08/FunctionCalls/FibonacciElement/Main.vm - -// Computes the n'th element of the Fibonacci series, recursively. -// n is given in argument[0]. Called by the Sys.init function -// (part of the Sys.vm file), which also pushes the argument[0] -// parameter before this code starts running. - -function Main.fibonacci 0 -push argument 0 -push constant 2 -lt // checks if n<2 -if-goto IF_TRUE -goto IF_FALSE -label IF_TRUE // if n<2, return n -push argument 0 -return -label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) -push argument 0 -push constant 2 -sub -call Main.fibonacci 1 // computes fib(n-2) -push argument 0 -push constant 1 -sub -call Main.fibonacci 1 // computes fib(n-1) -add // returns fib(n-1) + fib(n-2) -return -// 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/08/FunctionCalls/FibonacciElement/Sys.vm - -// Pushes a constant, say n, onto the stack, and calls the Main.fibonacii -// function, which computes the n'th element of the Fibonacci series. -// Note that by convention, the Sys.init function is called "automatically" -// by the bootstrap code. - -function Sys.init 0 -push constant 4 -call Main.fibonacci 1 // computes the 4'th fibonacci element -label WHILE -goto WHILE // loops infinitely +// 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/08/FunctionCalls/FibonacciElement/Main.vm + +// Computes the n'th element of the Fibonacci series, recursively. +// n is given in argument[0]. Called by the Sys.init function +// (part of the Sys.vm file), which also pushes the argument[0] +// parameter before this code starts running. + +function Main.fibonacci 0 +push argument 0 +push constant 2 +lt // checks if n<2 +if-goto IF_TRUE +goto IF_FALSE +label IF_TRUE // if n<2, return n +push argument 0 +return +label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) +push argument 0 +push constant 2 +sub +call Main.fibonacci 1 // computes fib(n-2) +push argument 0 +push constant 1 +sub +call Main.fibonacci 1 // computes fib(n-1) +add // returns fib(n-1) + fib(n-2) +return +// 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/08/FunctionCalls/FibonacciElement/Sys.vm + +// Pushes a constant, say n, onto the stack, and calls the Main.fibonacii +// function, which computes the n'th element of the Fibonacci series. +// Note that by convention, the Sys.init function is called "automatically" +// by the bootstrap code. + +function Sys.init 0 +push constant 4 +call Main.fibonacci 1 // computes the 4'th fibonacci element +label WHILE +goto WHILE // loops infinitely diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm_tst b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm_tst index 87c092086..39c1b0e5d 100644 --- a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm_tst +++ b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm_tst @@ -1,17 +1,17 @@ -// 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/08/FunctionCalls/FibonacciElement/FibonacciElementVME.tst - -load, // Load all the VM files from the current directory -output-file FibonacciElement.out, -compare-to FibonacciElement.cmp, -output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; - -set sp 261, - -repeat 110 { - vmstep; -} - -output; +// 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/08/FunctionCalls/FibonacciElement/FibonacciElementVME.tst + +load, // Load all the VM files from the current directory +output-file FibonacciElement.out, +compare-to FibonacciElement.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; + +set sp 261; + +repeat 110 { + vmstep; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/Main.vm b/projects/src/project_08/FunctionCalls/FibonacciElement/Main.vm index 55e5ad217..c84f5995f 100644 --- a/projects/src/project_08/FunctionCalls/FibonacciElement/Main.vm +++ b/projects/src/project_08/FunctionCalls/FibonacciElement/Main.vm @@ -1,30 +1,30 @@ -// 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/08/FunctionCalls/FibonacciElement/Main.vm - -// Computes the n'th element of the Fibonacci series, recursively. -// n is given in argument[0]. Called by the Sys.init function -// (part of the Sys.vm file), which also pushes the argument[0] -// parameter before this code starts running. - -function Main.fibonacci 0 -push argument 0 -push constant 2 -lt // checks if n<2 -if-goto IF_TRUE -goto IF_FALSE -label IF_TRUE // if n<2, return n -push argument 0 -return -label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) -push argument 0 -push constant 2 -sub -call Main.fibonacci 1 // computes fib(n-2) -push argument 0 -push constant 1 -sub -call Main.fibonacci 1 // computes fib(n-1) -add // returns fib(n-1) + fib(n-2) -return +// 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/08/FunctionCalls/FibonacciElement/Main.vm + +// Computes the n'th element of the Fibonacci series, recursively. +// n is given in argument[0]. Called by the Sys.init function +// (part of the Sys.vm file), which also pushes the argument[0] +// parameter before this code starts running. + +function Main.fibonacci 0 +push argument 0 +push constant 2 +lt // checks if n<2 +if-goto IF_TRUE +goto IF_FALSE +label IF_TRUE // if n<2, return n +push argument 0 +return +label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) +push argument 0 +push constant 2 +sub +call Main.fibonacci 1 // computes fib(n-2) +push argument 0 +push constant 1 +sub +call Main.fibonacci 1 // computes fib(n-1) +add // returns fib(n-1) + fib(n-2) +return diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/Sys.vm b/projects/src/project_08/FunctionCalls/FibonacciElement/Sys.vm index f3965c97a..4cd3dc4ba 100644 --- a/projects/src/project_08/FunctionCalls/FibonacciElement/Sys.vm +++ b/projects/src/project_08/FunctionCalls/FibonacciElement/Sys.vm @@ -1,15 +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/08/FunctionCalls/FibonacciElement/Sys.vm - -// Pushes a constant, say n, onto the stack, and calls the Main.fibonacii -// function, which computes the n'th element of the Fibonacci series. -// Note that by convention, the Sys.init function is called "automatically" -// by the bootstrap code. - -function Sys.init 0 -push constant 4 -call Main.fibonacci 1 // computes the 4'th fibonacci element -label WHILE -goto WHILE // loops infinitely +// 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/08/FunctionCalls/FibonacciElement/Sys.vm + +// Pushes a constant, say n, onto the stack, and calls the Main.fibonacii +// function, which computes the n'th element of the Fibonacci series. +// Note that by convention, the Sys.init function is called "automatically" +// by the bootstrap code. + +function Sys.init 0 +push constant 4 +call Main.fibonacci 1 // computes the 4'th fibonacci element +label WHILE +goto WHILE // loops infinitely diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.cmp b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.cmp index 9200202e6..978405da4 100644 --- a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.cmp +++ b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.cmp @@ -1,2 +1,2 @@ -| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] | RAM[5] | RAM[6] | -| 261 | 261 | 256 | 4000 | 5000 | 135 | 246 | +| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] | RAM[5] | RAM[6] | +| 261 | 261 | 256 | 4000 | 5000 | 135 | 246 | diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.hdl_tst b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.hdl_tst index 70e5523cd..0b4c128d5 100644 --- a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.hdl_tst +++ b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.hdl_tst @@ -1,65 +1,65 @@ -// Test file for NestedCall test. - -load NestedCall.asm, -output-file NestedCall.out, -compare-to NestedCall.cmp, -output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; - -set RAM[0] 261, -set RAM[1] 261, -set RAM[2] 256, -set RAM[3] -3, -set RAM[4] -4, -set RAM[5] -1, // test results -set RAM[6] -1, -set RAM[256] 1234, // fake stack frame from call Sys.init -set RAM[257] -1, -set RAM[258] -2, -set RAM[259] -3, -set RAM[260] -4, - -set RAM[261] -1, // Initialize stack to check for local segment -set RAM[262] -1, // being cleared to zero. -set RAM[263] -1, -set RAM[264] -1, -set RAM[265] -1, -set RAM[266] -1, -set RAM[267] -1, -set RAM[268] -1, -set RAM[269] -1, -set RAM[270] -1, -set RAM[271] -1, -set RAM[272] -1, -set RAM[273] -1, -set RAM[274] -1, -set RAM[275] -1, -set RAM[276] -1, -set RAM[277] -1, -set RAM[278] -1, -set RAM[279] -1, -set RAM[280] -1, -set RAM[281] -1, -set RAM[282] -1, -set RAM[283] -1, -set RAM[284] -1, -set RAM[285] -1, -set RAM[286] -1, -set RAM[287] -1, -set RAM[288] -1, -set RAM[289] -1, -set RAM[290] -1, -set RAM[291] -1, -set RAM[292] -1, -set RAM[293] -1, -set RAM[294] -1, -set RAM[295] -1, -set RAM[296] -1, -set RAM[297] -1, -set RAM[298] -1, -set RAM[299] -1, - -repeat 4000 { - ticktock; -} - -output; +// Test file for NestedCall test. + +load NestedCall.asm, +output-file NestedCall.out, +compare-to NestedCall.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; + +set RAM[0] 261, +set RAM[1] 261, +set RAM[2] 256, +set RAM[3] -3, +set RAM[4] -4, +set RAM[5] -1, // test results +set RAM[6] -1, +set RAM[256] 1234, // fake stack frame from call Sys.init +set RAM[257] -1, +set RAM[258] -2, +set RAM[259] -3, +set RAM[260] -4, + +set RAM[261] -1, // Initialize stack to check for local segment +set RAM[262] -1, // being cleared to zero. +set RAM[263] -1, +set RAM[264] -1, +set RAM[265] -1, +set RAM[266] -1, +set RAM[267] -1, +set RAM[268] -1, +set RAM[269] -1, +set RAM[270] -1, +set RAM[271] -1, +set RAM[272] -1, +set RAM[273] -1, +set RAM[274] -1, +set RAM[275] -1, +set RAM[276] -1, +set RAM[277] -1, +set RAM[278] -1, +set RAM[279] -1, +set RAM[280] -1, +set RAM[281] -1, +set RAM[282] -1, +set RAM[283] -1, +set RAM[284] -1, +set RAM[285] -1, +set RAM[286] -1, +set RAM[287] -1, +set RAM[288] -1, +set RAM[289] -1, +set RAM[290] -1, +set RAM[291] -1, +set RAM[292] -1, +set RAM[293] -1, +set RAM[294] -1, +set RAM[295] -1, +set RAM[296] -1, +set RAM[297] -1, +set RAM[298] -1, +set RAM[299] -1; + +repeat 4000 { + ticktock; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm index 8b0b003d0..646b6d3c9 100644 --- a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm +++ b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm @@ -1,63 +1,63 @@ -// Sys.vm for NestedCall test. - -// Sys.init() -// -// Calls Sys.main() and stores return value in temp 1. -// Does not return. (Enters infinite loop.) - -function Sys.init 0 -push constant 4000 // test THIS and THAT context save -pop pointer 0 -push constant 5000 -pop pointer 1 -call Sys.main 0 -pop temp 1 -label LOOP -goto LOOP - -// Sys.main() -// -// Sets locals 1, 2 and 3, leaving locals 0 and 4 unchanged to test -// default local initialization to 0. (RAM set to -1 by test setup.) -// Calls Sys.add12(123) and stores return value (135) in temp 0. -// Returns local 0 + local 1 + local 2 + local 3 + local 4 (456) to confirm -// that locals were not mangled by function call. - -function Sys.main 5 -push constant 4001 -pop pointer 0 -push constant 5001 -pop pointer 1 -push constant 200 -pop local 1 -push constant 40 -pop local 2 -push constant 6 -pop local 3 -push constant 123 -call Sys.add12 1 -pop temp 0 -push local 0 -push local 1 -push local 2 -push local 3 -push local 4 -add -add -add -add -return - -// Sys.add12(int n) -// -// Returns n+12. - -function Sys.add12 0 -push constant 4002 -pop pointer 0 -push constant 5002 -pop pointer 1 -push argument 0 -push constant 12 -add -return +// Sys.vm for NestedCall test. + +// Sys.init() +// +// Calls Sys.main() and stores return value in temp 1. +// Does not return. (Enters infinite loop.) + +function Sys.init 0 +push constant 4000 // test THIS and THAT context save +pop pointer 0 +push constant 5000 +pop pointer 1 +call Sys.main 0 +pop temp 1 +label LOOP +goto LOOP + +// Sys.main() +// +// Sets locals 1, 2 and 3, leaving locals 0 and 4 unchanged to test +// default local initialization to 0. (RAM set to -1 by test setup.) +// Calls Sys.add12(123) and stores return value (135) in temp 0. +// Returns local 0 + local 1 + local 2 + local 3 + local 4 (456) to confirm +// that locals were not mangled by function call. + +function Sys.main 5 +push constant 4001 +pop pointer 0 +push constant 5001 +pop pointer 1 +push constant 200 +pop local 1 +push constant 40 +pop local 2 +push constant 6 +pop local 3 +push constant 123 +call Sys.add12 1 +pop temp 0 +push local 0 +push local 1 +push local 2 +push local 3 +push local 4 +add +add +add +add +return + +// Sys.add12(int n) +// +// Returns n+12. + +function Sys.add12 0 +push constant 4002 +pop pointer 0 +push constant 5002 +pop pointer 1 +push argument 0 +push constant 12 +add +return diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm_tst b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm_tst index 2c689b870..4a46ffe60 100644 --- a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm_tst +++ b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm_tst @@ -1,70 +1,70 @@ -// Test file for NestedCall test. - -load Sys.vm, -output-file NestedCall.out, -compare-to NestedCall.cmp, -output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; - -set RAM[0] 261, -set RAM[1] 261, -set RAM[2] 256, -set RAM[3] -3, -set RAM[4] -4, -set RAM[5] -1, // test results -set RAM[6] -1, -set RAM[256] 1234, // fake stack frame from call Sys.init -set RAM[257] -1, -set RAM[258] -2, -set RAM[259] -3, -set RAM[260] -4, - -set RAM[261] -1, // Initialize stack to check for local segment -set RAM[262] -1, // being cleared to zero. -set RAM[263] -1, -set RAM[264] -1, -set RAM[265] -1, -set RAM[266] -1, -set RAM[267] -1, -set RAM[268] -1, -set RAM[269] -1, -set RAM[270] -1, -set RAM[271] -1, -set RAM[272] -1, -set RAM[273] -1, -set RAM[274] -1, -set RAM[275] -1, -set RAM[276] -1, -set RAM[277] -1, -set RAM[278] -1, -set RAM[279] -1, -set RAM[280] -1, -set RAM[281] -1, -set RAM[282] -1, -set RAM[283] -1, -set RAM[284] -1, -set RAM[285] -1, -set RAM[286] -1, -set RAM[287] -1, -set RAM[288] -1, -set RAM[289] -1, -set RAM[290] -1, -set RAM[291] -1, -set RAM[292] -1, -set RAM[293] -1, -set RAM[294] -1, -set RAM[295] -1, -set RAM[296] -1, -set RAM[297] -1, -set RAM[298] -1, -set RAM[299] -1, - -set sp 261, -set local 261, -set argument 256, -set this 3000, -set that 4000; - -repeat 50 { - vmstep; -} -output; +// Test file for NestedCall test. + +load Sys.vm, +output-file NestedCall.out, +compare-to NestedCall.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; + +set RAM[0] 261, +set RAM[1] 261, +set RAM[2] 256, +set RAM[3] -3, +set RAM[4] -4, +set RAM[5] -1, // test results +set RAM[6] -1, +set RAM[256] 1234, // fake stack frame from call Sys.init +set RAM[257] -1, +set RAM[258] -2, +set RAM[259] -3, +set RAM[260] -4, + +set RAM[261] -1, // Initialize stack to check for local segment +set RAM[262] -1, // being cleared to zero. +set RAM[263] -1, +set RAM[264] -1, +set RAM[265] -1, +set RAM[266] -1, +set RAM[267] -1, +set RAM[268] -1, +set RAM[269] -1, +set RAM[270] -1, +set RAM[271] -1, +set RAM[272] -1, +set RAM[273] -1, +set RAM[274] -1, +set RAM[275] -1, +set RAM[276] -1, +set RAM[277] -1, +set RAM[278] -1, +set RAM[279] -1, +set RAM[280] -1, +set RAM[281] -1, +set RAM[282] -1, +set RAM[283] -1, +set RAM[284] -1, +set RAM[285] -1, +set RAM[286] -1, +set RAM[287] -1, +set RAM[288] -1, +set RAM[289] -1, +set RAM[290] -1, +set RAM[291] -1, +set RAM[292] -1, +set RAM[293] -1, +set RAM[294] -1, +set RAM[295] -1, +set RAM[296] -1, +set RAM[297] -1, +set RAM[298] -1, +set RAM[299] -1, + +set sp 261, +set local 261, +set argument 256, +set this 3000, +set that 4000; + +repeat 50 { + vmstep; +} +output; diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCallStack.html b/projects/src/project_08/FunctionCalls/NestedCall/NestedCallStack.html index 70582b6f2..e75105487 100644 --- a/projects/src/project_08/FunctionCalls/NestedCall/NestedCallStack.html +++ b/projects/src/project_08/FunctionCalls/NestedCall/NestedCallStack.html @@ -1,306 +1,306 @@ - - - - - NestedCall.tst — Stack Frames - - - - - - - -
- - - - - - - - - - - -
Bootstrap init
Pointers
0256SP
1-1LCL
2-2ARG
3-3THIS
4-4THAT
Stack
256???←SP

- This is how my boot­strap code initial­izes the pointers before calling Sys.init(). -

- Setting the LCL, ARG, THIS and THAT point­ers to known illegal values helps identify - when a pointer is used before it is initial­ized. -

- (If you are running the NestedCall test with­out boot­strap code, you will not see this state.)

-
- - - - - - - - - - - - - - - - -
Entry to Sys.init()
Pointers
0261SP
1261LCL
2256ARG
3-3THIS
4-4THAT
Stack
256*Return IP←ARG
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261???←LCL, SP

- This is how NestedCall.tst initial­izes the pointers and stack. This is what RAM looks - like after my boot­strap calls Sys.init(). -

- (If your VM trans­lation includes the boot­strap, the -1 through -4 values may be - different if your boot­strap initial­izes them.)

-
- - - - - - - - - - - - - - - - - - - - -
Entry to Sys.main()
Pointers
0266SP
1266LCL
2261ARG
34000THIS
45000THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
266???←LCL, SP
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
After Sys.main() prologue
Pointers
0271SP
1266LCL
2261ARG
34000THIS
45000THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0←LCL
2670local 1
2680local 2
2690local 3
2700local 4
271???←SP

- The function prologue is the assembly language code generated for the - "function" VM command. -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Entry to Sys.add12(123)
Pointers
0277SP
1277LCL
2271ARG
34001THIS
45001THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0
267200local 1
26840local 2
2696local 3
2700local 4
271123argument 0←ARG
272*Return IP
273266Saved LCLSys.add12
274261Saved ARG frame
2754001Saved THIS
2765001Saved THAT
277???←LCL, SP
-
- -

- - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Before Sys.add12() return
Pointers
0278SP
1277LCL
2271ARG
34002THIS
45002THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0
267200local 1
26840local 2
2696local 3
2700local 4
271123argument 0←ARG
272*Return IP
273266Saved LCLSys.add12
274261Saved ARG frame
2754001Saved THIS
2765001Saved THAT
277135Return value←LCL
278???←SP
-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
After Sys.add12() return
Pointers
0272SP
1266LCL
2261ARG
34001THIS
45001THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0←LCL
267200local 1
26840local 2
2696local 3
2700local 4
271135Return value
272???←SP
-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Before Sys.main() return
Pointers
0272SP
1266LCL
2261ARG
34001THIS
45001THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0←LCL
267200local 1
26840local 2
2696local 3
2700local 4
271246Return value
272???←SP
-
- - - - - - - - - - - - - - - - -
After Sys.main() return
Pointers
0262SP
1261LCL
2256ARG
34000THIS
45000THAT
Stack
256*Return IP←ARG
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261246Return value←LCL
262???←SP
-
- - - - - - - - - - - - - - - -
In Sys.init() halt loop
Pointers
0261SP
1261LCL
2256ARG
34000THIS
45000THAT
Stack
256*Return IP←ARG
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261???←LCL, SP
-
- - + + + + + NestedCall.tst — Stack Frames + + + + + + + +
+ + + + + + + + + + + +
Bootstrap init
Pointers
0256SP
1-1LCL
2-2ARG
3-3THIS
4-4THAT
Stack
256???←SP

+ This is how my boot­strap code initial­izes the pointers before calling Sys.init(). +

+ Setting the LCL, ARG, THIS and THAT point­ers to known illegal values helps identify + when a pointer is used before it is initial­ized. +

+ (If you are running the NestedCall test with­out boot­strap code, you will not see this state.)

+
+ + + + + + + + + + + + + + + + +
Entry to Sys.init()
Pointers
0261SP
1261LCL
2256ARG
3-3THIS
4-4THAT
Stack
256*Return IP←ARG
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261???←LCL, SP

+ This is how NestedCall.tst initial­izes the pointers and stack. This is what RAM looks + like after my boot­strap calls Sys.init(). +

+ (If your VM trans­lation includes the boot­strap, the -1 through -4 values may be + different if your boot­strap initial­izes them.)

+
+ + + + + + + + + + + + + + + + + + + + +
Entry to Sys.main()
Pointers
0266SP
1266LCL
2261ARG
34000THIS
45000THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
266???←LCL, SP
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
After Sys.main() prologue
Pointers
0271SP
1266LCL
2261ARG
34000THIS
45000THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0←LCL
2670local 1
2680local 2
2690local 3
2700local 4
271???←SP

+ The function prologue is the assembly language code generated for the + "function" VM command. +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Entry to Sys.add12(123)
Pointers
0277SP
1277LCL
2271ARG
34001THIS
45001THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0
267200local 1
26840local 2
2696local 3
2700local 4
271123argument 0←ARG
272*Return IP
273266Saved LCLSys.add12
274261Saved ARG frame
2754001Saved THIS
2765001Saved THAT
277???←LCL, SP
+
+ +

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Before Sys.add12() return
Pointers
0278SP
1277LCL
2271ARG
34002THIS
45002THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0
267200local 1
26840local 2
2696local 3
2700local 4
271123argument 0←ARG
272*Return IP
273266Saved LCLSys.add12
274261Saved ARG frame
2754001Saved THIS
2765001Saved THAT
277135Return value←LCL
278???←SP
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
After Sys.add12() return
Pointers
0272SP
1266LCL
2261ARG
34001THIS
45001THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0←LCL
267200local 1
26840local 2
2696local 3
2700local 4
271135Return value
272???←SP
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Before Sys.main() return
Pointers
0272SP
1266LCL
2261ARG
34001THIS
45001THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0←LCL
267200local 1
26840local 2
2696local 3
2700local 4
271246Return value
272???←SP
+
+ + + + + + + + + + + + + + + + +
After Sys.main() return
Pointers
0262SP
1261LCL
2256ARG
34000THIS
45000THAT
Stack
256*Return IP←ARG
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261246Return value←LCL
262???←SP
+
+ + + + + + + + + + + + + + + +
In Sys.init() halt loop
Pointers
0261SP
1261LCL
2256ARG
34000THIS
45000THAT
Stack
256*Return IP←ARG
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261???←LCL, SP
+
+ + \ No newline at end of file diff --git a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.cmp b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.cmp index c3ea911de..ef72b7a4c 100644 --- a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.cmp +++ b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.cmp @@ -1,2 +1,2 @@ -| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] |RAM[310]| -| 311 | 305 | 300 | 3010 | 4010 | 1196 | +| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] |RAM[310]| +| 311 | 305 | 300 | 3010 | 4010 | 1196 | diff --git a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.hdl_tst b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.hdl_tst index c7b590562..5feaccca3 100644 --- a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.hdl_tst +++ b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.hdl_tst @@ -1,29 +1,29 @@ -// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.tst - -load SimpleFunction.asm, -output-file SimpleFunction.out, -compare-to SimpleFunction.cmp, -output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 - RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; - -set RAM[0] 317, -set RAM[1] 317, -set RAM[2] 310, -set RAM[3] 3000, -set RAM[4] 4000, -set RAM[310] 1234, -set RAM[311] 37, -set RAM[312] 1000, -set RAM[313] 305, -set RAM[314] 300, -set RAM[315] 3010, -set RAM[316] 4010, - -repeat 300 { - ticktock; -} - -output; +// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.tst + +load SimpleFunction.asm, +output-file SimpleFunction.out, +compare-to SimpleFunction.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 + RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; + +set RAM[0] 317, +set RAM[1] 317, +set RAM[2] 310, +set RAM[3] 3000, +set RAM[4] 4000, +set RAM[310] 1234, +set RAM[311] 37, +set RAM[312] 1000, +set RAM[313] 305, +set RAM[314] 300, +set RAM[315] 3010, +set RAM[316] 4010; + +repeat 300 { + ticktock; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm index d64a34ff4..59a76df2e 100644 --- a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm +++ b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm @@ -1,16 +1,16 @@ -// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.vm - -// Performs a simple calculation and returns the result. -function SimpleFunction.test 2 -push local 0 -push local 1 -add -not -push argument 0 -add -push argument 1 -sub -return +// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.vm + +// Performs a simple calculation and returns the result. +function SimpleFunction.test 2 +push local 0 +push local 1 +add +not +push argument 0 +add +push argument 1 +sub +return diff --git a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm_tst b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm_tst index c9267ee4d..a0307ed79 100644 --- a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm_tst +++ b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm_tst @@ -1,29 +1,29 @@ -// 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/08/FunctionCalls/SimpleFunction/SimpleFunctionVME.tst - -load SimpleFunction.vm, -output-file SimpleFunction.out, -compare-to SimpleFunction.cmp, -output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 - RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; - -set sp 317, -set local 317, -set argument 310, -set this 3000, -set that 4000, -set argument[0] 1234, -set argument[1] 37, -set argument[2] 9, -set argument[3] 305, -set argument[4] 300, -set argument[5] 3010, -set argument[6] 4010, - -repeat 10 { - vmstep; -} - -output; +// 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/08/FunctionCalls/SimpleFunction/SimpleFunctionVME.tst + +load SimpleFunction.vm, +output-file SimpleFunction.out, +compare-to SimpleFunction.cmp, +output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 + RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; + +set sp 317, +set local 317, +set argument 310, +set this 3000, +set that 4000, +set argument[0] 1234, +set argument[1] 37, +set argument[2] 9, +set argument[3] 305, +set argument[4] 300, +set argument[5] 3010, +set argument[6] 4010; + +repeat 10 { + vmstep; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/Class1.vm b/projects/src/project_08/FunctionCalls/StaticsTest/Class1.vm index c4635377e..c1e87cfe3 100644 --- a/projects/src/project_08/FunctionCalls/StaticsTest/Class1.vm +++ b/projects/src/project_08/FunctionCalls/StaticsTest/Class1.vm @@ -1,20 +1,20 @@ -// 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/08/FunctionCalls/StaticsTest/Class1.vm - -// Stores two supplied arguments in static[0] and static[1]. -function Class1.set 0 -push argument 0 -pop static 0 -push argument 1 -pop static 1 -push constant 0 -return - -// Returns static[0] - static[1]. -function Class1.get 0 -push static 0 -push static 1 -sub -return +// 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/08/FunctionCalls/StaticsTest/Class1.vm + +// Stores two supplied arguments in static[0] and static[1]. +function Class1.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class1.get 0 +push static 0 +push static 1 +sub +return diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/Class2.vm b/projects/src/project_08/FunctionCalls/StaticsTest/Class2.vm index 94f294668..4eca310ab 100644 --- a/projects/src/project_08/FunctionCalls/StaticsTest/Class2.vm +++ b/projects/src/project_08/FunctionCalls/StaticsTest/Class2.vm @@ -1,20 +1,20 @@ -// 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/08/FunctionCalls/StaticsTest/Class2.vm - -// Stores two supplied arguments in static[0] and static[1]. -function Class2.set 0 -push argument 0 -pop static 0 -push argument 1 -pop static 1 -push constant 0 -return - -// Returns static[0] - static[1]. -function Class2.get 0 -push static 0 -push static 1 -sub -return +// 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/08/FunctionCalls/StaticsTest/Class2.vm + +// Stores two supplied arguments in static[0] and static[1]. +function Class2.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class2.get 0 +push static 0 +push static 1 +sub +return diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.cmp b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.cmp index 5589f1ec2..309f058a5 100644 --- a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.cmp +++ b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.cmp @@ -1,2 +1,2 @@ -| RAM[0] |RAM[261]|RAM[262]| -| 263 | -2 | 8 | +| RAM[0] |RAM[261]|RAM[262]| +| 263 | -2 | 8 | diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.hdl_tst b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.hdl_tst index 1b9194ed9..a1eb87abb 100644 --- a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.hdl_tst +++ b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.hdl_tst @@ -1,17 +1,17 @@ -// 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/08/FunctionCalls/StaticsTest/StaticsTest.tst - -load StaticsTest.asm, -output-file StaticsTest.out, -compare-to StaticsTest.cmp, -output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; - -set RAM[0] 256, - -repeat 2500 { - ticktock; -} - -output; +// 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/08/FunctionCalls/StaticsTest/StaticsTest.tst + +load StaticsTest.asm, +output-file StaticsTest.out, +compare-to StaticsTest.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; + +set RAM[0] 256; + +repeat 2500 { + ticktock; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm index 394e4e975..20555853c 100644 --- a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm +++ b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm @@ -1,60 +1,60 @@ -// 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/08/FunctionCalls/StaticsTest/Class1.vm - -// Stores two supplied arguments in static[0] and static[1]. -function Class1.set 0 -push argument 0 -pop static 0 -push argument 1 -pop static 1 -push constant 0 -return - -// Returns static[0] - static[1]. -function Class1.get 0 -push static 0 -push static 1 -sub -return -// 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/08/FunctionCalls/StaticsTest/Class2.vm - -// Stores two supplied arguments in static[0] and static[1]. -function Class2.set 0 -push argument 0 -pop static 0 -push argument 1 -pop static 1 -push constant 0 -return - -// Returns static[0] - static[1]. -function Class2.get 0 -push static 0 -push static 1 -sub -return -// 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/08/FunctionCalls/StaticsTest/Sys.vm - -// Tests that different functions, stored in two different -// class files, manipulate the static segment correctly. -function Sys.init 0 -push constant 6 -push constant 8 -call Class1.set 2 -pop temp 0 // Dumps the return value -push constant 23 -push constant 15 -call Class2.set 2 -pop temp 0 // Dumps the return value -call Class1.get 0 -call Class2.get 0 -label WHILE -goto WHILE +// 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/08/FunctionCalls/StaticsTest/Class1.vm + +// Stores two supplied arguments in static[0] and static[1]. +function Class1.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class1.get 0 +push static 0 +push static 1 +sub +return +// 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/08/FunctionCalls/StaticsTest/Class2.vm + +// Stores two supplied arguments in static[0] and static[1]. +function Class2.set 0 +push argument 0 +pop static 0 +push argument 1 +pop static 1 +push constant 0 +return + +// Returns static[0] - static[1]. +function Class2.get 0 +push static 0 +push static 1 +sub +return +// 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/08/FunctionCalls/StaticsTest/Sys.vm + +// Tests that different functions, stored in two different +// class files, manipulate the static segment correctly. +function Sys.init 0 +push constant 6 +push constant 8 +call Class1.set 2 +pop temp 0 // Dumps the return value +push constant 23 +push constant 15 +call Class2.set 2 +pop temp 0 // Dumps the return value +call Class1.get 0 +call Class2.get 0 +label WHILE +goto WHILE diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm_tst b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm_tst index 130ba66b8..5f2fb187f 100644 --- a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm_tst +++ b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm_tst @@ -1,17 +1,17 @@ -// 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/08/FunctionCalls/StaticsTest/StaticsTestVME.tst - -load, // loads all the VM files from the current directory. -output-file StaticsTest.out, -compare-to StaticsTest.cmp, -output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; - -set sp 261, - -repeat 36 { - vmstep; -} - -output; +// 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/08/FunctionCalls/StaticsTest/StaticsTestVME.tst + +load, // loads all the VM files from the current directory. +output-file StaticsTest.out, +compare-to StaticsTest.cmp, +output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; + +set sp 261; + +repeat 36 { + vmstep; +} + +output; diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/Sys.vm b/projects/src/project_08/FunctionCalls/StaticsTest/Sys.vm index 370832264..361428294 100644 --- a/projects/src/project_08/FunctionCalls/StaticsTest/Sys.vm +++ b/projects/src/project_08/FunctionCalls/StaticsTest/Sys.vm @@ -1,20 +1,20 @@ -// 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/08/FunctionCalls/StaticsTest/Sys.vm - -// Tests that different functions, stored in two different -// class files, manipulate the static segment correctly. -function Sys.init 0 -push constant 6 -push constant 8 -call Class1.set 2 -pop temp 0 // Dumps the return value -push constant 23 -push constant 15 -call Class2.set 2 -pop temp 0 // Dumps the return value -call Class1.get 0 -call Class2.get 0 -label WHILE -goto WHILE +// 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/08/FunctionCalls/StaticsTest/Sys.vm + +// Tests that different functions, stored in two different +// class files, manipulate the static segment correctly. +function Sys.init 0 +push constant 6 +push constant 8 +call Class1.set 2 +pop temp 0 // Dumps the return value +push constant 23 +push constant 15 +call Class2.set 2 +pop temp 0 // Dumps the return value +call Class1.get 0 +call Class2.get 0 +label WHILE +goto WHILE diff --git a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.cmp b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.cmp index 00d35d2a9..1786c7cf8 100644 --- a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.cmp +++ b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.cmp @@ -1,2 +1,2 @@ -| RAM[0] |RAM[256]| -| 257 | 6 | +| RAM[0] |RAM[256]| +| 257 | 6 | diff --git a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.hdl_tst b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.hdl_tst index 50ca11885..fb773ae4d 100644 --- a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.hdl_tst +++ b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.hdl_tst @@ -1,20 +1,20 @@ -// 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/08/ProgramFlow/BasicLoop/BasicLoop.tst - -load BasicLoop.asm, -output-file BasicLoop.out, -compare-to BasicLoop.cmp, -output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; - -set RAM[0] 256, -set RAM[1] 300, -set RAM[2] 400, -set RAM[400] 3, - -repeat 600 { - ticktock; -} - -output; +// 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/08/ProgramFlow/BasicLoop/BasicLoop.tst + +load BasicLoop.asm, +output-file BasicLoop.out, +compare-to BasicLoop.cmp, +output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; + +set RAM[0] 256, +set RAM[1] 300, +set RAM[2] 400, +set RAM[400] 3; + +repeat 600 { + ticktock; +} + +output; diff --git a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm index dc5a92f5f..d46d10219 100644 --- a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm +++ b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm @@ -1,22 +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/08/ProgramFlow/BasicLoop/BasicLoop.vm - -// Computes the sum 1 + 2 + ... + argument[0] and pushes the -// result onto the stack. Argument[0] is initialized by the test -// script before this code starts running. -push constant 0 -pop local 0 // initializes sum = 0 -label LOOP_START -push argument 0 -push local 0 -add -pop local 0 // sum = sum + counter -push argument 0 -push constant 1 -sub -pop argument 0 // counter-- -push argument 0 -if-goto LOOP_START // If counter != 0, goto LOOP_START -push local 0 +// 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/08/ProgramFlow/BasicLoop/BasicLoop.vm + +// Computes the sum 1 + 2 + ... + argument[0] and pushes the +// result onto the stack. Argument[0] is initialized by the test +// script before this code starts running. +push constant 0 +pop local 0 // initializes sum = 0 +label LOOP_START +push argument 0 +push local 0 +add +pop local 0 // sum = sum + counter +push argument 0 +push constant 1 +sub +pop argument 0 // counter-- +push argument 0 +if-goto LOOP_START // If counter != 0, goto LOOP_START +push local 0 diff --git a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm_tst b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm_tst index 237fdff53..95978f87e 100644 --- a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm_tst +++ b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm_tst @@ -1,20 +1,20 @@ -// 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/08/ProgramFlow/BasicLoop/BasicLoopVME.tst - -load BasicLoop.vm, -output-file BasicLoop.out, -compare-to BasicLoop.cmp, -output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; - -set sp 256, -set local 300, -set argument 400, -set argument[0] 3, - -repeat 33 { - vmstep; -} - -output; +// 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/08/ProgramFlow/BasicLoop/BasicLoopVME.tst + +load BasicLoop.vm, +output-file BasicLoop.out, +compare-to BasicLoop.cmp, +output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; + +set sp 256, +set local 300, +set argument 400, +set argument[0] 3; + +repeat 33 { + vmstep; +} + +output; diff --git a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.cmp b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.cmp index c262a4b6b..304e7c1c0 100644 --- a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.cmp +++ b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.cmp @@ -1,2 +1,2 @@ -|RAM[3000]|RAM[3001]|RAM[3002]|RAM[3003]|RAM[3004]|RAM[3005]| -| 0 | 1 | 1 | 2 | 3 | 5 | +|RAM[3000]|RAM[3001]|RAM[3002]|RAM[3003]|RAM[3004]|RAM[3005]| +| 0 | 1 | 1 | 2 | 3 | 5 | diff --git a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.hdl_tst b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.hdl_tst index 07df2b925..6b4159c56 100644 --- a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.hdl_tst +++ b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.hdl_tst @@ -1,22 +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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.tst - -load FibonacciSeries.asm, -output-file FibonacciSeries.out, -compare-to FibonacciSeries.cmp, -output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 - RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; - -set RAM[0] 256, -set RAM[1] 300, -set RAM[2] 400, -set RAM[400] 6, -set RAM[401] 3000, - -repeat 1100 { - ticktock; -} - -output; +// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.tst + +load FibonacciSeries.asm, +output-file FibonacciSeries.out, +compare-to FibonacciSeries.cmp, +output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 + RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; + +set RAM[0] 256, +set RAM[1] 300, +set RAM[2] 400, +set RAM[400] 6, +set RAM[401] 3000; + +repeat 1100 { + ticktock; +} + +output; diff --git a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm index 6a643b6fd..41b5773d4 100644 --- a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm +++ b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm @@ -1,49 +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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm - -// Puts the first argument[0] elements of the Fibonacci series -// in the memory, starting in the address given in argument[1]. -// Argument[0] and argument[1] are initialized by the test script -// before this code starts running. - -push argument 1 -pop pointer 1 // that = argument[1] - -push constant 0 -pop that 0 // first element in the series = 0 -push constant 1 -pop that 1 // second element in the series = 1 - -push argument 0 -push constant 2 -sub -pop argument 0 // num_of_elements -= 2 (first 2 elements are set) - -label MAIN_LOOP_START - -push argument 0 -if-goto COMPUTE_ELEMENT // if num_of_elements > 0, goto COMPUTE_ELEMENT -goto END_PROGRAM // otherwise, goto END_PROGRAM - -label COMPUTE_ELEMENT - -push that 0 -push that 1 -add -pop that 2 // that[2] = that[0] + that[1] - -push pointer 1 -push constant 1 -add -pop pointer 1 // that += 1 - -push argument 0 -push constant 1 -sub -pop argument 0 // num_of_elements-- - -goto MAIN_LOOP_START - -label END_PROGRAM +// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm + +// Puts the first argument[0] elements of the Fibonacci series +// in the memory, starting in the address given in argument[1]. +// Argument[0] and argument[1] are initialized by the test script +// before this code starts running. + +push argument 1 +pop pointer 1 // that = argument[1] + +push constant 0 +pop that 0 // first element in the series = 0 +push constant 1 +pop that 1 // second element in the series = 1 + +push argument 0 +push constant 2 +sub +pop argument 0 // num_of_elements -= 2 (first 2 elements are set) + +label MAIN_LOOP_START + +push argument 0 +if-goto COMPUTE_ELEMENT // if num_of_elements > 0, goto COMPUTE_ELEMENT +goto END_PROGRAM // otherwise, goto END_PROGRAM + +label COMPUTE_ELEMENT + +push that 0 +push that 1 +add +pop that 2 // that[2] = that[0] + that[1] + +push pointer 1 +push constant 1 +add +pop pointer 1 // that += 1 + +push argument 0 +push constant 1 +sub +pop argument 0 // num_of_elements-- + +goto MAIN_LOOP_START + +label END_PROGRAM diff --git a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm_tst b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm_tst index 243f31bd6..19f1b9d1a 100644 --- a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm_tst +++ b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm_tst @@ -1,22 +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/08/ProgramFlow/FibonacciSeries/FibonacciSeriesVME.tst - -load FibonacciSeries.vm, -output-file FibonacciSeries.out, -compare-to FibonacciSeries.cmp, -output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 - RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; - -set sp 256, -set local 300, -set argument 400, -set argument[0] 6, -set argument[1] 3000, - -repeat 73 { - vmstep; -} - -output; +// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeriesVME.tst + +load FibonacciSeries.vm, +output-file FibonacciSeries.out, +compare-to FibonacciSeries.cmp, +output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 + RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; + +set sp 256, +set local 300, +set argument 400, +set argument[0] 6, +set argument[1] 3000; + +repeat 73 { + vmstep; +} + +output; diff --git a/projects/src/project_08/index.ts b/projects/src/project_08/index.ts index a8dd00bfe..bb4e511b7 100644 --- a/projects/src/project_08/index.ts +++ b/projects/src/project_08/index.ts @@ -26,7 +26,7 @@ export const VMS = { "SimpleFunction.tst": simple_function.hdl_tst, }, NestedCall: { - "NestedCall.vm": nested_call.vm, + "Sys.vm": nested_call.vm, // Test uses a special name here "NestedCall.vm_tst": nested_call.vm_tst, "NestedCall.cmp": nested_call.cmp, "NestedCall.tst": nested_call.hdl_tst, From 6519ba1eb548fdd661225e7b8ee11db6a8acd388 Mon Sep 17 00:00:00 2001 From: David Souther Date: Sun, 12 Nov 2023 15:19:22 -0500 Subject: [PATCH 10/14] VMTest passes projects 7 and 8 files --- simulator/src/languages/grammars/tst.ohm | 5 +- simulator/src/languages/grammars/tst.ohm.js | 5 +- simulator/src/languages/tst.test.ts | 26 +++ simulator/src/languages/tst.ts | 6 +- simulator/src/test/builder.ts | 3 + simulator/src/test/instruction.ts | 12 ++ simulator/src/test/tst.ts | 3 +- simulator/src/test/vmtst.test.ts | 37 +++++ simulator/src/test/vmtst.ts | 68 +++++++- simulator/src/vm/memory.ts | 77 ++++----- simulator/src/vm/vm.test.ts | 2 - simulator/src/vm/vm.ts | 166 +++++++++++++------- web/src/shell/editor.mock.tsx | 1 - 13 files changed, 292 insertions(+), 119 deletions(-) diff --git a/simulator/src/languages/grammars/tst.ohm b/simulator/src/languages/grammars/tst.ohm index a675b8d58..8eef1c665 100644 --- a/simulator/src/languages/grammars/tst.ohm +++ b/simulator/src/languages/grammars/tst.ohm @@ -17,13 +17,13 @@ Tst <: Base { | TstLoadROMOperation TstLoadROMOperation = ROM32K Load FileName - TstFileOperation = FileOperation FileName + TstFileOperation = FileOperation FileName? TstOutputListOperation = "output-list" OutputFormat+ OutputFormat = Name Index? percent FormatStyle wholeDec dot wholeDec dot wholeDec TstSetOperation = Set Name Index? Number Index = OpenSquare wholeDec? CloseSquare Condition = Value CompareOp Value - TstEvalOperation = Eval | TickTock | Tick | Tock + TstEvalOperation = Eval | TickTock | Tick | Tock | VmStep TstOutputOperation = Output TstEchoOperation = Echo String TstClearEchoOperation = ClearEcho @@ -36,6 +36,7 @@ Tst <: Base { Tick = "tick" Tock = "tock" TickTock = "ticktock" + VmStep = "vmstep" Echo = "echo" Repeat = "repeat" ClearEcho = "clear-echo" diff --git a/simulator/src/languages/grammars/tst.ohm.js b/simulator/src/languages/grammars/tst.ohm.js index 3c40e3585..00a53c828 100644 --- a/simulator/src/languages/grammars/tst.ohm.js +++ b/simulator/src/languages/grammars/tst.ohm.js @@ -18,13 +18,13 @@ Tst <: Base { | TstLoadROMOperation TstLoadROMOperation = ROM32K Load FileName - TstFileOperation = FileOperation FileName + TstFileOperation = FileOperation FileName? TstOutputListOperation = "output-list" OutputFormat+ OutputFormat = Name Index? percent FormatStyle wholeDec dot wholeDec dot wholeDec TstSetOperation = Set Name Index? Number Index = OpenSquare wholeDec? CloseSquare Condition = Value CompareOp Value - TstEvalOperation = Eval | TickTock | Tick | Tock + TstEvalOperation = Eval | TickTock | Tick | Tock | VmStep TstOutputOperation = Output TstEchoOperation = Echo String TstClearEchoOperation = ClearEcho @@ -37,6 +37,7 @@ Tst <: Base { Tick = "tick" Tock = "tock" TickTock = "ticktock" + VmStep = "vmstep" Echo = "echo" Repeat = "repeat" ClearEcho = "clear-echo" diff --git a/simulator/src/languages/tst.test.ts b/simulator/src/languages/tst.test.ts index 33a0671d3..96a3d9274 100644 --- a/simulator/src/languages/tst.test.ts +++ b/simulator/src/languages/tst.test.ts @@ -1,3 +1,8 @@ +import { + FileSystem, + ObjectFileSystemAdapter, +} from "@davidsouther/jiffies/lib/esm/fs.js"; +import { resetFiles } from "@nand2tetris/projects/index.js"; import { grammar, TST } from "./tst.js"; const NOT_TST = ` @@ -469,3 +474,24 @@ describe("tst language", () => { }); }); }); + +it("loads all project tst files", async () => { + const fs = new FileSystem(new ObjectFileSystemAdapter()); + await resetFiles(fs); + async function check() { + for (const stat of await fs.scandir(".")) { + if (stat.isDirectory()) { + fs.pushd(stat.name); + await check(); + fs.popd(); + } else { + if (stat.name.endsWith("vm_tst")) { + const tst = await fs.readFile(stat.name); + const match = grammar.match(tst); + expect(match).toHaveSucceeded(); + } + } + } + } + await check(); +}); diff --git a/simulator/src/languages/tst.ts b/simulator/src/languages/tst.ts index 1409b5f33..2f19ce4b9 100644 --- a/simulator/src/languages/tst.ts +++ b/simulator/src/languages/tst.ts @@ -20,7 +20,7 @@ export interface TstSetOperation { } export interface TstEvalOperation { - op: "eval" | "tick" | "tock" | "ticktock"; + op: "eval" | "tick" | "tock" | "ticktock" | "vmstep"; } export interface TstOutputOperation { @@ -49,7 +49,7 @@ export interface TstLoadROMOperation { export interface TstFileOperation { op: "load" | "output-file" | "compare-to"; - file: string; + file?: string; } export type TstOperation = @@ -183,7 +183,7 @@ tstSemantics.addAttribute("operation", { TstFileOperation(op, file) { return { op: op.sourceString as TstFileOperation["op"], - file: file.sourceString, + file: file?.sourceString, }; }, }); diff --git a/simulator/src/test/builder.ts b/simulator/src/test/builder.ts index ebd948922..b5dbbcedc 100644 --- a/simulator/src/test/builder.ts +++ b/simulator/src/test/builder.ts @@ -24,6 +24,7 @@ import { TestWhileInstruction, } from "./instruction.js"; import { Test } from "./tst.js"; +import { TestVMStepInstruction } from "./vmtst.js"; import { TestTickTockInstruction } from "./cputst.js"; function isTstLineStatment(line: TstStatement): line is TstLineStatement { @@ -55,6 +56,8 @@ function makeInstruction(inst: TstOperation) { return new TestTickTockInstruction(); case "eval": return new TestEvalInstruction(); + case "vmstep": + return new TestVMStepInstruction(); case "output": return new TestOutputInstruction(); case "set": diff --git a/simulator/src/test/instruction.ts b/simulator/src/test/instruction.ts index 812d8adbb..75936aa51 100644 --- a/simulator/src/test/instruction.ts +++ b/simulator/src/test/instruction.ts @@ -204,6 +204,18 @@ export class TestLoadROMInstruction implements TestInstruction { } } +export class TestLoadInstruction implements TestInstruction { + constructor(readonly file?: string) {} + + async do(test: Test) { + await test.load(this.file); + } + + *steps() { + yield this; + } +} + export class TestBreakpointInstruction implements TestInstruction { constructor(readonly variable: string, readonly value: number) {} diff --git a/simulator/src/test/tst.ts b/simulator/src/test/tst.ts index bec1a626e..aceb2a7f5 100644 --- a/simulator/src/test/tst.ts +++ b/simulator/src/test/tst.ts @@ -21,7 +21,7 @@ export abstract class Test { return undefined; } - async load(_filename: string): Promise { + async load(_filename?: string): Promise { return undefined; } async compareTo(_filename: string): Promise { @@ -45,7 +45,6 @@ export abstract class Test { } })(this); this._step = this._steps.next(); - this._step; //? this._log = ""; return this; } diff --git a/simulator/src/test/vmtst.test.ts b/simulator/src/test/vmtst.test.ts index e69de29bb..b0ce6c5ef 100644 --- a/simulator/src/test/vmtst.test.ts +++ b/simulator/src/test/vmtst.test.ts @@ -0,0 +1,37 @@ +import { VM_PROJECTS, resetFiles } from "@nand2tetris/projects/index.js"; +import { + FileSystem, + ObjectFileSystemAdapter, +} from "@davidsouther/jiffies/lib/esm/fs.js"; +import { TST } from "../languages/tst.js"; +import { unwrap } from "@davidsouther/jiffies/lib/esm/result.js"; +import { VMTest } from "./vmtst.js"; + +async function prepare(project: "07" | "08", name: string): Promise { + const fs = new FileSystem(new ObjectFileSystemAdapter({})); + await resetFiles(fs); + fs.cd(`/projects/${project}/${name}`); + const vm_tst = await fs.readFile(name + ".vm_tst"); + const tst = unwrap(TST.parse(vm_tst)); + const test = VMTest.from(tst).using(fs); + await test.load(); + return test; +} + +describe("VM Test Runner", () => { + test.each(VM_PROJECTS["07"])("07 VM Test Runner %s", async (name) => { + const test = await prepare("07", name); + + for (let i = 0; i < 100; i++) { + await test.step(); + } + }); + + test.each(VM_PROJECTS["08"])("08 VM Test Runner %s", async (name) => { + const test = await prepare("08", name); + + for (let i = 0; i < 100; i++) { + test.step(); + } + }); +}); diff --git a/simulator/src/test/vmtst.ts b/simulator/src/test/vmtst.ts index 318c1a7c6..0c34f4ef9 100644 --- a/simulator/src/test/vmtst.ts +++ b/simulator/src/test/vmtst.ts @@ -1,11 +1,26 @@ +import { FileSystem } from "@davidsouther/jiffies/lib/esm/fs.js"; +import { unwrap } from "@davidsouther/jiffies/lib/esm/result.js"; import { RAM } from "../cpu/memory.js"; -import { Vm } from "../vm/vm.js"; +import { Tst } from "../languages/tst.js"; +import { VM } from "../languages/vm.js"; +import { Segment, Vm } from "../vm/vm.js"; +import { fill } from "./builder.js"; import { TestInstruction } from "./instruction.js"; import { Test } from "./tst.js"; export class VMTest extends Test { vm: Vm = new Vm(); + static from(tst: Tst): VMTest { + const test = new VMTest(); + return fill(test, tst); + } + + using(fs: FileSystem): this { + this.fs = fs; + return this; + } + with(vm: Vm) { this.vm = vm; return this; @@ -24,7 +39,16 @@ export class VMTest extends Test { ) { return true; } - return false; + return [ + "argument", + "local", + "static", + "constant", + "this", + "that", + "pointer", + "temp", + ].includes(variable.toLowerCase()); } getVar(variable: string | number, index?: number): number { @@ -40,7 +64,7 @@ export class VMTest extends Test { ) { return this.vm.RAM.get(index); } - return 0; + return this.vm.memory.getSegment(variable as Segment, index ?? 0); } setVar(variable: string, value: number, index?: number): void { @@ -56,11 +80,49 @@ export class VMTest extends Test { ) { this.vm.RAM.set(index, value); } + if (index) { + this.vm.memory.setSegment(variable as Segment, index, value); + } else { + switch (variable.toLowerCase()) { + case "sp": + this.vm.memory.SP = value; + break; + case "arg": + case "argument": + this.vm.memory.ARG = value; + break; + case "lcl": + case "local": + this.vm.memory.LCL = value; + break; + case "this": + this.vm.memory.THIS = value; + break; + case "that": + this.vm.memory.THAT = value; + break; + } + } } vmstep(): void { this.vm.step(); } + + override async load(filename?: string) { + if (filename) { + const file = await this.fs.readFile(filename); + const { instructions } = unwrap(VM.parse(file)); + unwrap(this.vm.load(instructions)); + } else { + for (const file of await this.fs.scandir(".")) { + if (file.isFile() && file.name.endsWith(".vm")) { + await this.load(file.name); + } + } + } + unwrap(this.vm.bootstrap()); + } } export interface VMTestInstruction extends TestInstruction { diff --git a/simulator/src/vm/memory.ts b/simulator/src/vm/memory.ts index 8e3555bee..a1ae2239b 100644 --- a/simulator/src/vm/memory.ts +++ b/simulator/src/vm/memory.ts @@ -14,37 +14,32 @@ export class VmMemory extends RAM { get SP(): number { return this.get(SP); } + set SP(value: number) { + this.set(SP, value); + } get LCL(): number { return this.get(LCL); } + set LCL(value: number) { + this.set(LCL, value); + } get ARG(): number { return this.get(ARG); } + set ARG(value: number) { + this.set(ARG, value); + } get THIS(): number { return this.get(THIS); } + set THIS(value: number) { + this.set(THIS, value); + } get THAT(): number { return this.get(THAT); } - - get state() { - const temps = []; - for (let i = 5; i < 13; i++) { - temps.push(this.get(i)); - } - const internal = []; - for (let i = 13; i < 16; i++) { - internal.push(i); - } - return { - ["0: SP"]: this.SP, - ["1: LCL"]: this.LCL, - ["2: ARG"]: this.ARG, - ["3: THIS"]: this.THIS, - ["4: THAT"]: this.THAT, - TEMPS: temps, - VM: internal, - }; + set THAT(value: number) { + this.set(THAT, value); } get statics() { @@ -55,27 +50,6 @@ export class VmMemory extends RAM { return statics; } - get frame() { - // Arg0 Arg1... RET LCL ARG THIS THAT [SP] - const args = []; - for (let i = this.ARG; i < this.LCL - 5; i++) { - args.push(this.get(i)); - } - const locals = []; - for (let i = this.LCL; i < this.SP; i++) { - locals.push(this.get(i)); - } - const _this = []; - for (let i = 0; i < 5; i++) { - _this.push(this.this(i)); - } - return { - args, - locals, - this: _this, - }; - } - constructor() { super(); this.set(SP, 256); @@ -224,13 +198,14 @@ export class VmMemory extends RAM { const args = [...this.map((_, v) => v, arg, arg + argN)]; const locals = [...this.map((_, v) => v, lcl, lcl + localN)]; const stack = [...this.map((_, v) => v, stk, stk + stackN)]; - // [arg, argN, args]; //? - // [lcl, localN, locals]; //? - // [stk, stackN, stack]; //? + const this_ = [...this.map((_, v) => v, this.THIS, this.THIS + thisN)]; + const that = [...this.map((_, v) => v, this.THIS, this.THIS + thatN)]; return { args: { base: arg, count: argN, values: args }, locals: { base: lcl, count: localN, values: locals }, stack: { base: stk, count: stackN, values: stack }, + this: { base: stk, count: thisN, values: this_ }, + that: { base: stk, count: thatN, values: that }, frame: { RET: this.get(base), LCL: this.LCL, @@ -241,6 +216,22 @@ export class VmMemory extends RAM { }; } + getVmState(staticN = 240) { + const temps = [...this.map((_, v) => v, 5, 13)]; + const internal = [...this.map((_, v) => v, 13, 16)]; + const statics = [...this.map((_, v) => v, 16, 16 + staticN)]; + return { + ["0: SP"]: this.SP, + ["1: LCL"]: this.LCL, + ["2: ARG"]: this.ARG, + ["3: THIS"]: this.THIS, + ["4: THAT"]: this.THAT, + temps, + internal, + static: statics, + }; + } + binOp(fn: (a: number, b: number) => number) { const a = this.get(this.SP - 2); const b = this.get(this.SP - 1); diff --git a/simulator/src/vm/vm.test.ts b/simulator/src/vm/vm.test.ts index da3cdc54d..2a317aed0 100644 --- a/simulator/src/vm/vm.test.ts +++ b/simulator/src/vm/vm.test.ts @@ -307,8 +307,6 @@ test("08 / Simple Function / Simple Function", () => { vm.step(); } - vm.program; //? - const test = vm.read([0, 256]); expect(test).toEqual([257, 12]); }); diff --git a/simulator/src/vm/vm.ts b/simulator/src/vm/vm.ts index 78038f9b9..572bfa64c 100644 --- a/simulator/src/vm/vm.ts +++ b/simulator/src/vm/vm.ts @@ -75,6 +75,8 @@ export interface VmFrame { locals: VmFrameValues; args: VmFrameValues; stack: VmFrameValues; + this: VmFrameValues; + that: VmFrameValues; frame: { RET: number; ARG: number; @@ -122,6 +124,19 @@ const BOOTSTRAP: VmFunction = { ], }; +function BootstrapFor(name: string): VmFunction { + return { + name: "__bootstrap", + nVars: 0, + opBase: 0, + labels: {}, + operations: [ + { op: "function", name: "__bootstrap", nVars: 0 }, + { op: "call", name, nArgs: 0 }, + ], + }; +} + const END_LABEL = "__END"; const SYS_INIT: VmFunction = { name: "Sys.init", @@ -135,14 +150,11 @@ const SYS_INIT: VmFunction = { ], }; -const INITIAL_FNS = [BOOTSTRAP.name, IMPLICIT.name]; - export class Vm { - protected memory = new VmMemory(); - protected functionMap: Record = { - [BOOTSTRAP.name]: BOOTSTRAP, - }; - protected executionStack: VmFunctionInvocation[] = []; + memory = new VmMemory(); + entry = ""; + functionMap: Record = {}; + executionStack: VmFunctionInvocation[] = []; functions: VmFunction[] = []; program: VmOperation[] = []; @@ -177,55 +189,9 @@ export class Vm { static build(instructions: VmInstruction[]): Result { const vm = new Vm(); - - if (instructions[0]?.op !== "function") { - instructions.unshift({ op: "function", name: IMPLICIT.name, nVars: 0 }); - } - - let i = 0; - while (i < instructions.length) { - const buildFn = this.buildFunction(instructions, i); - - if (isErr(buildFn)) - return Err(new Error("Failed to build VM", { cause: Err(buildFn) })); - const [fn, i_] = unwrap(buildFn); - if (vm.functionMap[fn.name]) - throw new Error(`VM Already has a function named ${fn.name}`); - - vm.functionMap[fn.name] = fn; - i = i_; - } - - if (!vm.functionMap[SYS_INIT.name]) { - if (vm.functionMap["main"]) { - // Inject a Sys.init - vm.functionMap[SYS_INIT.name] = SYS_INIT; - } else if (vm.functionMap[IMPLICIT.name]) { - // Use __implicit instead of __bootstrap - delete vm.functionMap[BOOTSTRAP.name]; - } else { - return Err(Error("Could not determine an entry point for VM")); - } - } - - vm.registerStatics(); - - vm.functions = Object.values(vm.functionMap); - vm.functions.sort((a, b) => { - if (INITIAL_FNS.includes(a.name)) return -1; - if (INITIAL_FNS.includes(b.name)) return 1; - return a.name.localeCompare(b.name); - }); - - let offset = 0; - vm.program = vm.functions.reduce((prog, fn) => { - fn.opBase = offset; - offset += fn.operations.length; - return prog.concat(fn.operations); - }, [] as VmOperation[]); - - vm.reset(); - return Ok(vm); + const load = vm.load(instructions); + if (isErr(load)) return load; + return vm.bootstrap(); } private static buildFunction( @@ -348,7 +314,9 @@ export class Vm { get invocation() { const invocation = this.executionStack.at(-1); - if (invocation === undefined) throw new Error("Empty execution stack!"); + if (invocation === undefined) { + throw new Error("Empty execution stack!"); + } return invocation; } @@ -370,12 +338,86 @@ export class Vm { return this.currentFunction.operations[this.invocation.opPtr]; } + load(instructions: VmInstruction[]): Result { + if (instructions[0]?.op !== "function") { + instructions.unshift({ op: "function", name: IMPLICIT.name, nVars: 0 }); + } + + let i = 0; + while (i < instructions.length) { + const buildFn = Vm.buildFunction(instructions, i); + + if (isErr(buildFn)) + return Err(new Error("Failed to build VM", { cause: Err(buildFn) })); + const [fn, i_] = unwrap(buildFn); + if ( + this.functionMap[fn.name] && + this.memory.strict && + fn.name !== IMPLICIT.name + ) { + return Err(new Error(`VM Already has a function named ${fn.name}`)); + } + + this.functionMap[fn.name] = fn; + i = i_; + } + + this.registerStatics(); + + return Ok(this); + } + + bootstrap() { + if (!this.functionMap[SYS_INIT.name] && this.functionMap["main"]) { + this.functionMap[SYS_INIT.name] = SYS_INIT; + // TODO should this be an error from the compiler/OS? + } + + if (this.functionMap[SYS_INIT.name]) { + this.functionMap[BOOTSTRAP.name] = BootstrapFor(SYS_INIT.name); + this.entry = BOOTSTRAP.name; + } else if (this.functionMap[IMPLICIT.name]) { + this.entry = IMPLICIT.name; + } else { + const fnNames = Object.keys(this.functionMap); + if (fnNames.length === 1) { + this.functionMap[BOOTSTRAP.name] = BootstrapFor(fnNames[0]); + this.entry = BOOTSTRAP.name; + } + } + + if (this.functionMap[IMPLICIT.name] && this.functionMap[BOOTSTRAP.name]) { + return Err( + new Error("Cannot use both bootstrap and an implicit function") + ); + } + + if (this.entry === "") { + return Err(Error("Could not determine an entry point for VM")); + } + + this.functions = Object.values(this.functionMap); + this.functions.sort((a, b) => { + if (a.name === this.entry) return -1; + if (a.name === this.entry) return 1; + return 0; // Stable sort otherwise + }); + + let offset = 0; + this.program = this.functions.reduce((prog, fn) => { + fn.opBase = offset; + offset += fn.operations.length; + return prog.concat(fn.operations); + }, [] as VmOperation[]); + + this.reset(); + + return Ok(this); + } + reset() { - const bootstrap = this.functionMap[BOOTSTRAP.name] - ? BOOTSTRAP.name - : "__implicit"; this.executionStack = [ - { function: bootstrap, opPtr: 1, frameBase: 256, nArgs: 0 }, + { function: this.entry, opPtr: 1, frameBase: 256, nArgs: 0 }, ]; this.memory.reset(); this.memory.set(0, 256); @@ -520,6 +562,8 @@ export class Vm { count: frameEnd - frameBase, values: [...this.memory.map((_, v) => v, frameBase, frameEnd)], }, + ["this"]: { base: 0, count: 0, values: [] }, + that: { base: 0, count: 0, values: [] }, frame: { ARG: 0, LCL: 0, diff --git a/web/src/shell/editor.mock.tsx b/web/src/shell/editor.mock.tsx index f578f9a5b..33ec2b5eb 100644 --- a/web/src/shell/editor.mock.tsx +++ b/web/src/shell/editor.mock.tsx @@ -11,7 +11,6 @@ jest.mock("@monaco-editor/react", () => { > ); }); - console.log("mocked fake editor"); return FakeEditor; }); From 03fe68f82b95e9fa5c4e4a822edf5e281b83b4e1 Mon Sep 17 00:00:00 2001 From: David Souther Date: Sun, 12 Nov 2023 15:29:55 -0500 Subject: [PATCH 11/14] ci --- .../MemoryAccess/BasicTest/BasicTest.cmp | 2 - .../MemoryAccess/BasicTest/BasicTest.hdl_tst | 25 -- .../MemoryAccess/BasicTest/BasicTest.vm | 31 -- .../MemoryAccess/BasicTest/BasicTest.vm_tst | 25 -- .../MemoryAccess/PointerTest/PointerTest.cmp | 2 - .../PointerTest/PointerTest.hdl_tst | 20 -- .../MemoryAccess/PointerTest/PointerTest.vm | 22 -- .../PointerTest/PointerTest.vm_tst | 20 -- .../MemoryAccess/StaticTest/StaticTest.cmp | 2 - .../StaticTest/StaticTest.hdl_tst | 17 - .../MemoryAccess/StaticTest/StaticTest.vm | 17 - .../MemoryAccess/StaticTest/StaticTest.vm_tst | 17 - .../StackArithmetic/SimpleAdd/SimpleAdd.cmp | 2 - .../SimpleAdd/SimpleAdd.hdl_tst | 17 - .../StackArithmetic/SimpleAdd/SimpleAdd.vm | 9 - .../SimpleAdd/SimpleAdd.vm_tst | 17 - .../StackArithmetic/StackTest/StackTest.cmp | 4 - .../StackTest/StackTest.hdl_tst | 22 -- .../StackArithmetic/StackTest/StackTest.vm | 45 --- .../StackTest/StackTest.vm_tst | 22 -- .../FibonacciElement/FibonacciElement.cmp | 2 - .../FibonacciElement/FibonacciElement.hdl_tst | 18 -- .../FibonacciElement/FibonacciElement.vm | 45 --- .../FibonacciElement/FibonacciElement.vm_tst | 17 - .../FunctionCalls/FibonacciElement/Main.vm | 30 -- .../FunctionCalls/FibonacciElement/Sys.vm | 15 - .../FunctionCalls/NestedCall/NestedCall.cmp | 2 - .../NestedCall/NestedCall.hdl_tst | 65 ---- .../FunctionCalls/NestedCall/NestedCall.html | 196 ----------- .../FunctionCalls/NestedCall/NestedCall.vm | 63 ---- .../NestedCall/NestedCall.vm_tst | 70 ---- .../NestedCall/NestedCallStack.html | 306 ------------------ .../SimpleFunction/SimpleFunction.cmp | 2 - .../SimpleFunction/SimpleFunction.hdl_tst | 29 -- .../SimpleFunction/SimpleFunction.vm | 16 - .../SimpleFunction/SimpleFunction.vm_tst | 29 -- .../FunctionCalls/StaticsTest/Class1.vm | 20 -- .../FunctionCalls/StaticsTest/Class2.vm | 20 -- .../FunctionCalls/StaticsTest/StaticsTest.cmp | 2 - .../StaticsTest/StaticsTest.hdl_tst | 17 - .../FunctionCalls/StaticsTest/StaticsTest.vm | 60 ---- .../StaticsTest/StaticsTest.vm_tst | 17 - .../FunctionCalls/StaticsTest/Sys.vm | 20 -- .../ProgramFlow/BasicLoop/BasicLoop.cmp | 2 - .../ProgramFlow/BasicLoop/BasicLoop.hdl_tst | 20 -- .../ProgramFlow/BasicLoop/BasicLoop.vm | 22 -- .../ProgramFlow/BasicLoop/BasicLoop.vm_tst | 20 -- .../FibonacciSeries/FibonacciSeries.cmp | 2 - .../FibonacciSeries/FibonacciSeries.hdl_tst | 22 -- .../FibonacciSeries/FibonacciSeries.vm | 49 --- .../FibonacciSeries/FibonacciSeries.vm_tst | 22 -- 51 files changed, 1558 deletions(-) delete mode 100644 projects/src/project_07/MemoryAccess/BasicTest/BasicTest.cmp delete mode 100644 projects/src/project_07/MemoryAccess/BasicTest/BasicTest.hdl_tst delete mode 100644 projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm delete mode 100644 projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm_tst delete mode 100644 projects/src/project_07/MemoryAccess/PointerTest/PointerTest.cmp delete mode 100644 projects/src/project_07/MemoryAccess/PointerTest/PointerTest.hdl_tst delete mode 100644 projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm delete mode 100644 projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm_tst delete mode 100644 projects/src/project_07/MemoryAccess/StaticTest/StaticTest.cmp delete mode 100644 projects/src/project_07/MemoryAccess/StaticTest/StaticTest.hdl_tst delete mode 100644 projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm delete mode 100644 projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm_tst delete mode 100644 projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.cmp delete mode 100644 projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.hdl_tst delete mode 100644 projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm delete mode 100644 projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm_tst delete mode 100644 projects/src/project_07/StackArithmetic/StackTest/StackTest.cmp delete mode 100644 projects/src/project_07/StackArithmetic/StackTest/StackTest.hdl_tst delete mode 100644 projects/src/project_07/StackArithmetic/StackTest/StackTest.vm delete mode 100644 projects/src/project_07/StackArithmetic/StackTest/StackTest.vm_tst delete mode 100644 projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.cmp delete mode 100644 projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.hdl_tst delete mode 100644 projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm delete mode 100644 projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm_tst delete mode 100644 projects/src/project_08/FunctionCalls/FibonacciElement/Main.vm delete mode 100644 projects/src/project_08/FunctionCalls/FibonacciElement/Sys.vm delete mode 100644 projects/src/project_08/FunctionCalls/NestedCall/NestedCall.cmp delete mode 100644 projects/src/project_08/FunctionCalls/NestedCall/NestedCall.hdl_tst delete mode 100644 projects/src/project_08/FunctionCalls/NestedCall/NestedCall.html delete mode 100644 projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm delete mode 100644 projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm_tst delete mode 100644 projects/src/project_08/FunctionCalls/NestedCall/NestedCallStack.html delete mode 100644 projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.cmp delete mode 100644 projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.hdl_tst delete mode 100644 projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm delete mode 100644 projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm_tst delete mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/Class1.vm delete mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/Class2.vm delete mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.cmp delete mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.hdl_tst delete mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm delete mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm_tst delete mode 100644 projects/src/project_08/FunctionCalls/StaticsTest/Sys.vm delete mode 100644 projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.cmp delete mode 100644 projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.hdl_tst delete mode 100644 projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm delete mode 100644 projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm_tst delete mode 100644 projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.cmp delete mode 100644 projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.hdl_tst delete mode 100644 projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm delete mode 100644 projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm_tst diff --git a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.cmp b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.cmp deleted file mode 100644 index 85c19a7c7..000000000 --- a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.cmp +++ /dev/null @@ -1,2 +0,0 @@ -|RAM[256]|RAM[300]|RAM[401]|RAM[402]|RAM[3006|RAM[3012|RAM[3015|RAM[11] | -| 472 | 10 | 21 | 22 | 36 | 42 | 45 | 510 | diff --git a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.hdl_tst b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.hdl_tst deleted file mode 100644 index 9fb626ed1..000000000 --- a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.hdl_tst +++ /dev/null @@ -1,25 +0,0 @@ -// 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/07/MemoryAccess/BasicTest/BasicTest.tst - -load BasicTest.asm, -output-file BasicTest.out, -compare-to BasicTest.cmp, -output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 - RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 - RAM[3015]%D1.6.1 RAM[11]%D1.6.1; - -set RAM[0] 256, // stack pointer -set RAM[1] 300, // base address of the local segment -set RAM[2] 400, // base address of the argument segment -set RAM[3] 3000, // base address of the this segment -set RAM[4] 3010; // base address of the that segment - -repeat 600 { // enough cycles to complete the execution - ticktock; -} - -// Outputs the stack base and some values -// from the tested memory segments -output; diff --git a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm deleted file mode 100644 index 6fd45231f..000000000 --- a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm +++ /dev/null @@ -1,31 +0,0 @@ -// 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/07/MemoryAccess/BasicTest/BasicTest.vm - -// Executes pop and push commands using the virtual memory segments. -push constant 10 -pop local 0 -push constant 21 -push constant 22 -pop argument 2 -pop argument 1 -push constant 36 -pop this 6 -push constant 42 -push constant 45 -pop that 5 -pop that 2 -push constant 510 -pop temp 6 -push local 0 -push that 5 -add -push argument 1 -sub -push this 6 -push this 6 -add -sub -push temp 6 -add diff --git a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm_tst b/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm_tst deleted file mode 100644 index 784403077..000000000 --- a/projects/src/project_07/MemoryAccess/BasicTest/BasicTest.vm_tst +++ /dev/null @@ -1,25 +0,0 @@ -// 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/07/MemoryAccess/BasicTest/BasicTestVME.tst - -load BasicTest.vm, -output-file BasicTest.out, -compare-to BasicTest.cmp, -output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 RAM[401]%D1.6.1 - RAM[402]%D1.6.1 RAM[3006]%D1.6.1 RAM[3012]%D1.6.1 - RAM[3015]%D1.6.1 RAM[11]%D1.6.1; - -set sp 256, // stack pointer -set local 300, // base address of the local segment -set argument 400, // base address of the argument segment -set this 3000, // base address of the this segment -set that 3010; // base address of the that segment - -repeat 25 { // BasicTest.vm has 25 instructions - vmstep; -} - -// Outputs the stack base and some values -// from the tested memory segments -output; diff --git a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.cmp b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.cmp deleted file mode 100644 index 5d62de88b..000000000 --- a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.cmp +++ /dev/null @@ -1,2 +0,0 @@ -|RAM[256]| RAM[3] | RAM[4] |RAM[3032|RAM[3046| -| 6084 | 3030 | 3040 | 32 | 46 | diff --git a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.hdl_tst b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.hdl_tst deleted file mode 100644 index 177993270..000000000 --- a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.hdl_tst +++ /dev/null @@ -1,20 +0,0 @@ -// 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/07/MemoryAccess/PointerTest/PointerTest.tst - -load PointerTest.asm, -output-file PointerTest.out, -compare-to PointerTest.cmp, -output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 - RAM[4]%D1.6.1 RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; - -set RAM[0] 256; // initializes the stack pointer - -repeat 450 { // enough cycles to complete the execution - ticktock; -} - -// outputs the stack base, this, that, and -// some values from the the this and that segments -output; diff --git a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm deleted file mode 100644 index a6086d90a..000000000 --- a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm +++ /dev/null @@ -1,22 +0,0 @@ -// 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/07/MemoryAccess/PointerTest/PointerTest.vm - -// Executes pop and push commands using the -// pointer, this, and that segments. -push constant 3030 -pop pointer 0 -push constant 3040 -pop pointer 1 -push constant 32 -pop this 2 -push constant 46 -pop that 6 -push pointer 0 -push pointer 1 -add -push this 2 -sub -push that 6 -add diff --git a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm_tst b/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm_tst deleted file mode 100644 index de288ae08..000000000 --- a/projects/src/project_07/MemoryAccess/PointerTest/PointerTest.vm_tst +++ /dev/null @@ -1,20 +0,0 @@ -// 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/07/MemoryAccess/PointerTest/PointerTestVME.tst - -load PointerTest.vm, -output-file PointerTest.out, -compare-to PointerTest.cmp, -output-list RAM[256]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 - RAM[3032]%D1.6.1 RAM[3046]%D1.6.1; - -set RAM[0] 256; // initializes the stack pointer - -repeat 15 { // PointerTest.vm has 15 instructions - vmstep; -} - -// outputs the stack base, this, that, and -// some values from the the this and that segments -output; diff --git a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.cmp b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.cmp deleted file mode 100644 index 2bc908bd9..000000000 --- a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.cmp +++ /dev/null @@ -1,2 +0,0 @@ -|RAM[256]| -| 1110 | diff --git a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.hdl_tst b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.hdl_tst deleted file mode 100644 index 7c9eb1d96..000000000 --- a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.hdl_tst +++ /dev/null @@ -1,17 +0,0 @@ -// 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/07/MemoryAccess/StaticTest/StaticTest.tst - -load StaticTest.asm, -output-file StaticTest.out, -compare-to StaticTest.cmp, -output-list RAM[256]%D1.6.1; - -set RAM[0] 256; // initializes the stack pointer - -repeat 200 { // enough cycles to complete the execution - ticktock; -} - -output; // the stack base diff --git a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm deleted file mode 100644 index e24584bf9..000000000 --- a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm +++ /dev/null @@ -1,17 +0,0 @@ -// 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/07/MemoryAccess/StaticTest/StaticTest.vm - -// Executes pop and push commands using the static segment. -push constant 111 -push constant 333 -push constant 888 -pop static 8 -pop static 3 -pop static 1 -push static 3 -push static 1 -sub -push static 8 -add diff --git a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm_tst b/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm_tst deleted file mode 100644 index 2d8c38b15..000000000 --- a/projects/src/project_07/MemoryAccess/StaticTest/StaticTest.vm_tst +++ /dev/null @@ -1,17 +0,0 @@ -// 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/07/MemoryAccess/StaticTest/StaticTestVME.tst - -load StaticTest.vm, -output-file StaticTest.out, -compare-to StaticTest.cmp, -output-list RAM[256]%D1.6.1; - -set sp 256; // initializes the stack pointer - -repeat 11 { // StaticTest.vm has 11 instructions - vmstep; -} - -output; // the stack base diff --git a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.cmp b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.cmp deleted file mode 100644 index 6b3b20e52..000000000 --- a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.cmp +++ /dev/null @@ -1,2 +0,0 @@ -| RAM[0] | RAM[256] | -| 257 | 15 | diff --git a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.hdl_tst b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.hdl_tst deleted file mode 100644 index 92b54b7d2..000000000 --- a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.hdl_tst +++ /dev/null @@ -1,17 +0,0 @@ -// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.tst - -load SimpleAdd.asm, -output-file SimpleAdd.out, -compare-to SimpleAdd.cmp, -output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; - -set RAM[0] 256; // initializes the stack pointer - -repeat 60 { // enough cycles to complete the execution - ticktock; -} - -output; // the stack pointer and the stack base diff --git a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm deleted file mode 100644 index d80d9fa76..000000000 --- a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm +++ /dev/null @@ -1,9 +0,0 @@ -// 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/07/StackArithmetic/SimpleAdd/SimpleAdd.vm - -// Pushes and adds two constants. -push constant 7 -push constant 8 -add diff --git a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm_tst b/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm_tst deleted file mode 100644 index 71464350e..000000000 --- a/projects/src/project_07/StackArithmetic/SimpleAdd/SimpleAdd.vm_tst +++ /dev/null @@ -1,17 +0,0 @@ -// 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/07/StackArithmetic/SimpleAdd/SimpleAddVME.tst - -load SimpleAdd.vm, -output-file SimpleAdd.out, -compare-to SimpleAdd.cmp, -output-list RAM[0]%D2.6.2 RAM[256]%D2.6.2; - -set RAM[0] 256; // initializes the stack pointer - -repeat 3 { // SimpleAdd.vm has 3 instructions - vmstep; -} - -output; // the stack pointer and the stack base diff --git a/projects/src/project_07/StackArithmetic/StackTest/StackTest.cmp b/projects/src/project_07/StackArithmetic/StackTest/StackTest.cmp deleted file mode 100644 index cb182ec10..000000000 --- a/projects/src/project_07/StackArithmetic/StackTest/StackTest.cmp +++ /dev/null @@ -1,4 +0,0 @@ -| RAM[0] | RAM[256] | RAM[257] | RAM[258] | RAM[259] | RAM[260] | -| 266 | -1 | 0 | 0 | 0 | -1 | -| RAM[261] | RAM[262] | RAM[263] | RAM[264] | RAM[265] | -| 0 | -1 | 0 | 0 | -91 | diff --git a/projects/src/project_07/StackArithmetic/StackTest/StackTest.hdl_tst b/projects/src/project_07/StackArithmetic/StackTest/StackTest.hdl_tst deleted file mode 100644 index d70adce72..000000000 --- a/projects/src/project_07/StackArithmetic/StackTest/StackTest.hdl_tst +++ /dev/null @@ -1,22 +0,0 @@ -// 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/07/StackArithmetic/StackTest/StackTest.tst - -load StackTest.asm, -output-file StackTest.out, -compare-to StackTest.cmp, -output-list RAM[0]%D2.6.2 - RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; - -set RAM[0] 256; // initializes the stack pointer - -repeat 1000 { // enough cycles to complete the execution - ticktock; -} - -// outputs the stack pointer (RAM[0]) and -// the stack contents: RAM[256]-RAM[265] -output; -output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; -output; diff --git a/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm b/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm deleted file mode 100644 index c4181789e..000000000 --- a/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm +++ /dev/null @@ -1,45 +0,0 @@ -// 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/07/StackArithmetic/StackTest/StackTest.vm - -// Executes a sequence of arithmetic and logical operations -// on the stack. -push constant 17 -push constant 17 -eq -push constant 17 -push constant 16 -eq -push constant 16 -push constant 17 -eq -push constant 892 -push constant 891 -lt -push constant 891 -push constant 892 -lt -push constant 891 -push constant 891 -lt -push constant 32767 -push constant 32766 -gt -push constant 32766 -push constant 32767 -gt -push constant 32766 -push constant 32766 -gt -push constant 57 -push constant 31 -push constant 53 -add -push constant 112 -sub -neg -and -push constant 82 -or -not diff --git a/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm_tst b/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm_tst deleted file mode 100644 index e25f32911..000000000 --- a/projects/src/project_07/StackArithmetic/StackTest/StackTest.vm_tst +++ /dev/null @@ -1,22 +0,0 @@ -// 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/07/StackArithmetic/StackTest/StackTestVME.tst - -load StackTest.vm, -output-file StackTest.out, -compare-to StackTest.cmp, -output-list RAM[0]%D2.6.2 - RAM[256]%D2.6.2 RAM[257]%D2.6.2 RAM[258]%D2.6.2 RAM[259]%D2.6.2 RAM[260]%D2.6.2; - -set RAM[0] 256; // initializes the stack pointer - -repeat 38 { // StackTest.vm consists of 38 instructions - vmstep; -} - -// outputs the stack pointer (RAM[0]) and -// the stack contents: RAM[256]-RAM[265] -output; -output-list RAM[261]%D2.6.2 RAM[262]%D2.6.2 RAM[263]%D2.6.2 RAM[264]%D2.6.2 RAM[265]%D2.6.2; -output; diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.cmp b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.cmp deleted file mode 100644 index fdf5e2df3..000000000 --- a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.cmp +++ /dev/null @@ -1,2 +0,0 @@ -| RAM[0] |RAM[261]| -| 262 | 3 | diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.hdl_tst b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.hdl_tst deleted file mode 100644 index 6478bdcdd..000000000 --- a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.hdl_tst +++ /dev/null @@ -1,18 +0,0 @@ -// 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/08/FunctionCalls/FibonacciElement/FibonacciElement.tst - -// FibonacciElement.asm results from translating both Main.vm and Sys.vm into -// a single assembly program, stored in the file FibonacciElement.asm. - -load FibonacciElement.asm, -output-file FibonacciElement.out, -compare-to FibonacciElement.cmp, -output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; - -repeat 6000 { - ticktock; -} - -output; diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm deleted file mode 100644 index b10ac3576..000000000 --- a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm +++ /dev/null @@ -1,45 +0,0 @@ -// 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/08/FunctionCalls/FibonacciElement/Main.vm - -// Computes the n'th element of the Fibonacci series, recursively. -// n is given in argument[0]. Called by the Sys.init function -// (part of the Sys.vm file), which also pushes the argument[0] -// parameter before this code starts running. - -function Main.fibonacci 0 -push argument 0 -push constant 2 -lt // checks if n<2 -if-goto IF_TRUE -goto IF_FALSE -label IF_TRUE // if n<2, return n -push argument 0 -return -label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) -push argument 0 -push constant 2 -sub -call Main.fibonacci 1 // computes fib(n-2) -push argument 0 -push constant 1 -sub -call Main.fibonacci 1 // computes fib(n-1) -add // returns fib(n-1) + fib(n-2) -return -// 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/08/FunctionCalls/FibonacciElement/Sys.vm - -// Pushes a constant, say n, onto the stack, and calls the Main.fibonacii -// function, which computes the n'th element of the Fibonacci series. -// Note that by convention, the Sys.init function is called "automatically" -// by the bootstrap code. - -function Sys.init 0 -push constant 4 -call Main.fibonacci 1 // computes the 4'th fibonacci element -label WHILE -goto WHILE // loops infinitely diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm_tst b/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm_tst deleted file mode 100644 index 39c1b0e5d..000000000 --- a/projects/src/project_08/FunctionCalls/FibonacciElement/FibonacciElement.vm_tst +++ /dev/null @@ -1,17 +0,0 @@ -// 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/08/FunctionCalls/FibonacciElement/FibonacciElementVME.tst - -load, // Load all the VM files from the current directory -output-file FibonacciElement.out, -compare-to FibonacciElement.cmp, -output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1; - -set sp 261; - -repeat 110 { - vmstep; -} - -output; diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/Main.vm b/projects/src/project_08/FunctionCalls/FibonacciElement/Main.vm deleted file mode 100644 index c84f5995f..000000000 --- a/projects/src/project_08/FunctionCalls/FibonacciElement/Main.vm +++ /dev/null @@ -1,30 +0,0 @@ -// 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/08/FunctionCalls/FibonacciElement/Main.vm - -// Computes the n'th element of the Fibonacci series, recursively. -// n is given in argument[0]. Called by the Sys.init function -// (part of the Sys.vm file), which also pushes the argument[0] -// parameter before this code starts running. - -function Main.fibonacci 0 -push argument 0 -push constant 2 -lt // checks if n<2 -if-goto IF_TRUE -goto IF_FALSE -label IF_TRUE // if n<2, return n -push argument 0 -return -label IF_FALSE // if n>=2, returns fib(n-2)+fib(n-1) -push argument 0 -push constant 2 -sub -call Main.fibonacci 1 // computes fib(n-2) -push argument 0 -push constant 1 -sub -call Main.fibonacci 1 // computes fib(n-1) -add // returns fib(n-1) + fib(n-2) -return diff --git a/projects/src/project_08/FunctionCalls/FibonacciElement/Sys.vm b/projects/src/project_08/FunctionCalls/FibonacciElement/Sys.vm deleted file mode 100644 index 4cd3dc4ba..000000000 --- a/projects/src/project_08/FunctionCalls/FibonacciElement/Sys.vm +++ /dev/null @@ -1,15 +0,0 @@ -// 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/08/FunctionCalls/FibonacciElement/Sys.vm - -// Pushes a constant, say n, onto the stack, and calls the Main.fibonacii -// function, which computes the n'th element of the Fibonacci series. -// Note that by convention, the Sys.init function is called "automatically" -// by the bootstrap code. - -function Sys.init 0 -push constant 4 -call Main.fibonacci 1 // computes the 4'th fibonacci element -label WHILE -goto WHILE // loops infinitely diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.cmp b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.cmp deleted file mode 100644 index 978405da4..000000000 --- a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.cmp +++ /dev/null @@ -1,2 +0,0 @@ -| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] | RAM[5] | RAM[6] | -| 261 | 261 | 256 | 4000 | 5000 | 135 | 246 | diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.hdl_tst b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.hdl_tst deleted file mode 100644 index 0b4c128d5..000000000 --- a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.hdl_tst +++ /dev/null @@ -1,65 +0,0 @@ -// Test file for NestedCall test. - -load NestedCall.asm, -output-file NestedCall.out, -compare-to NestedCall.cmp, -output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; - -set RAM[0] 261, -set RAM[1] 261, -set RAM[2] 256, -set RAM[3] -3, -set RAM[4] -4, -set RAM[5] -1, // test results -set RAM[6] -1, -set RAM[256] 1234, // fake stack frame from call Sys.init -set RAM[257] -1, -set RAM[258] -2, -set RAM[259] -3, -set RAM[260] -4, - -set RAM[261] -1, // Initialize stack to check for local segment -set RAM[262] -1, // being cleared to zero. -set RAM[263] -1, -set RAM[264] -1, -set RAM[265] -1, -set RAM[266] -1, -set RAM[267] -1, -set RAM[268] -1, -set RAM[269] -1, -set RAM[270] -1, -set RAM[271] -1, -set RAM[272] -1, -set RAM[273] -1, -set RAM[274] -1, -set RAM[275] -1, -set RAM[276] -1, -set RAM[277] -1, -set RAM[278] -1, -set RAM[279] -1, -set RAM[280] -1, -set RAM[281] -1, -set RAM[282] -1, -set RAM[283] -1, -set RAM[284] -1, -set RAM[285] -1, -set RAM[286] -1, -set RAM[287] -1, -set RAM[288] -1, -set RAM[289] -1, -set RAM[290] -1, -set RAM[291] -1, -set RAM[292] -1, -set RAM[293] -1, -set RAM[294] -1, -set RAM[295] -1, -set RAM[296] -1, -set RAM[297] -1, -set RAM[298] -1, -set RAM[299] -1; - -repeat 4000 { - ticktock; -} - -output; diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.html b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.html deleted file mode 100644 index 0d8534dbb..000000000 --- a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - - NestedCall.tst — Nand2Tetris Calling Convention Test - - - - -

Synopsis

-NestedCall.tst is an intermediate test (in terms of complexity) intended to be used between the SimpleFunction and -FibonacciElement tests. It may be useful when SimpleFunction passes but FibonacciElement fails or crashes. NestedCall also -tests several requirements of the Function Calling Protocol that are not verified by the other -supplied tests. NestedCall can be used with or without the VM bootstrap code. -

-NestedCallVME.tst runs the same test on the VM Emulator. -

-The NestedCall tests and supporting documentation were written by Mark Armbrust. - - -

Test Structure

-

Startup

-NestedCall is implemented entirely within the Sys.vm file. The first function in Sys.vm is -Sys.init(). This allows it to be used before the bootstrap code has been added to the VM Translator -since there will be no file processing order issues. -

-NestedCall loads NestedCall.asm, sets up the stack to simulate the bootstrap's call to Sys.init(), then -begins execution at the beginning of NestedCall.asm. If the bootstrap is not present, the program begins -running with Sys.init() since it is the first function in Sys.vm. -

-If NestedCall.asm includes the bootstrap, the bootstrap will (re)initialize the stack and call Sys.init(), -so the test should see the same environment either way it gets to Sys.init(). -

-The test setup also initializes the LCL, ARG, THIS and THAT pointers to -1, -2, -3 and -4. - -

Sys.init()

- -THIS and THAT are set to known values so that context save and restore can be tested. -

-Sys.init() calls Sys.main() and stores the return value in temp 1. This tests call to and -return from a function with no arguments. - -

Sys.main()

-Sys.main() allocates 5 local variables. It sets local 1, local 2 and -local 3. local 0 and local 4 are intentionally not set. -

-THIS and THAT are changed so that context save and restore can be tested. -

-Sys.main() calls Sys.add12(123) and stores the return value in temp 0. This tests call to and -return from a function with arguments. -

-After Sys.add12() returns, Sys.main() sums local 0 through local 4 and returns the -result. This tests that the local segment was properly allocated on the stack and that the local -variables were not overwritten by the call to Sys.main(). It also tests that local 0 and -local 4 were properly initialized to 0. - -

Sys.add12()

- -THIS and THAT are set to known values so that context save and restore can be tested. -

-Returns argument 0 plus 12. - - -

Test Coverage

- -

-Functions with no arguments return to correct RIP (Return Instruction Point) with correct return value on stack.
-This can fail if the RIP is not correctly pushed on the stack by the calling code, or if the returning -code does not store the RIP in a temporary register before overwriting it with the return value. - -

-Functions with arguments return to correct RIP with correct return value on stack.
-This can fail if it is assumed that ARG points to the RIP. - -

-Functions with local variables allocate space on the stack for the local variables.
-This can fail if the function prologue is not written or if the SP is not updated after zeroing -the local variables. - -

-All local variables are initialized to 0.
-Common errors are to forget this completely, or for the zeroing loop to be off by one. - -

-THIS and THAT are correctly retained across function calls. Looking ahead, in Project 9 you will be asked to write a simple computer game in the high-level Jack language. You can run your game (following compilation) on the supplied VM Emulator. But, if you choose to translate the VM code that the compiler generates using your VM Translator, then code like -"push THIS, push THAT ... pop THIS, pop THAT" can cause some interesting failures! - - -

Debugging

-These comments assume that your VM translator has passed the SimpleFunction test. -

-If RAM[0] is incorrect, you have a stack skew. More data was pushed onto the stack by -call than was popped by return, or vice versa. See debugging with -breakpoints later in this section. -

-If one or more of RAM[1] through RAM[4] is incorrect, the LCL, -ARG, THIS and THAT pointers are not being correctly saved or restored. -Most likely problem is when they are being saved; the SimpleFunction test verified that -return restored them correctly. -

-If RAM[5] is incorrect there may be a problem with setting up the ARG pointer. -

-If RAM[4] is incorrect and RAM[5] is correct, there may be a problem with -allocation or initialization of local variables. - -

Debugging with breakpoints

- -To find tough bugs you can use the "breakpoint" facility in the CPU Emulator (red flag button). -You can use breakpoints to have you program stop when it gets to a particular RAM address. For -example:
- • load the NestedCall.tst file,
- • set a PC breakpoint at the ROM address for (Sys.main),
- • hit the run button.
-When the CPU Emulator stops at the breakpoint you can inspect the RAM to check the stack and pointers values. -(If the breakpoint isn't hit, you will need to to single-step debug through -your calling code to see why it didn't get there.) -

-Other useful places to set breakpoints are the entry points to the other functions and at the -first and final instructions generated for return commands. -

-NestedCallStack.html shows the expected stack values at various points -during the test. - -

Finding ROM address in your ASM code

-It is not easy to find the ROM locations where you want to set breakpoints, because there is no -one-to-one correspondence between the ASM file line numbers and the ROM addresses. This is made even more -difficult because the supplied CPU Emulator does not display the (LABELS) in its ROM panel. -

-There are two things that you can do to make this easier. -

-

Modify your assembler to generate a listing file.
-A listing file shows all the ASM source lines, including comments, as well as the ROM addresses and -the values of the labels and the instructions. For example, here is a snippet of a listing file generated by an assembler written by Mark Armbrust: -
-   20    16      @i      // i -= 1
-   21  FC88      M=M-1
-             
-   22  FC10      D=M     // if i > 0
-   23     6      @LOOP
-   24  E301      D;JGT   //      goto LOOP
-             
-   25        (STOP)
-   25    25      @STOP
-   26  EA87      0;JMP
-
-Data Symbols
-
-   16 D  i
-
-Code Symbols
-
-    6 C  LOOP
-   17 C  SKIP
-   25 C  STOP
-
-For the Nand2Tetris environment, it is most useful to list the ROM addresses and A-instruction -values in decimal. In the above snippet, the C-instruction values are -listed in hexadecimal. -

-The list file is generated during pass 2 of the Assembler, parallel to generating the .hack file. To -make it easier to handle blank and comment only lines, Mark has Parser.commandType() return -NO_COMMAND for source lines with no command. Mark also added Parser.sourceLine() that returns the -unmodified source line. -

-

Have your VM Translator write the VM source lines as comments in the ASM output.
-For example: -
-    // label LOOP
-(Sys.init$LOOP)
-    // goto LOOP
-@Sys.init$LOOP
-0;JMP
-    //
-    // // Sys.main()
-    // 
-    // // Sets locals 1, 2 and 3, leaving locals 0 and 4 unchanged to test
-    // // default local initialization to 0.  (RAM set to -1 by test setup.)
-    // // Calls Sys.add12(123) and stores return value (135) in temp 0.
-    // // Returns local 0 + local 1 + local 2 + local 3 + local 4 (456) to confirm
-    // // that locals were not mangled by function call.
-    // 
-    // function Sys.main 5
-(Sys.main)
-@5
-D=-A
-($3)
-@SP
-
-Note that comments in the VM source become double comments. Looking ahead, in Project 11 you will be asked to write a compiler for the Jack language. If your compiler will write the Jack source lines as comments in the -generated VM files, this convention will be quite useful. - - - \ No newline at end of file diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm deleted file mode 100644 index 646b6d3c9..000000000 --- a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm +++ /dev/null @@ -1,63 +0,0 @@ -// Sys.vm for NestedCall test. - -// Sys.init() -// -// Calls Sys.main() and stores return value in temp 1. -// Does not return. (Enters infinite loop.) - -function Sys.init 0 -push constant 4000 // test THIS and THAT context save -pop pointer 0 -push constant 5000 -pop pointer 1 -call Sys.main 0 -pop temp 1 -label LOOP -goto LOOP - -// Sys.main() -// -// Sets locals 1, 2 and 3, leaving locals 0 and 4 unchanged to test -// default local initialization to 0. (RAM set to -1 by test setup.) -// Calls Sys.add12(123) and stores return value (135) in temp 0. -// Returns local 0 + local 1 + local 2 + local 3 + local 4 (456) to confirm -// that locals were not mangled by function call. - -function Sys.main 5 -push constant 4001 -pop pointer 0 -push constant 5001 -pop pointer 1 -push constant 200 -pop local 1 -push constant 40 -pop local 2 -push constant 6 -pop local 3 -push constant 123 -call Sys.add12 1 -pop temp 0 -push local 0 -push local 1 -push local 2 -push local 3 -push local 4 -add -add -add -add -return - -// Sys.add12(int n) -// -// Returns n+12. - -function Sys.add12 0 -push constant 4002 -pop pointer 0 -push constant 5002 -pop pointer 1 -push argument 0 -push constant 12 -add -return diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm_tst b/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm_tst deleted file mode 100644 index 4a46ffe60..000000000 --- a/projects/src/project_08/FunctionCalls/NestedCall/NestedCall.vm_tst +++ /dev/null @@ -1,70 +0,0 @@ -// Test file for NestedCall test. - -load Sys.vm, -output-file NestedCall.out, -compare-to NestedCall.cmp, -output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[5]%D1.6.1 RAM[6]%D1.6.1; - -set RAM[0] 261, -set RAM[1] 261, -set RAM[2] 256, -set RAM[3] -3, -set RAM[4] -4, -set RAM[5] -1, // test results -set RAM[6] -1, -set RAM[256] 1234, // fake stack frame from call Sys.init -set RAM[257] -1, -set RAM[258] -2, -set RAM[259] -3, -set RAM[260] -4, - -set RAM[261] -1, // Initialize stack to check for local segment -set RAM[262] -1, // being cleared to zero. -set RAM[263] -1, -set RAM[264] -1, -set RAM[265] -1, -set RAM[266] -1, -set RAM[267] -1, -set RAM[268] -1, -set RAM[269] -1, -set RAM[270] -1, -set RAM[271] -1, -set RAM[272] -1, -set RAM[273] -1, -set RAM[274] -1, -set RAM[275] -1, -set RAM[276] -1, -set RAM[277] -1, -set RAM[278] -1, -set RAM[279] -1, -set RAM[280] -1, -set RAM[281] -1, -set RAM[282] -1, -set RAM[283] -1, -set RAM[284] -1, -set RAM[285] -1, -set RAM[286] -1, -set RAM[287] -1, -set RAM[288] -1, -set RAM[289] -1, -set RAM[290] -1, -set RAM[291] -1, -set RAM[292] -1, -set RAM[293] -1, -set RAM[294] -1, -set RAM[295] -1, -set RAM[296] -1, -set RAM[297] -1, -set RAM[298] -1, -set RAM[299] -1, - -set sp 261, -set local 261, -set argument 256, -set this 3000, -set that 4000; - -repeat 50 { - vmstep; -} -output; diff --git a/projects/src/project_08/FunctionCalls/NestedCall/NestedCallStack.html b/projects/src/project_08/FunctionCalls/NestedCall/NestedCallStack.html deleted file mode 100644 index e75105487..000000000 --- a/projects/src/project_08/FunctionCalls/NestedCall/NestedCallStack.html +++ /dev/null @@ -1,306 +0,0 @@ - - - - - NestedCall.tst — Stack Frames - - - - - - - -
- - - - - - - - - - - -
Bootstrap init
Pointers
0256SP
1-1LCL
2-2ARG
3-3THIS
4-4THAT
Stack
256???←SP

- This is how my boot­strap code initial­izes the pointers before calling Sys.init(). -

- Setting the LCL, ARG, THIS and THAT point­ers to known illegal values helps identify - when a pointer is used before it is initial­ized. -

- (If you are running the NestedCall test with­out boot­strap code, you will not see this state.)

-
- - - - - - - - - - - - - - - - -
Entry to Sys.init()
Pointers
0261SP
1261LCL
2256ARG
3-3THIS
4-4THAT
Stack
256*Return IP←ARG
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261???←LCL, SP

- This is how NestedCall.tst initial­izes the pointers and stack. This is what RAM looks - like after my boot­strap calls Sys.init(). -

- (If your VM trans­lation includes the boot­strap, the -1 through -4 values may be - different if your boot­strap initial­izes them.)

-
- - - - - - - - - - - - - - - - - - - - -
Entry to Sys.main()
Pointers
0266SP
1266LCL
2261ARG
34000THIS
45000THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
266???←LCL, SP
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
After Sys.main() prologue
Pointers
0271SP
1266LCL
2261ARG
34000THIS
45000THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0←LCL
2670local 1
2680local 2
2690local 3
2700local 4
271???←SP

- The function prologue is the assembly language code generated for the - "function" VM command. -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Entry to Sys.add12(123)
Pointers
0277SP
1277LCL
2271ARG
34001THIS
45001THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0
267200local 1
26840local 2
2696local 3
2700local 4
271123argument 0←ARG
272*Return IP
273266Saved LCLSys.add12
274261Saved ARG frame
2754001Saved THIS
2765001Saved THAT
277???←LCL, SP
-
- -

- - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Before Sys.add12() return
Pointers
0278SP
1277LCL
2271ARG
34002THIS
45002THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0
267200local 1
26840local 2
2696local 3
2700local 4
271123argument 0←ARG
272*Return IP
273266Saved LCLSys.add12
274261Saved ARG frame
2754001Saved THIS
2765001Saved THAT
277135Return value←LCL
278???←SP
-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
After Sys.add12() return
Pointers
0272SP
1266LCL
2261ARG
34001THIS
45001THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0←LCL
267200local 1
26840local 2
2696local 3
2700local 4
271135Return value
272???←SP
-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Before Sys.main() return
Pointers
0272SP
1266LCL
2261ARG
34001THIS
45001THAT
Stack
256*Return IP
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261*Return IP←ARG
262261Saved LCL
263256Saved ARGSys.main
2644000Saved THIS frame
2655000Saved THAT
2660local 0←LCL
267200local 1
26840local 2
2696local 3
2700local 4
271246Return value
272???←SP
-
- - - - - - - - - - - - - - - - -
After Sys.main() return
Pointers
0262SP
1261LCL
2256ARG
34000THIS
45000THAT
Stack
256*Return IP←ARG
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261246Return value←LCL
262???←SP
-
- - - - - - - - - - - - - - - -
In Sys.init() halt loop
Pointers
0261SP
1261LCL
2256ARG
34000THIS
45000THAT
Stack
256*Return IP←ARG
257-1Saved LCL
258-2Saved ARGSys.init
259-3Saved THIS frame
260-4Saved THAT
261???←LCL, SP
-
- - - \ No newline at end of file diff --git a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.cmp b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.cmp deleted file mode 100644 index ef72b7a4c..000000000 --- a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.cmp +++ /dev/null @@ -1,2 +0,0 @@ -| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] |RAM[310]| -| 311 | 305 | 300 | 3010 | 4010 | 1196 | diff --git a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.hdl_tst b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.hdl_tst deleted file mode 100644 index 5feaccca3..000000000 --- a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.hdl_tst +++ /dev/null @@ -1,29 +0,0 @@ -// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.tst - -load SimpleFunction.asm, -output-file SimpleFunction.out, -compare-to SimpleFunction.cmp, -output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 - RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; - -set RAM[0] 317, -set RAM[1] 317, -set RAM[2] 310, -set RAM[3] 3000, -set RAM[4] 4000, -set RAM[310] 1234, -set RAM[311] 37, -set RAM[312] 1000, -set RAM[313] 305, -set RAM[314] 300, -set RAM[315] 3010, -set RAM[316] 4010; - -repeat 300 { - ticktock; -} - -output; diff --git a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm deleted file mode 100644 index 59a76df2e..000000000 --- a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm +++ /dev/null @@ -1,16 +0,0 @@ -// 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/08/FunctionCalls/SimpleFunction/SimpleFunction.vm - -// Performs a simple calculation and returns the result. -function SimpleFunction.test 2 -push local 0 -push local 1 -add -not -push argument 0 -add -push argument 1 -sub -return diff --git a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm_tst b/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm_tst deleted file mode 100644 index a0307ed79..000000000 --- a/projects/src/project_08/FunctionCalls/SimpleFunction/SimpleFunction.vm_tst +++ /dev/null @@ -1,29 +0,0 @@ -// 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/08/FunctionCalls/SimpleFunction/SimpleFunctionVME.tst - -load SimpleFunction.vm, -output-file SimpleFunction.out, -compare-to SimpleFunction.cmp, -output-list RAM[0]%D1.6.1 RAM[1]%D1.6.1 RAM[2]%D1.6.1 - RAM[3]%D1.6.1 RAM[4]%D1.6.1 RAM[310]%D1.6.1; - -set sp 317, -set local 317, -set argument 310, -set this 3000, -set that 4000, -set argument[0] 1234, -set argument[1] 37, -set argument[2] 9, -set argument[3] 305, -set argument[4] 300, -set argument[5] 3010, -set argument[6] 4010; - -repeat 10 { - vmstep; -} - -output; diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/Class1.vm b/projects/src/project_08/FunctionCalls/StaticsTest/Class1.vm deleted file mode 100644 index c1e87cfe3..000000000 --- a/projects/src/project_08/FunctionCalls/StaticsTest/Class1.vm +++ /dev/null @@ -1,20 +0,0 @@ -// 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/08/FunctionCalls/StaticsTest/Class1.vm - -// Stores two supplied arguments in static[0] and static[1]. -function Class1.set 0 -push argument 0 -pop static 0 -push argument 1 -pop static 1 -push constant 0 -return - -// Returns static[0] - static[1]. -function Class1.get 0 -push static 0 -push static 1 -sub -return diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/Class2.vm b/projects/src/project_08/FunctionCalls/StaticsTest/Class2.vm deleted file mode 100644 index 4eca310ab..000000000 --- a/projects/src/project_08/FunctionCalls/StaticsTest/Class2.vm +++ /dev/null @@ -1,20 +0,0 @@ -// 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/08/FunctionCalls/StaticsTest/Class2.vm - -// Stores two supplied arguments in static[0] and static[1]. -function Class2.set 0 -push argument 0 -pop static 0 -push argument 1 -pop static 1 -push constant 0 -return - -// Returns static[0] - static[1]. -function Class2.get 0 -push static 0 -push static 1 -sub -return diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.cmp b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.cmp deleted file mode 100644 index 309f058a5..000000000 --- a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.cmp +++ /dev/null @@ -1,2 +0,0 @@ -| RAM[0] |RAM[261]|RAM[262]| -| 263 | -2 | 8 | diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.hdl_tst b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.hdl_tst deleted file mode 100644 index a1eb87abb..000000000 --- a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.hdl_tst +++ /dev/null @@ -1,17 +0,0 @@ -// 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/08/FunctionCalls/StaticsTest/StaticsTest.tst - -load StaticsTest.asm, -output-file StaticsTest.out, -compare-to StaticsTest.cmp, -output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; - -set RAM[0] 256; - -repeat 2500 { - ticktock; -} - -output; diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm deleted file mode 100644 index 20555853c..000000000 --- a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm +++ /dev/null @@ -1,60 +0,0 @@ -// 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/08/FunctionCalls/StaticsTest/Class1.vm - -// Stores two supplied arguments in static[0] and static[1]. -function Class1.set 0 -push argument 0 -pop static 0 -push argument 1 -pop static 1 -push constant 0 -return - -// Returns static[0] - static[1]. -function Class1.get 0 -push static 0 -push static 1 -sub -return -// 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/08/FunctionCalls/StaticsTest/Class2.vm - -// Stores two supplied arguments in static[0] and static[1]. -function Class2.set 0 -push argument 0 -pop static 0 -push argument 1 -pop static 1 -push constant 0 -return - -// Returns static[0] - static[1]. -function Class2.get 0 -push static 0 -push static 1 -sub -return -// 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/08/FunctionCalls/StaticsTest/Sys.vm - -// Tests that different functions, stored in two different -// class files, manipulate the static segment correctly. -function Sys.init 0 -push constant 6 -push constant 8 -call Class1.set 2 -pop temp 0 // Dumps the return value -push constant 23 -push constant 15 -call Class2.set 2 -pop temp 0 // Dumps the return value -call Class1.get 0 -call Class2.get 0 -label WHILE -goto WHILE diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm_tst b/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm_tst deleted file mode 100644 index 5f2fb187f..000000000 --- a/projects/src/project_08/FunctionCalls/StaticsTest/StaticsTest.vm_tst +++ /dev/null @@ -1,17 +0,0 @@ -// 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/08/FunctionCalls/StaticsTest/StaticsTestVME.tst - -load, // loads all the VM files from the current directory. -output-file StaticsTest.out, -compare-to StaticsTest.cmp, -output-list RAM[0]%D1.6.1 RAM[261]%D1.6.1 RAM[262]%D1.6.1; - -set sp 261; - -repeat 36 { - vmstep; -} - -output; diff --git a/projects/src/project_08/FunctionCalls/StaticsTest/Sys.vm b/projects/src/project_08/FunctionCalls/StaticsTest/Sys.vm deleted file mode 100644 index 361428294..000000000 --- a/projects/src/project_08/FunctionCalls/StaticsTest/Sys.vm +++ /dev/null @@ -1,20 +0,0 @@ -// 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/08/FunctionCalls/StaticsTest/Sys.vm - -// Tests that different functions, stored in two different -// class files, manipulate the static segment correctly. -function Sys.init 0 -push constant 6 -push constant 8 -call Class1.set 2 -pop temp 0 // Dumps the return value -push constant 23 -push constant 15 -call Class2.set 2 -pop temp 0 // Dumps the return value -call Class1.get 0 -call Class2.get 0 -label WHILE -goto WHILE diff --git a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.cmp b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.cmp deleted file mode 100644 index 1786c7cf8..000000000 --- a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.cmp +++ /dev/null @@ -1,2 +0,0 @@ -| RAM[0] |RAM[256]| -| 257 | 6 | diff --git a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.hdl_tst b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.hdl_tst deleted file mode 100644 index fb773ae4d..000000000 --- a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.hdl_tst +++ /dev/null @@ -1,20 +0,0 @@ -// 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/08/ProgramFlow/BasicLoop/BasicLoop.tst - -load BasicLoop.asm, -output-file BasicLoop.out, -compare-to BasicLoop.cmp, -output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; - -set RAM[0] 256, -set RAM[1] 300, -set RAM[2] 400, -set RAM[400] 3; - -repeat 600 { - ticktock; -} - -output; diff --git a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm deleted file mode 100644 index d46d10219..000000000 --- a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm +++ /dev/null @@ -1,22 +0,0 @@ -// 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/08/ProgramFlow/BasicLoop/BasicLoop.vm - -// Computes the sum 1 + 2 + ... + argument[0] and pushes the -// result onto the stack. Argument[0] is initialized by the test -// script before this code starts running. -push constant 0 -pop local 0 // initializes sum = 0 -label LOOP_START -push argument 0 -push local 0 -add -pop local 0 // sum = sum + counter -push argument 0 -push constant 1 -sub -pop argument 0 // counter-- -push argument 0 -if-goto LOOP_START // If counter != 0, goto LOOP_START -push local 0 diff --git a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm_tst b/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm_tst deleted file mode 100644 index 95978f87e..000000000 --- a/projects/src/project_08/ProgramFlow/BasicLoop/BasicLoop.vm_tst +++ /dev/null @@ -1,20 +0,0 @@ -// 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/08/ProgramFlow/BasicLoop/BasicLoopVME.tst - -load BasicLoop.vm, -output-file BasicLoop.out, -compare-to BasicLoop.cmp, -output-list RAM[0]%D1.6.1 RAM[256]%D1.6.1; - -set sp 256, -set local 300, -set argument 400, -set argument[0] 3; - -repeat 33 { - vmstep; -} - -output; diff --git a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.cmp b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.cmp deleted file mode 100644 index 304e7c1c0..000000000 --- a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.cmp +++ /dev/null @@ -1,2 +0,0 @@ -|RAM[3000]|RAM[3001]|RAM[3002]|RAM[3003]|RAM[3004]|RAM[3005]| -| 0 | 1 | 1 | 2 | 3 | 5 | diff --git a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.hdl_tst b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.hdl_tst deleted file mode 100644 index 6b4159c56..000000000 --- a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.hdl_tst +++ /dev/null @@ -1,22 +0,0 @@ -// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.tst - -load FibonacciSeries.asm, -output-file FibonacciSeries.out, -compare-to FibonacciSeries.cmp, -output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 - RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; - -set RAM[0] 256, -set RAM[1] 300, -set RAM[2] 400, -set RAM[400] 6, -set RAM[401] 3000; - -repeat 1100 { - ticktock; -} - -output; diff --git a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm deleted file mode 100644 index 41b5773d4..000000000 --- a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm +++ /dev/null @@ -1,49 +0,0 @@ -// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm - -// Puts the first argument[0] elements of the Fibonacci series -// in the memory, starting in the address given in argument[1]. -// Argument[0] and argument[1] are initialized by the test script -// before this code starts running. - -push argument 1 -pop pointer 1 // that = argument[1] - -push constant 0 -pop that 0 // first element in the series = 0 -push constant 1 -pop that 1 // second element in the series = 1 - -push argument 0 -push constant 2 -sub -pop argument 0 // num_of_elements -= 2 (first 2 elements are set) - -label MAIN_LOOP_START - -push argument 0 -if-goto COMPUTE_ELEMENT // if num_of_elements > 0, goto COMPUTE_ELEMENT -goto END_PROGRAM // otherwise, goto END_PROGRAM - -label COMPUTE_ELEMENT - -push that 0 -push that 1 -add -pop that 2 // that[2] = that[0] + that[1] - -push pointer 1 -push constant 1 -add -pop pointer 1 // that += 1 - -push argument 0 -push constant 1 -sub -pop argument 0 // num_of_elements-- - -goto MAIN_LOOP_START - -label END_PROGRAM diff --git a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm_tst b/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm_tst deleted file mode 100644 index 19f1b9d1a..000000000 --- a/projects/src/project_08/ProgramFlow/FibonacciSeries/FibonacciSeries.vm_tst +++ /dev/null @@ -1,22 +0,0 @@ -// 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/08/ProgramFlow/FibonacciSeries/FibonacciSeriesVME.tst - -load FibonacciSeries.vm, -output-file FibonacciSeries.out, -compare-to FibonacciSeries.cmp, -output-list RAM[3000]%D1.6.2 RAM[3001]%D1.6.2 RAM[3002]%D1.6.2 - RAM[3003]%D1.6.2 RAM[3004]%D1.6.2 RAM[3005]%D1.6.2; - -set sp 256, -set local 300, -set argument 400, -set argument[0] 6, -set argument[1] 3000; - -repeat 73 { - vmstep; -} - -output; From cacd3c042460ab89b0ce9dfd030bfd688b413fa4 Mon Sep 17 00:00:00 2001 From: David Souther Date: Sun, 12 Nov 2023 15:34:11 -0500 Subject: [PATCH 12/14] Extension piece got missed --- extension/src/commands/hardware.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/src/commands/hardware.ts b/extension/src/commands/hardware.ts index 58c771780..ce5ce089b 100644 --- a/extension/src/commands/hardware.ts +++ b/extension/src/commands/hardware.ts @@ -1,6 +1,6 @@ export async function hardware(fileUri: string) { // The await eval() hack is for https://github.com/microsoft/TypeScript/issues/43329 - const tst = await import("@nand2tetris/simulator/tst.js"); + const tst = await import("@nand2tetris/simulator/test/chiptst.js"); console.log(`Hardware for ${fileUri}`); console.log(new tst.ChipTest()); } From 4c8bcdcfca9043299008c710011cb38b4dcf83a0 Mon Sep 17 00:00:00 2001 From: David Souther Date: Mon, 18 Dec 2023 08:57:08 -0500 Subject: [PATCH 13/14] Fix up merge differential --- components/src/stores/asm.store.ts | 19 +++++---- simulator/src/languages/asm.ts | 63 ++++++++++++++++++------------ simulator/src/languages/base.ts | 4 ++ web/src/pages/vm.tsx | 2 +- 4 files changed, 54 insertions(+), 34 deletions(-) diff --git a/components/src/stores/asm.store.ts b/components/src/stores/asm.store.ts index cc6c61a2f..259e93a43 100644 --- a/components/src/stores/asm.store.ts +++ b/components/src/stores/asm.store.ts @@ -78,8 +78,11 @@ class Translator { this.lineNumbers = Array(lineNum); let currentLine = 0; for (const instruction of this.asm.instructions) { - if (instruction.type === "A" || instruction.type === "C") { - this.lineNumbers[instruction.lineNum] = currentLine; + if ( + (instruction.type === "A" || instruction.type === "C") && + instruction.loc != undefined + ) { + this.lineNumbers[instruction.loc.line] = currentLine; currentLine += 1; } } @@ -92,7 +95,7 @@ class Translator { this.current += 1; const instruction = this.asm.instructions[this.current]; if (instruction.type === "A" || instruction.type === "C") { - highlightInfo.sourceHighlight = instruction.span; + highlightInfo.sourceHighlight = instruction.loc; const result = translateInstruction(this.asm.instructions[this.current]); if (result === undefined) { return; @@ -103,10 +106,12 @@ class Translator { end: (this.current + 1) * 17, }; - highlightInfo.highlightMap.set( - instruction.span, - highlightInfo.resultHighlight - ); + if (highlightInfo.sourceHighlight) { + highlightInfo.highlightMap.set( + highlightInfo.sourceHighlight, + highlightInfo.resultHighlight + ); + } if (isAValueInstruction(instruction)) { const variable = this.variables.get(instruction.value); diff --git a/simulator/src/languages/asm.ts b/simulator/src/languages/asm.ts index 427ae7de0..ed36dc115 100644 --- a/simulator/src/languages/asm.ts +++ b/simulator/src/languages/asm.ts @@ -5,6 +5,7 @@ import { ASSIGN_ASM, ASSIGN_OP, COMMANDS, + COMMANDS_ASM, COMMANDS_OP, JUMP, JUMP_ASM, @@ -12,7 +13,7 @@ import { } from "../cpu/alu.js"; import { KEYBOARD_OFFSET, SCREEN_OFFSET } from "../cpu/memory.js"; import { makeC } from "../util/asm.js"; -import { Span, baseSemantics, grammars, makeParser } from "./base.js"; +import { Location, baseSemantics, grammars, makeParser } from "./base.js"; import asmGrammar from "./grammars/asm.ohm.js"; @@ -32,15 +33,13 @@ export type AsmAInstruction = AsmALabelInstruction | AsmAValueInstruction; export interface AsmALabelInstruction { type: "A"; label: string; - span: Span; - lineNum: number; + loc?: Location; } export interface AsmAValueInstruction { type: "A"; value: number; - span: Span; - lineNum: number; + loc?: Location; } export function isAValueInstruction( @@ -61,14 +60,13 @@ export interface AsmCInstruction { isM: boolean; store?: ASSIGN_OP; jump?: JUMP_OP; - span: Span; - lineNum: number; + loc?: Location; } export interface AsmLabelInstruction { type: "L"; label: string; - lineNum: number; + loc?: Location; } asmSemantics.addAttribute("root", { @@ -88,16 +86,16 @@ asmSemantics.addAttribute("asm", { }); asmSemantics.addAttribute("instruction", { - AInstruction(_at, val): AsmAInstruction { + AInstruction({ source: start }, { name, source: end }): AsmAInstruction { try { return { type: "A", - label: val.name, - span: { - start: _at.source.startIdx, - end: val.source.endIdx, + label: name, + loc: { + start: start.startIdx, + end: end.endIdx, + line: start.getLineAndColumn().lineNum, }, - lineNum: _at.source.getLineAndColumn().lineNum, }; } catch (e) { // Pass @@ -106,12 +104,12 @@ asmSemantics.addAttribute("instruction", { try { return { type: "A", - value: val.value, - span: { - start: _at.source.startIdx, - end: val.source.endIdx, + value: name, + loc: { + start: start.startIdx, + end: end.endIdx, + line: start.getLineAndColumn().lineNum, }, - lineNum: _at.source.getLineAndColumn().lineNum, }; } catch (e) { // pass @@ -128,21 +126,25 @@ asmSemantics.addAttribute("instruction", { type: "C", op: COMMANDS.getOp(op), isM, - span: { + loc: { start: assignN.source.startIdx, end: jmpN.source.endIdx, + line: assignN.source.getLineAndColumn().lineNum, }, - lineNum: assignN.source.getLineAndColumn().lineNum, }; if (jmp) inst.jump = JUMP.asm[jmp]; if (assign) inst.store = ASSIGN.asm[assign]; return inst; }, - Label(_o, { name }, _c): AsmLabelInstruction { + Label({ source }, { name }, _c): AsmLabelInstruction { return { type: "L", label: name, - lineNum: _o.source.getLineAndColumn().lineNum, + loc: { + start: 0, + end: name.length, + line: source.getLineAndColumn().lineNum, + }, }; }, }); @@ -289,8 +291,14 @@ export function emit(asm: Asm): number[] { const A = (source: string | number): AsmAInstruction => typeof source === "string" - ? { type: "A", label: source } - : { type: "A", value: source }; + ? { + type: "A", + label: source, + } + : { + type: "A", + value: source, + }; const C = ( assign: ASSIGN_ASM, op: COMMANDS_ASM, @@ -312,7 +320,10 @@ const AC = ( op: COMMANDS_ASM, jmp?: JUMP_ASM ) => [A(source), C(assign, op, jmp)]; -const L = (label: string): AsmLabelInstruction => ({ type: "L", label }); +const L = (label: string): AsmLabelInstruction => ({ + type: "L", + label, +}); export const ASM = { grammar: asmGrammar, diff --git a/simulator/src/languages/base.ts b/simulator/src/languages/base.ts index 63ad9abc2..3491ed20b 100644 --- a/simulator/src/languages/base.ts +++ b/simulator/src/languages/base.ts @@ -2,6 +2,10 @@ import ohm from "ohm-js"; import { int10, int16, int2 } from "../util/twos.js"; import { Err, Ok, Result } from "@davidsouther/jiffies/lib/esm/result.js"; +export interface Location extends Span { + line: number; +} + export const UNKNOWN_PARSE_ERROR = `Unknown parse error`; import baseGrammar from "./grammars/base.ohm.js"; diff --git a/web/src/pages/vm.tsx b/web/src/pages/vm.tsx index fcd2508eb..c7f646e85 100644 --- a/web/src/pages/vm.tsx +++ b/web/src/pages/vm.tsx @@ -18,7 +18,7 @@ const VM = () => { const runner = useRef(); useEffect(() => { runner.current = new (class ChipTimer extends Timer { - override tick() { + override async tick() { actions.step(); return false; } From ca3f1f5b9dcf09fcbcd6e2546d620a1f4e942356 Mon Sep 17 00:00:00 2001 From: David Souther Date: Mon, 18 Dec 2023 10:24:46 -0500 Subject: [PATCH 14/14] Use expanded Span throughout --- components/src/stores/asm.store.ts | 8 +- components/src/stores/chip.store.test.ts | 12 +- components/src/stores/chip.store.ts | 1 + simulator/src/languages/asm.test.ts | 161 +++++++++-------------- simulator/src/languages/asm.ts | 95 ++++--------- simulator/src/languages/base.ts | 15 ++- simulator/src/languages/tst.test.ts | 26 +++- simulator/src/languages/tst.ts | 17 +-- simulator/src/test/chiptst.test.ts | 2 + web/src/pages/asm.tsx | 8 +- web/src/shell/editor.tsx | 2 +- 11 files changed, 148 insertions(+), 199 deletions(-) diff --git a/components/src/stores/asm.store.ts b/components/src/stores/asm.store.ts index 259e93a43..9dd9c5873 100644 --- a/components/src/stores/asm.store.ts +++ b/components/src/stores/asm.store.ts @@ -80,9 +80,9 @@ class Translator { for (const instruction of this.asm.instructions) { if ( (instruction.type === "A" || instruction.type === "C") && - instruction.loc != undefined + instruction.span != undefined ) { - this.lineNumbers[instruction.loc.line] = currentLine; + this.lineNumbers[instruction.span.line] = currentLine; currentLine += 1; } } @@ -95,7 +95,7 @@ class Translator { this.current += 1; const instruction = this.asm.instructions[this.current]; if (instruction.type === "A" || instruction.type === "C") { - highlightInfo.sourceHighlight = instruction.loc; + highlightInfo.sourceHighlight = instruction.span; const result = translateInstruction(this.asm.instructions[this.current]); if (result === undefined) { return; @@ -104,6 +104,7 @@ class Translator { highlightInfo.resultHighlight = { start: this.current * 17, end: (this.current + 1) * 17, + line: -1, }; if (highlightInfo.sourceHighlight) { @@ -228,6 +229,7 @@ export function makeAsmStore( state.resultHighlight = { start: i * 17, end: (i + 1) * 17, + line: -1, }; return; } diff --git a/components/src/stores/chip.store.test.ts b/components/src/stores/chip.store.test.ts index b1dff4977..1c282bb01 100644 --- a/components/src/stores/chip.store.test.ts +++ b/components/src/stores/chip.store.test.ts @@ -162,7 +162,11 @@ describe("ChipStore", () => { it("starts the cursor on the first instruction", () => { expect(state.store.state.files.tst).toBe(not.tst); - expect(state.store.state.controls.span).toEqual({ start: 0, end: 33 }); + expect(state.store.state.controls.span).toEqual({ + start: 0, + end: 33, + line: 1, + }); }); it("leaves the cursor on the final character", async () => { @@ -174,7 +178,11 @@ describe("ChipStore", () => { // Past the end of the test await state.store.actions.stepTest(); - expect(state.store.state.controls.span).toEqual({ start: 81, end: 82 }); + expect(state.store.state.controls.span).toEqual({ + start: 81, + end: 82, + line: 4, + }); }); }); }); diff --git a/components/src/stores/chip.store.ts b/components/src/stores/chip.store.ts index e2829f0c2..8638140b3 100644 --- a/components/src/stores/chip.store.ts +++ b/components/src/stores/chip.store.ts @@ -260,6 +260,7 @@ export function makeChipStore( state.controls.span = { start: end - 1, end, + line: state.files.tst.split("\n").length, }; } } diff --git a/simulator/src/languages/asm.test.ts b/simulator/src/languages/asm.test.ts index 5ce7e12d3..6748550c5 100644 --- a/simulator/src/languages/asm.test.ts +++ b/simulator/src/languages/asm.test.ts @@ -16,8 +16,7 @@ describe("asm language", () => { type: "A", label: "R0", value: undefined, - lineNum: 1, - span: { start: 0, end: 3 }, + span: { line: 1, start: 0, end: 3 }, }); }); @@ -28,8 +27,7 @@ describe("asm language", () => { type: "A", label: undefined, value: 5, - lineNum: 1, - span: { start: 0, end: 2 }, + span: { line: 1, start: 0, end: 2 }, }); }); @@ -40,8 +38,7 @@ describe("asm language", () => { type: "C", op: COMMANDS.getOp("-1"), isM: false, - lineNum: 1, - span: { start: 0, end: 2 }, + span: { line: 1, start: 0, end: 2 }, }); }); @@ -53,8 +50,7 @@ describe("asm language", () => { op: COMMANDS.getOp("M"), store: ASSIGN.asm["D"], isM: true, - lineNum: 1, - span: { start: 0, end: 3 }, + span: { line: 1, start: 0, end: 3 }, }); }); @@ -66,8 +62,7 @@ describe("asm language", () => { op: COMMANDS.getOp("A+1"), store: ASSIGN.asm["M"], isM: true, - lineNum: 1, - span: { start: 0, end: 5 }, + span: { line: 1, start: 0, end: 5 }, }); }); @@ -79,8 +74,7 @@ describe("asm language", () => { op: COMMANDS.getOp("D"), jump: JUMP.asm["JEQ"], isM: false, - lineNum: 1, - span: { start: 0, end: 5 }, + span: { line: 1, start: 0, end: 5 }, }); }); @@ -93,8 +87,7 @@ describe("asm language", () => { jump: JUMP.asm["JEQ"], store: ASSIGN.asm["A"], isM: false, - lineNum: 1, - span: { start: 0, end: 7 }, + span: { line: 1, start: 0, end: 7 }, }); }); @@ -107,129 +100,113 @@ describe("asm language", () => { { type: "A", label: "R0", - lineNum: 4, - span: { start: 34, end: 37 }, + span: { line: 4, start: 34, end: 37 }, }, { type: "C", op: COMMANDS.getOp("M"), store: ASSIGN.asm["D"], isM: true, - lineNum: 5, - span: { start: 41, end: 44 }, + span: { line: 5, start: 41, end: 44 }, }, { type: "A", label: "R1", - lineNum: 6, - span: { start: 81, end: 84 }, + span: { line: 6, start: 81, end: 84 }, }, { type: "C", op: COMMANDS.getOp("D-M"), store: ASSIGN.asm["D"], isM: true, - lineNum: 7, - span: { start: 88, end: 93 }, + span: { line: 7, start: 88, end: 93 }, }, { type: "A", label: "OUTPUT_FIRST", - lineNum: 8, - span: { start: 144, end: 157 }, + span: { line: 8, start: 144, end: 157 }, }, { type: "C", op: COMMANDS.getOp("D"), jump: JUMP.asm["JGT"], isM: false, - lineNum: 9, - span: { start: 161, end: 166 }, + span: { line: 9, start: 161, end: 166 }, }, { type: "A", label: "R1", - lineNum: 10, - span: { start: 228, end: 231 }, + span: { line: 10, start: 228, end: 231 }, }, { type: "C", op: COMMANDS.getOp("M"), store: ASSIGN.asm["D"], isM: true, - lineNum: 11, - span: { start: 235, end: 238 }, + span: { line: 11, start: 235, end: 238 }, }, { type: "A", label: "OUTPUT_D", - lineNum: 12, - span: { start: 276, end: 285 }, + span: { line: 12, start: 276, end: 285 }, }, { type: "C", op: COMMANDS.getOp("0"), jump: JUMP.asm["JMP"], isM: false, - lineNum: 13, - span: { start: 289, end: 294 }, + span: { line: 13, start: 289, end: 294 }, }, { type: "L", label: "OUTPUT_FIRST", - lineNum: 14, + span: { line: 14, start: 323, end: 337 }, }, { type: "A", label: "R0", - lineNum: 15, - span: { start: 341, end: 344 }, + span: { line: 15, start: 341, end: 344 }, }, { type: "C", op: COMMANDS.getOp("M"), store: ASSIGN.asm["D"], isM: true, - lineNum: 16, - span: { start: 361, end: 364 }, + span: { line: 16, start: 361, end: 364 }, }, { type: "L", label: "OUTPUT_D", - lineNum: 17, + span: { line: 17, start: 398, end: 408 }, }, { type: "A", label: "R2", - lineNum: 18, - span: { start: 412, end: 415 }, + span: { line: 18, start: 412, end: 415 }, }, { type: "C", op: COMMANDS.getOp("D"), store: ASSIGN.asm["M"], isM: false, - lineNum: 19, - span: { start: 419, end: 422 }, + span: { line: 19, start: 419, end: 422 }, }, { type: "L", label: "INFINITE_LOOP", - lineNum: 20, + span: { line: 20, start: 466, end: 481 }, }, { type: "A", label: "INFINITE_LOOP", - lineNum: 21, - span: { start: 485, end: 499 }, + span: { line: 21, start: 485, end: 499 }, }, { type: "C", op: COMMANDS.getOp("0"), jump: JUMP.asm["JMP"], isM: false, - lineNum: 22, - span: { start: 503, end: 508 }, + span: { line: 22, start: 503, end: 508 }, }, ]); }); @@ -246,129 +223,113 @@ describe("asm language", () => { { type: "A", value: 0, - lineNum: 4, - span: { start: 34, end: 37 }, + span: { line: 4, start: 34, end: 37 }, }, { type: "C", op: COMMANDS.getOp("M"), store: ASSIGN.asm["D"], isM: true, - lineNum: 5, - span: { start: 41, end: 44 }, + span: { line: 5, start: 41, end: 44 }, }, { type: "A", value: 1, - lineNum: 6, - span: { start: 81, end: 84 }, + span: { line: 6, start: 81, end: 84 }, }, { type: "C", op: COMMANDS.getOp("D-M"), store: ASSIGN.asm["D"], isM: true, - lineNum: 7, - span: { start: 88, end: 93 }, + span: { line: 7, start: 88, end: 93 }, }, { type: "A", value: 10, - lineNum: 8, - span: { start: 144, end: 157 }, + span: { line: 8, start: 144, end: 157 }, }, { type: "C", op: COMMANDS.getOp("D"), jump: JUMP.asm["JGT"], isM: false, - lineNum: 9, - span: { start: 161, end: 166 }, + span: { line: 9, start: 161, end: 166 }, }, { type: "A", value: 1, - lineNum: 10, - span: { start: 228, end: 231 }, + span: { line: 10, start: 228, end: 231 }, }, { type: "C", op: COMMANDS.getOp("M"), store: ASSIGN.asm["D"], isM: true, - lineNum: 11, - span: { start: 235, end: 238 }, + span: { line: 11, start: 235, end: 238 }, }, { type: "A", value: 12, - lineNum: 12, - span: { start: 276, end: 285 }, + span: { line: 12, start: 276, end: 285 }, }, { type: "C", op: COMMANDS.getOp("0"), jump: JUMP.asm["JMP"], isM: false, - lineNum: 13, - span: { start: 289, end: 294 }, + span: { line: 13, start: 289, end: 294 }, }, { type: "L", label: "OUTPUT_FIRST", - lineNum: 14, + span: { line: 14, start: 323, end: 337 }, }, { type: "A", value: 0, - lineNum: 15, - span: { start: 341, end: 344 }, + span: { line: 15, start: 341, end: 344 }, }, { type: "C", op: COMMANDS.getOp("M"), store: ASSIGN.asm["D"], isM: true, - lineNum: 16, - span: { start: 361, end: 364 }, + span: { line: 16, start: 361, end: 364 }, }, { type: "L", label: "OUTPUT_D", - lineNum: 17, + span: { line: 17, start: 398, end: 408 }, }, { type: "A", value: 2, - lineNum: 18, - span: { start: 412, end: 415 }, + span: { line: 18, start: 412, end: 415 }, }, { type: "C", op: COMMANDS.getOp("D"), store: ASSIGN.asm["M"], isM: false, - lineNum: 19, - span: { start: 419, end: 422 }, + span: { line: 19, start: 419, end: 422 }, }, { type: "L", label: "INFINITE_LOOP", - lineNum: 20, + span: { line: 20, start: 466, end: 481 }, }, { type: "A", value: 14, - lineNum: 21, - span: { start: 485, end: 499 }, + span: { line: 21, start: 485, end: 499 }, }, { type: "C", op: COMMANDS.getOp("0"), jump: JUMP.asm["JMP"], isM: false, - lineNum: 22, - span: { start: 503, end: 508 }, + span: { line: 22, start: 503, end: 508 }, }, ]); }); @@ -384,22 +345,22 @@ describe("asm language", () => { // prettier-ignore expect(bin).toEqual([ - 0b0_000000000000000, // @R0 - 0b111_1_110000_010_000, // D=M - 0b0_000000000000001, // @R1 - 0b111_1_010011_010_000, // D=D-M - 0b0_000000000001010, // @OUTPUT_FIRST#10 - 0b111_0_001100_000_001, // D;JGT - 0b0_000000000000001, // @R1 - 0b111_1_110000_010_000, // D=M - 0b0_000000000001100, // @OUTPUT_D#12 - 0b111_0_101010_000_111, // 0;JMP (OUTPUT_FIRST:10) - 0b0_000000000000000, // @R0 - 0b111_1_110000_010_000, // D=M (OUTPUT_D:12) - 0b0_000000000000010, // @R2 - 0b111_0_001100_001_000, // M=D (INFINITE LOOP:14) - 0b0_000000000001110, // @INFINITE_LOOP#14 - 0b111_0_101010_000_111, // 0;JMP + 0b0_000000000000000, // @R0 0x0000 0 + 0b111_1_110000_010_000, // D=M 0xFE10 + 0b0_000000000000001, // @R1 0x0001 + 0b111_1_010011_010_000, // D=D-M 0xF8D0 + 0b0_000000000001010, // @OUTPUT_FIRST#10 0x000A + 0b111_0_001100_000_001, // D;JGT 0xE301 + 0b0_000000000000001, // @R1 0x0001 + 0b111_1_110000_010_000, // D=M 0xFE10 + 0b0_000000000001100, // @OUTPUT_D#12 0x000C + 0b111_0_101010_000_111, // 0;JMP (OUTPUT_FIRST:10) 0xEA85 + 0b0_000000000000000, // @R0 0x0000 + 0b111_1_110000_010_000, // D=M (OUTPUT_D:12) 0x000C + 0b0_000000000000010, // @R2 0x0002 + 0b111_0_001100_001_000, // M=D (INFINITE LOOP:14) 0xE308 + 0b0_000000000001110, // @INFINITE_LOOP#14 0x0014 + 0b111_0_101010_000_111, // 0;JMP 0xEA83 ]); }); }); diff --git a/simulator/src/languages/asm.ts b/simulator/src/languages/asm.ts index ed36dc115..b1644c0ec 100644 --- a/simulator/src/languages/asm.ts +++ b/simulator/src/languages/asm.ts @@ -13,7 +13,7 @@ import { } from "../cpu/alu.js"; import { KEYBOARD_OFFSET, SCREEN_OFFSET } from "../cpu/memory.js"; import { makeC } from "../util/asm.js"; -import { Location, baseSemantics, grammars, makeParser } from "./base.js"; +import { Span, baseSemantics, grammars, makeParser, span } from "./base.js"; import asmGrammar from "./grammars/asm.ohm.js"; @@ -33,13 +33,13 @@ export type AsmAInstruction = AsmALabelInstruction | AsmAValueInstruction; export interface AsmALabelInstruction { type: "A"; label: string; - loc?: Location; + span?: Span; } export interface AsmAValueInstruction { type: "A"; value: number; - loc?: Location; + span?: Span; } export function isAValueInstruction( @@ -60,13 +60,13 @@ export interface AsmCInstruction { isM: boolean; store?: ASSIGN_OP; jump?: JUMP_OP; - loc?: Location; + span?: Span; } export interface AsmLabelInstruction { type: "L"; label: string; - loc?: Location; + span?: Span; } asmSemantics.addAttribute("root", { @@ -86,66 +86,18 @@ asmSemantics.addAttribute("asm", { }); asmSemantics.addAttribute("instruction", { - AInstruction({ source: start }, { name, source: end }): AsmAInstruction { - try { - return { - type: "A", - label: name, - loc: { - start: start.startIdx, - end: end.endIdx, - line: start.getLineAndColumn().lineNum, - }, - }; - } catch (e) { - // Pass - } - - try { - return { - type: "A", - value: name, - loc: { - start: start.startIdx, - end: end.endIdx, - line: start.getLineAndColumn().lineNum, - }, - }; - } catch (e) { - // pass - } - - throw new Error(`AsmAInstruction must have either a name or a value`); + AInstruction(_at, name): AsmAInstruction { + return A(name.value, span(this.source)); }, CInstruction(assignN, opN, jmpN): AsmCInstruction { - const assign = assignN.child(0)?.child(0)?.sourceString as ASSIGN_ASM; - const op = opN.sourceString; - const jmp = jmpN.child(0)?.child(1)?.sourceString as JUMP_ASM; - const isM = opN.sourceString.includes("M"); - const inst: AsmCInstruction = { - type: "C", - op: COMMANDS.getOp(op), - isM, - loc: { - start: assignN.source.startIdx, - end: jmpN.source.endIdx, - line: assignN.source.getLineAndColumn().lineNum, - }, - }; - if (jmp) inst.jump = JUMP.asm[jmp]; - if (assign) inst.store = ASSIGN.asm[assign]; - return inst; + const assign = (assignN.child(0)?.child(0)?.sourceString ?? + "") as ASSIGN_ASM; + const op = opN.sourceString as COMMANDS_ASM; + const jmp = (jmpN.child(0)?.child(1)?.sourceString ?? "") as JUMP_ASM; + return C(assign, op, jmp, span(this.source)); }, - Label({ source }, { name }, _c): AsmLabelInstruction { - return { - type: "L", - label: name, - loc: { - start: 0, - end: name.length, - line: source.getLineAndColumn().lineNum, - }, - }; + Label(_o, { name }, _c): AsmLabelInstruction { + return L(name, span(this.source)); }, }); @@ -289,40 +241,47 @@ export function emit(asm: Asm): number[] { .filter((op): op is number => op !== undefined); } -const A = (source: string | number): AsmAInstruction => +const A = (source: string | number, span?: Span): AsmAInstruction => typeof source === "string" ? { type: "A", label: source, + span, } : { type: "A", value: source, + span, }; + const C = ( assign: ASSIGN_ASM, op: COMMANDS_ASM, - jmp?: JUMP_ASM + jmp?: JUMP_ASM, + span?: Span ): AsmCInstruction => { - const isM = assign.includes("M") || op.includes("M"); const inst: AsmCInstruction = { type: "C", - op: COMMANDS.asm[op], - isM, + op: COMMANDS.getOp(op), + isM: op.includes("M"), + span, }; if (jmp) inst.jump = JUMP.asm[jmp]; if (assign) inst.store = ASSIGN.asm[assign]; return inst; }; + const AC = ( source: string | number, assign: ASSIGN_ASM, op: COMMANDS_ASM, jmp?: JUMP_ASM ) => [A(source), C(assign, op, jmp)]; -const L = (label: string): AsmLabelInstruction => ({ + +const L = (label: string, span?: Span): AsmLabelInstruction => ({ type: "L", label, + span, }); export const ASM = { diff --git a/simulator/src/languages/base.ts b/simulator/src/languages/base.ts index 3491ed20b..f00fec39d 100644 --- a/simulator/src/languages/base.ts +++ b/simulator/src/languages/base.ts @@ -1,11 +1,7 @@ -import ohm from "ohm-js"; +import ohm, { Interval } from "ohm-js"; import { int10, int16, int2 } from "../util/twos.js"; import { Err, Ok, Result } from "@davidsouther/jiffies/lib/esm/result.js"; -export interface Location extends Span { - line: number; -} - export const UNKNOWN_PARSE_ERROR = `Unknown parse error`; import baseGrammar from "./grammars/base.ohm.js"; @@ -89,4 +85,13 @@ export function makeParser( export interface Span { start: number; end: number; + line: number; +} + +export function span(span: Interval): Span { + return { + start: span.startIdx, + end: span.endIdx, + line: span.getLineAndColumn().lineNum, + }; } diff --git a/simulator/src/languages/tst.test.ts b/simulator/src/languages/tst.test.ts index 96a3d9274..7407eaa2c 100644 --- a/simulator/src/languages/tst.test.ts +++ b/simulator/src/languages/tst.test.ts @@ -168,8 +168,8 @@ describe("tst language", () => { expect(match).toHaveSucceeded(); expect(TST.semantics(match).tst).toEqual({ lines: [ - { ops: [{ op: "eval" }], span: { start: 0, end: 5 } }, - { ops: [{ op: "eval" }], span: { start: 7, end: 12 } }, + { ops: [{ op: "eval" }], span: { start: 0, end: 5, line: 1 } }, + { ops: [{ op: "eval" }], span: { start: 7, end: 12, line: 3 } }, ], }); }); @@ -183,6 +183,7 @@ describe("tst language", () => { span: { start: 1, end: 34, + line: 2, }, ops: [ { @@ -214,6 +215,7 @@ describe("tst language", () => { span: { end: 59, start: 36, + line: 4, }, ops: [ { op: "set", id: "in", value: 0 }, @@ -225,6 +227,7 @@ describe("tst language", () => { span: { start: 60, end: 83, + line: 5, }, ops: [ { op: "set", id: "in", value: 1 }, @@ -245,6 +248,7 @@ describe("tst language", () => { span: { start: 1, end: 58, + line: 2, }, ops: [ { @@ -294,6 +298,7 @@ describe("tst language", () => { span: { start: 59, end: 94, + line: 3, }, ops: [ { op: "set", id: "in", value: 0 }, @@ -306,6 +311,7 @@ describe("tst language", () => { span: { start: 95, end: 108, + line: 3, }, ops: [{ op: "tock" }, { op: "output" }], }, @@ -313,6 +319,7 @@ describe("tst language", () => { span: { start: 109, end: 144, + line: 4, }, ops: [ { op: "set", id: "in", value: 0 }, @@ -335,6 +342,7 @@ describe("tst language", () => { span: { start: 1, end: 35, + line: 2, }, ops: [ { @@ -367,6 +375,7 @@ describe("tst language", () => { span: { start: 36, end: 64, + line: 3, }, ops: [ { op: "set", id: "in", value: 33413 /* unsigned */ }, @@ -390,13 +399,15 @@ describe("tst language", () => { span: { start: 15, end: 28, + line: 3, }, ops: [{ op: "eval" }, { op: "output" }], }, ], span: { start: 1, - end: 10, + end: 30, + line: 2, }, }, ], @@ -412,13 +423,15 @@ describe("tst language", () => { count: -1, span: { start: 1, - end: 7, + end: 27, + line: 2, }, statements: [ { span: { start: 12, end: 25, + line: 3, }, ops: [{ op: "eval" }, { op: "output" }], }, @@ -436,7 +449,8 @@ describe("tst language", () => { { span: { start: 0, - end: 15, + end: 27, + line: 1, }, condition: { op: "<>", @@ -448,6 +462,7 @@ describe("tst language", () => { span: { start: 20, end: 25, + line: 2, }, ops: [{ op: "eval" }], }, @@ -467,6 +482,7 @@ describe("tst language", () => { span: { start: 0, end: 21, + line: 1, }, ops: [{ op: "loadRom", file: "Max.hack" }], }, diff --git a/simulator/src/languages/tst.ts b/simulator/src/languages/tst.ts index 2f19ce4b9..54941dea9 100644 --- a/simulator/src/languages/tst.ts +++ b/simulator/src/languages/tst.ts @@ -1,7 +1,7 @@ /** Reads tst files to apply and perform test runs. */ import ohm from "ohm-js"; -import { baseSemantics, grammars, makeParser, Span } from "./base.js"; +import { baseSemantics, grammars, makeParser, span, Span } from "./base.js"; export interface TstEchoOperation { op: "echo"; @@ -203,20 +203,14 @@ tstSemantics.addAttribute("statement", { return { statements: statements.children.map(({ statement }) => statement), condition: cond.condition, - span: { - start: op.source.startIdx, - end: cond.source.endIdx, - }, + span: span(this.source), }; }, TstRepeat(op, count, _o, statements, _c) { return { statements: statements.children.map(({ statement }) => statement), count: count.child(0)?.value ?? -1, - span: { - start: op.source.startIdx, - end: count.source.endIdx, - }, + span: span(this.source), }; }, TstStatement(list, end) { @@ -224,10 +218,7 @@ tstSemantics.addAttribute("statement", { ops: list .asIteration() .children.map((node) => node.operation as TstOperation), - span: { - start: this.source.startIdx, - end: this.source.endIdx, - }, + span: span(this.source), }; if (end.sourceString === "!") { stmt.break = true; diff --git a/simulator/src/test/chiptst.test.ts b/simulator/src/test/chiptst.test.ts index d06bfd8f3..1c3d4a5d0 100644 --- a/simulator/src/test/chiptst.test.ts +++ b/simulator/src/test/chiptst.test.ts @@ -147,12 +147,14 @@ describe("Chip Test", () => { { op: "output" }, ], span: { + line: 1, start: 0, end: 27, }, }, ], span: { + line: 1, start: 0, end: 27, }, diff --git a/web/src/pages/asm.tsx b/web/src/pages/asm.tsx index 636fc9535..42c11dac3 100644 --- a/web/src/pages/asm.tsx +++ b/web/src/pages/asm.tsx @@ -180,7 +180,9 @@ export const Asm = () => { grammar={ASM.parser} language={"asm"} highlight={ - state.translating ? state.sourceHighlight : { start: 0, end: 0 } + state.translating + ? state.sourceHighlight + : { start: 0, end: 0, line: 1 } } lineNumberTransform={(n) => { if (!state.translating) { @@ -300,7 +302,9 @@ export const Asm = () => {