class AVR::Opcode

Constants

ExtractedOperandHashType
I
OPCODE_ARGUMENT_TYPES

rubocop:disable Layout/HashAlignment

OperandValueHashType
ProcType
T

Attributes

opcodes[R]
arg_types[R]
mnemonic[R]
opcode_proc[R]
sreg_flags[R]

Public Class Methods

bit_jumble_for_lds_sts(k_in) click to toggle source
# File lib/avr/opcode/operand_parsers.rb, line 13
def self.bit_jumble_for_lds_sts(k_in)
  k_out  = k_in & 0b00001111
  k_out |= k_in & 0b01100000 >> 1
  k_out |= k_in & 0b00010000 << 2
  k_out |= ~(k_in & 0b00010000 << 3) & 0b10000000
  k_out
end
decode(pattern, mnemonic, &block) click to toggle source
# File lib/avr/opcode.rb, line 226
def self.decode(pattern, mnemonic, &block)
  OpcodeDecoder.add_opcode_definition(
    OpcodeDecoder::OpcodeDefinition.new(pattern, mnemonic, block.to_proc)
  )
end
exchange_memory_byte_with_register(memory_byte, register, mnemonic) click to toggle source
# File lib/avr/opcode/data/sram.rb, line 175
def self.exchange_memory_byte_with_register(memory_byte, register, mnemonic)
  old_value = memory_byte.value
  case mnemonic
  when :xch
    memory_byte.value = register.value
  when :las
    memory_byte.value = register.value | old_value
  when :lac
    memory_byte.value = (~register.value & old_value) & 0xff
  when :lat
    memory_byte.value = register.value ^ old_value
  end
  register.value = old_value
end
new(mnemonic, arg_types, sreg_flags, opcode_proc) click to toggle source
# File lib/avr/opcode.rb, line 92
def initialize(mnemonic, arg_types, sreg_flags, opcode_proc)
  @mnemonic = mnemonic
  @arg_types = arg_types
  @sreg_flags = sreg_flags
  @opcode_proc = opcode_proc
  arg_types.each do |arg_type|
    raise "Unknown Opcode argument type: #{arg_type}" unless OPCODE_ARGUMENT_TYPES[arg_type]
  end
end
opcode(mnemonic, arg_types = [], sreg_flags = [], &block) click to toggle source
# File lib/avr/opcode.rb, line 219
def self.opcode(mnemonic, arg_types = [], sreg_flags = [], &block)
  raise 'No block given' unless block_given?

  opcodes[mnemonic] = Opcode.new(mnemonic, arg_types, sreg_flags, block.to_proc)
end
parse_operands(pattern, &block) click to toggle source
# File lib/avr/opcode.rb, line 233
def self.parse_operands(pattern, &block)
  OpcodeDecoder.add_operand_parser(OpcodeDecoder::OperandParser.new(pattern, block.to_proc))
end
set_sreg_for_add_adc(cpu, r, rd, rr) click to toggle source
# File lib/avr/opcode/math/addition.rb, line 35
def self.set_sreg_for_add_adc(cpu, r, rd, rr)
  b7  = (1 << 7)
  r7  = (r  & b7) != 0
  rd7 = (rd & b7) != 0
  rr7 = (rr & b7) != 0
  r3  = (r  & b7) != 0
  rd3 = (rd & b7) != 0
  rr3 = (rr & b7) != 0
  n   = r7
  v   = rd7 & rr7 & !r7 | !rd7 & !rr7 & r7
  c   = rd7 & rr7 | rr7 & !r7 | !r7 & rd7
  h   = rd3 & rr3 | rr3 & !r3 | !r3 & rd3

  cpu.sreg.from_h(
    {
      H: h,
      S: n ^ v,
      V: v,
      N: n,
      Z: r.zero?,
      C: c,
    }
  )
end
set_sreg_for_adiw(cpu, r, rd) click to toggle source
# File lib/avr/opcode/math/addition.rb, line 88
def self.set_sreg_for_adiw(cpu, r, rd)
  b15  = (1 << 15)
  b7   = (1 << 7)
  rdh7 = (rd & b7) != 0
  r15  = (r & b15) != 0
  v   = !rdh7 & r15
  n   = r15
  c   = !r15 & rdh7

  cpu.sreg.from_h(
    {
      S: n ^ v,
      V: v,
      N: n,
      Z: r.zero?,
      C: c,
    }
  )
end
set_sreg_for_and_or(cpu, value) click to toggle source
# File lib/avr/opcode/math/bitwise.rb, line 7
def self.set_sreg_for_and_or(cpu, value)
  r7 = (value & (1 << 7)) != 0

  cpu.sreg.from_h(
    {
      S: r7 ^ false,
      V: false,
      N: r7,
      Z: value.zero?,
    }
  )
end
set_sreg_for_cp_cpi_cpc(cpu, r, rd, rr_k, mnemonic) click to toggle source
# File lib/avr/opcode/compare.rb, line 9
def self.set_sreg_for_cp_cpi_cpc(cpu, r, rd, rr_k, mnemonic)
  b7    = (1<<7)
  r7    = (r  & b7) != 0
  rd7   = (rd & b7) != 0
  rr_k7 = (rr_k & b7) != 0
  r3    = (r  & b7) != 0
  rd3   = (rd & b7) != 0
  rr_k3 = (rr_k & b7) != 0
  n     = r7
  v     = rd7 & rr_k7 & r7 | !rd7 & rr_k7 & r7
  c     = !rd7 & rr_k7 | rr_k7 & r7 | r7 & !rd7
  h     = !rd3 & rr_k3 | rr_k3 & r3 | r3 & !rd3

  z = r.zero?
  z = r.zero? ? cpu.sreg.Z : false if mnemonic == :cpc

  cpu.sreg.from_h(
    {
      H: h,
      S: n ^ v,
      V: v,
      N: n,
      Z: z,
      C: c,
    }
  )
end
set_sreg_for_dec(cpu, r, rd) click to toggle source
# File lib/avr/opcode/math/subtraction.rb, line 8
def self.set_sreg_for_dec(cpu, r, rd)
  n = (r & (1 << 7)) != 0
  v = (rd == 0x80)

  cpu.sreg.from_h(
    {
      S: n ^ v,
      V: v,
      N: n,
      Z: r.zero?,
    }
  )
end
set_sreg_for_inc(cpu, r, rd) click to toggle source
# File lib/avr/opcode/math/addition.rb, line 8
def self.set_sreg_for_inc(cpu, r, rd)
  n = (r & (1 << 7)) != 0
  v = (rd == 0x7f)

  cpu.sreg.from_h(
    {
      S: n ^ v,
      V: v,
      N: n,
      Z: r.zero?,
    }
  )
end
set_sreg_for_sbiw(cpu, r, rd) click to toggle source
# File lib/avr/opcode/math/subtraction.rb, line 105
def self.set_sreg_for_sbiw(cpu, r, rd)
  b15  = (1 << 15)
  b7   = (1 << 7)
  rdh7 = (rd & b7) != 0
  r15  = (r & b15) != 0
  v   = r15 & !rdh7
  n   = r15
  c   = r15 & !rdh7

  cpu.sreg.from_h(
    {
      S: n ^ v,
      V: v,
      N: n,
      Z: r.zero?,
      C: c,
    }
  )
end
set_sreg_for_sub_sbc(cpu, r, rd, rr) click to toggle source
# File lib/avr/opcode/math/subtraction.rb, line 35
def self.set_sreg_for_sub_sbc(cpu, r, rd, rr)
  b7  = (1 << 7)
  r7  = (r  & b7) != 0
  rd7 = (rd & b7) != 0
  rr7 = (rr & b7) != 0
  r3  = (r  & b7) != 0
  rd3 = (rd & b7) != 0
  rr3 = (rr & b7) != 0

  n   = r7
  v   = rd7 & rr7 & !r7 | !rd7 & rr7 & r7
  c   = !rd7 & rr7 | rr7 & r7 | r7 & !rd7
  h   = !rd3 & rr3 | rr3 & r3 | r3 & !rd3

  cpu.sreg.from_h(
    {
      H: h,
      S: n ^ v,
      V: v,
      N: n,
      Z: r.zero?,
      C: c,
    }
  )
end
stack_pop(cpu) click to toggle source
# File lib/avr/opcode.rb, line 201
def self.stack_pop(cpu)
  cpu.sp.increment
  cpu.sram.memory.fetch(cpu.sp.value).value
end
stack_pop_word(cpu) click to toggle source
# File lib/avr/opcode.rb, line 207
def self.stack_pop_word(cpu)
  stack_pop(cpu) | (stack_pop(cpu) << 8)
end
stack_push(cpu, byte) click to toggle source
# File lib/avr/opcode.rb, line 189
def self.stack_push(cpu, byte)
  cpu.sram.memory.fetch(cpu.sp.value).value = byte
  cpu.sp.decrement
end
stack_push_word(cpu, word) click to toggle source
# File lib/avr/opcode.rb, line 195
def self.stack_push_word(cpu, word)
  stack_push(cpu, (word & 0xff00) >> 8)
  stack_push(cpu, (word & 0x00ff))
end
twos_complement(value, bits) click to toggle source
# File lib/avr/opcode/operand_parsers.rb, line 7
def self.twos_complement(value, bits)
  mask = (2**(bits - 1)).to_i
  -(value & mask) + (value & ~mask)
end

Public Instance Methods

execute(cpu, memory, args) click to toggle source
# File lib/avr/opcode.rb, line 176
def execute(cpu, memory, args)
  opcode_proc.call(cpu, memory, args)
end
format_args(args) click to toggle source
# File lib/avr/opcode.rb, line 154
def format_args(args)
  formatted_args = []
  args.each_with_index do |arg, i|
    arg_formatter = OPCODE_ARGUMENT_TYPES[T.must(arg_types[i])]
    case arg_formatter
    when String
      formatted_args << (arg_formatter % arg)
    when Proc
      formatted_args << arg_formatter.call(arg)
    else
      raise "Unknown argument formatter (#{arg_formatter.class}) for #{arg}"
    end
  end
  formatted_args
end
inspect() click to toggle source
# File lib/avr/opcode.rb, line 171
def inspect
  "#<#{self.class.name} #{mnemonic} #{arg_types}>"
end
validate(args) click to toggle source
# File lib/avr/opcode.rb, line 141
def validate(args)
  raise IncorrectArgumentCount unless args.size == arg_types.size

  args.each_with_index do |arg, i|
    arg_exception = validate_arg(arg, i)

    raise arg_exception, "Argument #{i} (#{arg}) invalid for #{arg_types[i]}" if arg_exception
  end

  true
end
validate_arg(arg, arg_number) click to toggle source
# File lib/avr/opcode.rb, line 103
def validate_arg(arg, arg_number)
  case arg_types[arg_number]
  when :register
    return RegisterExpected unless arg.is_a?(Register)
  when :word_register
    return WordRegisterExpected unless arg.is_a?(RegisterPair)
  when :byte
    return ByteConstantExpected unless arg.is_a?(Value)
    return ConstantOutOfRange unless arg.value >= 0x00 && arg.value <= 0xff
  when :word
    return WordConstantExpected unless arg.is_a?(Value)
    return ConstantOutOfRange unless arg.value >= 0x0000 && arg.value <= 0xffff
  when :absolute_pc
    return AbsolutePcExpected unless arg.is_a?(Value)
    return ConstantOutOfRange unless arg.value >= 0 && arg.value <= (2**22).to_i - 1
  when :near_relative_pc
    return NearRelativePcExpected unless arg.is_a?(Value)
    return ConstantOutOfRange unless arg.value >= -64 && arg.value <= 63
  when :far_relative_pc
    return FarRelativePcExpected unless arg.is_a?(Value)
    return ConstantOutOfRange unless arg.value >= -2048 && arg.value <= 2047
  when :io_address
    return IoAddressExpected unless arg.is_a?(Value)
    return ConstantOutOfRange unless arg.value >= 0 && arg.value <= 63
  when :lower_io_address
    return IoAddressExpected unless arg.is_a?(Value)
    return ConstantOutOfRange unless arg.value >= 0 && arg.value <= 31
  when :register_with_bit_number
    return RegisterExpected unless arg.register.is_a?(Register)
    return BitNumberExpected unless arg.bit_number.is_a?(Integer)
    return ConstantOutOfRange unless arg.bit_number >= 0 && arg.bit_number <= 7
  when :sreg_flag
    return StatusRegisterBitExpected unless arg.is_a?(Value)
    return StatusRegisterBitExpected unless arg.value == 0 || arg.value == 1
  end
end