Class: AVR::CPU

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/avr/cpu.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(device) ⇒ CPU

Returns a new instance of CPU.



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/avr/cpu.rb', line 82

def initialize(device)
  @device = device
  @pc = 0
  @next_pc = 0
  @sram = SRAM.new(device.ram_start + device.sram_size)

  @registers = RegisterFile.new(self)

  device.register_count.times do |n|
    registers.add(MemoryByteRegister.new(self, "r#{n}", @sram.memory[n]))
  end

  device.word_register_map.each do |name, map|
    registers.add(RegisterPair.new(self, @registers[map[:l]], @registers[map[:h]], name))
  end

  @io_registers = RegisterFile.new(self)
  device.io_registers.each do |name|
    address = device.data_memory_map[name]
    next unless address

    bit_names = device.register_bit_names_map[name]
    if bit_names
      io_registers.add(MemoryByteRegisterWithNamedBits.new(self, name.to_s, @sram.memory[address], bit_names))
    else
      io_registers.add(MemoryByteRegister.new(self, name.to_s, @sram.memory[address]))
    end
  end

  @sreg = SREG.new(self)

  @sp = SP.new(
    self,
    @sram.memory[device.data_memory_map[:SPL]],
    @sram.memory[device.data_memory_map[:SPH]],
    device.ram_end
  )

  @decoder = OpcodeDecoder.new

  @ports = {}
  device.port_map.each do |name, addr|
    @ports[name] = Port.new(self, name, addr[:pin], addr[:ddr], addr[:port])
  end

  @clock = Clock.new('cpu')
  @clock.push_sink(Clock::Sink.new('cpu') { step })

  @tracer = nil
end

Instance Attribute Details

#clockObject (readonly)

Returns the value of attribute clock.



76
77
78
# File 'lib/avr/cpu.rb', line 76

def clock
  @clock
end

#decoderObject (readonly)

Returns the value of attribute decoder.



70
71
72
# File 'lib/avr/cpu.rb', line 70

def decoder
  @decoder
end

#deviceObject (readonly)

Returns the value of attribute device.



9
10
11
# File 'lib/avr/cpu.rb', line 9

def device
  @device
end

#io_registersObject (readonly)

Returns the value of attribute io_registers.



59
60
61
# File 'lib/avr/cpu.rb', line 59

def io_registers
  @io_registers
end

#next_pcObject

Returns the value of attribute next_pc.



15
16
17
# File 'lib/avr/cpu.rb', line 15

def next_pc
  @next_pc
end

#pcObject

Returns the value of attribute pc.



12
13
14
# File 'lib/avr/cpu.rb', line 12

def pc
  @pc
end

#portsObject (readonly)

Returns the value of attribute ports.



73
74
75
# File 'lib/avr/cpu.rb', line 73

def ports
  @ports
end

#registersObject (readonly)

Returns the value of attribute registers.



21
22
23
# File 'lib/avr/cpu.rb', line 21

def registers
  @registers
end

#spObject (readonly)

Returns the value of attribute sp.



67
68
69
# File 'lib/avr/cpu.rb', line 67

def sp
  @sp
end

#sramObject (readonly)

Returns the value of attribute sram.



18
19
20
# File 'lib/avr/cpu.rb', line 18

def sram
  @sram
end

#sregObject (readonly)

Returns the value of attribute sreg.



64
65
66
# File 'lib/avr/cpu.rb', line 64

def sreg
  @sreg
end

#tracerObject (readonly)

Returns the value of attribute tracer.



79
80
81
# File 'lib/avr/cpu.rb', line 79

def tracer
  @tracer
end

Instance Method Details

#decodeObject



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/avr/cpu.rb', line 212

def decode
  offset = next_pc
  word = fetch
  decoded_opcode = decoder.decode(word)
  unless decoded_opcode
    raise 'Unable to decode 0x%04x at offset 0x%04x words (0x%04x bytes)' % [
      word,
      offset,
      offset * 2,
    ]
  end

  decoded_opcode.opcode_definition.parse(
    self,
    decoded_opcode.opcode_definition,
    decoded_opcode.prepare_operands(self)
  )
end

#fetchObject



187
188
189
190
191
# File 'lib/avr/cpu.rb', line 187

def fetch
  word = device.flash.word(next_pc)
  @next_pc += 1
  word
end

#instruction(mnemonic, *args) ⇒ Object



194
195
196
# File 'lib/avr/cpu.rb', line 194

def instruction(mnemonic, *args)
  Instruction.new(self, mnemonic, args)
end

#interrupt(name_or_vector_number) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
# File 'lib/avr/cpu.rb', line 199

def interrupt(name_or_vector_number)
  sreg.I = false
  case name_or_vector_number
  when Integer
    address = name_or_vector_number * 2
  when Symbol
    address = device.interrupt_vector_map[name_or_vector_number]
  end

  instruction(:call, Value.new(address)).execute
end

#notify_at_tick(tick, &block) ⇒ Object



133
134
135
# File 'lib/avr/cpu.rb', line 133

def notify_at_tick(tick, &block)
  clock.notify_at_tick(tick, Clock::Sink.new("notify #{block} at #{tick}", block.to_proc))
end

#peekObject



232
233
234
235
236
237
238
239
# File 'lib/avr/cpu.rb', line 232

def peek
  save_pc = pc
  save_next_pc = next_pc
  i = decode
  @pc = save_pc
  @next_pc = save_next_pc
  i
end


144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/avr/cpu.rb', line 144

def print_status
  puts 'Status:'
  puts '%8s = %d' % ['Ticks', clock.ticks]
  puts '%8s = %d opcodes' % ['Cache', decoder.cache.size]
  puts '%8s = 0x%04x words' % ['PC', pc]
  puts '%8s = 0x%04x bytes' % ['PC', pc * 2]
  puts '%8s = 0x%04x (%d bytes used)' % ['SP', sp.value, device.ram_end - sp.value]
  puts '%8s = 0x%02x [%s]' % ['SREG', sreg.value, sreg.bit_values]
  puts
  puts 'Registers:'
  registers.print_status
  puts
  puts 'IO Registers:'
  io_registers.print_status
  puts
  puts 'IO Ports:'
  puts '%4s  %s' % ['', Port::PINS.join(' ')]
  ports.each do |name, port|
    puts '%4s: %s' % [name, port.pin_states.join(' ')]
  end
  puts
  puts 'Next instruction:'
  puts '  ' + peek.to_s
  puts
end

#r0Object



24
25
26
# File 'lib/avr/cpu.rb', line 24

def r0
  registers.fetch(:r0)
end

#r0=(value) ⇒ Object



29
30
31
# File 'lib/avr/cpu.rb', line 29

def r0=(value)
  registers.fetch(:r0).value = value
end

#r1Object



34
35
36
# File 'lib/avr/cpu.rb', line 34

def r1
  registers.fetch(:r1)
end

#r1=(value) ⇒ Object



39
40
41
# File 'lib/avr/cpu.rb', line 39

def r1=(value)
  registers.fetch(:r1).value = value
end

#resetObject



180
181
182
183
184
# File 'lib/avr/cpu.rb', line 180

def reset
  @pc = 0
  @next_pc = 0
  sreg.reset
end

#reset_to_clean_stateObject



171
172
173
174
175
176
177
# File 'lib/avr/cpu.rb', line 171

def reset_to_clean_state
  reset
  registers.reset
  io_registers.reset
  sram.reset
  sp.value = device.ram_end
end

#stepObject



242
243
244
245
246
247
248
249
250
251
252
# File 'lib/avr/cpu.rb', line 242

def step
  i = decode
  @tracer&.call(i)
  begin
    i.execute
  rescue StandardError
    puts "*** Caught exception while executing #{i}, CPU status:"
    print_status
    raise
  end
end

#trace(&block) ⇒ Object



138
139
140
141
# File 'lib/avr/cpu.rb', line 138

def trace(&block)
  @tracer = nil
  @tracer = block.to_proc if block_given?
end

#XObject



44
45
46
# File 'lib/avr/cpu.rb', line 44

def X
  registers.fetch(:X)
end

#YObject



49
50
51
# File 'lib/avr/cpu.rb', line 49

def Y
  registers.fetch(:Y)
end

#ZObject



54
55
56
# File 'lib/avr/cpu.rb', line 54

def Z
  registers.fetch(:Z)
end