require_relative "instruction" module Asm # ADDRESSING MODE 1 # Logic ,Maths, Move and compare instructions (last three below) class LogicInstruction < Instruction def initialize(opcode , condition_code , update_status , args) super(opcode , condition_code , update_status , args) @rn = nil @i = 0 @rd = args[0] end attr_accessor :i, :rn, :rd # Build representation for source value def build @rn = args[1] do_build args[2] end #(stays in subclases, while build is overriden to provide different arguments) def do_build(arg) if arg.is_a?(Asm::StringLiteral) # do pc relative addressing with the difference to the instuction # 8 is for the funny pipeline adjustment (ie oc pointing to fetch and not execute) arg = Asm::NumLiteral.new( arg.position - self.position - 8 ) end if (arg.is_a?(Asm::NumLiteral)) if (arg.value.fits_u8?) # no shifting needed @operand = arg.value @i = 1 elsif (op_with_rot = calculate_u8_with_rr(arg)) @operand = op_with_rot @i = 1 else raise Asm::AssemblyError.new("cannot fit numeric literal argument in operand #{arg}") end elsif (arg.is_a?(Asm::Register)) @operand = arg @i = 0 elsif (arg.is_a?(Asm::Shift)) rm_ref = arg.argument @i = 0 shift_op = {'lsl' => 0b000, 'lsr' => 0b010, 'asr' => 0b100, 'ror' => 0b110, 'rrx' => 0b110}[arg.type] if (arg.type == 'ror' and arg.value.nil?) # ror #0 == rrx raise Asm::AssemblyError.new('cannot rotate by zero', arg) end arg1 = arg.value if (arg1.is_a?(Asm::NumLiteral)) if (arg1.value >= 32) raise Asm::AssemblyError.new('cannot shift by more than 31', arg1) end shift_imm = arg1.value elsif (arg1.is_a?(Asm::Register)) shift_op val |= 0x1; shift_imm = arg1.number << 1 elsif (arg.type == 'rrx') shift_imm = 0 end @operand = rm_ref | (shift_op << 4) | (shift_imm << 4+3) else raise Asm::AssemblyError.new("invalid operand argument #{arg.inspect}") end end def assemble(io) build instuction_class = 0b00 # OPC_DATA_PROCESSING val = operand.is_a?(Register) ? operand.bits : operand val |= (rd.bits << 12) val |= (rn.bits << 12+4) val |= (update_status_flag << 12+4+4)#20 val |= (op_bit_code << 12+4+4 +1) val |= (i << 12+4+4 +1+4) val |= (instuction_class << 12+4+4 +1+4+1) val |= (cond_bit_code << 12+4+4 +1+4+1+2) io.write_uint32 val end end class CompareInstruction < LogicInstruction def initialize(opcode , condition_code , update_status , args) super(opcode , condition_code , update_status , args) @update_status_flag = 1 @rn = args[0] @rd = reg "r0" end def build do_build args[1] end end class MoveInstruction < LogicInstruction def initialize(opcode , condition_code , update_status , args) super(opcode , condition_code , update_status , args) @rn = reg "r0" # register zero = zero bit pattern end def build do_build args[1] end end end