class AVR::CPU

Constants

I

Attributes

clock[R]
decoder[R]
device[R]
io_registers[R]
next_pc[RW]
pc[RW]
ports[R]
registers[R]
sp[R]
sram[R]
sreg[R]
tracer[R]

Public Class Methods

new(device) click to toggle source
# 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

Public Instance Methods

X() click to toggle source
# File lib/avr/cpu.rb, line 44
def X
  registers.fetch(:X)
end
Y() click to toggle source
# File lib/avr/cpu.rb, line 49
def Y
  registers.fetch(:Y)
end
Z() click to toggle source
# File lib/avr/cpu.rb, line 54
def Z
  registers.fetch(:Z)
end
decode() click to toggle source
# 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
fetch() click to toggle source
# File lib/avr/cpu.rb, line 187
def fetch
  word = device.flash.word(next_pc)
  @next_pc += 1
  word
end
instruction(mnemonic, *args) click to toggle source
# File lib/avr/cpu.rb, line 194
def instruction(mnemonic, *args)
  Instruction.new(self, mnemonic, args)
end
interrupt(name_or_vector_number) click to toggle source
# 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) click to toggle source
# 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
peek() click to toggle source
# 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
print_status() click to toggle source
r0() click to toggle source
# File lib/avr/cpu.rb, line 24
def r0
  registers.fetch(:r0)
end
r0=(value) click to toggle source
# File lib/avr/cpu.rb, line 29
def r0=(value)
  registers.fetch(:r0).value = value
end
r1() click to toggle source
# File lib/avr/cpu.rb, line 34
def r1
  registers.fetch(:r1)
end
r1=(value) click to toggle source
# File lib/avr/cpu.rb, line 39
def r1=(value)
  registers.fetch(:r1).value = value
end
reset() click to toggle source
# File lib/avr/cpu.rb, line 180
def reset
  @pc = 0
  @next_pc = 0
  sreg.reset
end
reset_to_clean_state() click to toggle source
# 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
step() click to toggle source
# 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) click to toggle source
# File lib/avr/cpu.rb, line 138
def trace(&block)
  @tracer = nil
  @tracer = block.to_proc if block_given?
end