Class: Gruesome::Z::Memory

Inherits:
Object
  • Object
show all
Defined in:
lib/gruesome/z/memory.rb

Overview

This class holds the memory for the virtual machine

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(contents, save_file_name) ⇒ Memory

Returns a new instance of Memory.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/gruesome/z/memory.rb', line 43

def initialize(contents, save_file_name)
  @call_stack = []
  @save_file_name = save_file_name
  @stack = []
  @memory = contents
  @num_locals = 0

  # Get the header information
  @header = Header.new(@memory)
  @program_counter = @header.entry

  # With the header info, discover the bounds of each memory region
  @dyn_base = 0x0
  @dyn_limit = @header.static_mem_base

  # Cannot Write to Static Memory
  @static_base = @header.static_mem_base
  @static_limit = @memory.length

  # Cannot Access High Memory
  @high_base = @header.high_mem_base
  @high_limit = @memory.length

  # Error if high memory overlaps dynamic memory
  if @high_base < @dyn_limit
    # XXX: ERROR
  end

  # Check machine endianess
  @endian = [1].pack('S')[0] == 1 ? 'little' : 'big'
end

Instance Attribute Details

#num_localsObject (readonly)

Returns the value of attribute num_locals.



41
42
43
# File 'lib/gruesome/z/memory.rb', line 41

def num_locals
  @num_locals
end

#program_counterObject

Returns the value of attribute program_counter.



40
41
42
# File 'lib/gruesome/z/memory.rb', line 40

def program_counter
  @program_counter
end

Instance Method Details

#contentsObject



208
209
210
# File 'lib/gruesome/z/memory.rb', line 208

def contents
  @memory
end

#force_readb(address) ⇒ Object



154
155
156
157
158
159
160
161
162
# File 'lib/gruesome/z/memory.rb', line 154

def force_readb(address)
  if address < @memory.size
    @memory.getbyte(address)
  else
    # XXX: Access Violation
    raise "Major Access Violation accessing $" + sprintf("%04x", address)
    nil
  end
end

#force_readw(address) ⇒ Object



164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/gruesome/z/memory.rb', line 164

def force_readw(address)
  if (address + 1) < @memory.size
    if @endian == 'little'
      (@memory.getbyte(address+1) << 8) | @memory.getbyte(address)
    else
      (@memory.getbyte(address) << 8) | @memory.getbyte(address+1)
    end
  else
    # XXX: Access Violation
    raise "Major Access Violation accessing $" + sprintf("%04x", address)
    nil
  end
end

#force_readzstr(index, max_len = -1)) ⇒ Object



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/gruesome/z/memory.rb', line 243

def force_readzstr(index, max_len = -1)
  chrs = []
  continue = true
  orig_index = index

  until continue == false do
    if max_len != -1 and (index + 2 - orig_index) > max_len
      break
    end

    byte1 = force_readb(index)
    byte2 = force_readb(index+1)

    index += 2

    chrs << ((byte1 >> 2) & 0b11111)
    chrs << (((byte1 & 0b11) << 3) | (byte2 >> 5))
    chrs << (byte2 & 0b11111)

    continue = (byte1 & 0b10000000) == 0
  end

  return [index - orig_index, chrs]
end

#force_writeb(address, value) ⇒ Object



178
179
180
181
182
183
184
185
186
# File 'lib/gruesome/z/memory.rb', line 178

def force_writeb(address, value)
  if address < @memory.size
    @memory.setbyte(address, (value & 255))
  else
    # XXX: Access Violation
    raise "Major Access (W) Violation accessing $" + sprintf("%04x", address)
    nil
  end
end

#force_writew(address, value) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/gruesome/z/memory.rb', line 188

def force_writew(address, value)
  if (address + 1) < @memory.size
    low_byte = value & 255
    high_byte = (value >> 8) & 255

    if @endian == 'little'
      tmp = high_byte
      high_byte = low_byte
      low_byte = tmp
    end

    @memory.setbyte(address, high_byte)
    @memory.setbyte(address+1, low_byte)
  else
    # XXX: Access Violation
    raise "Major Access (W) Violation accessing $" + sprintf("%04x", address)
    nil
  end
end

#packed_address_to_byte_address(address) ⇒ Object



75
76
77
78
79
80
# File 'lib/gruesome/z/memory.rb', line 75

def packed_address_to_byte_address(address)
  if @header.version <=3
    address * 2
  else
  end
end

#pop_routineObject

Tears down the environment for the current routine



104
105
106
107
108
109
110
111
112
# File 'lib/gruesome/z/memory.rb', line 104

def pop_routine()
  # return the return address
  return_addr = @stack[0]
  @stack = @call_stack.pop
  destination = @call_stack.pop
  @num_locals = @call_stack.pop

  {:destination => destination, :return_address => return_addr}
end

#push_routine(return_addr, num_locals, destination) ⇒ Object

Sets up the environment for a new routine



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/gruesome/z/memory.rb', line 83

def push_routine(return_addr, num_locals, destination)
  # pushes the stack onto the call stack
  @call_stack.push @num_locals
  @call_stack.push destination
  @call_stack.push @stack

  # empties the current stack
  @stack = Array.new()

  # pushes the return address onto the stack
  @stack.push(return_addr)

  # push locals
  num_locals.times do
    @stack.push 0
  end

  @num_locals = num_locals
end

#readb(address) ⇒ Object



114
115
116
117
118
119
120
121
122
# File 'lib/gruesome/z/memory.rb', line 114

def readb(address)
  if address < @high_base
    force_readb(address)
  else
    # XXX: Access violation
    raise "Access Violation accessing $" + sprintf("%04x", address)
    nil
  end
end

#readv(index) ⇒ Object

Read from variable number index



213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/gruesome/z/memory.rb', line 213

def readv(index)
  if index == 0
    # pop from stack
    @stack.pop
  elsif index >= 16
    index -= 16
    readw(@header.global_var_addr + (index*2))
  elsif index <= @num_locals
    @stack[index]
  else
    # XXX: Error
  end
end

#readw(address) ⇒ Object



124
125
126
127
128
129
130
131
132
# File 'lib/gruesome/z/memory.rb', line 124

def readw(address)
  if (address + 1) < @high_base
    force_readw(address)
  else
    # XXX: Access violation
    raise "Access Violation accessing $" + sprintf("%04x", address)
    nil
  end
end

#restoreObject



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/gruesome/z/memory.rb', line 297

def restore
  # Restore, if it can, the contents of memory from disk
  File.open(@save_file_name, "rb") do |f|
    @call_stack = []

    @program_counter = f.readline.to_i
    call_stack_size = f.readline.to_i

    call_stack_size.times do
      num_locals = f.readline.to_i
      destination = f.readline.to_i
      stack_size = f.readline.to_i

      stack = []
      stack_size.times do |i|
        stack.push f.readline.to_i
      end

      @call_stack.push num_locals
      @call_stack.push destination
      @call_stack.push stack
    end

    @num_locals = f.readline.to_i
    stack_size = f.readline.to_i

    @stack = []
    stack_size.times do |i|
      @stack.push f.readline.to_i
    end

    i = 0
    f.read.each_byte do |b|
      force_writeb(i, b)
      i += 1
    end
  end
end

#saveObject



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/gruesome/z/memory.rb', line 268

def save
  # Save contents of dynamic memory to disk
  File.open(@save_file_name, "wb+") do |f|
    f.puts @program_counter
    f.puts (@call_stack.size / 3)
    @call_stack.each_with_index do |call_stack, i|
      if (i % 3) == 0 or (i % 3) == 1
        f.puts call_stack
      else
        # this is stack
        stack = call_stack
        f.puts stack.size
        stack.each do |stack_entry|
          f.puts stack_entry
        end
      end
    end
    f.puts @num_locals
    f.puts @stack.size
    @stack.each do |stack_entry|
      f.puts stack_entry
    end

    @dyn_limit.times do |i|
      f.write force_readb(i).chr
    end
  end
end

#writeb(address, value) ⇒ Object



134
135
136
137
138
139
140
141
142
# File 'lib/gruesome/z/memory.rb', line 134

def writeb(address, value)
  if address < @static_base
    force_writeb(address, value)
  else
    # XXX: Access violation
    raise "Access Violation (W) accessing $" + sprintf("%04x", address)
    nil
  end
end

#writev(index, value) ⇒ Object

Write value to variable number index



228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/gruesome/z/memory.rb', line 228

def writev(index, value)
  value &= 65535
  if index == 0
    # push to stack
    @stack.push value
  elsif index >= 16
    index -= 16
    writew(@header.global_var_addr + (index*2), value)
  elsif index <= @num_locals
    @stack[index] = value
  else
    # XXX: Error
  end
end

#writew(address, value) ⇒ Object



144
145
146
147
148
149
150
151
152
# File 'lib/gruesome/z/memory.rb', line 144

def writew(address, value)
  if (address + 1) < @static_base
    force_writew(address, value)
  else
    # XXX: Access violation
    raise "Access Violation (W) accessing $" + sprintf("%04x", address)
    nil
  end
end