gruesome 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,390 +9,407 @@ require_relative 'dictionary'
9
9
  require_relative 'object_table'
10
10
 
11
11
  module Gruesome
12
- module Z
13
- class Processor
14
- def initialize(memory)
15
- @memory = memory
16
- @header = Header.new(@memory.contents)
17
- @abbreviation_table = AbbreviationTable.new(@memory)
18
- @object_table = ObjectTable.new(@memory)
19
- @dictionary = Dictionary.new(@memory)
20
- end
12
+ module Z
13
+ class Processor
14
+ def initialize(memory)
15
+ @memory = memory
16
+ @header = Header.new(@memory.contents)
17
+ @abbreviation_table = AbbreviationTable.new(@memory)
18
+ @object_table = ObjectTable.new(@memory)
19
+ @dictionary = Dictionary.new(@memory)
20
+ end
21
21
 
22
- def routine_call(address, arguments, result_variable = nil)
23
- if address == 0
24
- # special case, do not call, simply return false
25
- if result_variable != nil
26
- @memory.writev(result_variable, 0)
27
- end
28
- else
29
- return_addr = @memory.program_counter
30
- @memory.program_counter = address
22
+ def routine_call(address, arguments, result_variable = nil)
23
+ if address == 0
24
+ # special case, do not call, simply return false
25
+ if result_variable != nil
26
+ @memory.writev(result_variable, 0)
27
+ end
28
+ else
29
+ return_addr = @memory.program_counter
30
+ @memory.program_counter = address
31
31
 
32
- # read routine
33
- num_locals = @memory.force_readb(@memory.program_counter)
34
- @memory.program_counter += 1
32
+ # read routine
33
+ num_locals = @memory.force_readb(@memory.program_counter)
34
+ @memory.program_counter += 1
35
35
 
36
- # create environment
37
- @memory.push_routine(return_addr, num_locals, result_variable)
36
+ # create environment
37
+ @memory.push_routine(return_addr, num_locals, result_variable)
38
38
 
39
- if @header.version <= 4
40
- # read initial values when version 1-4
41
- (1..num_locals).each do |i|
42
- @memory.writev(i, @memory.force_readw(@memory.program_counter))
43
- @memory.program_counter += 2
44
- end
45
- else
46
- # reset local vars to 0
47
- (1..num_locals).each do |i|
48
- @memory.writev(i, 0)
49
- end
50
- end
39
+ if @header.version <= 4
40
+ # read initial values when version 1-4
41
+ (1..num_locals).each do |i|
42
+ @memory.writev(i, @memory.force_readw(@memory.program_counter))
43
+ @memory.program_counter += 2
44
+ end
45
+ else
46
+ # reset local vars to 0
47
+ (1..num_locals).each do |i|
48
+ @memory.writev(i, 0)
49
+ end
50
+ end
51
51
 
52
- # copy arguments over into locals
53
- idx = 1
54
- arguments.each do |i|
55
- @memory.writev(idx, i)
56
- idx += 1
57
- end
58
- end
59
- end
52
+ # copy arguments over into locals
53
+ idx = 1
54
+ arguments.each do |i|
55
+ @memory.writev(idx, i)
56
+ idx += 1
57
+ end
58
+ end
59
+ end
60
60
 
61
- def routine_return(result)
62
- frame = @memory.pop_routine
61
+ def routine_return(result)
62
+ frame = @memory.pop_routine
63
63
 
64
- if frame[:destination] != nil
65
- @memory.writev(frame[:destination], result)
66
- end
67
- @memory.program_counter = frame[:return_address]
68
- end
64
+ if frame[:destination] != nil
65
+ @memory.writev(frame[:destination], result)
66
+ end
67
+ @memory.program_counter = frame[:return_address]
68
+ end
69
69
 
70
- def branch(branch_to, branch_on, result)
71
- if (result == branch_on)
72
- if branch_to == 0
73
- routine_return(0)
74
- elsif branch_to == 1
75
- routine_return(1)
76
- else
77
- @memory.program_counter = branch_to
78
- # @memory.program_counter -= 2
79
- end
80
- end
81
- end
70
+ def branch(branch_to, branch_on, result)
71
+ if (result == branch_on)
72
+ if branch_to == 0
73
+ routine_return(0)
74
+ elsif branch_to == 1
75
+ routine_return(1)
76
+ else
77
+ @memory.program_counter = branch_to
78
+ # @memory.program_counter -= 2
79
+ end
80
+ end
81
+ end
82
82
 
83
- def execute(instruction)
84
- # Pull values from the variables if needed by the instruction
85
- # there are some exceptions for variable-by-reference instructions
86
- operands = instruction.operands.each_with_index.map do |operand, idx|
87
- if idx == 0 and Opcode.is_variable_by_reference?(instruction.opcode, @header.version)
88
- operand
89
- elsif instruction.types[idx] == OperandType::VARIABLE
90
- @memory.readv(operand)
91
- else
92
- operand
93
- end
94
- end
83
+ def execute(instruction)
84
+ # Pull values from the variables if needed by the instruction
85
+ # there are some exceptions for variable-by-reference instructions
86
+ operands = instruction.operands.each_with_index.map do |operand, idx|
87
+ if idx == 0 and Opcode.is_variable_by_reference?(instruction.opcode, @header.version)
88
+ operand
89
+ elsif instruction.types[idx] == OperandType::VARIABLE
90
+ @memory.readv(operand)
91
+ else
92
+ operand
93
+ end
94
+ end
95
95
 
96
- case instruction.opcode
97
- when Opcode::ART_SHIFT
98
- places = unsigned_to_signed(operands[1])
99
- if places < 0
100
- @memory.writev(instruction.destination, unsigned_to_signed(operands[0]) >> places.abs)
101
- else
102
- @memory.writev(instruction.destination, operands[0] << places)
103
- end
104
- when Opcode::CALL, Opcode::CALL_1N
105
- routine_call(@memory.packed_address_to_byte_address(operands[0]), operands[1..-1], instruction.destination)
106
- when Opcode::CLEAR_ATTR
107
- @object_table.object_clear_attribute(operands[0], operands[1])
108
- when Opcode::DEC
109
- @memory.writev(operands[0], unsigned_to_signed(@memory.readv(operands[0])) - 1)
110
- when Opcode::INC
111
- @memory.writev(operands[0], unsigned_to_signed(@memory.readv(operands[0])) + 1)
112
- when Opcode::INC_CHK
113
- new_value = unsigned_to_signed(@memory.readv(operands[0])) + 1
114
- @memory.writev(operands[0], new_value)
115
- result = new_value > unsigned_to_signed(operands[1])
116
- branch(instruction.branch_to, instruction.branch_on, result)
117
- when Opcode::DEC_CHK
118
- new_value = unsigned_to_signed(@memory.readv(operands[0])) - 1
119
- @memory.writev(operands[0], new_value)
120
- result = new_value < unsigned_to_signed(operands[1])
121
- branch(instruction.branch_to, instruction.branch_on, result)
122
- when Opcode::INSERT_OBJ
123
- @object_table.object_insert_object(operands[1], operands[0])
124
- when Opcode::GET_CHILD
125
- child = @object_table.object_get_child(operands[0])
126
- @memory.writev(instruction.destination, child)
127
- result = child != 0
128
- branch(instruction.branch_to, instruction.branch_on, result)
129
- when Opcode::GET_PARENT
130
- parent = @object_table.object_get_parent(operands[0])
131
- @memory.writev(instruction.destination, parent)
132
- when Opcode::GET_PROP
133
- prop = @object_table.object_get_property_word(operands[0], operands[1])
134
- @memory.writev(instruction.destination, prop)
135
- when Opcode::GET_PROP_ADDR
136
- prop = @object_table.object_get_property_addr(operands[0], operands[1])
137
- @memory.writev(instruction.destination, prop)
138
- when Opcode::GET_PROP_LEN
139
- if operands[0] == 0
140
- result = 0
141
- else
142
- result = @object_table.object_get_property_data_size_from_address(operands[0])
143
- end
144
- @memory.writev(instruction.destination, result)
145
- when Opcode::GET_SIBLING
146
- sibling = @object_table.object_get_sibling(operands[0])
147
- @memory.writev(instruction.destination, sibling)
148
- result = sibling != 0
149
- branch(instruction.branch_to, instruction.branch_on, result)
150
- when Opcode::JUMP, Opcode::PIRACY
151
- @memory.program_counter += unsigned_to_signed(operands[0])
152
- @memory.program_counter -= 2
153
- when Opcode::JE
154
- result = operands[1..-1].inject(false) { |result, element|
155
- result | (operands[0] == element)
156
- }
157
- branch(instruction.branch_to, instruction.branch_on, result)
158
- when Opcode::JG
159
- result = operands[1..-1].inject(false) { |result, element|
160
- result | (unsigned_to_signed(operands[0]) > unsigned_to_signed(element))
161
- }
162
- branch(instruction.branch_to, instruction.branch_on, result)
163
- when Opcode::JIN
164
- result = @object_table.object_get_parent(operands[0]) == operands[1]
165
- branch(instruction.branch_to, instruction.branch_on, result)
166
- when Opcode::JL
167
- result = operands[1..-1].inject(false) { |result, element|
168
- result | (unsigned_to_signed(operands[0]) < unsigned_to_signed(element))
169
- }
170
- branch(instruction.branch_to, instruction.branch_on, result)
171
- when Opcode::JZ
172
- result = operands[0] == 0
173
- branch(instruction.branch_to, instruction.branch_on, result)
174
- when Opcode::LOAD
175
- if operands[0] != instruction.destination
176
- @memory.writev(instruction.destination, @memory.readv(operands[0]))
96
+ case instruction.opcode
97
+ when Opcode::ART_SHIFT
98
+ places = unsigned_to_signed(operands[1])
99
+ if places < 0
100
+ @memory.writev(instruction.destination, unsigned_to_signed(operands[0]) >> places.abs)
101
+ else
102
+ @memory.writev(instruction.destination, operands[0] << places)
103
+ end
104
+ when Opcode::CALL, Opcode::CALL_1N
105
+ routine_call(@memory.packed_address_to_byte_address(operands[0]), operands[1..-1], instruction.destination)
106
+ when Opcode::CLEAR_ATTR
107
+ @object_table.object_clear_attribute(operands[0], operands[1])
108
+ when Opcode::DEC
109
+ @memory.writev(operands[0], unsigned_to_signed(@memory.readv(operands[0])) - 1)
110
+ when Opcode::INC
111
+ @memory.writev(operands[0], unsigned_to_signed(@memory.readv(operands[0])) + 1)
112
+ when Opcode::INC_CHK
113
+ new_value = unsigned_to_signed(@memory.readv(operands[0])) + 1
114
+ @memory.writev(operands[0], new_value)
115
+ result = new_value > unsigned_to_signed(operands[1])
116
+ branch(instruction.branch_to, instruction.branch_on, result)
117
+ when Opcode::DEC_CHK
118
+ new_value = unsigned_to_signed(@memory.readv(operands[0])) - 1
119
+ @memory.writev(operands[0], new_value)
120
+ result = new_value < unsigned_to_signed(operands[1])
121
+ branch(instruction.branch_to, instruction.branch_on, result)
122
+ when Opcode::INSERT_OBJ
123
+ @object_table.object_insert_object(operands[1], operands[0])
124
+ when Opcode::GET_CHILD
125
+ child = @object_table.object_get_child(operands[0])
126
+ @memory.writev(instruction.destination, child)
127
+ result = child != 0
128
+ branch(instruction.branch_to, instruction.branch_on, result)
129
+ when Opcode::GET_PARENT
130
+ parent = @object_table.object_get_parent(operands[0])
131
+ @memory.writev(instruction.destination, parent)
132
+ when Opcode::GET_PROP
133
+ prop = @object_table.object_get_property_word(operands[0], operands[1])
134
+ @memory.writev(instruction.destination, prop)
135
+ when Opcode::GET_PROP_ADDR
136
+ prop = @object_table.object_get_property_addr(operands[0], operands[1])
137
+ @memory.writev(instruction.destination, prop)
138
+ when Opcode::GET_PROP_LEN
139
+ if operands[0] == 0
140
+ result = 0
141
+ else
142
+ result = @object_table.object_get_property_data_size_from_address(operands[0])
143
+ end
144
+ @memory.writev(instruction.destination, result)
145
+ when Opcode::GET_SIBLING
146
+ sibling = @object_table.object_get_sibling(operands[0])
147
+ @memory.writev(instruction.destination, sibling)
148
+ result = sibling != 0
149
+ branch(instruction.branch_to, instruction.branch_on, result)
150
+ when Opcode::JUMP, Opcode::PIRACY
151
+ @memory.program_counter += unsigned_to_signed(operands[0])
152
+ @memory.program_counter -= 2
153
+ when Opcode::JE
154
+ result = operands[1..-1].inject(false) { |result, element|
155
+ result | (operands[0] == element)
156
+ }
157
+ branch(instruction.branch_to, instruction.branch_on, result)
158
+ when Opcode::JG
159
+ result = operands[1..-1].inject(false) { |result, element|
160
+ result | (unsigned_to_signed(operands[0]) > unsigned_to_signed(element))
161
+ }
162
+ branch(instruction.branch_to, instruction.branch_on, result)
163
+ when Opcode::JIN
164
+ result = @object_table.object_get_parent(operands[0]) == operands[1]
165
+ branch(instruction.branch_to, instruction.branch_on, result)
166
+ when Opcode::JL
167
+ result = operands[1..-1].inject(false) { |result, element|
168
+ result | (unsigned_to_signed(operands[0]) < unsigned_to_signed(element))
169
+ }
170
+ branch(instruction.branch_to, instruction.branch_on, result)
171
+ when Opcode::JZ
172
+ result = operands[0] == 0
173
+ branch(instruction.branch_to, instruction.branch_on, result)
174
+ when Opcode::LOAD
175
+ if operands[0] != instruction.destination
176
+ @memory.writev(instruction.destination, @memory.readv(operands[0]))
177
177
 
178
- # make sure to re-push the value since LOAD does not
179
- # change the stack but uses the value directly
180
- if operands[0] == 0
181
- @memory.writev(0, @memory.readv(instruction.destination))
182
- end
183
- end
184
- when Opcode::LOADB
185
- @memory.writev(instruction.destination, @memory.readb(operands[0] + unsigned_to_signed(operands[1])))
186
- when Opcode::LOADW
187
- @memory.writev(instruction.destination, @memory.readw(operands[0] + unsigned_to_signed(operands[1])*2))
188
- when Opcode::LOG_SHIFT
189
- places = unsigned_to_signed(operands[1])
190
- if places < 0
191
- @memory.writev(instruction.destination, operands[0] >> places.abs)
192
- else
193
- @memory.writev(instruction.destination, operands[0] << places)
194
- end
195
- when Opcode::NOP
196
- when Opcode::NEW_LINE
197
- puts
198
- when Opcode::POP
199
- # get rid of the first item on stack
200
- @memory.readv(0)
201
- when Opcode::PRINT
202
- print operands[0]
203
- when Opcode::PRINT_ADDR
204
- print ZSCII.translate(0, @header.version, @memory.force_readzstr(operands[0])[1], @abbreviation_table)
205
- when Opcode::PRINT_CHAR
206
- print ZSCII.translate_Zchar(operands[0])
207
- when Opcode::PRINT_NUM
208
- print unsigned_to_signed(operands[0]).to_s
209
- when Opcode::PRINT_OBJ
210
- print @object_table.object_short_text(operands[0])
211
- when Opcode::PRINT_PADDR
212
- str_addr = @memory.packed_address_to_byte_address(operands[0])
213
- print ZSCII.translate(0, @header.version, @memory.force_readzstr(str_addr)[1], @abbreviation_table)
214
- when Opcode::PRINT_RET
215
- puts operands[0]
216
- routine_return(1)
217
- when Opcode::PULL
218
- if @header.version == 6
219
- # TODO: Version 6 PULL instruction
220
- #
221
- # stack to pull from is given as operand[0]
222
- # instruction.destination is the destination resister
223
- else
224
- # pop value from stack
225
- @memory.writev(operands[0], @memory.readv(0))
226
- end
227
- when Opcode::PUSH
228
- # add value to stack
229
- @memory.writev(0, operands[0])
230
- when Opcode::PUT_PROP
231
- object_id = operands[0]
232
- prop_id = operands[1]
233
- prop_value = operands[2]
178
+ # make sure to re-push the value since LOAD does not
179
+ # change the stack but uses the value directly
180
+ if operands[0] == 0
181
+ @memory.writev(0, @memory.readv(instruction.destination))
182
+ end
183
+ end
184
+ when Opcode::LOADB
185
+ @memory.writev(instruction.destination, @memory.readb(operands[0] + unsigned_to_signed(operands[1])))
186
+ when Opcode::LOADW
187
+ @memory.writev(instruction.destination, @memory.readw(operands[0] + unsigned_to_signed(operands[1])*2))
188
+ when Opcode::LOG_SHIFT
189
+ places = unsigned_to_signed(operands[1])
190
+ if places < 0
191
+ @memory.writev(instruction.destination, operands[0] >> places.abs)
192
+ else
193
+ @memory.writev(instruction.destination, operands[0] << places)
194
+ end
195
+ when Opcode::NOP
196
+ when Opcode::NEW_LINE
197
+ puts
198
+ when Opcode::POP
199
+ # get rid of the first item on stack
200
+ @memory.readv(0)
201
+ when Opcode::PRINT
202
+ print operands[0]
203
+ when Opcode::PRINT_ADDR
204
+ print ZSCII.translate(0, @header.version, @memory.force_readzstr(operands[0])[1], @abbreviation_table)
205
+ when Opcode::PRINT_CHAR
206
+ print ZSCII.translate_Zchar(operands[0])
207
+ when Opcode::PRINT_NUM
208
+ print unsigned_to_signed(operands[0]).to_s
209
+ when Opcode::PRINT_OBJ
210
+ print @object_table.object_short_text(operands[0])
211
+ when Opcode::PRINT_PADDR
212
+ str_addr = @memory.packed_address_to_byte_address(operands[0])
213
+ print ZSCII.translate(0, @header.version, @memory.force_readzstr(str_addr)[1], @abbreviation_table)
214
+ when Opcode::PRINT_RET
215
+ puts operands[0]
216
+ routine_return(1)
217
+ when Opcode::PULL
218
+ if @header.version == 6
219
+ # TODO: Version 6 PULL instruction
220
+ #
221
+ # stack to pull from is given as operand[0]
222
+ # instruction.destination is the destination resister
223
+ else
224
+ # pop value from stack
225
+ @memory.writev(operands[0], @memory.readv(0))
226
+ end
227
+ when Opcode::PUSH
228
+ # add value to stack
229
+ @memory.writev(0, operands[0])
230
+ when Opcode::PUT_PROP
231
+ object_id = operands[0]
232
+ prop_id = operands[1]
233
+ prop_value = operands[2]
234
234
 
235
- @object_table.object_set_property_word(object_id, prop_id, prop_value)
236
- when Opcode::RANDOM
237
- value = unsigned_to_signed(operands[0])
238
- if value < 0
239
- # seed with value
240
- srand(value)
241
- result = 0
242
- elsif value == 0
243
- # seed with timestamp
244
- srand()
245
- result = 0
246
- else
247
- # pull random number from between 1 and value
248
- result = rand(value-1) + 1
249
- end
250
- @memory.writev(instruction.destination, result)
251
- when Opcode::REMOVE_OBJ
252
- @object_table.object_remove_object(operands[0])
253
- when Opcode::RET
254
- routine_return(operands[0])
255
- when Opcode::RET_POPPED
256
- routine_return(@memory.readv(0))
257
- when Opcode::RTRUE
258
- routine_return(1)
259
- when Opcode::RFALSE
260
- routine_return(0)
261
- when Opcode::SET_ATTR
262
- @object_table.object_set_attribute(operands[0], operands[1])
263
- when Opcode::SREAD
264
- # read the maximum number of bytes in the text-buffer
265
- max_bytes = @memory.force_readb(operands[0])
235
+ @object_table.object_set_property_word(object_id, prop_id, prop_value)
236
+ when Opcode::RANDOM
237
+ value = unsigned_to_signed(operands[0])
238
+ if value < 0
239
+ # seed with value
240
+ srand(value)
241
+ result = 0
242
+ elsif value == 0
243
+ # seed with timestamp
244
+ srand()
245
+ result = 0
246
+ else
247
+ # pull random number from between 1 and value
248
+ result = rand(value-1) + 1
249
+ end
250
+ @memory.writev(instruction.destination, result)
251
+ when Opcode::REMOVE_OBJ
252
+ @object_table.object_remove_object(operands[0])
253
+ when Opcode::RESTORE
254
+ if @header.version <= 4
255
+ @memory.restore
256
+ if @header.version >= 4
257
+ @memory.writev(instruction.destination, 1)
258
+ end
259
+ branch(instruction.branch_to, instruction.branch_on, true)
260
+ end
261
+ when Opcode::RET
262
+ routine_return(operands[0])
263
+ when Opcode::RET_POPPED
264
+ routine_return(@memory.readv(0))
265
+ when Opcode::RTRUE
266
+ routine_return(1)
267
+ when Opcode::RFALSE
268
+ routine_return(0)
269
+ when Opcode::SAVE
270
+ if @header.version <= 4
271
+ @memory.save
272
+ if @header.version >= 4
273
+ @memory.writev(instruction.destination, 1)
274
+ end
275
+ branch(instruction.branch_to, instruction.branch_on, true)
276
+ end
277
+ when Opcode::SET_ATTR
278
+ @object_table.object_set_attribute(operands[0], operands[1])
279
+ when Opcode::SREAD
280
+ # read the maximum number of bytes in the text-buffer
281
+ max_bytes = @memory.force_readb(operands[0])
266
282
 
267
- # address of the next byte in the text-buffer
268
- addr = operands[0] + 1
283
+ # address of the next byte in the text-buffer
284
+ addr = operands[0] + 1
269
285
 
270
- # read in a line of input from stdin
271
- line = $stdin.readline[0..-2]
286
+ # read in a line of input from stdin
287
+ line = $stdin.readline[0..-2]
272
288
 
273
- # truncate line to fit the max characters given by text-buffer
274
- if line.length > max_bytes
275
- line = line[0..max_bytes]
276
- end
289
+ # truncate line to fit the max characters given by text-buffer
290
+ if line.length > max_bytes
291
+ line = line[0..max_bytes]
292
+ end
277
293
 
278
- # tokenize
279
- lexed = @dictionary.tokenize(line)
294
+ # tokenize
295
+ lexed = @dictionary.tokenize(line)
280
296
 
281
- # parse
282
- parsed = @dictionary.parse(lexed)
297
+ # parse
298
+ parsed = @dictionary.parse(lexed)
283
299
 
284
- # encode the line into a ZChar stream
285
- str = ZSCII.encode_to_zchars(line, @header.version)
300
+ # encode the line into a ZChar stream
301
+ str = ZSCII.encode_to_zchars(line, @header.version)
286
302
 
287
- # write the text to the text-buffer
288
- num_bytes = 1
289
- first_position = 1
290
- if @header.version >= 5
291
- num_bytes += 1
292
- @memory.force_writeb(addr, line.length)
293
- first_position = 2
294
- addr += 1
295
- end
303
+ # write the text to the text-buffer
304
+ num_bytes = 1
305
+ first_position = 1
306
+ if @header.version >= 5
307
+ num_bytes += 1
308
+ @memory.force_writeb(addr, line.length)
309
+ first_position = 2
310
+ addr += 1
311
+ end
296
312
 
297
- str.each do |zchr|
298
- num_bytes += 1
299
- if num_bytes > max_bytes
300
- break
301
- end
302
- @memory.force_writeb(addr, zchr)
303
- addr += 1
304
- end
313
+ str.each do |zchr|
314
+ num_bytes += 1
315
+ if num_bytes > max_bytes
316
+ break
317
+ end
318
+ @memory.force_writeb(addr, zchr)
319
+ addr += 1
320
+ end
305
321
 
306
- if @header.version < 5
307
- # terminator
308
- if num_bytes <= max_bytes
309
- @memory.force_writeb(addr, 0)
310
- end
311
- end
322
+ if @header.version < 5
323
+ # terminator
324
+ if num_bytes <= max_bytes
325
+ @memory.force_writeb(addr, 0)
326
+ end
327
+ end
312
328
 
313
- # write the parse-buffer
314
- max_bytes = @memory.force_readb(operands[1])
315
- max_bytes = 2 + max_bytes * 4
316
- addr = operands[1] + 1
317
- num_bytes = 1
329
+ # write the parse-buffer
330
+ max_bytes = @memory.force_readb(operands[1])
331
+ max_bytes = 2 + max_bytes * 4
332
+ addr = operands[1] + 1
333
+ num_bytes = 1
318
334
 
319
- if num_bytes <= max_bytes
320
- @memory.force_writeb(addr, lexed.length)
321
- addr += 1
322
- end
335
+ if num_bytes <= max_bytes
336
+ @memory.force_writeb(addr, lexed.length)
337
+ addr += 1
338
+ end
323
339
 
324
- parsed.each do |token, index|
325
- num_bytes += 4
326
- if num_bytes > max_bytes
327
- break
328
- end
329
- @memory.force_writew(addr, token[:address])
330
- addr += 2
331
- @memory.force_writeb(addr, token[:size])
332
- addr += 1
333
- @memory.force_writeb(addr, token[:position]+first_position)
334
- addr += 1
335
- end
336
- when Opcode::TEST
337
- result = (operands[0] & operands[1]) == operands[1]
338
- branch(instruction.branch_to, instruction.branch_on, result)
339
- when Opcode::TEST_ATTR
340
- result = @object_table.object_has_attribute?(operands[0], operands[1])
341
- branch(instruction.branch_to, instruction.branch_on, result)
342
- when Opcode::ADD
343
- @memory.writev(instruction.destination,
344
- unsigned_to_signed(operands[0]) + unsigned_to_signed(operands[1]))
345
- when Opcode::SUB
346
- @memory.writev(instruction.destination,
347
- unsigned_to_signed(operands[0]) - unsigned_to_signed(operands[1]))
348
- when Opcode::MUL
349
- @memory.writev(instruction.destination,
350
- unsigned_to_signed(operands[0]) * unsigned_to_signed(operands[1]))
351
- when Opcode::DIV
352
- result = unsigned_to_signed(operands[0]).to_f / unsigned_to_signed(operands[1]).to_f
353
- if result < 0
354
- result = -(result.abs.floor)
355
- else
356
- result = result.floor
357
- end
358
- @memory.writev(instruction.destination, result.to_i)
359
- when Opcode::MOD
360
- a = unsigned_to_signed(operands[0])
361
- b = unsigned_to_signed(operands[1])
362
- result = a.abs % b.abs
363
- if a < 0
364
- result = -result
365
- end
366
- @memory.writev(instruction.destination, result.to_i)
367
- when Opcode::NOT
368
- @memory.writev(instruction.destination, ~(operands[0]))
369
- when Opcode::OR
370
- @memory.writev(instruction.destination, operands[0] | operands[1])
371
- when Opcode::AND
372
- @memory.writev(instruction.destination, operands[0] & operands[1])
373
- when Opcode::STORE
374
- if operands[0] == 0
375
- @memory.readv(operands[0])
376
- end
377
- @memory.writev(operands[0], operands[1])
378
- when Opcode::STOREB
379
- @memory.writeb(operands[0] + unsigned_to_signed(operands[1]), operands[2])
380
- when Opcode::STOREW
381
- @memory.writew(operands[0] + unsigned_to_signed(operands[1])*2, operands[2])
382
- else
383
- raise "opcode " + Opcode.name(instruction.opcode, @header.version) + " not implemented"
384
- end
385
- end
340
+ parsed.each do |token, index|
341
+ num_bytes += 4
342
+ if num_bytes > max_bytes
343
+ break
344
+ end
345
+ @memory.force_writew(addr, token[:address])
346
+ addr += 2
347
+ @memory.force_writeb(addr, token[:size])
348
+ addr += 1
349
+ @memory.force_writeb(addr, token[:position]+first_position)
350
+ addr += 1
351
+ end
352
+ when Opcode::TEST
353
+ result = (operands[0] & operands[1]) == operands[1]
354
+ branch(instruction.branch_to, instruction.branch_on, result)
355
+ when Opcode::TEST_ATTR
356
+ result = @object_table.object_has_attribute?(operands[0], operands[1])
357
+ branch(instruction.branch_to, instruction.branch_on, result)
358
+ when Opcode::ADD
359
+ @memory.writev(instruction.destination,
360
+ unsigned_to_signed(operands[0]) + unsigned_to_signed(operands[1]))
361
+ when Opcode::SUB
362
+ @memory.writev(instruction.destination,
363
+ unsigned_to_signed(operands[0]) - unsigned_to_signed(operands[1]))
364
+ when Opcode::MUL
365
+ @memory.writev(instruction.destination,
366
+ unsigned_to_signed(operands[0]) * unsigned_to_signed(operands[1]))
367
+ when Opcode::DIV
368
+ result = unsigned_to_signed(operands[0]).to_f / unsigned_to_signed(operands[1]).to_f
369
+ if result < 0
370
+ result = -(result.abs.floor)
371
+ else
372
+ result = result.floor
373
+ end
374
+ @memory.writev(instruction.destination, result.to_i)
375
+ when Opcode::MOD
376
+ a = unsigned_to_signed(operands[0])
377
+ b = unsigned_to_signed(operands[1])
378
+ result = a.abs % b.abs
379
+ if a < 0
380
+ result = -result
381
+ end
382
+ @memory.writev(instruction.destination, result.to_i)
383
+ when Opcode::NOT
384
+ @memory.writev(instruction.destination, ~(operands[0]))
385
+ when Opcode::OR
386
+ @memory.writev(instruction.destination, operands[0] | operands[1])
387
+ when Opcode::AND
388
+ @memory.writev(instruction.destination, operands[0] & operands[1])
389
+ when Opcode::STORE
390
+ if operands[0] == 0
391
+ @memory.readv(operands[0])
392
+ end
393
+ @memory.writev(operands[0], operands[1])
394
+ when Opcode::STOREB
395
+ @memory.writeb(operands[0] + unsigned_to_signed(operands[1]), operands[2])
396
+ when Opcode::STOREW
397
+ @memory.writew(operands[0] + unsigned_to_signed(operands[1])*2, operands[2])
398
+ else
399
+ puts instruction.opcode
400
+ raise "opcode " + Opcode.name(instruction.opcode, @header.version) + " not implemented"
401
+ end
402
+ end
386
403
 
387
- def unsigned_to_signed(op)
388
- sign = op & 0x8000
389
- if sign != 0
390
- -(65536 - op)
391
- else
392
- op
393
- end
394
- end
395
- private :unsigned_to_signed
396
- end
397
- end
404
+ def unsigned_to_signed(op)
405
+ sign = op & 0x8000
406
+ if sign != 0
407
+ -(65536 - op)
408
+ else
409
+ op
410
+ end
411
+ end
412
+ private :unsigned_to_signed
413
+ end
414
+ end
398
415
  end