gruesome 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,1947 +10,1947 @@ require_relative '../../lib/gruesome/z/object_table'
10
10
  # already moves the PC to the next instruction
11
11
 
12
12
  describe Gruesome::Z::Processor do
13
- describe "#execute" do
14
- before(:each) do
15
- zork = File.open('test/zork1.z3', 'r')
16
- @zork_memory = Gruesome::Z::Memory.new(zork.read(zork.size))
17
- @processor = Gruesome::Z::Processor.new(@zork_memory)
18
- @zork_memory.program_counter = 12345
19
- end
20
-
21
- # Note: The decoder already gets the exact branch address
22
- # which is why we don't specify an offset here
23
- describe "Branch Instruction" do
24
- after(:each) do
25
- end
26
-
27
- # not necessarily a branch
28
- describe "call" do
29
- it "should branch to the routine with two local variables given as first operand and store result in destination variable" do
30
- # set up a routine at address $2000
31
- @zork_memory.force_writeb(0x2000, 2)
32
- @zork_memory.force_writew(0x2001, 0)
33
- @zork_memory.force_writew(0x2003, 0)
34
-
35
- # The packed address is 0x2000 / 2
36
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
37
- [Gruesome::Z::OperandType::LARGE],
38
- [0x1000], 128, nil, nil, 0)
39
- @processor.execute(i)
40
- @zork_memory.program_counter.should eql(0x2005)
41
- end
42
-
43
- it "should simply set the destination variable to false when routine address is 0" do
44
- @zork_memory.writev(128, 12345)
45
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
46
- [Gruesome::Z::OperandType::LARGE],
47
- [0], 128, nil, nil, 0)
48
- @processor.execute(i)
49
- @zork_memory.readv(128).should eql(0)
50
- @zork_memory.program_counter.should eql(12345)
51
- end
52
-
53
- it "should create a stack with only the return address when no arguments or local variables are used" do
54
- # set up a routine at address $2000 with no locals
55
- @zork_memory.force_writeb(0x2000, 0)
56
-
57
- # The packed address is 0x2000 / 2
58
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
59
- [Gruesome::Z::OperandType::LARGE],
60
- [0x1000], 128, nil, nil, 0)
61
- @processor.execute(i)
62
- @zork_memory.program_counter.should eql(0x2001)
63
- @zork_memory.readv(0).should eql(12345)
64
- end
65
-
66
- it "should create a stack with only the return address and all arguments copied to locals" do
67
- # set up a routine at address $2000 with two locals
68
- @zork_memory.force_writeb(0x2000, 2)
69
- @zork_memory.force_writew(0x2001, 345)
70
- @zork_memory.force_writew(0x2003, 456)
71
-
72
- # The packed address is 0x2000 / 2
73
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
74
- [Gruesome::Z::OperandType::LARGE],
75
- [0x1000], 128, nil, nil, 0)
76
-
77
- @processor.execute(i)
78
- @zork_memory.program_counter.should eql(0x2005)
79
- @zork_memory.readv(0).should eql(456)
80
- @zork_memory.readv(0).should eql(345)
81
- @zork_memory.readv(0).should eql(12345)
82
- end
83
- end
84
-
85
- # not necessarily a branch
86
- describe "call_1n" do
87
- it "should branch to the routine with two local variables given as first operand" do
88
- # set up a routine at address $2000
89
- @zork_memory.force_writeb(0x2000, 2)
90
- @zork_memory.force_writew(0x2001, 0)
91
- @zork_memory.force_writew(0x2003, 0)
92
-
93
- # The packed address is 0x2000 / 2
94
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL_1N,
95
- [Gruesome::Z::OperandType::LARGE],
96
- [0x1000], nil, nil, nil, 0)
97
- @processor.execute(i)
98
- @zork_memory.program_counter.should eql(0x2005)
99
- end
100
-
101
- it "should simply do nothing when routine address is 0" do
102
- @zork_memory.writev(128, 12345)
103
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL_1N,
104
- [Gruesome::Z::OperandType::LARGE],
105
- [0], nil, nil, nil, 0)
106
- @processor.execute(i)
107
- @zork_memory.program_counter.should eql(12345)
108
- end
109
-
110
- it "should create a stack with only the return address when no arguments or local variables are used" do
111
- # set up a routine at address $2000 with no locals
112
- @zork_memory.force_writeb(0x2000, 0)
113
-
114
- # The packed address is 0x2000 / 2
115
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL_1N,
116
- [Gruesome::Z::OperandType::LARGE],
117
- [0x1000], nil, nil, nil, 0)
118
- @processor.execute(i)
119
- @zork_memory.program_counter.should eql(0x2001)
120
- @zork_memory.readv(0).should eql(12345)
121
- end
122
- end
123
-
124
- describe "dec_chk" do
125
- it "should decrement the value in the variable given as the operand" do
126
- @zork_memory.writev(128, 12345)
127
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
128
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
129
- [128, 12345], nil, nil, nil, 0)
130
- @processor.execute(i)
131
- @zork_memory.readv(128).should eql(12344)
132
- end
133
-
134
- it "should consider the value signed and decrement 0 to -1" do
135
- @zork_memory.writev(128, 0)
136
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
137
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
138
- [128, 12345], nil, nil, nil, 0)
139
- @processor.execute(i)
140
- @zork_memory.readv(128).should eql(-1+65536)
141
- end
142
-
143
- it "should edit the value on the stack in place" do
144
- @zork_memory.writev(0, 11111)
145
- @zork_memory.writev(0, 12345)
146
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
147
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
148
- [0, 12345], nil, nil, nil, 0)
149
- @processor.execute(i)
150
- @zork_memory.readv(0).should eql(12344)
151
- @zork_memory.readv(0).should eql(11111)
152
- end
153
-
154
- it "should branch if the value after decrementing is less than the value given by the operand" do
155
- @zork_memory.writev(128, 12345)
156
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
157
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
158
- [128, 12345], nil, 2000, true, 0)
159
- @processor.execute(i)
160
- @zork_memory.program_counter = 2000
161
- end
162
-
163
- it "should not branch if the value after decrementing is not less than the value given by the operand" do
164
- @zork_memory.writev(128, 12345)
165
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
166
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
167
- [128, 12345], nil, 2000, true, 0)
168
- @processor.execute(i)
169
- @zork_memory.program_counter = 12345
170
- end
171
-
172
- it "should not branch if the value after decrementing is less than the value given by the operand and condition is negated" do
173
- @zork_memory.writev(128, 12345)
174
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
175
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
176
- [128, 12345], nil, 2000, false, 0)
177
- @processor.execute(i)
178
- @zork_memory.program_counter = 12345
179
- end
180
-
181
- it "should branch if the value after decrementing is not less than the value given by the operand and condition is negated" do
182
- @zork_memory.writev(128, 12347)
183
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
184
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
185
- [128, 12346], nil, 2000, false, 0)
186
- @processor.execute(i)
187
- @zork_memory.program_counter = 2000
188
- end
189
-
190
- end
191
-
192
- describe "inc_chk" do
193
- it "should increment the value in the variable given as the operand" do
194
- @zork_memory.writev(128, 12345)
195
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
196
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
197
- [128, 12345], nil, nil, nil, 0)
198
- @processor.execute(i)
199
- @zork_memory.readv(128).should eql(12346)
200
- end
201
-
202
- it "should consider the value signed and increment -1 to 0" do
203
- @zork_memory.writev(128, -1+65536)
204
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
205
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
206
- [128, 12345], nil, nil, nil, 0)
207
- @processor.execute(i)
208
- @zork_memory.readv(128).should eql(0)
209
- end
210
-
211
- it "should edit the value on the stack in place" do
212
- @zork_memory.writev(0, 11111)
213
- @zork_memory.writev(0, 12345)
214
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
215
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
216
- [0, 12345], nil, nil, nil, 0)
217
- @processor.execute(i)
218
- @zork_memory.readv(0).should eql(12346)
219
- @zork_memory.readv(0).should eql(11111)
220
- end
221
-
222
- it "should branch if the value after incrementing is greater than the value given by the operand" do
223
- @zork_memory.writev(128, 12345)
224
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
225
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
226
- [128, 12345], nil, 2000, true, 0)
227
- @processor.execute(i)
228
- @zork_memory.program_counter = 2000
229
- end
230
-
231
- it "should not branch if the value after incrementing is not greater than the value given by the operand" do
232
- @zork_memory.writev(128, 12345)
233
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
234
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
235
- [128, 12346], nil, 2000, true, 0)
236
- @processor.execute(i)
237
- @zork_memory.program_counter = 12345
238
- end
239
-
240
- it "should not branch if the value after incrementing is greater than the value given by the operand and condition is negated" do
241
- @zork_memory.writev(128, 12345)
242
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
243
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
244
- [128, 12345], nil, 2000, false, 0)
245
- @processor.execute(i)
246
- @zork_memory.program_counter = 12345
247
- end
248
-
249
- it "should branch if the value after incrementing is not greater than the value given by the operand and condition is negated" do
250
- @zork_memory.writev(128, 12345)
251
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
252
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
253
- [128, 12346], nil, 2000, false, 0)
254
- @processor.execute(i)
255
- @zork_memory.program_counter = 2000
256
- end
257
- end
258
-
259
- # not necessarily a branch
260
- describe "ret" do
261
- it "should return to the routine that called it" do
262
- # set up a routine at address $2000
263
- @zork_memory.force_writeb(0x2000, 2)
264
- @zork_memory.force_writew(0x2001, 0)
265
- @zork_memory.force_writew(0x2003, 0)
266
-
267
- # The packed address is 0x2000 / 2
268
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
269
- [Gruesome::Z::OperandType::LARGE],
270
- [0x1000], 128, nil, nil, 0)
271
-
272
- @processor.execute(i)
273
-
274
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RET,
275
- [Gruesome::Z::OperandType::LARGE],
276
- [123], nil, nil, nil, 0)
277
-
278
- @processor.execute(i)
279
-
280
- @zork_memory.program_counter.should eql(12345)
281
- end
282
-
283
- it "should set the variable indicated by the call with the return value as an immediate" do
284
- # set up a routine at address $2000
285
- @zork_memory.force_writeb(0x2000, 2)
286
- @zork_memory.force_writew(0x2001, 0)
287
- @zork_memory.force_writew(0x2003, 0)
288
-
289
- # The packed address is 0x2000 / 2
290
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
291
- [Gruesome::Z::OperandType::LARGE],
292
- [0x1000], 128, nil, nil, 0)
293
-
294
- @processor.execute(i)
295
-
296
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RET,
297
- [Gruesome::Z::OperandType::LARGE],
298
- [123], nil, nil, nil, 0)
299
-
300
- @processor.execute(i)
301
-
302
- @zork_memory.readv(128).should eql(123)
303
- end
304
-
305
- it "should be able to push the result (given as an immediate) to the stack if the call requests variable 0" do
306
- # set up a routine at address $2000
307
- @zork_memory.force_writeb(0x2000, 2)
308
- @zork_memory.force_writew(0x2001, 0)
309
- @zork_memory.force_writew(0x2003, 0)
310
-
311
- # The packed address is 0x2000 / 2
312
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
313
- [Gruesome::Z::OperandType::LARGE],
314
- [0x1000], 0, nil, nil, 0)
315
-
316
- @processor.execute(i)
317
-
318
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RET,
319
- [Gruesome::Z::OperandType::LARGE],
320
- [123], nil, nil, nil, 0)
321
-
322
- @processor.execute(i)
323
-
324
- @zork_memory.readv(0).should eql(123)
325
- end
326
- end
327
-
328
- # not necessarily a branch
329
- describe "ret_popped" do
330
- it "should return to the routine that called it" do
331
- # set up a routine at address $2000
332
- @zork_memory.force_writeb(0x2000, 2)
333
- @zork_memory.force_writew(0x2001, 0)
334
- @zork_memory.force_writew(0x2003, 0)
335
-
336
- # The packed address is 0x2000 / 2
337
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
338
- [Gruesome::Z::OperandType::LARGE],
339
- [0x1000], 128, nil, nil, 0)
340
-
341
- @processor.execute(i)
342
-
343
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RET_POPPED,
344
- [Gruesome::Z::OperandType::LARGE],
345
- [123], nil, nil, nil, 0)
346
-
347
- @processor.execute(i)
348
-
349
- @zork_memory.program_counter.should eql(12345)
350
- end
351
-
352
- it "should be able to push top of callee stack to the stack of the caller" do
353
- # set up a routine at address $2000
354
- @zork_memory.force_writeb(0x2000, 2)
355
- @zork_memory.force_writew(0x2001, 0)
356
- @zork_memory.force_writew(0x2003, 0)
357
- @zork_memory.writev(0, 11111)
13
+ describe "#execute" do
14
+ before(:each) do
15
+ zork = File.open('test/zork1.z3', 'r')
16
+ @zork_memory = Gruesome::Z::Memory.new(zork.read(zork.size))
17
+ @processor = Gruesome::Z::Processor.new(@zork_memory)
18
+ @zork_memory.program_counter = 12345
19
+ end
20
+
21
+ # Note: The decoder already gets the exact branch address
22
+ # which is why we don't specify an offset here
23
+ describe "Branch Instruction" do
24
+ after(:each) do
25
+ end
26
+
27
+ # not necessarily a branch
28
+ describe "call" do
29
+ it "should branch to the routine with two local variables given as first operand and store result in destination variable" do
30
+ # set up a routine at address $2000
31
+ @zork_memory.force_writeb(0x2000, 2)
32
+ @zork_memory.force_writew(0x2001, 0)
33
+ @zork_memory.force_writew(0x2003, 0)
34
+
35
+ # The packed address is 0x2000 / 2
36
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
37
+ [Gruesome::Z::OperandType::LARGE],
38
+ [0x1000], 128, nil, nil, 0)
39
+ @processor.execute(i)
40
+ @zork_memory.program_counter.should eql(0x2005)
41
+ end
42
+
43
+ it "should simply set the destination variable to false when routine address is 0" do
44
+ @zork_memory.writev(128, 12345)
45
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
46
+ [Gruesome::Z::OperandType::LARGE],
47
+ [0], 128, nil, nil, 0)
48
+ @processor.execute(i)
49
+ @zork_memory.readv(128).should eql(0)
50
+ @zork_memory.program_counter.should eql(12345)
51
+ end
52
+
53
+ it "should create a stack with only the return address when no arguments or local variables are used" do
54
+ # set up a routine at address $2000 with no locals
55
+ @zork_memory.force_writeb(0x2000, 0)
56
+
57
+ # The packed address is 0x2000 / 2
58
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
59
+ [Gruesome::Z::OperandType::LARGE],
60
+ [0x1000], 128, nil, nil, 0)
61
+ @processor.execute(i)
62
+ @zork_memory.program_counter.should eql(0x2001)
63
+ @zork_memory.readv(0).should eql(12345)
64
+ end
65
+
66
+ it "should create a stack with only the return address and all arguments copied to locals" do
67
+ # set up a routine at address $2000 with two locals
68
+ @zork_memory.force_writeb(0x2000, 2)
69
+ @zork_memory.force_writew(0x2001, 345)
70
+ @zork_memory.force_writew(0x2003, 456)
71
+
72
+ # The packed address is 0x2000 / 2
73
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
74
+ [Gruesome::Z::OperandType::LARGE],
75
+ [0x1000], 128, nil, nil, 0)
76
+
77
+ @processor.execute(i)
78
+ @zork_memory.program_counter.should eql(0x2005)
79
+ @zork_memory.readv(0).should eql(456)
80
+ @zork_memory.readv(0).should eql(345)
81
+ @zork_memory.readv(0).should eql(12345)
82
+ end
83
+ end
84
+
85
+ # not necessarily a branch
86
+ describe "call_1n" do
87
+ it "should branch to the routine with two local variables given as first operand" do
88
+ # set up a routine at address $2000
89
+ @zork_memory.force_writeb(0x2000, 2)
90
+ @zork_memory.force_writew(0x2001, 0)
91
+ @zork_memory.force_writew(0x2003, 0)
92
+
93
+ # The packed address is 0x2000 / 2
94
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL_1N,
95
+ [Gruesome::Z::OperandType::LARGE],
96
+ [0x1000], nil, nil, nil, 0)
97
+ @processor.execute(i)
98
+ @zork_memory.program_counter.should eql(0x2005)
99
+ end
100
+
101
+ it "should simply do nothing when routine address is 0" do
102
+ @zork_memory.writev(128, 12345)
103
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL_1N,
104
+ [Gruesome::Z::OperandType::LARGE],
105
+ [0], nil, nil, nil, 0)
106
+ @processor.execute(i)
107
+ @zork_memory.program_counter.should eql(12345)
108
+ end
109
+
110
+ it "should create a stack with only the return address when no arguments or local variables are used" do
111
+ # set up a routine at address $2000 with no locals
112
+ @zork_memory.force_writeb(0x2000, 0)
113
+
114
+ # The packed address is 0x2000 / 2
115
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL_1N,
116
+ [Gruesome::Z::OperandType::LARGE],
117
+ [0x1000], nil, nil, nil, 0)
118
+ @processor.execute(i)
119
+ @zork_memory.program_counter.should eql(0x2001)
120
+ @zork_memory.readv(0).should eql(12345)
121
+ end
122
+ end
123
+
124
+ describe "dec_chk" do
125
+ it "should decrement the value in the variable given as the operand" do
126
+ @zork_memory.writev(128, 12345)
127
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
128
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
129
+ [128, 12345], nil, nil, nil, 0)
130
+ @processor.execute(i)
131
+ @zork_memory.readv(128).should eql(12344)
132
+ end
133
+
134
+ it "should consider the value signed and decrement 0 to -1" do
135
+ @zork_memory.writev(128, 0)
136
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
137
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
138
+ [128, 12345], nil, nil, nil, 0)
139
+ @processor.execute(i)
140
+ @zork_memory.readv(128).should eql(-1+65536)
141
+ end
142
+
143
+ it "should edit the value on the stack in place" do
144
+ @zork_memory.writev(0, 11111)
145
+ @zork_memory.writev(0, 12345)
146
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
147
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
148
+ [0, 12345], nil, nil, nil, 0)
149
+ @processor.execute(i)
150
+ @zork_memory.readv(0).should eql(12344)
151
+ @zork_memory.readv(0).should eql(11111)
152
+ end
153
+
154
+ it "should branch if the value after decrementing is less than the value given by the operand" do
155
+ @zork_memory.writev(128, 12345)
156
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
157
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
158
+ [128, 12345], nil, 2000, true, 0)
159
+ @processor.execute(i)
160
+ @zork_memory.program_counter = 2000
161
+ end
162
+
163
+ it "should not branch if the value after decrementing is not less than the value given by the operand" do
164
+ @zork_memory.writev(128, 12345)
165
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
166
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
167
+ [128, 12345], nil, 2000, true, 0)
168
+ @processor.execute(i)
169
+ @zork_memory.program_counter = 12345
170
+ end
171
+
172
+ it "should not branch if the value after decrementing is less than the value given by the operand and condition is negated" do
173
+ @zork_memory.writev(128, 12345)
174
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
175
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
176
+ [128, 12345], nil, 2000, false, 0)
177
+ @processor.execute(i)
178
+ @zork_memory.program_counter = 12345
179
+ end
180
+
181
+ it "should branch if the value after decrementing is not less than the value given by the operand and condition is negated" do
182
+ @zork_memory.writev(128, 12347)
183
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC_CHK,
184
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
185
+ [128, 12346], nil, 2000, false, 0)
186
+ @processor.execute(i)
187
+ @zork_memory.program_counter = 2000
188
+ end
189
+
190
+ end
191
+
192
+ describe "inc_chk" do
193
+ it "should increment the value in the variable given as the operand" do
194
+ @zork_memory.writev(128, 12345)
195
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
196
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
197
+ [128, 12345], nil, nil, nil, 0)
198
+ @processor.execute(i)
199
+ @zork_memory.readv(128).should eql(12346)
200
+ end
201
+
202
+ it "should consider the value signed and increment -1 to 0" do
203
+ @zork_memory.writev(128, -1+65536)
204
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
205
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
206
+ [128, 12345], nil, nil, nil, 0)
207
+ @processor.execute(i)
208
+ @zork_memory.readv(128).should eql(0)
209
+ end
210
+
211
+ it "should edit the value on the stack in place" do
212
+ @zork_memory.writev(0, 11111)
213
+ @zork_memory.writev(0, 12345)
214
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
215
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
216
+ [0, 12345], nil, nil, nil, 0)
217
+ @processor.execute(i)
218
+ @zork_memory.readv(0).should eql(12346)
219
+ @zork_memory.readv(0).should eql(11111)
220
+ end
221
+
222
+ it "should branch if the value after incrementing is greater than the value given by the operand" do
223
+ @zork_memory.writev(128, 12345)
224
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
225
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
226
+ [128, 12345], nil, 2000, true, 0)
227
+ @processor.execute(i)
228
+ @zork_memory.program_counter = 2000
229
+ end
230
+
231
+ it "should not branch if the value after incrementing is not greater than the value given by the operand" do
232
+ @zork_memory.writev(128, 12345)
233
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
234
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
235
+ [128, 12346], nil, 2000, true, 0)
236
+ @processor.execute(i)
237
+ @zork_memory.program_counter = 12345
238
+ end
239
+
240
+ it "should not branch if the value after incrementing is greater than the value given by the operand and condition is negated" do
241
+ @zork_memory.writev(128, 12345)
242
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
243
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
244
+ [128, 12345], nil, 2000, false, 0)
245
+ @processor.execute(i)
246
+ @zork_memory.program_counter = 12345
247
+ end
248
+
249
+ it "should branch if the value after incrementing is not greater than the value given by the operand and condition is negated" do
250
+ @zork_memory.writev(128, 12345)
251
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC_CHK,
252
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
253
+ [128, 12346], nil, 2000, false, 0)
254
+ @processor.execute(i)
255
+ @zork_memory.program_counter = 2000
256
+ end
257
+ end
258
+
259
+ # not necessarily a branch
260
+ describe "ret" do
261
+ it "should return to the routine that called it" do
262
+ # set up a routine at address $2000
263
+ @zork_memory.force_writeb(0x2000, 2)
264
+ @zork_memory.force_writew(0x2001, 0)
265
+ @zork_memory.force_writew(0x2003, 0)
266
+
267
+ # The packed address is 0x2000 / 2
268
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
269
+ [Gruesome::Z::OperandType::LARGE],
270
+ [0x1000], 128, nil, nil, 0)
271
+
272
+ @processor.execute(i)
273
+
274
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RET,
275
+ [Gruesome::Z::OperandType::LARGE],
276
+ [123], nil, nil, nil, 0)
277
+
278
+ @processor.execute(i)
279
+
280
+ @zork_memory.program_counter.should eql(12345)
281
+ end
282
+
283
+ it "should set the variable indicated by the call with the return value as an immediate" do
284
+ # set up a routine at address $2000
285
+ @zork_memory.force_writeb(0x2000, 2)
286
+ @zork_memory.force_writew(0x2001, 0)
287
+ @zork_memory.force_writew(0x2003, 0)
288
+
289
+ # The packed address is 0x2000 / 2
290
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
291
+ [Gruesome::Z::OperandType::LARGE],
292
+ [0x1000], 128, nil, nil, 0)
293
+
294
+ @processor.execute(i)
295
+
296
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RET,
297
+ [Gruesome::Z::OperandType::LARGE],
298
+ [123], nil, nil, nil, 0)
299
+
300
+ @processor.execute(i)
301
+
302
+ @zork_memory.readv(128).should eql(123)
303
+ end
304
+
305
+ it "should be able to push the result (given as an immediate) to the stack if the call requests variable 0" do
306
+ # set up a routine at address $2000
307
+ @zork_memory.force_writeb(0x2000, 2)
308
+ @zork_memory.force_writew(0x2001, 0)
309
+ @zork_memory.force_writew(0x2003, 0)
310
+
311
+ # The packed address is 0x2000 / 2
312
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
313
+ [Gruesome::Z::OperandType::LARGE],
314
+ [0x1000], 0, nil, nil, 0)
315
+
316
+ @processor.execute(i)
317
+
318
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RET,
319
+ [Gruesome::Z::OperandType::LARGE],
320
+ [123], nil, nil, nil, 0)
321
+
322
+ @processor.execute(i)
323
+
324
+ @zork_memory.readv(0).should eql(123)
325
+ end
326
+ end
327
+
328
+ # not necessarily a branch
329
+ describe "ret_popped" do
330
+ it "should return to the routine that called it" do
331
+ # set up a routine at address $2000
332
+ @zork_memory.force_writeb(0x2000, 2)
333
+ @zork_memory.force_writew(0x2001, 0)
334
+ @zork_memory.force_writew(0x2003, 0)
335
+
336
+ # The packed address is 0x2000 / 2
337
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
338
+ [Gruesome::Z::OperandType::LARGE],
339
+ [0x1000], 128, nil, nil, 0)
340
+
341
+ @processor.execute(i)
342
+
343
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RET_POPPED,
344
+ [Gruesome::Z::OperandType::LARGE],
345
+ [123], nil, nil, nil, 0)
346
+
347
+ @processor.execute(i)
348
+
349
+ @zork_memory.program_counter.should eql(12345)
350
+ end
351
+
352
+ it "should be able to push top of callee stack to the stack of the caller" do
353
+ # set up a routine at address $2000
354
+ @zork_memory.force_writeb(0x2000, 2)
355
+ @zork_memory.force_writew(0x2001, 0)
356
+ @zork_memory.force_writew(0x2003, 0)
357
+ @zork_memory.writev(0, 11111)
358
358
 
359
- # The packed address is 0x2000 / 2
360
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
361
- [Gruesome::Z::OperandType::LARGE],
362
- [0x1000], 0, nil, nil, 0)
359
+ # The packed address is 0x2000 / 2
360
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
361
+ [Gruesome::Z::OperandType::LARGE],
362
+ [0x1000], 0, nil, nil, 0)
363
363
 
364
- @processor.execute(i)
365
- @zork_memory.writev(0, 22222)
366
- @zork_memory.writev(0, 23456)
364
+ @processor.execute(i)
365
+ @zork_memory.writev(0, 22222)
366
+ @zork_memory.writev(0, 23456)
367
367
 
368
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RET_POPPED,
369
- [Gruesome::Z::OperandType::LARGE],
370
- [123], nil, nil, nil, 0)
368
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RET_POPPED,
369
+ [Gruesome::Z::OperandType::LARGE],
370
+ [123], nil, nil, nil, 0)
371
371
 
372
- @processor.execute(i)
372
+ @processor.execute(i)
373
373
 
374
- @zork_memory.readv(0).should eql(23456)
375
- @zork_memory.readv(0).should eql(11111)
376
- end
377
- end
374
+ @zork_memory.readv(0).should eql(23456)
375
+ @zork_memory.readv(0).should eql(11111)
376
+ end
377
+ end
378
378
 
379
- # not necessarily a branch
380
- describe "rfalse" do
381
- it "should set the variable indicated by the call with 0" do
382
- # set up a routine at address $2000
383
- @zork_memory.force_writeb(0x2000, 2)
384
- @zork_memory.force_writew(0x2001, 0)
385
- @zork_memory.force_writew(0x2003, 0)
379
+ # not necessarily a branch
380
+ describe "rfalse" do
381
+ it "should set the variable indicated by the call with 0" do
382
+ # set up a routine at address $2000
383
+ @zork_memory.force_writeb(0x2000, 2)
384
+ @zork_memory.force_writew(0x2001, 0)
385
+ @zork_memory.force_writew(0x2003, 0)
386
386
 
387
- # The packed address is 0x2000 / 2
388
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
389
- [Gruesome::Z::OperandType::LARGE],
390
- [0x1000], 128, nil, nil, 0)
387
+ # The packed address is 0x2000 / 2
388
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
389
+ [Gruesome::Z::OperandType::LARGE],
390
+ [0x1000], 128, nil, nil, 0)
391
391
 
392
- @processor.execute(i)
392
+ @processor.execute(i)
393
393
 
394
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RFALSE,
395
- [], [], nil, nil, nil, 0)
394
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RFALSE,
395
+ [], [], nil, nil, nil, 0)
396
396
 
397
- @processor.execute(i)
397
+ @processor.execute(i)
398
398
 
399
- @zork_memory.readv(128).should eql(0)
400
- end
399
+ @zork_memory.readv(128).should eql(0)
400
+ end
401
401
 
402
- it "should push 0 to the caller's stack when indicated" do
403
- # set up a routine at address $2000
404
- @zork_memory.force_writeb(0x2000, 2)
405
- @zork_memory.force_writew(0x2001, 0)
406
- @zork_memory.force_writew(0x2003, 0)
407
-
408
- # The packed address is 0x2000 / 2
409
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
410
- [Gruesome::Z::OperandType::LARGE],
411
- [0x1000], 0, nil, nil, 0)
412
-
413
- @processor.execute(i)
414
-
415
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RFALSE,
416
- [], [], nil, nil, nil, 0)
417
-
418
- @processor.execute(i)
419
-
420
- @zork_memory.readv(0).should eql(0)
421
- end
422
- end
423
-
424
- # not necessarily a branch
425
- describe "rtrue" do
426
- it "should set the variable indicated by the call with 1" do
427
- # set up a routine at address $2000
428
- @zork_memory.force_writeb(0x2000, 2)
429
- @zork_memory.force_writew(0x2001, 0)
430
- @zork_memory.force_writew(0x2003, 0)
431
-
432
- # The packed address is 0x2000 / 2
433
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
434
- [Gruesome::Z::OperandType::LARGE],
435
- [0x1000], 128, nil, nil, 0)
436
-
437
- @processor.execute(i)
438
-
439
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RTRUE,
440
- [], [], nil, nil, nil, 0)
441
-
442
- @processor.execute(i)
443
-
444
- @zork_memory.readv(128).should eql(1)
445
- end
446
-
447
- it "should push 1 to the caller's stack when indicated" do
448
- # set up a routine at address $2000
449
- @zork_memory.force_writeb(0x2000, 2)
450
- @zork_memory.force_writew(0x2001, 0)
451
- @zork_memory.force_writew(0x2003, 0)
452
-
453
- # The packed address is 0x2000 / 2
454
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
455
- [Gruesome::Z::OperandType::LARGE],
456
- [0x1000], 0, nil, nil, 0)
457
-
458
- @processor.execute(i)
459
-
460
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RTRUE,
461
- [], [], nil, nil, nil, 0)
462
-
463
- @processor.execute(i)
464
-
465
- @zork_memory.readv(0).should eql(1)
466
- end
467
- end
468
-
469
- describe "jg" do
470
- it "should branch if the first operand is greater than the second" do
471
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JG,
472
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
473
- [(-12345+65536), (-23456+65536)], nil, 2000, true, 0)
474
-
475
- @processor.execute(i)
476
- @zork_memory.program_counter.should eql(2000)
477
- end
478
-
479
- it "should not branch if the first operand is not greater than the second" do
480
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JG,
481
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
482
- [12345, 12345], nil, 2000, true, 0)
483
-
484
- @processor.execute(i)
485
- @zork_memory.program_counter.should eql(12345)
486
- end
487
-
488
- it "should not branch if the first operand is greater than the second and condition is negated" do
489
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JG,
490
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
491
- [(-12345+65536), (-23456+65536)], nil, 2000, false, 0)
492
-
493
- @processor.execute(i)
494
- @zork_memory.program_counter.should eql(12345)
495
- end
496
-
497
- it "should branch if the first operand is not greater than the second and condition is negated" do
498
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JG,
499
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
500
- [(-12345+65536), 12345], nil, 2000, false, 0)
501
-
502
- @processor.execute(i)
503
- @zork_memory.program_counter.should eql(2000)
504
- end
505
- end
506
-
507
- describe "je" do
508
- it "should branch if the first operand is equal to one of four operands" do
509
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
510
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE,
511
- Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
512
- [(-12345+65536), 123, 1234, (-12345+65536)], nil, 2000, true, 0)
513
-
514
- @processor.execute(i)
515
- @zork_memory.program_counter.should eql(2000)
516
- end
517
-
518
- it "should not branch if the first operand is not equal to one of four operands" do
519
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
520
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE,
521
- Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
522
- [(-123+65536), 123, 1234, (12345+65536)], nil, 2000, true, 0)
523
-
524
- @processor.execute(i)
525
- @zork_memory.program_counter.should eql(12345)
526
- end
527
-
528
- it "should not branch if the first operand is equal to one of four operands and condition is negated" do
529
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
530
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE,
531
- Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
532
- [(-12345+65536), 1234, 123, (-12345+65536)], nil, 2000, false, 0)
533
-
534
- @processor.execute(i)
535
- @zork_memory.program_counter.should eql(12345)
536
- end
537
-
538
- it "should branch if the first operand is not equal to one of four operands and condition is negated" do
539
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
540
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE,
541
- Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
542
- [(-123+65536), 123, 12345, 12344], nil, 2000, false, 0)
543
-
544
- @processor.execute(i)
545
- @zork_memory.program_counter.should eql(2000)
546
- end
547
-
548
- it "should branch if the first operand is equal to one of three operands" do
549
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
550
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
551
- [(-12345+65536), 123, (-12345+65536)], nil, 2000, true, 0)
552
-
553
- @processor.execute(i)
554
- @zork_memory.program_counter.should eql(2000)
555
- end
556
-
557
- it "should not branch if the first operand is not equal to one of three operands" do
558
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
559
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
560
- [(-123+65536), 123, (12345+65536)], nil, 2000, true, 0)
561
-
562
- @processor.execute(i)
563
- @zork_memory.program_counter.should eql(12345)
564
- end
565
-
566
- it "should not branch if the first operand is equal to one of three operands and condition is negated" do
567
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
568
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
569
- [(-12345+65536), 123, (-12345+65536)], nil, 2000, false, 0)
570
-
571
- @processor.execute(i)
572
- @zork_memory.program_counter.should eql(12345)
573
- end
574
-
575
- it "should branch if the first operand is not equal to one of three operands and condition is negated" do
576
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
577
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
578
- [(-123+65536), 12345, 12344], nil, 2000, false, 0)
579
-
580
- @processor.execute(i)
581
- @zork_memory.program_counter.should eql(2000)
582
- end
583
-
584
- it "should branch if the first operand is equal to the second of two operands" do
585
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
586
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
587
- [(-12345+65536), (-12345+65536)], nil, 2000, true, 0)
588
-
589
- @processor.execute(i)
590
- @zork_memory.program_counter.should eql(2000)
591
- end
592
-
593
- it "should not branch if the first operand is not equal to the second of two operands" do
594
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
595
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
596
- [(-123+65536), (12345+65536)], nil, 2000, true, 0)
597
-
598
- @processor.execute(i)
599
- @zork_memory.program_counter.should eql(12345)
600
- end
601
-
602
- it "should not branch if the first operand is equal to the second of two operands and condition is negated" do
603
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
604
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
605
- [(-12345+65536), (-12345+65536)], nil, 2000, false, 0)
606
-
607
- @processor.execute(i)
608
- @zork_memory.program_counter.should eql(12345)
609
- end
610
-
611
- it "should branch if the first operand is not equal to the second of two operands and condition is negated" do
612
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
613
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
614
- [(-123+65536), (12345+65536)], nil, 2000, false, 0)
615
-
616
- @processor.execute(i)
617
- @zork_memory.program_counter.should eql(2000)
618
- end
619
- end
620
-
621
- describe "jl" do
622
- it "should branch if the first operand is less than the second" do
623
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JL,
624
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
625
- [(-23456+65536), (-12345+65536)], nil, 2000, true, 0)
626
-
627
- @processor.execute(i)
628
- @zork_memory.program_counter.should eql(2000)
629
- end
630
-
631
- it "should not branch if the first operand is not less than the second" do
632
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JL,
633
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
634
- [12345, 12345], nil, 2000, true, 0)
635
-
636
- @processor.execute(i)
637
- @zork_memory.program_counter.should eql(12345)
638
- end
639
-
640
- it "should not branch if the first operand is less than the second and condition is negated" do
641
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JL,
642
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
643
- [(-23456+65536), (-12345+65536)], nil, 2000, false, 0)
644
-
645
- @processor.execute(i)
646
- @zork_memory.program_counter.should eql(12345)
647
- end
648
-
649
- it "should branch if the first operand is not less than the second and condition is negated" do
650
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JL,
651
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
652
- [12345, (-12345+65536)], nil, 2000, false, 0)
653
-
654
- @processor.execute(i)
655
- @zork_memory.program_counter.should eql(2000)
656
- end
657
- end
658
-
659
- describe "jz" do
660
- it "should branch if the first operand is zero" do
661
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JZ,
662
- [Gruesome::Z::OperandType::LARGE],
663
- [0], nil, 2000, true, 0)
664
-
665
- @processor.execute(i)
666
- @zork_memory.program_counter.should eql(2000)
667
- end
668
-
669
- it "should not branch if the first operand is not zero" do
670
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JZ,
671
- [Gruesome::Z::OperandType::LARGE],
672
- [12345], nil, 2000, true, 0)
673
-
674
- @processor.execute(i)
675
- @zork_memory.program_counter.should eql(12345)
676
- end
677
-
678
- it "should not branch if the first operand is zero and condition is negated" do
679
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JZ,
680
- [Gruesome::Z::OperandType::LARGE],
681
- [0], nil, 2000, false, 0)
682
-
683
- @processor.execute(i)
684
- @zork_memory.program_counter.should eql(12345)
685
- end
686
-
687
- it "should branch if the first operand is not zero and condition is negated" do
688
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JZ,
689
- [Gruesome::Z::OperandType::LARGE],
690
- [12345], nil, 2000, false, 0)
691
-
692
- @processor.execute(i)
693
- @zork_memory.program_counter.should eql(2000)
694
- end
695
- end
696
-
697
- describe "jump" do
698
- it "should update the program counter via a signed offset" do
699
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JUMP,
700
- [Gruesome::Z::OperandType::LARGE],
701
- [(-12343+65536)], nil, nil, nil, 0)
702
-
703
- @processor.execute(i)
704
- @zork_memory.program_counter.should eql(0)
705
- end
706
- end
707
-
708
- describe "piracy" do
709
- it "should simply act as a jump and update the program counter via a signed offset" do
710
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PIRACY,
711
- [Gruesome::Z::OperandType::LARGE],
712
- [(-12343+65536)], nil, nil, nil, 0)
713
-
714
- @processor.execute(i)
715
- @zork_memory.program_counter.should eql(0)
716
- end
717
- end
718
-
719
- describe "test" do
720
- it "should branch if the first operand has all bits set that the second has set" do
721
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST,
722
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
723
- [0b1000110110111101, 0b1000100010001000], nil, 2000, true, 0)
724
-
725
- @processor.execute(i)
726
- @zork_memory.program_counter.should eql(2000)
727
- end
728
-
729
- it "should not branch if the first operand does not have all bits set that the second has set" do
730
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST,
731
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
732
- [0b1000110110111101, 0b1111100010001000], nil, 2000, true, 0)
733
-
734
- @processor.execute(i)
735
- @zork_memory.program_counter.should eql(12345)
736
- end
737
-
738
- it "should not branch if the first operand has all bits set that the second has set and condition is negated" do
739
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST,
740
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
741
- [0b1000110110111101, 0b1000100010001000], nil, 2000, false, 0)
742
-
743
- @processor.execute(i)
744
- @zork_memory.program_counter.should eql(12345)
745
- end
746
-
747
- it "should branch if the first operand does not have all bits set that the second has set and condition is negated" do
748
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST,
749
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
750
- [0b1000110110111101, 0b1111100010001000], nil, 2000, false, 0)
751
-
752
- @processor.execute(i)
753
- @zork_memory.program_counter.should eql(2000)
754
- end
755
- end
756
- end
757
-
758
- describe "Store Instruction" do
759
- before(:each) do
760
- @zork_memory.writev(128, 0)
761
- end
762
-
763
- after(:each) do
764
- # instructions should not affect PC
765
- @zork_memory.program_counter.should eql(12345)
766
- end
767
-
768
- describe "art_shift" do
769
- it "should shift left when places is positive" do
770
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::ART_SHIFT,
771
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
772
- [1234, 2], 128, nil, nil, 0)
773
-
774
- @processor.execute(i)
775
-
776
- @zork_memory.readv(128).should eql(((1234 << 2) & 65535))
777
- end
778
-
779
- it "should shift right when places is positive and sign extend" do
780
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::ART_SHIFT,
781
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
782
- [-123+65536, -2+65536], 128, nil, nil, 0)
783
-
784
- @processor.execute(i)
785
-
786
- @zork_memory.readv(128).should eql((-123 >> 2) & 65535)
787
- end
788
- end
789
-
790
- describe "load" do
791
- it "should store the value of the variable into the result" do
792
- @zork_memory.writev(128, 30)
793
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::LOAD,
794
- [Gruesome::Z::OperandType::VARIABLE],
795
- [128], 130, nil, nil, 0)
796
- @processor.execute(i)
797
- @zork_memory.readv(130).should eql(30)
798
- end
799
-
800
- it "should not pop the value off of the stack if variable %00 is used" do
801
- @zork_memory.writev(0, 11111)
802
- @zork_memory.writev(0, 12345)
803
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::LOAD,
804
- [Gruesome::Z::OperandType::VARIABLE],
805
- [0], 130, nil, nil, 0)
806
- @processor.execute(i)
807
- @zork_memory.readv(130).should eql(12345)
808
- @zork_memory.readv(0).should eql(12345)
809
- @zork_memory.readv(0).should eql(11111)
810
- end
811
- end
812
-
813
- describe "loadb" do
814
- it "should store the value of the byte at the location given by the base and offset into the result" do
815
- @zork_memory.writeb(2589+200, 127)
816
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::LOADB,
817
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
818
- [2589, 200], 130, nil, nil, 0)
819
- @processor.execute(i)
820
- @zork_memory.readv(130).should eql(127)
821
- end
822
- end
823
-
824
- describe "loadw" do
825
- it "should store the value of the word at the location given by the base and offset into the result" do
826
- @zork_memory.writew(2480+200, 12345)
827
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::LOADW,
828
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
829
- [2480, 100], 130, nil, nil, 0)
830
- @processor.execute(i)
831
- @zork_memory.readv(130).should eql(12345)
832
- end
833
- end
834
-
835
- describe "random" do
836
- it "should return 0 when a negative value is used to seed the generator" do
837
- @zork_memory.writev(130, 11111)
838
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RANDOM,
839
- [Gruesome::Z::OperandType::LARGE],
840
- [-1+65536], 130, nil, nil, 0)
841
- @processor.execute(i)
842
- @zork_memory.readv(130).should eql(0)
843
- end
844
-
845
- it "should return 0 when 0 is used to seed the generator" do
846
- @zork_memory.writev(130, 11111)
847
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RANDOM,
848
- [Gruesome::Z::OperandType::LARGE],
849
- [-1+65536], 130, nil, nil, 0)
850
- @processor.execute(i)
851
- @zork_memory.readv(130).should eql(0)
852
- end
853
-
854
- it "should be able to be seeded with a negative value such that the behavior is predicable" do
855
- srand = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RANDOM,
856
- [Gruesome::Z::OperandType::LARGE],
857
- [-1+65536], 130, nil, nil, 0)
858
- @processor.execute(srand)
859
-
860
- rnd = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RANDOM,
861
- [Gruesome::Z::OperandType::LARGE],
862
- [1234], 130, nil, nil, 0)
863
- @processor.execute(rnd)
864
- store1 = @zork_memory.readv(130)
865
- @processor.execute(rnd)
866
- store2 = @zork_memory.readv(130)
867
-
868
- @processor.execute(srand)
869
-
870
- @processor.execute(rnd)
871
- @zork_memory.readv(130).should eql(store1)
872
- @processor.execute(rnd)
873
- @zork_memory.readv(130).should eql(store2)
874
- end
875
- end
876
- end
877
-
878
- describe "Input Instruction" do
879
- before(:each) do
880
- # We take over stdin so that we can simulate the keyboard input
881
- @stdin = $stdin
882
-
883
- # sread text-buffer parse-buffer (v 1-3)
884
-
885
- # text-buffer byte 0 indicates maximum length
886
- # parse-buffer byte 0 indicates maximum words
887
-
888
- @zork_memory.force_writeb(0x1000, 50)
889
- end
890
-
891
- after(:each) do
892
- $stdin = @stdin
893
-
894
- # The program counter should not be changed
895
- @zork_memory.program_counter.should eql(12345)
896
- end
897
-
898
- describe "sread" do
899
- it "should read in a line of text" do
900
- $stdin = StringIO.new("foo bar johnson\n")
901
-
902
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::SREAD,
903
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
904
- [0x1000, 0x1200], nil, nil, nil, 0)
905
- @processor.execute(i)
906
- end
907
- end
908
- end
909
-
910
- describe "Output and Branching Instruction" do
911
- before(:each) do
912
- # We take over stdout so that we can see what it prints
913
- @stdout = $stdout
914
- $stdout = StringIO.new
915
- end
916
-
917
- after(:each) do
918
- $stdout = @stdout
919
- end
920
-
921
- describe "print_ret" do
922
- it "should return to the routine that called it" do
923
- # set up a routine at address $2000
924
- @zork_memory.force_writeb(0x2000, 2)
925
- @zork_memory.force_writew(0x2001, 0)
926
- @zork_memory.force_writew(0x2003, 0)
927
-
928
- # The packed address is 0x2000 / 2
929
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
930
- [Gruesome::Z::OperandType::LARGE],
931
- [0x1000], 128, nil, nil, 0)
932
-
933
- @processor.execute(i)
934
-
935
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_RET,
936
- [Gruesome::Z::OperandType::STRING],
937
- ["Hello World"], nil, nil, nil, 0)
938
-
939
- @processor.execute(i)
940
-
941
- @zork_memory.program_counter.should eql(12345)
942
- end
943
-
944
- it "should print out the string given as an operand followed by a newline to stdout" do
945
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_RET,
946
- [Gruesome::Z::OperandType::STRING],
947
- ["Hello World"], nil, nil, nil, 0)
948
-
949
- @processor.execute(i)
950
- $stdout.string.should eql("Hello World\n")
951
- end
952
-
953
- it "should as a return value set the variable indicated by the call with 1" do
954
- # set up a routine at address $2000
955
- @zork_memory.force_writeb(0x2000, 2)
956
- @zork_memory.force_writew(0x2001, 0)
957
- @zork_memory.force_writew(0x2003, 0)
958
-
959
- # The packed address is 0x2000 / 2
960
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
961
- [Gruesome::Z::OperandType::LARGE],
962
- [0x1000], 128, nil, nil, 0)
963
-
964
- @processor.execute(i)
965
-
966
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_RET,
967
- [Gruesome::Z::OperandType::STRING],
968
- ["Hello World"], nil, nil, nil, 0)
969
-
970
- @processor.execute(i)
971
-
972
- @zork_memory.readv(128).should eql(1)
973
- end
974
-
975
- it "should as a return value push 1 to the caller's stack when indicated" do
976
- # set up a routine at address $2000
977
- @zork_memory.force_writeb(0x2000, 2)
978
- @zork_memory.force_writew(0x2001, 0)
979
- @zork_memory.force_writew(0x2003, 0)
980
- @zork_memory.writev(0, 11111)
981
-
982
- # The packed address is 0x2000 / 2
983
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
984
- [Gruesome::Z::OperandType::LARGE],
985
- [0x1000], 0, nil, nil, 0)
986
-
987
- @processor.execute(i)
988
-
989
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_RET,
990
- [Gruesome::Z::OperandType::STRING],
991
- ["Hello World"], nil, nil, nil, 0)
992
-
993
- @processor.execute(i)
994
-
995
- @zork_memory.readv(0).should eql(1)
996
- @zork_memory.readv(0).should eql(11111)
997
- end
998
- end
999
- end
1000
-
1001
- describe "Output Instruction" do
1002
- before(:each) do
1003
- # We take over stdout so that we can see what it prints
1004
- @stdout = $stdout
1005
- $stdout = StringIO.new
1006
- end
1007
-
1008
- after(:each) do
1009
- $stdout = @stdout
1010
-
1011
- # The program counter should not be changed
1012
- @zork_memory.program_counter.should eql(12345)
1013
- end
1014
-
1015
- describe "new_line" do
1016
- it "should print a carriage return" do
1017
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::NEW_LINE,
1018
- [], [], nil, nil, nil, 0)
1019
- @processor.execute(i)
1020
- $stdout.string.should eql("\n")
1021
- end
1022
- end
1023
-
1024
- describe "print_char" do
1025
- it "should print out the zchar given as an operand to stdout" do
1026
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_CHAR,
1027
- [Gruesome::Z::OperandType::LARGE],
1028
- [215], nil, nil, nil, 0)
1029
-
1030
- @processor.execute(i)
1031
- $stdout.string.should eql("\u00fe")
1032
- end
1033
- end
1034
-
1035
- describe "print_num" do
1036
- it "should print out a number given as an operand in decimal to stdout" do
1037
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_NUM,
1038
- [Gruesome::Z::OperandType::LARGE],
1039
- [12345], nil, nil, nil, 0)
1040
-
1041
- @processor.execute(i)
1042
- $stdout.string.should eql("12345")
1043
- end
1044
-
1045
- it "should print out a signed number given as an operand in decimal to stdout" do
1046
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_NUM,
1047
- [Gruesome::Z::OperandType::LARGE],
1048
- [-12345+65536], nil, nil, nil, 0)
1049
-
1050
- @processor.execute(i)
1051
- $stdout.string.should eql("-12345")
1052
- end
1053
- end
1054
-
1055
- describe "print" do
1056
- it "should print out the string given as an operand to stdout" do
1057
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT,
1058
- [Gruesome::Z::OperandType::STRING],
1059
- ["Hello World"], nil, nil, nil, 0)
1060
-
1061
- @processor.execute(i)
1062
- $stdout.string.should eql("Hello World")
1063
- end
1064
- end
1065
-
1066
- describe "print_addr" do
1067
- it "should print out the string located at the byte address given by the operand" do
1068
- # 'grue' is written at 0x4291
1069
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_ADDR,
1070
- [Gruesome::Z::OperandType::LARGE],
1071
- [0x4291], nil, nil, nil, 0)
1072
-
1073
- @processor.execute(i)
1074
- $stdout.string.should eql("grue")
1075
- end
1076
- end
1077
-
1078
- describe "print_paddr" do
1079
- it "should print out the string located at the packed address given by the operand" do
1080
- # 'ZORK I: The Great Underground Empire' is written at 0x6ee4 (packed: 0x3772)
1081
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_PADDR,
1082
- [Gruesome::Z::OperandType::LARGE],
1083
- [0x3772], nil, nil, nil, 0)
1084
-
1085
- @processor.execute(i)
1086
- $stdout.string[/(.*)\n/,1].should eql("ZORK I: The Great Underground Empire")
1087
- end
1088
- end
1089
-
1090
- describe "log_shift" do
1091
- it "should shift left when places is positive" do
1092
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::LOG_SHIFT,
1093
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1094
- [-12345+65536, 2], 128, nil, nil, 0)
1095
-
1096
- @processor.execute(i)
1097
-
1098
- @zork_memory.readv(128).should eql((((-12345+65536) << 2) & 65535))
1099
- end
1100
-
1101
- it "should shift right when places is positive and not sign extend" do
1102
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::LOG_SHIFT,
1103
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1104
- [-123+65536, -2+65536], 128, nil, nil, 0)
1105
-
1106
- @processor.execute(i)
1107
-
1108
- @zork_memory.readv(128).should eql(((-123+65536) >> 2))
1109
- end
1110
- end
1111
-
1112
- describe "not" do
1113
- it "should perform a logical negation on the operand and assign to the appropriate variable" do
1114
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::NOT,
1115
- [Gruesome::Z::OperandType::LARGE],
1116
- [12345], 128, nil, nil, 0)
1117
-
1118
- @processor.execute(i)
1119
-
1120
- @zork_memory.readv(128).should eql((~12345)+65536)
1121
- end
1122
- end
1123
-
1124
- describe "and" do
1125
- it "should bitwise and two signed shorts together and assign to the appropriate variable" do
1126
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::AND,
1127
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1128
- [-12345+65536, 12344], 128, nil, nil, 0)
1129
-
1130
- @processor.execute(i)
1131
-
1132
- @zork_memory.readv(128).should eql((-12345 & 12344) & 65535)
1133
- end
1134
- end
1135
-
1136
- describe "or" do
1137
- it "should bitwise or two signed shorts together and assign to the appropriate variable" do
1138
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::OR,
1139
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1140
- [-12345+65536, 12344], 128, nil, nil, 0)
1141
-
1142
- @processor.execute(i)
402
+ it "should push 0 to the caller's stack when indicated" do
403
+ # set up a routine at address $2000
404
+ @zork_memory.force_writeb(0x2000, 2)
405
+ @zork_memory.force_writew(0x2001, 0)
406
+ @zork_memory.force_writew(0x2003, 0)
407
+
408
+ # The packed address is 0x2000 / 2
409
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
410
+ [Gruesome::Z::OperandType::LARGE],
411
+ [0x1000], 0, nil, nil, 0)
412
+
413
+ @processor.execute(i)
414
+
415
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RFALSE,
416
+ [], [], nil, nil, nil, 0)
417
+
418
+ @processor.execute(i)
419
+
420
+ @zork_memory.readv(0).should eql(0)
421
+ end
422
+ end
423
+
424
+ # not necessarily a branch
425
+ describe "rtrue" do
426
+ it "should set the variable indicated by the call with 1" do
427
+ # set up a routine at address $2000
428
+ @zork_memory.force_writeb(0x2000, 2)
429
+ @zork_memory.force_writew(0x2001, 0)
430
+ @zork_memory.force_writew(0x2003, 0)
431
+
432
+ # The packed address is 0x2000 / 2
433
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
434
+ [Gruesome::Z::OperandType::LARGE],
435
+ [0x1000], 128, nil, nil, 0)
436
+
437
+ @processor.execute(i)
438
+
439
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RTRUE,
440
+ [], [], nil, nil, nil, 0)
441
+
442
+ @processor.execute(i)
443
+
444
+ @zork_memory.readv(128).should eql(1)
445
+ end
446
+
447
+ it "should push 1 to the caller's stack when indicated" do
448
+ # set up a routine at address $2000
449
+ @zork_memory.force_writeb(0x2000, 2)
450
+ @zork_memory.force_writew(0x2001, 0)
451
+ @zork_memory.force_writew(0x2003, 0)
452
+
453
+ # The packed address is 0x2000 / 2
454
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
455
+ [Gruesome::Z::OperandType::LARGE],
456
+ [0x1000], 0, nil, nil, 0)
457
+
458
+ @processor.execute(i)
459
+
460
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RTRUE,
461
+ [], [], nil, nil, nil, 0)
462
+
463
+ @processor.execute(i)
464
+
465
+ @zork_memory.readv(0).should eql(1)
466
+ end
467
+ end
468
+
469
+ describe "jg" do
470
+ it "should branch if the first operand is greater than the second" do
471
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JG,
472
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
473
+ [(-12345+65536), (-23456+65536)], nil, 2000, true, 0)
474
+
475
+ @processor.execute(i)
476
+ @zork_memory.program_counter.should eql(2000)
477
+ end
478
+
479
+ it "should not branch if the first operand is not greater than the second" do
480
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JG,
481
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
482
+ [12345, 12345], nil, 2000, true, 0)
483
+
484
+ @processor.execute(i)
485
+ @zork_memory.program_counter.should eql(12345)
486
+ end
487
+
488
+ it "should not branch if the first operand is greater than the second and condition is negated" do
489
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JG,
490
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
491
+ [(-12345+65536), (-23456+65536)], nil, 2000, false, 0)
492
+
493
+ @processor.execute(i)
494
+ @zork_memory.program_counter.should eql(12345)
495
+ end
496
+
497
+ it "should branch if the first operand is not greater than the second and condition is negated" do
498
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JG,
499
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
500
+ [(-12345+65536), 12345], nil, 2000, false, 0)
501
+
502
+ @processor.execute(i)
503
+ @zork_memory.program_counter.should eql(2000)
504
+ end
505
+ end
506
+
507
+ describe "je" do
508
+ it "should branch if the first operand is equal to one of four operands" do
509
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
510
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE,
511
+ Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
512
+ [(-12345+65536), 123, 1234, (-12345+65536)], nil, 2000, true, 0)
513
+
514
+ @processor.execute(i)
515
+ @zork_memory.program_counter.should eql(2000)
516
+ end
517
+
518
+ it "should not branch if the first operand is not equal to one of four operands" do
519
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
520
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE,
521
+ Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
522
+ [(-123+65536), 123, 1234, (12345+65536)], nil, 2000, true, 0)
523
+
524
+ @processor.execute(i)
525
+ @zork_memory.program_counter.should eql(12345)
526
+ end
527
+
528
+ it "should not branch if the first operand is equal to one of four operands and condition is negated" do
529
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
530
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE,
531
+ Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
532
+ [(-12345+65536), 1234, 123, (-12345+65536)], nil, 2000, false, 0)
533
+
534
+ @processor.execute(i)
535
+ @zork_memory.program_counter.should eql(12345)
536
+ end
537
+
538
+ it "should branch if the first operand is not equal to one of four operands and condition is negated" do
539
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
540
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE,
541
+ Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
542
+ [(-123+65536), 123, 12345, 12344], nil, 2000, false, 0)
543
+
544
+ @processor.execute(i)
545
+ @zork_memory.program_counter.should eql(2000)
546
+ end
547
+
548
+ it "should branch if the first operand is equal to one of three operands" do
549
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
550
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
551
+ [(-12345+65536), 123, (-12345+65536)], nil, 2000, true, 0)
552
+
553
+ @processor.execute(i)
554
+ @zork_memory.program_counter.should eql(2000)
555
+ end
556
+
557
+ it "should not branch if the first operand is not equal to one of three operands" do
558
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
559
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
560
+ [(-123+65536), 123, (12345+65536)], nil, 2000, true, 0)
561
+
562
+ @processor.execute(i)
563
+ @zork_memory.program_counter.should eql(12345)
564
+ end
565
+
566
+ it "should not branch if the first operand is equal to one of three operands and condition is negated" do
567
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
568
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
569
+ [(-12345+65536), 123, (-12345+65536)], nil, 2000, false, 0)
570
+
571
+ @processor.execute(i)
572
+ @zork_memory.program_counter.should eql(12345)
573
+ end
574
+
575
+ it "should branch if the first operand is not equal to one of three operands and condition is negated" do
576
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
577
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
578
+ [(-123+65536), 12345, 12344], nil, 2000, false, 0)
579
+
580
+ @processor.execute(i)
581
+ @zork_memory.program_counter.should eql(2000)
582
+ end
583
+
584
+ it "should branch if the first operand is equal to the second of two operands" do
585
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
586
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
587
+ [(-12345+65536), (-12345+65536)], nil, 2000, true, 0)
588
+
589
+ @processor.execute(i)
590
+ @zork_memory.program_counter.should eql(2000)
591
+ end
592
+
593
+ it "should not branch if the first operand is not equal to the second of two operands" do
594
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
595
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
596
+ [(-123+65536), (12345+65536)], nil, 2000, true, 0)
597
+
598
+ @processor.execute(i)
599
+ @zork_memory.program_counter.should eql(12345)
600
+ end
601
+
602
+ it "should not branch if the first operand is equal to the second of two operands and condition is negated" do
603
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
604
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
605
+ [(-12345+65536), (-12345+65536)], nil, 2000, false, 0)
606
+
607
+ @processor.execute(i)
608
+ @zork_memory.program_counter.should eql(12345)
609
+ end
610
+
611
+ it "should branch if the first operand is not equal to the second of two operands and condition is negated" do
612
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JE,
613
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
614
+ [(-123+65536), (12345+65536)], nil, 2000, false, 0)
615
+
616
+ @processor.execute(i)
617
+ @zork_memory.program_counter.should eql(2000)
618
+ end
619
+ end
620
+
621
+ describe "jl" do
622
+ it "should branch if the first operand is less than the second" do
623
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JL,
624
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
625
+ [(-23456+65536), (-12345+65536)], nil, 2000, true, 0)
626
+
627
+ @processor.execute(i)
628
+ @zork_memory.program_counter.should eql(2000)
629
+ end
630
+
631
+ it "should not branch if the first operand is not less than the second" do
632
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JL,
633
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
634
+ [12345, 12345], nil, 2000, true, 0)
635
+
636
+ @processor.execute(i)
637
+ @zork_memory.program_counter.should eql(12345)
638
+ end
639
+
640
+ it "should not branch if the first operand is less than the second and condition is negated" do
641
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JL,
642
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
643
+ [(-23456+65536), (-12345+65536)], nil, 2000, false, 0)
644
+
645
+ @processor.execute(i)
646
+ @zork_memory.program_counter.should eql(12345)
647
+ end
648
+
649
+ it "should branch if the first operand is not less than the second and condition is negated" do
650
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JL,
651
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
652
+ [12345, (-12345+65536)], nil, 2000, false, 0)
653
+
654
+ @processor.execute(i)
655
+ @zork_memory.program_counter.should eql(2000)
656
+ end
657
+ end
658
+
659
+ describe "jz" do
660
+ it "should branch if the first operand is zero" do
661
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JZ,
662
+ [Gruesome::Z::OperandType::LARGE],
663
+ [0], nil, 2000, true, 0)
664
+
665
+ @processor.execute(i)
666
+ @zork_memory.program_counter.should eql(2000)
667
+ end
668
+
669
+ it "should not branch if the first operand is not zero" do
670
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JZ,
671
+ [Gruesome::Z::OperandType::LARGE],
672
+ [12345], nil, 2000, true, 0)
673
+
674
+ @processor.execute(i)
675
+ @zork_memory.program_counter.should eql(12345)
676
+ end
677
+
678
+ it "should not branch if the first operand is zero and condition is negated" do
679
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JZ,
680
+ [Gruesome::Z::OperandType::LARGE],
681
+ [0], nil, 2000, false, 0)
682
+
683
+ @processor.execute(i)
684
+ @zork_memory.program_counter.should eql(12345)
685
+ end
686
+
687
+ it "should branch if the first operand is not zero and condition is negated" do
688
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JZ,
689
+ [Gruesome::Z::OperandType::LARGE],
690
+ [12345], nil, 2000, false, 0)
691
+
692
+ @processor.execute(i)
693
+ @zork_memory.program_counter.should eql(2000)
694
+ end
695
+ end
696
+
697
+ describe "jump" do
698
+ it "should update the program counter via a signed offset" do
699
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JUMP,
700
+ [Gruesome::Z::OperandType::LARGE],
701
+ [(-12343+65536)], nil, nil, nil, 0)
702
+
703
+ @processor.execute(i)
704
+ @zork_memory.program_counter.should eql(0)
705
+ end
706
+ end
707
+
708
+ describe "piracy" do
709
+ it "should simply act as a jump and update the program counter via a signed offset" do
710
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PIRACY,
711
+ [Gruesome::Z::OperandType::LARGE],
712
+ [(-12343+65536)], nil, nil, nil, 0)
713
+
714
+ @processor.execute(i)
715
+ @zork_memory.program_counter.should eql(0)
716
+ end
717
+ end
718
+
719
+ describe "test" do
720
+ it "should branch if the first operand has all bits set that the second has set" do
721
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST,
722
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
723
+ [0b1000110110111101, 0b1000100010001000], nil, 2000, true, 0)
724
+
725
+ @processor.execute(i)
726
+ @zork_memory.program_counter.should eql(2000)
727
+ end
728
+
729
+ it "should not branch if the first operand does not have all bits set that the second has set" do
730
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST,
731
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
732
+ [0b1000110110111101, 0b1111100010001000], nil, 2000, true, 0)
733
+
734
+ @processor.execute(i)
735
+ @zork_memory.program_counter.should eql(12345)
736
+ end
737
+
738
+ it "should not branch if the first operand has all bits set that the second has set and condition is negated" do
739
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST,
740
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
741
+ [0b1000110110111101, 0b1000100010001000], nil, 2000, false, 0)
742
+
743
+ @processor.execute(i)
744
+ @zork_memory.program_counter.should eql(12345)
745
+ end
746
+
747
+ it "should branch if the first operand does not have all bits set that the second has set and condition is negated" do
748
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST,
749
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
750
+ [0b1000110110111101, 0b1111100010001000], nil, 2000, false, 0)
751
+
752
+ @processor.execute(i)
753
+ @zork_memory.program_counter.should eql(2000)
754
+ end
755
+ end
756
+ end
757
+
758
+ describe "Store Instruction" do
759
+ before(:each) do
760
+ @zork_memory.writev(128, 0)
761
+ end
762
+
763
+ after(:each) do
764
+ # instructions should not affect PC
765
+ @zork_memory.program_counter.should eql(12345)
766
+ end
767
+
768
+ describe "art_shift" do
769
+ it "should shift left when places is positive" do
770
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::ART_SHIFT,
771
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
772
+ [1234, 2], 128, nil, nil, 0)
773
+
774
+ @processor.execute(i)
775
+
776
+ @zork_memory.readv(128).should eql(((1234 << 2) & 65535))
777
+ end
778
+
779
+ it "should shift right when places is positive and sign extend" do
780
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::ART_SHIFT,
781
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
782
+ [-123+65536, -2+65536], 128, nil, nil, 0)
783
+
784
+ @processor.execute(i)
785
+
786
+ @zork_memory.readv(128).should eql((-123 >> 2) & 65535)
787
+ end
788
+ end
789
+
790
+ describe "load" do
791
+ it "should store the value of the variable into the result" do
792
+ @zork_memory.writev(128, 30)
793
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::LOAD,
794
+ [Gruesome::Z::OperandType::VARIABLE],
795
+ [128], 130, nil, nil, 0)
796
+ @processor.execute(i)
797
+ @zork_memory.readv(130).should eql(30)
798
+ end
799
+
800
+ it "should not pop the value off of the stack if variable %00 is used" do
801
+ @zork_memory.writev(0, 11111)
802
+ @zork_memory.writev(0, 12345)
803
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::LOAD,
804
+ [Gruesome::Z::OperandType::VARIABLE],
805
+ [0], 130, nil, nil, 0)
806
+ @processor.execute(i)
807
+ @zork_memory.readv(130).should eql(12345)
808
+ @zork_memory.readv(0).should eql(12345)
809
+ @zork_memory.readv(0).should eql(11111)
810
+ end
811
+ end
812
+
813
+ describe "loadb" do
814
+ it "should store the value of the byte at the location given by the base and offset into the result" do
815
+ @zork_memory.writeb(2589+200, 127)
816
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::LOADB,
817
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
818
+ [2589, 200], 130, nil, nil, 0)
819
+ @processor.execute(i)
820
+ @zork_memory.readv(130).should eql(127)
821
+ end
822
+ end
823
+
824
+ describe "loadw" do
825
+ it "should store the value of the word at the location given by the base and offset into the result" do
826
+ @zork_memory.writew(2480+200, 12345)
827
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::LOADW,
828
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
829
+ [2480, 100], 130, nil, nil, 0)
830
+ @processor.execute(i)
831
+ @zork_memory.readv(130).should eql(12345)
832
+ end
833
+ end
834
+
835
+ describe "random" do
836
+ it "should return 0 when a negative value is used to seed the generator" do
837
+ @zork_memory.writev(130, 11111)
838
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RANDOM,
839
+ [Gruesome::Z::OperandType::LARGE],
840
+ [-1+65536], 130, nil, nil, 0)
841
+ @processor.execute(i)
842
+ @zork_memory.readv(130).should eql(0)
843
+ end
844
+
845
+ it "should return 0 when 0 is used to seed the generator" do
846
+ @zork_memory.writev(130, 11111)
847
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RANDOM,
848
+ [Gruesome::Z::OperandType::LARGE],
849
+ [-1+65536], 130, nil, nil, 0)
850
+ @processor.execute(i)
851
+ @zork_memory.readv(130).should eql(0)
852
+ end
853
+
854
+ it "should be able to be seeded with a negative value such that the behavior is predicable" do
855
+ srand = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RANDOM,
856
+ [Gruesome::Z::OperandType::LARGE],
857
+ [-1+65536], 130, nil, nil, 0)
858
+ @processor.execute(srand)
859
+
860
+ rnd = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::RANDOM,
861
+ [Gruesome::Z::OperandType::LARGE],
862
+ [1234], 130, nil, nil, 0)
863
+ @processor.execute(rnd)
864
+ store1 = @zork_memory.readv(130)
865
+ @processor.execute(rnd)
866
+ store2 = @zork_memory.readv(130)
867
+
868
+ @processor.execute(srand)
869
+
870
+ @processor.execute(rnd)
871
+ @zork_memory.readv(130).should eql(store1)
872
+ @processor.execute(rnd)
873
+ @zork_memory.readv(130).should eql(store2)
874
+ end
875
+ end
876
+ end
877
+
878
+ describe "Input Instruction" do
879
+ before(:each) do
880
+ # We take over stdin so that we can simulate the keyboard input
881
+ @stdin = $stdin
882
+
883
+ # sread text-buffer parse-buffer (v 1-3)
884
+
885
+ # text-buffer byte 0 indicates maximum length
886
+ # parse-buffer byte 0 indicates maximum words
887
+
888
+ @zork_memory.force_writeb(0x1000, 50)
889
+ end
890
+
891
+ after(:each) do
892
+ $stdin = @stdin
893
+
894
+ # The program counter should not be changed
895
+ @zork_memory.program_counter.should eql(12345)
896
+ end
897
+
898
+ describe "sread" do
899
+ it "should read in a line of text" do
900
+ $stdin = StringIO.new("foo bar johnson\n")
901
+
902
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::SREAD,
903
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
904
+ [0x1000, 0x1200], nil, nil, nil, 0)
905
+ @processor.execute(i)
906
+ end
907
+ end
908
+ end
909
+
910
+ describe "Output and Branching Instruction" do
911
+ before(:each) do
912
+ # We take over stdout so that we can see what it prints
913
+ @stdout = $stdout
914
+ $stdout = StringIO.new
915
+ end
916
+
917
+ after(:each) do
918
+ $stdout = @stdout
919
+ end
920
+
921
+ describe "print_ret" do
922
+ it "should return to the routine that called it" do
923
+ # set up a routine at address $2000
924
+ @zork_memory.force_writeb(0x2000, 2)
925
+ @zork_memory.force_writew(0x2001, 0)
926
+ @zork_memory.force_writew(0x2003, 0)
927
+
928
+ # The packed address is 0x2000 / 2
929
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
930
+ [Gruesome::Z::OperandType::LARGE],
931
+ [0x1000], 128, nil, nil, 0)
932
+
933
+ @processor.execute(i)
934
+
935
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_RET,
936
+ [Gruesome::Z::OperandType::STRING],
937
+ ["Hello World"], nil, nil, nil, 0)
938
+
939
+ @processor.execute(i)
940
+
941
+ @zork_memory.program_counter.should eql(12345)
942
+ end
943
+
944
+ it "should print out the string given as an operand followed by a newline to stdout" do
945
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_RET,
946
+ [Gruesome::Z::OperandType::STRING],
947
+ ["Hello World"], nil, nil, nil, 0)
948
+
949
+ @processor.execute(i)
950
+ $stdout.string.should eql("Hello World\n")
951
+ end
952
+
953
+ it "should as a return value set the variable indicated by the call with 1" do
954
+ # set up a routine at address $2000
955
+ @zork_memory.force_writeb(0x2000, 2)
956
+ @zork_memory.force_writew(0x2001, 0)
957
+ @zork_memory.force_writew(0x2003, 0)
958
+
959
+ # The packed address is 0x2000 / 2
960
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
961
+ [Gruesome::Z::OperandType::LARGE],
962
+ [0x1000], 128, nil, nil, 0)
963
+
964
+ @processor.execute(i)
965
+
966
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_RET,
967
+ [Gruesome::Z::OperandType::STRING],
968
+ ["Hello World"], nil, nil, nil, 0)
969
+
970
+ @processor.execute(i)
971
+
972
+ @zork_memory.readv(128).should eql(1)
973
+ end
974
+
975
+ it "should as a return value push 1 to the caller's stack when indicated" do
976
+ # set up a routine at address $2000
977
+ @zork_memory.force_writeb(0x2000, 2)
978
+ @zork_memory.force_writew(0x2001, 0)
979
+ @zork_memory.force_writew(0x2003, 0)
980
+ @zork_memory.writev(0, 11111)
981
+
982
+ # The packed address is 0x2000 / 2
983
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CALL,
984
+ [Gruesome::Z::OperandType::LARGE],
985
+ [0x1000], 0, nil, nil, 0)
986
+
987
+ @processor.execute(i)
988
+
989
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_RET,
990
+ [Gruesome::Z::OperandType::STRING],
991
+ ["Hello World"], nil, nil, nil, 0)
992
+
993
+ @processor.execute(i)
994
+
995
+ @zork_memory.readv(0).should eql(1)
996
+ @zork_memory.readv(0).should eql(11111)
997
+ end
998
+ end
999
+ end
1000
+
1001
+ describe "Output Instruction" do
1002
+ before(:each) do
1003
+ # We take over stdout so that we can see what it prints
1004
+ @stdout = $stdout
1005
+ $stdout = StringIO.new
1006
+ end
1007
+
1008
+ after(:each) do
1009
+ $stdout = @stdout
1010
+
1011
+ # The program counter should not be changed
1012
+ @zork_memory.program_counter.should eql(12345)
1013
+ end
1014
+
1015
+ describe "new_line" do
1016
+ it "should print a carriage return" do
1017
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::NEW_LINE,
1018
+ [], [], nil, nil, nil, 0)
1019
+ @processor.execute(i)
1020
+ $stdout.string.should eql("\n")
1021
+ end
1022
+ end
1023
+
1024
+ describe "print_char" do
1025
+ it "should print out the zchar given as an operand to stdout" do
1026
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_CHAR,
1027
+ [Gruesome::Z::OperandType::LARGE],
1028
+ [215], nil, nil, nil, 0)
1029
+
1030
+ @processor.execute(i)
1031
+ $stdout.string.should eql("\u00fe")
1032
+ end
1033
+ end
1034
+
1035
+ describe "print_num" do
1036
+ it "should print out a number given as an operand in decimal to stdout" do
1037
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_NUM,
1038
+ [Gruesome::Z::OperandType::LARGE],
1039
+ [12345], nil, nil, nil, 0)
1040
+
1041
+ @processor.execute(i)
1042
+ $stdout.string.should eql("12345")
1043
+ end
1044
+
1045
+ it "should print out a signed number given as an operand in decimal to stdout" do
1046
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_NUM,
1047
+ [Gruesome::Z::OperandType::LARGE],
1048
+ [-12345+65536], nil, nil, nil, 0)
1049
+
1050
+ @processor.execute(i)
1051
+ $stdout.string.should eql("-12345")
1052
+ end
1053
+ end
1054
+
1055
+ describe "print" do
1056
+ it "should print out the string given as an operand to stdout" do
1057
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT,
1058
+ [Gruesome::Z::OperandType::STRING],
1059
+ ["Hello World"], nil, nil, nil, 0)
1060
+
1061
+ @processor.execute(i)
1062
+ $stdout.string.should eql("Hello World")
1063
+ end
1064
+ end
1065
+
1066
+ describe "print_addr" do
1067
+ it "should print out the string located at the byte address given by the operand" do
1068
+ # 'grue' is written at 0x4291
1069
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_ADDR,
1070
+ [Gruesome::Z::OperandType::LARGE],
1071
+ [0x4291], nil, nil, nil, 0)
1072
+
1073
+ @processor.execute(i)
1074
+ $stdout.string.should eql("grue")
1075
+ end
1076
+ end
1077
+
1078
+ describe "print_paddr" do
1079
+ it "should print out the string located at the packed address given by the operand" do
1080
+ # 'ZORK I: The Great Underground Empire' is written at 0x6ee4 (packed: 0x3772)
1081
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_PADDR,
1082
+ [Gruesome::Z::OperandType::LARGE],
1083
+ [0x3772], nil, nil, nil, 0)
1084
+
1085
+ @processor.execute(i)
1086
+ $stdout.string[/(.*)\n/,1].should eql("ZORK I: The Great Underground Empire")
1087
+ end
1088
+ end
1089
+
1090
+ describe "log_shift" do
1091
+ it "should shift left when places is positive" do
1092
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::LOG_SHIFT,
1093
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1094
+ [-12345+65536, 2], 128, nil, nil, 0)
1095
+
1096
+ @processor.execute(i)
1097
+
1098
+ @zork_memory.readv(128).should eql((((-12345+65536) << 2) & 65535))
1099
+ end
1100
+
1101
+ it "should shift right when places is positive and not sign extend" do
1102
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::LOG_SHIFT,
1103
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1104
+ [-123+65536, -2+65536], 128, nil, nil, 0)
1105
+
1106
+ @processor.execute(i)
1107
+
1108
+ @zork_memory.readv(128).should eql(((-123+65536) >> 2))
1109
+ end
1110
+ end
1111
+
1112
+ describe "not" do
1113
+ it "should perform a logical negation on the operand and assign to the appropriate variable" do
1114
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::NOT,
1115
+ [Gruesome::Z::OperandType::LARGE],
1116
+ [12345], 128, nil, nil, 0)
1117
+
1118
+ @processor.execute(i)
1119
+
1120
+ @zork_memory.readv(128).should eql((~12345)+65536)
1121
+ end
1122
+ end
1123
+
1124
+ describe "and" do
1125
+ it "should bitwise and two signed shorts together and assign to the appropriate variable" do
1126
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::AND,
1127
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1128
+ [-12345+65536, 12344], 128, nil, nil, 0)
1129
+
1130
+ @processor.execute(i)
1131
+
1132
+ @zork_memory.readv(128).should eql((-12345 & 12344) & 65535)
1133
+ end
1134
+ end
1135
+
1136
+ describe "or" do
1137
+ it "should bitwise or two signed shorts together and assign to the appropriate variable" do
1138
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::OR,
1139
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1140
+ [-12345+65536, 12344], 128, nil, nil, 0)
1141
+
1142
+ @processor.execute(i)
1143
1143
 
1144
- @zork_memory.readv(128).should eql((-12345 | 12344) & 65535)
1145
- end
1146
- end
1144
+ @zork_memory.readv(128).should eql((-12345 | 12344) & 65535)
1145
+ end
1146
+ end
1147
1147
 
1148
- describe "add" do
1149
- it "should add two signed shorts together and assign to the appropriate variable" do
1150
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::ADD,
1151
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1152
- [-12345+65536, 12344], 128, nil, nil, 0)
1148
+ describe "add" do
1149
+ it "should add two signed shorts together and assign to the appropriate variable" do
1150
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::ADD,
1151
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1152
+ [-12345+65536, 12344], 128, nil, nil, 0)
1153
1153
 
1154
- @processor.execute(i)
1154
+ @processor.execute(i)
1155
1155
 
1156
- @zork_memory.readv(128).should eql(-1+65536)
1157
- end
1158
- end
1156
+ @zork_memory.readv(128).should eql(-1+65536)
1157
+ end
1158
+ end
1159
1159
 
1160
- describe "sub" do
1161
- it "should subtract two signed shorts together and assign to the appropriate variable" do
1162
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::SUB,
1163
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1164
- [-12345+65536, 12344], 128, nil, nil, 0)
1160
+ describe "sub" do
1161
+ it "should subtract two signed shorts together and assign to the appropriate variable" do
1162
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::SUB,
1163
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1164
+ [-12345+65536, 12344], 128, nil, nil, 0)
1165
1165
 
1166
- @processor.execute(i)
1166
+ @processor.execute(i)
1167
1167
 
1168
- @zork_memory.readv(128).should eql(-24689+65536)
1169
- end
1170
- end
1168
+ @zork_memory.readv(128).should eql(-24689+65536)
1169
+ end
1170
+ end
1171
1171
 
1172
- describe "mul" do
1173
- it "should multiply two signed shorts together and assign to the appropriate variable" do
1174
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::MUL,
1175
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1176
- [-12345+65536, 12344], 128, nil, nil, 0)
1172
+ describe "mul" do
1173
+ it "should multiply two signed shorts together and assign to the appropriate variable" do
1174
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::MUL,
1175
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1176
+ [-12345+65536, 12344], 128, nil, nil, 0)
1177
1177
 
1178
- @processor.execute(i)
1178
+ @processor.execute(i)
1179
1179
 
1180
- @zork_memory.readv(128).should eql(50056)
1181
- end
1182
- end
1180
+ @zork_memory.readv(128).should eql(50056)
1181
+ end
1182
+ end
1183
1183
 
1184
- describe "div" do
1185
- it "should divide one negative and one positive short together and assign to the appropriate variable" do
1186
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DIV,
1187
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1188
- [-11+65536, 2], 128, nil, nil, 0)
1184
+ describe "div" do
1185
+ it "should divide one negative and one positive short together and assign to the appropriate variable" do
1186
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DIV,
1187
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1188
+ [-11+65536, 2], 128, nil, nil, 0)
1189
1189
 
1190
- @processor.execute(i)
1190
+ @processor.execute(i)
1191
1191
 
1192
- @zork_memory.readv(128).should eql(-5+65536)
1193
- end
1192
+ @zork_memory.readv(128).should eql(-5+65536)
1193
+ end
1194
1194
 
1195
- it "should divide one positive and one negative short together and assign to the appropriate variable" do
1196
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DIV,
1197
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1198
- [11, -2+65536], 128, nil, nil, 0)
1195
+ it "should divide one positive and one negative short together and assign to the appropriate variable" do
1196
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DIV,
1197
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1198
+ [11, -2+65536], 128, nil, nil, 0)
1199
1199
 
1200
- @processor.execute(i)
1200
+ @processor.execute(i)
1201
1201
 
1202
- @zork_memory.readv(128).should eql(-5+65536)
1203
- end
1202
+ @zork_memory.readv(128).should eql(-5+65536)
1203
+ end
1204
1204
 
1205
- it "should divide two positive shorts together and assign to the appropriate variable" do
1206
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DIV,
1207
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1208
- [11, 2], 128, nil, nil, 0)
1205
+ it "should divide two positive shorts together and assign to the appropriate variable" do
1206
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DIV,
1207
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1208
+ [11, 2], 128, nil, nil, 0)
1209
1209
 
1210
- @processor.execute(i)
1210
+ @processor.execute(i)
1211
1211
 
1212
- @zork_memory.readv(128).should eql(5)
1213
- end
1212
+ @zork_memory.readv(128).should eql(5)
1213
+ end
1214
1214
 
1215
- it "should divide two negative shorts together and assign to the appropriate variable" do
1216
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DIV,
1217
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1218
- [-11+65536, -2+65536], 128, nil, nil, 0)
1215
+ it "should divide two negative shorts together and assign to the appropriate variable" do
1216
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DIV,
1217
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1218
+ [-11+65536, -2+65536], 128, nil, nil, 0)
1219
1219
 
1220
- @processor.execute(i)
1220
+ @processor.execute(i)
1221
1221
 
1222
- @zork_memory.readv(128).should eql(5)
1223
- end
1224
- end
1222
+ @zork_memory.readv(128).should eql(5)
1223
+ end
1224
+ end
1225
1225
 
1226
- describe "mul" do
1227
- it "should modulo one negative and one positive short together and assign to the appropriate variable" do
1228
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::MOD,
1229
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1230
- [-13+65536, 5], 128, nil, nil, 0)
1226
+ describe "mul" do
1227
+ it "should modulo one negative and one positive short together and assign to the appropriate variable" do
1228
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::MOD,
1229
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1230
+ [-13+65536, 5], 128, nil, nil, 0)
1231
1231
 
1232
- @processor.execute(i)
1232
+ @processor.execute(i)
1233
1233
 
1234
- @zork_memory.readv(128).should eql(-3+65536)
1235
- end
1234
+ @zork_memory.readv(128).should eql(-3+65536)
1235
+ end
1236
1236
 
1237
- it "should modulo one positive and one negative short together and assign to the appropriate variable" do
1238
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::MOD,
1239
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1240
- [13, -5+65536], 128, nil, nil, 0)
1237
+ it "should modulo one positive and one negative short together and assign to the appropriate variable" do
1238
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::MOD,
1239
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1240
+ [13, -5+65536], 128, nil, nil, 0)
1241
1241
 
1242
- @processor.execute(i)
1242
+ @processor.execute(i)
1243
1243
 
1244
- @zork_memory.readv(128).should eql(3)
1245
- end
1244
+ @zork_memory.readv(128).should eql(3)
1245
+ end
1246
1246
 
1247
- it "should modulo two positive shorts together and assign to the appropriate variable" do
1248
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::MOD,
1249
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1250
- [13, 5], 128, nil, nil, 0)
1247
+ it "should modulo two positive shorts together and assign to the appropriate variable" do
1248
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::MOD,
1249
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1250
+ [13, 5], 128, nil, nil, 0)
1251
1251
 
1252
- @processor.execute(i)
1252
+ @processor.execute(i)
1253
1253
 
1254
- @zork_memory.readv(128).should eql(3)
1255
- end
1254
+ @zork_memory.readv(128).should eql(3)
1255
+ end
1256
1256
 
1257
- it "should modulo two negative shorts together and assign to the appropriate variable" do
1258
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::MOD,
1259
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1260
- [-13+65536, -5+65536], 128, nil, nil, 0)
1257
+ it "should modulo two negative shorts together and assign to the appropriate variable" do
1258
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::MOD,
1259
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1260
+ [-13+65536, -5+65536], 128, nil, nil, 0)
1261
1261
 
1262
- @processor.execute(i)
1262
+ @processor.execute(i)
1263
1263
 
1264
- @zork_memory.readv(128).should eql(-3+65536)
1265
- end
1266
- end
1267
- end
1264
+ @zork_memory.readv(128).should eql(-3+65536)
1265
+ end
1266
+ end
1267
+ end
1268
1268
 
1269
- describe "Object" do
1270
- before(:each) do
1271
- # Build object table
1272
- @zork_memory.force_writew(0x0a, 0x200)
1269
+ describe "Object" do
1270
+ before(:each) do
1271
+ # Build object table
1272
+ @zork_memory.force_writew(0x0a, 0x200)
1273
1273
 
1274
- # Build property defaults (for versions 1-3)
1275
- # Each property will have the default value as
1276
- # equally the property number (remember properties
1277
- # start counting at 1)
1278
- 31.times do |i|
1279
- @zork_memory.force_writew(0x200 + (i*2), i+1)
1280
- end
1281
- addr = 0x200 + (31 * 2)
1274
+ # Build property defaults (for versions 1-3)
1275
+ # Each property will have the default value as
1276
+ # equally the property number (remember properties
1277
+ # start counting at 1)
1278
+ 31.times do |i|
1279
+ @zork_memory.force_writew(0x200 + (i*2), i+1)
1280
+ end
1281
+ addr = 0x200 + (31 * 2)
1282
1282
 
1283
- # Build a couple of objects
1283
+ # Build a couple of objects
1284
1284
 
1285
- # Object #1
1285
+ # Object #1
1286
1286
 
1287
- # Attributes: 2, 3, 10, 31
1288
- # Parent: nil
1289
- # Sibling: nil
1290
- # Child: #2
1287
+ # Attributes: 2, 3, 10, 31
1288
+ # Parent: nil
1289
+ # Sibling: nil
1290
+ # Child: #2
1291
1291
 
1292
- @zork_memory.force_writeb(addr+0, 0b00110000)
1293
- @zork_memory.force_writeb(addr+1, 0b00100000)
1294
- @zork_memory.force_writeb(addr+2, 0b00000000)
1295
- @zork_memory.force_writeb(addr+3, 0b00000001)
1292
+ @zork_memory.force_writeb(addr+0, 0b00110000)
1293
+ @zork_memory.force_writeb(addr+1, 0b00100000)
1294
+ @zork_memory.force_writeb(addr+2, 0b00000000)
1295
+ @zork_memory.force_writeb(addr+3, 0b00000001)
1296
1296
 
1297
- @zork_memory.force_writeb(addr+4, 0)
1298
- @zork_memory.force_writeb(addr+5, 0)
1299
- @zork_memory.force_writeb(addr+6, 2)
1297
+ @zork_memory.force_writeb(addr+4, 0)
1298
+ @zork_memory.force_writeb(addr+5, 0)
1299
+ @zork_memory.force_writeb(addr+6, 2)
1300
1300
 
1301
- @zork_memory.force_writew(addr+7, 0x300)
1301
+ @zork_memory.force_writew(addr+7, 0x300)
1302
1302
 
1303
- addr += 9
1303
+ addr += 9
1304
1304
 
1305
- # Object #2
1305
+ # Object #2
1306
1306
 
1307
- # Attributes: 5, 7, 11, 18, 25
1308
- # Parent: #1
1309
- # Sibling: #3
1310
- # Child: nil
1307
+ # Attributes: 5, 7, 11, 18, 25
1308
+ # Parent: #1
1309
+ # Sibling: #3
1310
+ # Child: nil
1311
1311
 
1312
- @zork_memory.force_writeb(addr+0, 0b00000101)
1313
- @zork_memory.force_writeb(addr+1, 0b00010000)
1314
- @zork_memory.force_writeb(addr+2, 0b00100000)
1315
- @zork_memory.force_writeb(addr+3, 0b01000001)
1312
+ @zork_memory.force_writeb(addr+0, 0b00000101)
1313
+ @zork_memory.force_writeb(addr+1, 0b00010000)
1314
+ @zork_memory.force_writeb(addr+2, 0b00100000)
1315
+ @zork_memory.force_writeb(addr+3, 0b01000001)
1316
1316
 
1317
- @zork_memory.force_writeb(addr+4, 1)
1318
- @zork_memory.force_writeb(addr+5, 3)
1319
- @zork_memory.force_writeb(addr+6, 0)
1320
-
1321
- @zork_memory.force_writew(addr+7, 0x300)
1322
-
1323
- addr += 9
1324
-
1325
- # Object #3
1326
-
1327
- # Attributes: 0
1328
- # Parent: #1
1329
- # Sibling: #2
1330
- # Child: nil
1317
+ @zork_memory.force_writeb(addr+4, 1)
1318
+ @zork_memory.force_writeb(addr+5, 3)
1319
+ @zork_memory.force_writeb(addr+6, 0)
1320
+
1321
+ @zork_memory.force_writew(addr+7, 0x300)
1322
+
1323
+ addr += 9
1324
+
1325
+ # Object #3
1326
+
1327
+ # Attributes: 0
1328
+ # Parent: #1
1329
+ # Sibling: #2
1330
+ # Child: nil
1331
1331
 
1332
- @zork_memory.force_writeb(addr+0, 0b10000000)
1333
- @zork_memory.force_writeb(addr+1, 0b00000000)
1334
- @zork_memory.force_writeb(addr+2, 0b00000000)
1335
- @zork_memory.force_writeb(addr+3, 0b00000000)
1336
-
1337
- @zork_memory.force_writeb(addr+4, 1)
1338
- @zork_memory.force_writeb(addr+5, 2)
1339
- @zork_memory.force_writeb(addr+6, 0)
1340
-
1341
- @zork_memory.force_writew(addr+7, 0x4290)
1342
-
1343
- addr += 9
1344
-
1345
- # Properties Table
1346
- #
1347
- # 'grue' is written at 0x4291
1348
- # So, lets abuse that
1349
- #
1350
- # Give the short-name a length of 4
1351
- @zork_memory.force_writeb(0x4290, 2)
1352
-
1353
- # Now the property list
1354
- written_size = (2 - 1) << 5
1355
- property_number = 15
1356
- @zork_memory.force_writeb(0x4295, written_size + property_number)
1357
- @zork_memory.force_writew(0x4296, 34567)
1358
-
1359
- written_size = (1 - 1) << 5
1360
- property_number = 20
1361
- @zork_memory.force_writeb(0x4298, written_size + property_number)
1362
- @zork_memory.force_writeb(0x4299, 123)
1363
-
1364
- # End list
1365
- @zork_memory.force_writeb(0x429a, 0)
1366
-
1367
- @object_table = Gruesome::Z::ObjectTable.new(@zork_memory)
1368
-
1369
- # need to reinstantiate the processor
1370
- @processor = Gruesome::Z::Processor.new(@zork_memory)
1371
- end
1372
-
1373
- describe "Output Instruction" do
1374
- before(:each) do
1375
- # We take over stdout so that we can see what it prints
1376
- @stdout = $stdout
1377
- $stdout = StringIO.new
1378
- end
1379
-
1380
- after(:each) do
1381
- $stdout = @stdout
1382
-
1383
- # The program counter should not be changed
1384
- @zork_memory.program_counter.should eql(12345)
1385
- end
1386
-
1387
- describe "print_obj" do
1388
- it "should print to stdout out the short name of the object whose index is given as an operand" do
1389
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_OBJ,
1390
- [Gruesome::Z::OperandType::LARGE],
1391
- [3], nil, nil, nil, 0)
1392
-
1393
- @processor.execute(i)
1394
- $stdout.string.should eql("grue")
1395
- end
1396
- end
1397
- end
1398
-
1399
- describe "Branch Instruction" do
1400
- describe "get_child" do
1401
- # Note:
1402
- # - Object 1 has one child: Object 2
1403
- # - Object 2 has no children
1404
-
1405
- it "should not branch if the child object index of the requested object is 0" do
1406
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_CHILD,
1407
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1408
- [2], 128, 2000, true, 0)
1409
-
1410
- @processor.execute(i)
1411
- @zork_memory.program_counter.should eql(12345)
1412
- end
1413
-
1414
- it "should branch if the child object index exists for the requested object" do
1415
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_CHILD,
1416
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1417
- [1], 128, 2000, true, 0)
1418
- @processor.execute(i)
1419
- @zork_memory.program_counter.should eql(2000)
1420
- end
1421
-
1422
- it "should branch if the child object index of the requested object is 0 and condition is negated" do
1423
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_CHILD,
1424
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1425
- [2], 128, 2000, false, 0)
1426
-
1427
- @processor.execute(i)
1428
- @zork_memory.program_counter.should eql(2000)
1429
- end
1430
-
1431
- it "should not branch if the child object index exists for the requested object and condition is negated" do
1432
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_CHILD,
1433
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1434
- [1], 128, 2000, false, 0)
1435
- @processor.execute(i)
1436
- @zork_memory.program_counter.should eql(12345)
1437
- end
1438
-
1439
-
1440
- it "should store the child object index to the destination variable" do
1441
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_CHILD,
1442
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1443
- [1], 128, 2000, true, 0)
1444
- @processor.execute(i)
1445
- @zork_memory.readv(128).should eql(2)
1446
- end
1447
- end
1448
-
1449
- describe "get_sibling" do
1450
- # Note:
1451
- # - Object 1 has no siblings
1452
- # - Object 2 has one sibling: Object 3
1453
-
1454
- it "should not branch if the sibling object index of the requested object is 0" do
1455
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_SIBLING,
1456
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1457
- [1], 128, 2000, true, 0)
1458
-
1459
- @processor.execute(i)
1460
- @zork_memory.program_counter.should eql(12345)
1461
- end
1462
-
1463
- it "should branch if the sibling object index exists for the requested object" do
1464
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_SIBLING,
1465
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1466
- [2], 128, 2000, true, 0)
1467
- @processor.execute(i)
1468
- @zork_memory.program_counter.should eql(2000)
1469
- end
1470
-
1471
- it "should branch if the sibling object index of the requested object is 0 and condition is negated" do
1472
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_SIBLING,
1473
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1474
- [1], 128, 2000, false, 0)
1475
-
1476
- @processor.execute(i)
1477
- @zork_memory.program_counter.should eql(2000)
1478
- end
1479
-
1480
- it "should not branch if the sibling object index exists for the requested object and condition is negated" do
1481
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_SIBLING,
1482
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1483
- [2], 128, 2000, false, 0)
1484
- @processor.execute(i)
1485
- @zork_memory.program_counter.should eql(12345)
1486
- end
1487
-
1488
-
1489
- it "should store the sibling object index to the destination variable" do
1490
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_SIBLING,
1491
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1492
- [2], 128, 2000, true, 0)
1493
- @processor.execute(i)
1494
- @zork_memory.readv(128).should eql(3)
1495
- end
1496
- end
1497
-
1498
- describe "get_parent" do
1499
- # Note:
1500
- # - Object 1 has no parents
1501
- # - Object 2 has a parent: Object 1
1502
-
1503
- it "should store the parent object index to the destination variable" do
1504
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PARENT,
1505
- [Gruesome::Z::OperandType::LARGE],
1506
- [2], 128, 2000, true, 0)
1507
- @processor.execute(i)
1508
- @zork_memory.readv(128).should eql(1)
1509
- end
1510
- end
1511
-
1512
- describe "jin" do
1513
- # Note:
1514
- # - Object 1 has no parents
1515
- # - Object 2 has a parent: Object 1
1516
-
1517
- it "should not branch if the given object is not a child of the other" do
1518
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JIN,
1519
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1520
- [1, 2], 128, 2000, true, 0)
1521
-
1522
- @processor.execute(i)
1523
- @zork_memory.program_counter.should eql(12345)
1524
- end
1525
-
1526
- it "should branch if the given object is a child of the other" do
1527
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JIN,
1528
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1529
- [2,1], 128, 2000, true, 0)
1530
- @processor.execute(i)
1531
- @zork_memory.program_counter.should eql(2000)
1532
- end
1533
-
1534
- it "should branch if the given object is not a child of the other and condition is negated" do
1535
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JIN,
1536
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1537
- [1, 2], 128, 2000, false, 0)
1538
-
1539
- @processor.execute(i)
1540
- @zork_memory.program_counter.should eql(2000)
1541
- end
1542
-
1543
- it "should not branch if the given object is a child of the other and condition is negated" do
1544
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JIN,
1545
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1546
- [2,1], 128, 2000, false, 0)
1547
- @processor.execute(i)
1548
- @zork_memory.program_counter.should eql(12345)
1549
- end
1550
- end
1551
-
1552
- describe "test_attr" do
1553
- it "should branch if the object has the attribute set" do
1554
- @object_table.object_has_attribute?(1, 10).should eql(true)
1555
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST_ATTR,
1556
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1557
- [1, 10], nil, 2000, true, 0)
1558
-
1559
- @processor.execute(i)
1560
- @zork_memory.program_counter.should eql(2000)
1561
- end
1562
-
1563
- it "should not branch if the object does not have the attribute set" do
1564
- @object_table.object_has_attribute?(1, 11).should eql(false)
1565
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST_ATTR,
1566
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1567
- [1, 11], nil, 2000, true, 0)
1568
-
1569
- @processor.execute(i)
1570
- @zork_memory.program_counter.should eql(12345)
1571
- end
1572
-
1573
- it "should not branch if the first operand has all bits set that the second has set and condition is negated" do
1574
- @object_table.object_has_attribute?(1, 10).should eql(true)
1575
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST_ATTR,
1576
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1577
- [1, 10], nil, 2000, false, 0)
1578
-
1579
- @processor.execute(i)
1580
- @zork_memory.program_counter.should eql(12345)
1581
- end
1582
-
1583
- it "should branch if the first operand does not have all bits set that the second has set and condition is negated" do
1584
- @object_table.object_has_attribute?(1, 11).should eql(false)
1585
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST_ATTR,
1586
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1587
- [1, 11], nil, 2000, false, 0)
1588
-
1589
- @processor.execute(i)
1590
- @zork_memory.program_counter.should eql(2000)
1591
- end
1592
-
1593
- end
1594
- end
1595
-
1596
- describe "Instruction" do
1597
- after(:each) do
1598
- # The program counter should not be changed
1599
- @zork_memory.program_counter.should eql(12345)
1600
- end
1601
-
1602
- describe "put_prop" do
1603
- it "should set the property in the object's list when it is a byte" do
1604
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PUT_PROP,
1605
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1606
- [3, 20, 234], nil, nil, nil, 0)
1607
- @processor.execute(i)
1608
- @object_table.object_get_property_word(3, 20).should eql(234)
1609
- end
1610
-
1611
- it "should store the least significant part of the value to the property in the object's list when the property is a byte" do
1612
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PUT_PROP,
1613
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1614
- [3, 20, 0x5432], nil, nil, nil, 0)
1615
- @processor.execute(i)
1616
- @object_table.object_get_property_word(3, 20).should eql(0x32)
1617
- end
1618
-
1619
- it "should set the property in the object's list when it is a word" do
1620
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PUT_PROP,
1621
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1622
- [3, 15, 54321], nil, nil, nil, 0)
1623
- @processor.execute(i)
1624
- @object_table.object_get_property_word(3, 15).should eql(54321)
1625
- end
1626
-
1627
- # XXX: Check for halt when property does not exist
1628
- end
1629
-
1630
- describe "get_prop" do
1631
- it "should retrieve the property in the object's list when it is a byte" do
1632
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP,
1633
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1634
- [3, 20], 128, nil, nil, 0)
1635
- @processor.execute(i)
1636
- @zork_memory.readv(128).should eql(123)
1637
- end
1638
-
1639
- it "should retrieve the property in the object's list when it is a word" do
1640
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP,
1641
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1642
- [3, 15], 128, nil, nil, 0)
1643
- @processor.execute(i)
1644
- @zork_memory.readv(128).should eql(34567)
1645
- end
1646
-
1647
- it "should retrieve the default property when the object list does not have the property listed" do
1648
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP,
1649
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1650
- [3, 28], 128, nil, nil, 0)
1651
- @processor.execute(i)
1652
- @zork_memory.readv(128).should eql(28)
1653
- end
1654
- end
1655
-
1656
- describe "get_prop_addr" do
1657
- it "should retrieve the address of the property in the object's list" do
1658
- @zork_memory.writev(128, 11111)
1659
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP_ADDR,
1660
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1661
- [3, 20], 128, nil, nil, 0)
1662
- @processor.execute(i)
1663
- @zork_memory.readv(128).should eql(0x4299)
1664
- end
1665
-
1666
- it "should set the variable given to 0 when the property is not in the object's list" do
1667
- @zork_memory.writev(128, 11111)
1668
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP_ADDR,
1669
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1670
- [3, 28], 128, nil, nil, 0)
1671
- @processor.execute(i)
1672
- @zork_memory.readv(128).should eql(0)
1673
- end
1674
- end
1675
-
1676
- describe "get_prop_len" do
1677
- it "should retrieve the property data size for the byte property in the object's list" do
1678
- @zork_memory.writev(128, 11111)
1679
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP_LEN,
1680
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1681
- [0x4299], 128, nil, nil, 0)
1682
- @processor.execute(i)
1683
- @zork_memory.readv(128).should eql(1)
1684
- end
1685
-
1686
- it "should retrieve the property data size for the word property in the object's list" do
1687
- @zork_memory.writev(128, 11111)
1688
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP_LEN,
1689
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1690
- [0x4296], 128, nil, nil, 0)
1691
- @processor.execute(i)
1692
- @zork_memory.readv(128).should eql(2)
1693
- end
1694
-
1695
- it "should return 0 when the property address given is 0" do
1696
- @zork_memory.writev(128, 11111)
1697
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP_LEN,
1698
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1699
- [0], 128, nil, nil, 0)
1700
- @processor.execute(i)
1701
- @zork_memory.readv(128).should eql(0)
1702
- end
1703
- end
1704
-
1705
- describe "insert_obj" do
1706
- it "should insert the object given as the child of the other object given" do
1707
- @object_table.object_get_child(2).should eql(0)
1708
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INSERT_OBJ,
1709
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1710
- [3, 2], nil, nil, nil, 0)
1711
- @processor.execute(i)
1712
-
1713
- @object_table.object_get_child(2).should eql(3)
1714
- end
1715
-
1716
- it "should set the sibling of the given object as the previous child of the other object given" do
1717
- @object_table.object_get_sibling(3).should eql(2)
1718
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INSERT_OBJ,
1719
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1720
- [3, 2], nil, nil, nil, 0)
1721
- @processor.execute(i)
1722
-
1723
- @object_table.object_get_sibling(3).should eql(0)
1724
- end
1725
- end
1726
-
1727
- describe "remove_obj" do
1728
- it "should clear the parent of the given object" do
1729
- @object_table.object_get_parent(2).should eql(1)
1730
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::REMOVE_OBJ,
1731
- [Gruesome::Z::OperandType::LARGE],
1732
- [2], nil, nil, nil, 0)
1733
- @processor.execute(i)
1734
-
1735
- @object_table.object_get_parent(2).should eql(0)
1736
- end
1737
- end
1738
-
1739
-
1740
- describe "clear_attr" do
1741
- it "should clear the attribute when it exists in the object attribute list without altering other attributes" do
1742
- @object_table.object_has_attribute?(2, 25).should eql(true)
1743
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CLEAR_ATTR,
1744
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1745
- [2, 25], nil, nil, nil, 0)
1746
- @processor.execute(i)
1747
-
1748
- @object_table.object_has_attribute?(2, 25).should eql(false)
1749
- @object_table.object_has_attribute?(2, 31).should eql(true)
1750
- end
1751
-
1752
- it "should do nothing when the attribute is already cleared" do
1753
- @object_table.object_has_attribute?(2, 26).should eql(false)
1754
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CLEAR_ATTR,
1755
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1756
- [2, 26], nil, nil, nil, 0)
1757
- @processor.execute(i)
1758
-
1759
- @object_table.object_has_attribute?(2, 26).should eql(false)
1760
- @object_table.object_has_attribute?(2, 31).should eql(true)
1761
- end
1762
- end
1763
-
1764
- describe "set_attr" do
1765
- it "should set the attribute when it exists in the object attribute list without altering other attributes" do
1766
- @object_table.object_has_attribute?(2, 26).should eql(false)
1767
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::SET_ATTR,
1768
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1769
- [2, 26], nil, nil, nil, 0)
1770
- @processor.execute(i)
1771
-
1772
- @object_table.object_has_attribute?(2, 26).should eql(true)
1773
- @object_table.object_has_attribute?(2, 31).should eql(true)
1774
- end
1775
-
1776
- it "should do nothing when the attribute is already set" do
1777
- @object_table.object_has_attribute?(2, 25).should eql(true)
1778
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::SET_ATTR,
1779
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1780
- [2, 25], nil, nil, nil, 0)
1781
- @processor.execute(i)
1782
-
1783
- @object_table.object_has_attribute?(2, 25).should eql(true)
1784
- @object_table.object_has_attribute?(2, 31).should eql(true)
1785
- end
1786
- end
1787
- end
1788
- end
1789
-
1790
- describe "Instruction" do
1791
- after(:each) do
1792
- # The program counter should not be changed
1793
- @zork_memory.program_counter.should eql(12345)
1794
- end
1795
-
1796
- describe "store" do
1797
- it "should store the value into the variable referenced by the operand" do
1798
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::STORE,
1799
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
1800
- [128, -13+65536], nil, nil, nil, 0)
1801
-
1802
- @processor.execute(i)
1803
-
1804
- @zork_memory.readv(128).should eql(-13+65536)
1805
- end
1806
-
1807
- it "should write to the stack in-place when variable %00 is used" do
1808
- @zork_memory.writev(0, 11111)
1809
- @zork_memory.writev(0, 12345)
1810
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::STORE,
1811
- [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
1812
- [0, -13+65536], nil, nil, nil, 0)
1813
-
1814
- @processor.execute(i)
1815
-
1816
- @zork_memory.readv(0).should eql(-13+65536)
1817
- @zork_memory.readv(0).should eql(11111)
1818
- end
1819
- end
1820
-
1821
- describe "storeb" do
1822
- it "should store the byte given into the byte address given by the operands providing base and offset" do
1823
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::STOREB,
1824
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1825
- [2000, 100, 123], nil, nil, nil, 0)
1826
-
1827
- @processor.execute(i)
1828
-
1829
- @zork_memory.force_readb(2000+100).should eql(123)
1830
- end
1831
- end
1832
-
1833
- describe "storew" do
1834
- it "should store the word given into the byte address given by the operands providing base and offset" do
1835
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::STOREW,
1836
- [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1837
- [2000, 100, 12345], nil, nil, nil, 0)
1838
-
1839
- @processor.execute(i)
1840
-
1841
- @zork_memory.force_readw(2000+200).should eql(12345)
1842
- end
1843
- end
1844
-
1845
- describe "pull" do
1846
- it "should pop the value from the stack that was most recently pushed" do
1847
- @zork_memory.writev(0, 23456)
1848
- @zork_memory.writev(0, 34567)
1849
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PULL,
1850
- [Gruesome::Z::OperandType::VARIABLE], [128], nil, nil, nil, 0)
1851
-
1852
- @processor.execute(i)
1853
- @zork_memory.readv(128).should eql(34567)
1854
- @zork_memory.readv(0).should eql(23456)
1855
- end
1856
-
1857
- it "should not change the stack if the given variable is %00" do
1858
- @zork_memory.writev(0, 23456)
1859
- @zork_memory.writev(0, 34567)
1860
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PULL,
1861
- [Gruesome::Z::OperandType::VARIABLE], [0], nil, nil, nil, 0)
1862
-
1863
- @processor.execute(i)
1864
- @zork_memory.readv(0).should eql(34567)
1865
- @zork_memory.readv(0).should eql(23456)
1866
- end
1867
- end
1868
-
1869
- describe "push" do
1870
- it "should push the value on the stack such that a read of variable %00 will yield that value" do
1871
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PUSH,
1872
- [Gruesome::Z::OperandType::LARGE],
1873
- [23456], nil, nil, nil, 0)
1874
-
1875
- @processor.execute(i)
1876
-
1877
- @zork_memory.readv(0).should eql(23456)
1878
- end
1879
- end
1880
-
1881
- describe "pop" do
1882
- it "should throw away the most recently pushed item on the stack" do
1883
- @zork_memory.writev(0, 23456)
1884
- @zork_memory.writev(0, 34567)
1885
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::POP,
1886
- [], [], nil, nil, nil, 0)
1887
-
1888
- @processor.execute(i)
1889
- @zork_memory.readv(0).should eql(23456)
1890
- end
1891
- end
1892
-
1893
- describe "dec" do
1894
- it "should decrement the value in the variable given as the operand" do
1895
- @zork_memory.writev(128, 12345)
1896
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC,
1897
- [Gruesome::Z::OperandType::VARIABLE],
1898
- [128], nil, nil, nil, 0)
1899
- @processor.execute(i)
1900
- @zork_memory.readv(128).should eql(12344)
1901
- end
1902
-
1903
- it "should consider the value signed and decrement 0 to -1" do
1904
- @zork_memory.writev(128, 0)
1905
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC,
1906
- [Gruesome::Z::OperandType::VARIABLE],
1907
- [128], nil, nil, nil, 0)
1908
- @processor.execute(i)
1909
- @zork_memory.readv(128).should eql(-1+65536)
1910
- end
1911
-
1912
- it "should edit the value on the stack in place" do
1913
- @zork_memory.writev(0, 11111)
1914
- @zork_memory.writev(0, 12345)
1915
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC,
1916
- [Gruesome::Z::OperandType::VARIABLE],
1917
- [0], nil, nil, nil, 0)
1918
- @processor.execute(i)
1919
- @zork_memory.readv(0).should eql(12344)
1920
- @zork_memory.readv(0).should eql(11111)
1921
- end
1922
- end
1923
-
1924
- describe "inc" do
1925
- it "should increment the value in the variable given as the operand" do
1926
- @zork_memory.writev(128, 12345)
1927
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC,
1928
- [Gruesome::Z::OperandType::VARIABLE],
1929
- [128], nil, nil, nil, 0)
1930
- @processor.execute(i)
1931
- @zork_memory.readv(128).should eql(12346)
1932
- end
1933
-
1934
- it "should consider the value signed and increment -1 to 0" do
1935
- @zork_memory.writev(128, -1+65536)
1936
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC,
1937
- [Gruesome::Z::OperandType::VARIABLE],
1938
- [128], nil, nil, nil, 0)
1939
- @processor.execute(i)
1940
- @zork_memory.readv(128).should eql(0)
1941
- end
1942
-
1943
- it "should edit the value on the stack in place" do
1944
- @zork_memory.writev(0, 11111)
1945
- @zork_memory.writev(0, 12345)
1946
- i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC,
1947
- [Gruesome::Z::OperandType::VARIABLE],
1948
- [0], nil, nil, nil, 0)
1949
- @processor.execute(i)
1950
- @zork_memory.readv(0).should eql(12346)
1951
- @zork_memory.readv(0).should eql(11111)
1952
- end
1953
- end
1954
- end
1955
- end
1332
+ @zork_memory.force_writeb(addr+0, 0b10000000)
1333
+ @zork_memory.force_writeb(addr+1, 0b00000000)
1334
+ @zork_memory.force_writeb(addr+2, 0b00000000)
1335
+ @zork_memory.force_writeb(addr+3, 0b00000000)
1336
+
1337
+ @zork_memory.force_writeb(addr+4, 1)
1338
+ @zork_memory.force_writeb(addr+5, 2)
1339
+ @zork_memory.force_writeb(addr+6, 0)
1340
+
1341
+ @zork_memory.force_writew(addr+7, 0x4290)
1342
+
1343
+ addr += 9
1344
+
1345
+ # Properties Table
1346
+ #
1347
+ # 'grue' is written at 0x4291
1348
+ # So, lets abuse that
1349
+ #
1350
+ # Give the short-name a length of 4
1351
+ @zork_memory.force_writeb(0x4290, 2)
1352
+
1353
+ # Now the property list
1354
+ written_size = (2 - 1) << 5
1355
+ property_number = 15
1356
+ @zork_memory.force_writeb(0x4295, written_size + property_number)
1357
+ @zork_memory.force_writew(0x4296, 34567)
1358
+
1359
+ written_size = (1 - 1) << 5
1360
+ property_number = 20
1361
+ @zork_memory.force_writeb(0x4298, written_size + property_number)
1362
+ @zork_memory.force_writeb(0x4299, 123)
1363
+
1364
+ # End list
1365
+ @zork_memory.force_writeb(0x429a, 0)
1366
+
1367
+ @object_table = Gruesome::Z::ObjectTable.new(@zork_memory)
1368
+
1369
+ # need to reinstantiate the processor
1370
+ @processor = Gruesome::Z::Processor.new(@zork_memory)
1371
+ end
1372
+
1373
+ describe "Output Instruction" do
1374
+ before(:each) do
1375
+ # We take over stdout so that we can see what it prints
1376
+ @stdout = $stdout
1377
+ $stdout = StringIO.new
1378
+ end
1379
+
1380
+ after(:each) do
1381
+ $stdout = @stdout
1382
+
1383
+ # The program counter should not be changed
1384
+ @zork_memory.program_counter.should eql(12345)
1385
+ end
1386
+
1387
+ describe "print_obj" do
1388
+ it "should print to stdout out the short name of the object whose index is given as an operand" do
1389
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PRINT_OBJ,
1390
+ [Gruesome::Z::OperandType::LARGE],
1391
+ [3], nil, nil, nil, 0)
1392
+
1393
+ @processor.execute(i)
1394
+ $stdout.string.should eql("grue")
1395
+ end
1396
+ end
1397
+ end
1398
+
1399
+ describe "Branch Instruction" do
1400
+ describe "get_child" do
1401
+ # Note:
1402
+ # - Object 1 has one child: Object 2
1403
+ # - Object 2 has no children
1404
+
1405
+ it "should not branch if the child object index of the requested object is 0" do
1406
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_CHILD,
1407
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1408
+ [2], 128, 2000, true, 0)
1409
+
1410
+ @processor.execute(i)
1411
+ @zork_memory.program_counter.should eql(12345)
1412
+ end
1413
+
1414
+ it "should branch if the child object index exists for the requested object" do
1415
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_CHILD,
1416
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1417
+ [1], 128, 2000, true, 0)
1418
+ @processor.execute(i)
1419
+ @zork_memory.program_counter.should eql(2000)
1420
+ end
1421
+
1422
+ it "should branch if the child object index of the requested object is 0 and condition is negated" do
1423
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_CHILD,
1424
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1425
+ [2], 128, 2000, false, 0)
1426
+
1427
+ @processor.execute(i)
1428
+ @zork_memory.program_counter.should eql(2000)
1429
+ end
1430
+
1431
+ it "should not branch if the child object index exists for the requested object and condition is negated" do
1432
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_CHILD,
1433
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1434
+ [1], 128, 2000, false, 0)
1435
+ @processor.execute(i)
1436
+ @zork_memory.program_counter.should eql(12345)
1437
+ end
1438
+
1439
+
1440
+ it "should store the child object index to the destination variable" do
1441
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_CHILD,
1442
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1443
+ [1], 128, 2000, true, 0)
1444
+ @processor.execute(i)
1445
+ @zork_memory.readv(128).should eql(2)
1446
+ end
1447
+ end
1448
+
1449
+ describe "get_sibling" do
1450
+ # Note:
1451
+ # - Object 1 has no siblings
1452
+ # - Object 2 has one sibling: Object 3
1453
+
1454
+ it "should not branch if the sibling object index of the requested object is 0" do
1455
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_SIBLING,
1456
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1457
+ [1], 128, 2000, true, 0)
1458
+
1459
+ @processor.execute(i)
1460
+ @zork_memory.program_counter.should eql(12345)
1461
+ end
1462
+
1463
+ it "should branch if the sibling object index exists for the requested object" do
1464
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_SIBLING,
1465
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1466
+ [2], 128, 2000, true, 0)
1467
+ @processor.execute(i)
1468
+ @zork_memory.program_counter.should eql(2000)
1469
+ end
1470
+
1471
+ it "should branch if the sibling object index of the requested object is 0 and condition is negated" do
1472
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_SIBLING,
1473
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1474
+ [1], 128, 2000, false, 0)
1475
+
1476
+ @processor.execute(i)
1477
+ @zork_memory.program_counter.should eql(2000)
1478
+ end
1479
+
1480
+ it "should not branch if the sibling object index exists for the requested object and condition is negated" do
1481
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_SIBLING,
1482
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1483
+ [2], 128, 2000, false, 0)
1484
+ @processor.execute(i)
1485
+ @zork_memory.program_counter.should eql(12345)
1486
+ end
1487
+
1488
+
1489
+ it "should store the sibling object index to the destination variable" do
1490
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_SIBLING,
1491
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1492
+ [2], 128, 2000, true, 0)
1493
+ @processor.execute(i)
1494
+ @zork_memory.readv(128).should eql(3)
1495
+ end
1496
+ end
1497
+
1498
+ describe "get_parent" do
1499
+ # Note:
1500
+ # - Object 1 has no parents
1501
+ # - Object 2 has a parent: Object 1
1502
+
1503
+ it "should store the parent object index to the destination variable" do
1504
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PARENT,
1505
+ [Gruesome::Z::OperandType::LARGE],
1506
+ [2], 128, 2000, true, 0)
1507
+ @processor.execute(i)
1508
+ @zork_memory.readv(128).should eql(1)
1509
+ end
1510
+ end
1511
+
1512
+ describe "jin" do
1513
+ # Note:
1514
+ # - Object 1 has no parents
1515
+ # - Object 2 has a parent: Object 1
1516
+
1517
+ it "should not branch if the given object is not a child of the other" do
1518
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JIN,
1519
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1520
+ [1, 2], 128, 2000, true, 0)
1521
+
1522
+ @processor.execute(i)
1523
+ @zork_memory.program_counter.should eql(12345)
1524
+ end
1525
+
1526
+ it "should branch if the given object is a child of the other" do
1527
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JIN,
1528
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1529
+ [2,1], 128, 2000, true, 0)
1530
+ @processor.execute(i)
1531
+ @zork_memory.program_counter.should eql(2000)
1532
+ end
1533
+
1534
+ it "should branch if the given object is not a child of the other and condition is negated" do
1535
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JIN,
1536
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1537
+ [1, 2], 128, 2000, false, 0)
1538
+
1539
+ @processor.execute(i)
1540
+ @zork_memory.program_counter.should eql(2000)
1541
+ end
1542
+
1543
+ it "should not branch if the given object is a child of the other and condition is negated" do
1544
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::JIN,
1545
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1546
+ [2,1], 128, 2000, false, 0)
1547
+ @processor.execute(i)
1548
+ @zork_memory.program_counter.should eql(12345)
1549
+ end
1550
+ end
1551
+
1552
+ describe "test_attr" do
1553
+ it "should branch if the object has the attribute set" do
1554
+ @object_table.object_has_attribute?(1, 10).should eql(true)
1555
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST_ATTR,
1556
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1557
+ [1, 10], nil, 2000, true, 0)
1558
+
1559
+ @processor.execute(i)
1560
+ @zork_memory.program_counter.should eql(2000)
1561
+ end
1562
+
1563
+ it "should not branch if the object does not have the attribute set" do
1564
+ @object_table.object_has_attribute?(1, 11).should eql(false)
1565
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST_ATTR,
1566
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1567
+ [1, 11], nil, 2000, true, 0)
1568
+
1569
+ @processor.execute(i)
1570
+ @zork_memory.program_counter.should eql(12345)
1571
+ end
1572
+
1573
+ it "should not branch if the first operand has all bits set that the second has set and condition is negated" do
1574
+ @object_table.object_has_attribute?(1, 10).should eql(true)
1575
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST_ATTR,
1576
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1577
+ [1, 10], nil, 2000, false, 0)
1578
+
1579
+ @processor.execute(i)
1580
+ @zork_memory.program_counter.should eql(12345)
1581
+ end
1582
+
1583
+ it "should branch if the first operand does not have all bits set that the second has set and condition is negated" do
1584
+ @object_table.object_has_attribute?(1, 11).should eql(false)
1585
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::TEST_ATTR,
1586
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1587
+ [1, 11], nil, 2000, false, 0)
1588
+
1589
+ @processor.execute(i)
1590
+ @zork_memory.program_counter.should eql(2000)
1591
+ end
1592
+
1593
+ end
1594
+ end
1595
+
1596
+ describe "Instruction" do
1597
+ after(:each) do
1598
+ # The program counter should not be changed
1599
+ @zork_memory.program_counter.should eql(12345)
1600
+ end
1601
+
1602
+ describe "put_prop" do
1603
+ it "should set the property in the object's list when it is a byte" do
1604
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PUT_PROP,
1605
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1606
+ [3, 20, 234], nil, nil, nil, 0)
1607
+ @processor.execute(i)
1608
+ @object_table.object_get_property_word(3, 20).should eql(234)
1609
+ end
1610
+
1611
+ it "should store the least significant part of the value to the property in the object's list when the property is a byte" do
1612
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PUT_PROP,
1613
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1614
+ [3, 20, 0x5432], nil, nil, nil, 0)
1615
+ @processor.execute(i)
1616
+ @object_table.object_get_property_word(3, 20).should eql(0x32)
1617
+ end
1618
+
1619
+ it "should set the property in the object's list when it is a word" do
1620
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PUT_PROP,
1621
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1622
+ [3, 15, 54321], nil, nil, nil, 0)
1623
+ @processor.execute(i)
1624
+ @object_table.object_get_property_word(3, 15).should eql(54321)
1625
+ end
1626
+
1627
+ # XXX: Check for halt when property does not exist
1628
+ end
1629
+
1630
+ describe "get_prop" do
1631
+ it "should retrieve the property in the object's list when it is a byte" do
1632
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP,
1633
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1634
+ [3, 20], 128, nil, nil, 0)
1635
+ @processor.execute(i)
1636
+ @zork_memory.readv(128).should eql(123)
1637
+ end
1638
+
1639
+ it "should retrieve the property in the object's list when it is a word" do
1640
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP,
1641
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1642
+ [3, 15], 128, nil, nil, 0)
1643
+ @processor.execute(i)
1644
+ @zork_memory.readv(128).should eql(34567)
1645
+ end
1646
+
1647
+ it "should retrieve the default property when the object list does not have the property listed" do
1648
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP,
1649
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1650
+ [3, 28], 128, nil, nil, 0)
1651
+ @processor.execute(i)
1652
+ @zork_memory.readv(128).should eql(28)
1653
+ end
1654
+ end
1655
+
1656
+ describe "get_prop_addr" do
1657
+ it "should retrieve the address of the property in the object's list" do
1658
+ @zork_memory.writev(128, 11111)
1659
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP_ADDR,
1660
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1661
+ [3, 20], 128, nil, nil, 0)
1662
+ @processor.execute(i)
1663
+ @zork_memory.readv(128).should eql(0x4299)
1664
+ end
1665
+
1666
+ it "should set the variable given to 0 when the property is not in the object's list" do
1667
+ @zork_memory.writev(128, 11111)
1668
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP_ADDR,
1669
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1670
+ [3, 28], 128, nil, nil, 0)
1671
+ @processor.execute(i)
1672
+ @zork_memory.readv(128).should eql(0)
1673
+ end
1674
+ end
1675
+
1676
+ describe "get_prop_len" do
1677
+ it "should retrieve the property data size for the byte property in the object's list" do
1678
+ @zork_memory.writev(128, 11111)
1679
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP_LEN,
1680
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1681
+ [0x4299], 128, nil, nil, 0)
1682
+ @processor.execute(i)
1683
+ @zork_memory.readv(128).should eql(1)
1684
+ end
1685
+
1686
+ it "should retrieve the property data size for the word property in the object's list" do
1687
+ @zork_memory.writev(128, 11111)
1688
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP_LEN,
1689
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1690
+ [0x4296], 128, nil, nil, 0)
1691
+ @processor.execute(i)
1692
+ @zork_memory.readv(128).should eql(2)
1693
+ end
1694
+
1695
+ it "should return 0 when the property address given is 0" do
1696
+ @zork_memory.writev(128, 11111)
1697
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::GET_PROP_LEN,
1698
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1699
+ [0], 128, nil, nil, 0)
1700
+ @processor.execute(i)
1701
+ @zork_memory.readv(128).should eql(0)
1702
+ end
1703
+ end
1704
+
1705
+ describe "insert_obj" do
1706
+ it "should insert the object given as the child of the other object given" do
1707
+ @object_table.object_get_child(2).should eql(0)
1708
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INSERT_OBJ,
1709
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1710
+ [3, 2], nil, nil, nil, 0)
1711
+ @processor.execute(i)
1712
+
1713
+ @object_table.object_get_child(2).should eql(3)
1714
+ end
1715
+
1716
+ it "should set the sibling of the given object as the previous child of the other object given" do
1717
+ @object_table.object_get_sibling(3).should eql(2)
1718
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INSERT_OBJ,
1719
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1720
+ [3, 2], nil, nil, nil, 0)
1721
+ @processor.execute(i)
1722
+
1723
+ @object_table.object_get_sibling(3).should eql(0)
1724
+ end
1725
+ end
1726
+
1727
+ describe "remove_obj" do
1728
+ it "should clear the parent of the given object" do
1729
+ @object_table.object_get_parent(2).should eql(1)
1730
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::REMOVE_OBJ,
1731
+ [Gruesome::Z::OperandType::LARGE],
1732
+ [2], nil, nil, nil, 0)
1733
+ @processor.execute(i)
1734
+
1735
+ @object_table.object_get_parent(2).should eql(0)
1736
+ end
1737
+ end
1738
+
1739
+
1740
+ describe "clear_attr" do
1741
+ it "should clear the attribute when it exists in the object attribute list without altering other attributes" do
1742
+ @object_table.object_has_attribute?(2, 25).should eql(true)
1743
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CLEAR_ATTR,
1744
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1745
+ [2, 25], nil, nil, nil, 0)
1746
+ @processor.execute(i)
1747
+
1748
+ @object_table.object_has_attribute?(2, 25).should eql(false)
1749
+ @object_table.object_has_attribute?(2, 31).should eql(true)
1750
+ end
1751
+
1752
+ it "should do nothing when the attribute is already cleared" do
1753
+ @object_table.object_has_attribute?(2, 26).should eql(false)
1754
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::CLEAR_ATTR,
1755
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1756
+ [2, 26], nil, nil, nil, 0)
1757
+ @processor.execute(i)
1758
+
1759
+ @object_table.object_has_attribute?(2, 26).should eql(false)
1760
+ @object_table.object_has_attribute?(2, 31).should eql(true)
1761
+ end
1762
+ end
1763
+
1764
+ describe "set_attr" do
1765
+ it "should set the attribute when it exists in the object attribute list without altering other attributes" do
1766
+ @object_table.object_has_attribute?(2, 26).should eql(false)
1767
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::SET_ATTR,
1768
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1769
+ [2, 26], nil, nil, nil, 0)
1770
+ @processor.execute(i)
1771
+
1772
+ @object_table.object_has_attribute?(2, 26).should eql(true)
1773
+ @object_table.object_has_attribute?(2, 31).should eql(true)
1774
+ end
1775
+
1776
+ it "should do nothing when the attribute is already set" do
1777
+ @object_table.object_has_attribute?(2, 25).should eql(true)
1778
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::SET_ATTR,
1779
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1780
+ [2, 25], nil, nil, nil, 0)
1781
+ @processor.execute(i)
1782
+
1783
+ @object_table.object_has_attribute?(2, 25).should eql(true)
1784
+ @object_table.object_has_attribute?(2, 31).should eql(true)
1785
+ end
1786
+ end
1787
+ end
1788
+ end
1789
+
1790
+ describe "Instruction" do
1791
+ after(:each) do
1792
+ # The program counter should not be changed
1793
+ @zork_memory.program_counter.should eql(12345)
1794
+ end
1795
+
1796
+ describe "store" do
1797
+ it "should store the value into the variable referenced by the operand" do
1798
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::STORE,
1799
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
1800
+ [128, -13+65536], nil, nil, nil, 0)
1801
+
1802
+ @processor.execute(i)
1803
+
1804
+ @zork_memory.readv(128).should eql(-13+65536)
1805
+ end
1806
+
1807
+ it "should write to the stack in-place when variable %00 is used" do
1808
+ @zork_memory.writev(0, 11111)
1809
+ @zork_memory.writev(0, 12345)
1810
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::STORE,
1811
+ [Gruesome::Z::OperandType::VARIABLE, Gruesome::Z::OperandType::LARGE],
1812
+ [0, -13+65536], nil, nil, nil, 0)
1813
+
1814
+ @processor.execute(i)
1815
+
1816
+ @zork_memory.readv(0).should eql(-13+65536)
1817
+ @zork_memory.readv(0).should eql(11111)
1818
+ end
1819
+ end
1820
+
1821
+ describe "storeb" do
1822
+ it "should store the byte given into the byte address given by the operands providing base and offset" do
1823
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::STOREB,
1824
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1825
+ [2000, 100, 123], nil, nil, nil, 0)
1826
+
1827
+ @processor.execute(i)
1828
+
1829
+ @zork_memory.force_readb(2000+100).should eql(123)
1830
+ end
1831
+ end
1832
+
1833
+ describe "storew" do
1834
+ it "should store the word given into the byte address given by the operands providing base and offset" do
1835
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::STOREW,
1836
+ [Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE, Gruesome::Z::OperandType::LARGE],
1837
+ [2000, 100, 12345], nil, nil, nil, 0)
1838
+
1839
+ @processor.execute(i)
1840
+
1841
+ @zork_memory.force_readw(2000+200).should eql(12345)
1842
+ end
1843
+ end
1844
+
1845
+ describe "pull" do
1846
+ it "should pop the value from the stack that was most recently pushed" do
1847
+ @zork_memory.writev(0, 23456)
1848
+ @zork_memory.writev(0, 34567)
1849
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PULL,
1850
+ [Gruesome::Z::OperandType::VARIABLE], [128], nil, nil, nil, 0)
1851
+
1852
+ @processor.execute(i)
1853
+ @zork_memory.readv(128).should eql(34567)
1854
+ @zork_memory.readv(0).should eql(23456)
1855
+ end
1856
+
1857
+ it "should not change the stack if the given variable is %00" do
1858
+ @zork_memory.writev(0, 23456)
1859
+ @zork_memory.writev(0, 34567)
1860
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PULL,
1861
+ [Gruesome::Z::OperandType::VARIABLE], [0], nil, nil, nil, 0)
1862
+
1863
+ @processor.execute(i)
1864
+ @zork_memory.readv(0).should eql(34567)
1865
+ @zork_memory.readv(0).should eql(23456)
1866
+ end
1867
+ end
1868
+
1869
+ describe "push" do
1870
+ it "should push the value on the stack such that a read of variable %00 will yield that value" do
1871
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::PUSH,
1872
+ [Gruesome::Z::OperandType::LARGE],
1873
+ [23456], nil, nil, nil, 0)
1874
+
1875
+ @processor.execute(i)
1876
+
1877
+ @zork_memory.readv(0).should eql(23456)
1878
+ end
1879
+ end
1880
+
1881
+ describe "pop" do
1882
+ it "should throw away the most recently pushed item on the stack" do
1883
+ @zork_memory.writev(0, 23456)
1884
+ @zork_memory.writev(0, 34567)
1885
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::POP,
1886
+ [], [], nil, nil, nil, 0)
1887
+
1888
+ @processor.execute(i)
1889
+ @zork_memory.readv(0).should eql(23456)
1890
+ end
1891
+ end
1892
+
1893
+ describe "dec" do
1894
+ it "should decrement the value in the variable given as the operand" do
1895
+ @zork_memory.writev(128, 12345)
1896
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC,
1897
+ [Gruesome::Z::OperandType::VARIABLE],
1898
+ [128], nil, nil, nil, 0)
1899
+ @processor.execute(i)
1900
+ @zork_memory.readv(128).should eql(12344)
1901
+ end
1902
+
1903
+ it "should consider the value signed and decrement 0 to -1" do
1904
+ @zork_memory.writev(128, 0)
1905
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC,
1906
+ [Gruesome::Z::OperandType::VARIABLE],
1907
+ [128], nil, nil, nil, 0)
1908
+ @processor.execute(i)
1909
+ @zork_memory.readv(128).should eql(-1+65536)
1910
+ end
1911
+
1912
+ it "should edit the value on the stack in place" do
1913
+ @zork_memory.writev(0, 11111)
1914
+ @zork_memory.writev(0, 12345)
1915
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::DEC,
1916
+ [Gruesome::Z::OperandType::VARIABLE],
1917
+ [0], nil, nil, nil, 0)
1918
+ @processor.execute(i)
1919
+ @zork_memory.readv(0).should eql(12344)
1920
+ @zork_memory.readv(0).should eql(11111)
1921
+ end
1922
+ end
1923
+
1924
+ describe "inc" do
1925
+ it "should increment the value in the variable given as the operand" do
1926
+ @zork_memory.writev(128, 12345)
1927
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC,
1928
+ [Gruesome::Z::OperandType::VARIABLE],
1929
+ [128], nil, nil, nil, 0)
1930
+ @processor.execute(i)
1931
+ @zork_memory.readv(128).should eql(12346)
1932
+ end
1933
+
1934
+ it "should consider the value signed and increment -1 to 0" do
1935
+ @zork_memory.writev(128, -1+65536)
1936
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC,
1937
+ [Gruesome::Z::OperandType::VARIABLE],
1938
+ [128], nil, nil, nil, 0)
1939
+ @processor.execute(i)
1940
+ @zork_memory.readv(128).should eql(0)
1941
+ end
1942
+
1943
+ it "should edit the value on the stack in place" do
1944
+ @zork_memory.writev(0, 11111)
1945
+ @zork_memory.writev(0, 12345)
1946
+ i = Gruesome::Z::Instruction.new(Gruesome::Z::Opcode::INC,
1947
+ [Gruesome::Z::OperandType::VARIABLE],
1948
+ [0], nil, nil, nil, 0)
1949
+ @processor.execute(i)
1950
+ @zork_memory.readv(0).should eql(12346)
1951
+ @zork_memory.readv(0).should eql(11111)
1952
+ end
1953
+ end
1954
+ end
1955
+ end
1956
1956
  end