-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathtest_08.py
executable file
·378 lines (298 loc) · 12 KB
/
test_08.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
#! /usr/bin/env pytest
import itertools
from nand import run
import project_05, project_06, test_07
import project_08
# TODO: add fine-grained tests for each opcode. These tests ported from nand2tetris provide good
# coverage, but they don't isolate problems well for debugging.
def test_basic_loop(chip=project_05.Computer, assemble=project_06.assemble, translator=project_08.Translator, simulator='codegen'):
translate = translator()
# 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.
translate.push_constant(0)
translate.pop_local(0) # initializes sum = 0
translate.label("LOOP_START")
translate.push_argument(0)
translate.push_local(0)
translate.add()
translate.pop_local(0) # sum = sum + counter
translate.push_argument(0)
translate.push_constant(1)
translate.sub()
translate.pop_argument(0) # counter--
translate.push_argument(0)
translate.if_goto("LOOP_START") # If counter > 0, goto LOOP_START
translate.push_local(0)
translate.finish()
computer = run(chip, simulator=simulator)
test_07.init_sp(computer)
computer.poke(1, 300)
computer.poke(2, 400)
computer.poke(400, 3)
translate.asm.run(assemble, computer, stop_cycles=600, debug=True)
assert computer.sp == 257
assert computer.peek(256) == 6
def test_fibonacci_series(chip=project_05.Computer, assemble=project_06.assemble, translator=project_08.Translator, simulator='codegen'):
translate = translator()
# 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.
translate.push_argument(1)
translate.pop_pointer(1) # that = argument[1]
translate.push_constant(0)
translate.pop_that(0) # first element in the series = 0
translate.push_constant(1)
translate.pop_that(1) # second element in the series = 1
translate.push_argument(0)
translate.push_constant(2)
translate.sub()
translate.pop_argument(0) # num_of_elements -= 2 (first 2 elements are set)
translate.label("MAIN_LOOP_START")
translate.push_argument(0)
translate.if_goto("COMPUTE_ELEMENT") # if num_of_elements > 0, goto COMPUTE_ELEMENT
translate.goto("END_PROGRAM") # otherwise, goto END_PROGRAM
translate.label("COMPUTE_ELEMENT")
translate.push_that(0)
translate.push_that(1)
translate.add()
translate.pop_that(2) # that[2] = that[0] + that[1]
translate.push_pointer(1)
translate.push_constant(1)
translate.add()
translate.pop_pointer(1) # that += 1
translate.push_argument(0)
translate.push_constant(1)
translate.sub()
translate.pop_argument(0) # num_of_elements--
translate.goto("MAIN_LOOP_START")
translate.label("END_PROGRAM")
translate.finish()
computer = run(chip, simulator=simulator)
test_07.init_sp(computer)
computer.poke(1, 300)
computer.poke(2, 400)
computer.poke(400, 6)
computer.poke(401, 3000)
translate.asm.run(assemble, computer, stop_cycles=1100, debug=True)
assert computer.peek(3000) == 0
assert computer.peek(3001) == 1
assert computer.peek(3002) == 1
assert computer.peek(3003) == 2
assert computer.peek(3004) == 3
assert computer.peek(3005) == 5
def test_simple_function(chip=project_05.Computer, assemble=project_06.assemble, translator=project_08.Translator, simulator='codegen'):
translate = translator()
# Performs a simple calculation and returns the result.
translate.function("SimpleFunction", "test", 2)
translate.push_local(0)
translate.push_local(1)
translate.add()
translate.not_op()
translate.push_argument(0)
translate.add()
translate.push_argument(1)
translate.sub()
translate.return_op()
translate.finish()
computer = run(chip, simulator=simulator)
test_07.init_sp(computer, 317)
computer.poke(1, 317)
computer.poke(2, 310)
computer.poke(3, 3000)
computer.poke(4, 4000)
computer.poke(310, 1234)
computer.poke(311, 37)
computer.poke(312, translate.asm.instruction_count) # return address: the infinite loop after the end of the program
computer.poke(313, 305)
computer.poke(314, 300)
computer.poke(315, 3010)
computer.poke(316, 4010)
translate.asm.run(assemble, computer, debug=True)
assert computer.sp == 311
assert computer.peek(1) == 305
assert computer.peek(2) == 300
assert computer.peek(3) == 3010
assert computer.peek(4) == 4010
assert computer.peek(310) == 1196
def test_nested_call(chip=project_05.Computer, assemble=project_06.assemble, translator=project_08.Translator, simulator='codegen'):
"""Multiple function calls, with and without arguments.
"""
translate = translator()
# Performs a simple calculation and returns the result.
# Sys.init()
#
# Calls Sys.main() and stores return value in temp 1.
# Does not return. (Enters infinite loop.)
translate.function("Sys", "init", 0)
translate.push_constant(4000) # test THIS and THAT context save
translate.pop_pointer(0)
translate.push_constant(5000)
translate.pop_pointer(1)
translate.call("Sys", "main", 0)
translate.pop_temp(1)
translate.label("LOOP")
translate.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.
translate.function("Sys", "main", 5)
translate.push_constant(4001)
translate.pop_pointer(0)
translate.push_constant(5001)
translate.pop_pointer(1)
translate.push_constant(200)
translate.pop_local(1)
translate.push_constant(40)
translate.pop_local(2)
translate.push_constant(6)
translate.pop_local(3)
translate.push_constant(123)
translate.call("Sys", "add12", 1)
translate.pop_temp(0)
translate.push_local(0)
translate.push_local(1)
translate.push_local(2)
translate.push_local(3)
translate.push_local(4)
translate.add()
translate.add()
translate.add()
translate.add()
translate.return_op()
# Sys.add12(int n)
#
# Returns n+12.
translate.function("Sys", "add12", 0)
translate.push_constant(4002)
translate.pop_pointer(0)
translate.push_constant(5002)
translate.pop_pointer(1)
translate.push_argument(0)
translate.push_constant(12)
translate.add()
translate.return_op()
translate.finish()
computer = run(chip, simulator=simulator)
test_07.init_sp(computer, 261)
computer.poke(1, 261)
computer.poke(2, 256)
computer.poke(3, -3)
computer.poke(4, -4)
computer.poke(5, -1) # test results
computer.poke(6, -1)
computer.poke(256, 1234) # fake stack frame from call Sys.init
computer.poke(257, -1)
computer.poke(258, -2)
computer.poke(259, -3)
computer.poke(260, -4)
# Initialize stack to check for local segment
# being cleared to zero.
for i in range(261, 300):
computer.poke(i, -1)
translate.asm.run(assemble, computer, stop_cycles=4000, debug=True)
assert computer.sp == 261
assert computer.peek(1) == 261
assert computer.peek(2) == 256
assert computer.peek(3) == 4000
assert computer.peek(4) == 5000
assert computer.peek(5) == 135
assert computer.peek(6) == 246
def test_fibonacci_element(chip=project_05.Computer, assemble=project_06.assemble, translator=project_08.Translator, simulator='codegen'):
"""Sys.init, declared out of sequence, requiring the translator to supply initialization and then
call Sys.init. This is finally a fully legitimate VM program, executed in the normal way.
"""
translate = translator()
# Note: seems like this should just happen, but the previous tests actually require it _not_ to.
translate.preamble()
# 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.
translate.function("Main", "fibonacci", 0)
translate.push_argument(0)
translate.push_constant(2)
translate.lt() # checks if n<2
translate.if_goto("IF_TRUE")
translate.goto("IF_FALSE")
translate.label("IF_TRUE") # if n<2, return n
translate.push_argument(0)
translate.return_op()
translate.label("IF_FALSE") # if n>=2, returns fib(n-2)+fib(n-1)
translate.push_argument(0)
translate.push_constant(2)
translate.sub()
translate.call("Main", "fibonacci", 1) # computes fib(n-2)
translate.push_argument(0)
translate.push_constant(1)
translate.sub()
translate.call("Main", "fibonacci", 1) # computes fib(n-1)
translate.add() # returns fib(n-1) + fib(n-2)
translate.return_op()
# Sys.vm:
# Pushes a constant, say n, onto the stack, and calls the Main.fibonacci
# 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.
translate.function("Sys", "init", 0)
translate.push_constant(4)
translate.call("Main", "fibonacci", 1) # computes the 4'th fibonacci element
translate.label("WHILE")
translate.goto("WHILE") # loops infinitely
translate.finish()
computer = run(chip, simulator=simulator)
# Note: no initialization this time
translate.asm.run(assemble, computer, stop_cycles=2000, debug=True)
assert computer.sp == 262
assert computer.peek(261) == 3
def test_statics_multiple_files(chip=project_05.Computer, assemble=project_06.assemble, translator=project_08.Translator, simulator='codegen'):
"""Tests that different functions, stored in two different classes, manipulate the static
segment correctly.
Note: the original materials actually refer to _files_ not _classes_, but I think in the context
of this language there's a one-to-one correspondence.
"""
translate = translator()
# Note: seems like this should just happen, but the previous tests actually require it _not_ to.
translate.preamble()
# Sys.vm:
translate.function("Sys", "init", 0)
translate.push_constant(6)
translate.push_constant(8)
translate.call("Class1", "set", 2)
translate.pop_temp(0) # Dumps the return value
translate.push_constant(23)
translate.push_constant(15)
translate.call("Class2", "set", 2)
translate.pop_temp(0) # Dumps the return value
translate.call("Class1", "get", 0)
translate.call("Class2", "get", 0)
translate.label("WHILE")
translate.goto("WHILE")
for class_name in ["Class1", "Class2"]:
# Stores two supplied arguments in static[0] and static[1].
translate.function(class_name, "set", 0)
translate.push_argument(0)
translate.pop_static(0)
translate.push_argument(1)
translate.pop_static(1)
translate.push_constant(0)
translate.return_op()
# Returns static[0] - static[1].
translate.function(class_name, "get", 0)
translate.push_static(0)
translate.push_static(1)
translate.sub()
translate.return_op()
translate.finish()
computer = run(chip, simulator=simulator)
# Note: no initialization this time
translate.asm.run(assemble, computer, stop_cycles=2500, debug=True)
assert computer.sp == 263
assert computer.peek(261) == -2
assert computer.peek(262) == 8