rubyx/lib/arm/logic_instruction.rb

107 lines
3.4 KiB
Ruby
Raw Normal View History

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