2014-05-05 21:21:11 +02:00
|
|
|
require_relative "nodes"
|
2014-05-03 14:13:15 +02:00
|
|
|
|
2014-05-03 21:18:04 +02:00
|
|
|
module Arm
|
2014-05-03 14:13:15 +02:00
|
|
|
# ADDRESSING MODE 2
|
|
|
|
# Implemented: immediate offset with offset=0
|
2014-05-03 21:18:04 +02:00
|
|
|
class MemoryInstruction < Vm::MemoryInstruction
|
2014-05-05 21:21:11 +02:00
|
|
|
include Arm::Constants
|
2014-05-03 14:13:15 +02:00
|
|
|
|
2014-06-01 20:20:44 +02:00
|
|
|
def initialize(result , left , right = nil , attributes = {})
|
|
|
|
super(result , left , right , attributes)
|
2014-05-16 18:56:13 +02:00
|
|
|
@attributes[:update_status] = 0 if @attributes[:update_status] == nil
|
2014-05-14 09:47:30 +02:00
|
|
|
@attributes[:condition_code] = :al if @attributes[:condition_code] == nil
|
2014-05-06 20:36:28 +02:00
|
|
|
@operand = 0
|
|
|
|
|
2014-05-03 14:13:15 +02:00
|
|
|
@pre_post_index = 0 #P flag
|
|
|
|
@add_offset = 0 #U flag
|
|
|
|
@is_load = opcode.to_s[0] == "l" ? 1 : 0 #L (load) flag
|
|
|
|
end
|
|
|
|
|
2014-05-16 22:08:45 +02:00
|
|
|
# arm intructions are pretty sensible, and always 4 bytes (thumb not supported)
|
2014-05-05 21:21:11 +02:00
|
|
|
def length
|
|
|
|
4
|
|
|
|
end
|
|
|
|
|
2014-05-03 14:13:15 +02:00
|
|
|
# Build representation for target address
|
|
|
|
def build
|
2014-06-01 20:20:44 +02:00
|
|
|
arg = @left
|
2014-05-15 20:35:45 +02:00
|
|
|
arg = "r#{arg.register}".to_sym if( arg.is_a? Vm::Word )
|
2014-05-03 14:13:15 +02:00
|
|
|
#str / ldr are _serious instructions. With BIG possibilities not half are implemented
|
2014-05-06 20:36:28 +02:00
|
|
|
if (arg.is_a?(Symbol)) #symbol is register
|
2014-05-03 14:13:15 +02:00
|
|
|
@rn = arg
|
2014-06-01 20:20:44 +02:00
|
|
|
if @right
|
|
|
|
@operand = @right
|
2014-06-01 21:06:59 +02:00
|
|
|
unless( @operand.is_a? Symbol)
|
|
|
|
if (@operand < 0)
|
|
|
|
@add_offset = 0
|
|
|
|
#TODO test/check/understand
|
|
|
|
@operand *= -1
|
|
|
|
else
|
|
|
|
@add_offset = 1
|
|
|
|
end
|
|
|
|
if (@operand.abs > 4095)
|
|
|
|
raise "reference offset too large/small (max 4095) #{arg} #{inspect}"
|
|
|
|
end
|
2014-05-03 14:13:15 +02:00
|
|
|
end
|
|
|
|
end
|
2014-05-15 15:54:23 +02:00
|
|
|
elsif (arg.is_a?(Vm::StringConstant) ) #use pc relative
|
2014-05-06 20:36:28 +02:00
|
|
|
@rn = :pc
|
|
|
|
@operand = arg.position - self.position - 8 #stringtable is after code
|
|
|
|
@add_offset = 1
|
|
|
|
if (@operand.abs > 4095)
|
|
|
|
raise "reference offset too large/small (max 4095) #{arg} #{inspect}"
|
|
|
|
end
|
2014-05-15 15:54:23 +02:00
|
|
|
elsif( arg.is_a?(Vm::IntegerConstant) )
|
|
|
|
raise "is this working ?? #{arg} #{inspect}"
|
2014-05-03 14:13:15 +02:00
|
|
|
@pre_post_index = 1
|
|
|
|
@rn = pc
|
|
|
|
@use_addrtable_reloc = true
|
|
|
|
@addrtable_reloc_target = arg
|
|
|
|
else
|
2014-05-05 21:21:11 +02:00
|
|
|
raise "invalid operand argument #{arg.inspect} #{inspect}"
|
2014-05-03 14:13:15 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def assemble(io)
|
|
|
|
build
|
|
|
|
#not sure about these 2 constants. They produce the correct output for str r0 , r1
|
|
|
|
# but i can't help thinking that that is because they are not used in that instruction and
|
|
|
|
# so it doesn't matter. Will see
|
|
|
|
@add_offset = 1
|
2014-05-16 22:08:45 +02:00
|
|
|
# TODO to be continued
|
|
|
|
@add_offset = 0 if @attributes[:add_offset]
|
2014-05-03 14:13:15 +02:00
|
|
|
@pre_post_index = 1
|
2014-06-01 21:06:59 +02:00
|
|
|
@pre_post_index = 0 if @attributes[:flaggie]
|
2014-05-10 15:08:53 +02:00
|
|
|
w = 0 #W flag
|
|
|
|
byte_access = opcode.to_s[-1] == "b" ? 1 : 0 #B (byte) flag
|
2014-05-03 14:13:15 +02:00
|
|
|
instuction_class = 0b01 # OPC_MEMORY_ACCESS
|
2014-06-01 21:06:59 +02:00
|
|
|
if @operand.is_a?(Symbol)
|
|
|
|
val = reg_code(@operand)
|
|
|
|
@pre_post_index = 0
|
|
|
|
i = 1 # not quite sure about this, but it gives the output of as. read read read.
|
|
|
|
else
|
|
|
|
i = 0 #I flag (third bit)
|
|
|
|
val = @operand
|
|
|
|
end
|
2014-05-15 20:35:45 +02:00
|
|
|
val = shift(val , 0 ) # for the test
|
2014-06-01 20:20:44 +02:00
|
|
|
val |= shift(reg_code(@result) , 12 )
|
2014-05-15 20:35:45 +02:00
|
|
|
val |= shift(reg_code(@rn) , 12+4) #16
|
|
|
|
val |= shift(@is_load , 12+4 +4)
|
|
|
|
val |= shift(w , 12+4 +4+1)
|
|
|
|
val |= shift(byte_access , 12+4 +4+1+1)
|
2014-06-01 21:06:59 +02:00
|
|
|
val |= shift(@add_offset , 12+4 +4+1+1+1)
|
|
|
|
val |= shift(@pre_post_index, 12+4 +4+1+1+1+1)#24
|
|
|
|
val |= shift(i , 12+4 +4+1+1+1+1 +1)
|
2014-05-15 20:35:45 +02:00
|
|
|
val |= shift(instuction_class,12+4 +4+1+1+1+1 +1+1)
|
|
|
|
val |= shift(cond_bit_code , 12+4 +4+1+1+1+1 +1+1+2)
|
2014-05-03 14:13:15 +02:00
|
|
|
io.write_uint32 val
|
2014-05-15 20:35:45 +02:00
|
|
|
end
|
|
|
|
def shift val , by
|
|
|
|
raise "Not integer #{val}:#{val.class} #{inspect}" unless val.is_a? Fixnum
|
|
|
|
val << by
|
2014-05-03 14:13:15 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|