diff --git a/lib/asm/arm/builder_b.rb b/lib/asm/arm/builder_b.rb index c6037a2c..ce03c68c 100644 --- a/lib/asm/arm/builder_b.rb +++ b/lib/asm/arm/builder_b.rb @@ -31,69 +31,56 @@ module Asm a end - class MathReferenceArgNode < Asm::ReferenceArgNode - attr_accessor :op, :right - end - def simplify_reference(arg) - node = MathReferenceArgNode.new - - if (arg.is_a?(Asm::MathNode)) - node.argument = arg.left - node.op = arg.op - node.right = arg.right - else - node.argument = arg - end - - node - end - # Build representation for target address - def build_operand(arg1) - if (arg1.is_a?(Asm::ReferenceArgNode)) - argr = simplify_reference(arg1.argument) - arg = argr.argument - if (arg.is_a?(Asm::RegisterArgNode)) - @i = 0 - @pre_post_index = 1 - @w = 0 - @rn = reg_ref(arg) - @operand = 0 - - if (argr.op and argr.right.is_a?(Asm::NumLiteralArgNode)) - val = argr.right.value - if (val < 0) - @add_offset = 0 - val *= -1 - else - @add_offset = 1 - end - if (val.abs > 4095) - raise Asm::AssemblyError.new('reference offset too large/small (max 4095)', argr.right) - end - @operand = val - elsif (argr.op) - raise Asm::AssemblyError.new('reference offset must be an integer literal', argr.right) + def build_operand(arg) + #str / ldr are _seruous instructions. With BIG possibilities no half are implemented + if (arg.is_a?(Asm::RegisterArgNode)) + @i = 0 + @pre_post_index = 0 + @w = 0 + @rn = reg_ref(arg) + @operand = 0 + + if (false ) #argr.op and argr.right.is_a?(Asm::NumLiteralArgNode)) + + # this if was buggy even before + # but as mentioned here we'd have to implement the options + # though a better syntax will have to be found + val = argr.right.value + if (val < 0) + @add_offset = 0 + val *= -1 + else + @add_offset = 1 end + if (val.abs > 4095) + raise Asm::AssemblyError.new('reference offset too large/small (max 4095)', argr.right) + end + @operand = val else - raise Asm::AssemblyError.new(Asm::ERRSTR_INVALID_ARG, arg) + # raise Asm::AssemblyError.new(Asm::ERRSTR_INVALID_ARG, arg) end - elsif (arg1.is_a?(Asm::LabelEquivAddrArgNode) or arg1.is_a?(Asm::NumEquivAddrArgNode)) + elsif (arg.is_a?(Asm::LabelEquivAddrArgNode) or arg.is_a?(Asm::NumEquivAddrArgNode)) @i = 0 @pre_post_index = 1 @w = 0 @rn = 15 # pc @operand = 0 @use_addrtable_reloc = true - @addrtable_reloc_target = arg1 + @addrtable_reloc_target = arg else - puts "Invalid #{arg1.inspect}" - raise Asm::AssemblyError.new(Asm::ERRSTR_INVALID_ARG, arg1.inspect) + puts "Invalid #{arg.inspect}" + raise Asm::AssemblyError.new(Asm::ERRSTR_INVALID_ARG, arg.inspect) end end def write(io, as, ast_asm, inst) - val = operand | (rd << 12) | (rn << 12+4) | + #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 + @pre_post_index = 1 + val = operand | (rd << 12 ) | (rn << 12 + 4) | (load_store << 12+4+4) | (w << 12+4+4+1) | (byte_access << 12+4+4+1+1) | (add_offset << 12+4+4+1+1+1) | (pre_post_index << 12+4+4+1+1+1+1) | (i << 12+4+4+1+1+1+1+1) | diff --git a/lib/asm/nodes.rb b/lib/asm/nodes.rb index 14fe2344..d34344b5 100644 --- a/lib/asm/nodes.rb +++ b/lib/asm/nodes.rb @@ -65,13 +65,6 @@ module Asm class LabelEquivAddrArgNode < LabelRefArgNode end - class ReferenceArgNode < ArgNode - attr_accessor :argument - def initilize arg - @argument = arg - end - end - class ParseError < StandardError def initialize(message, s) super(message) diff --git a/test/test_crystal.rb b/test/test_crystal.rb index b6568994..47a998d1 100644 --- a/test/test_crystal.rb +++ b/test/test_crystal.rb @@ -37,6 +37,17 @@ class TestArmAsm < MiniTest::Test code = @generator.and( [:reg , 'r1'] , [:reg , 'r2'] , [:reg , 'r3']).first assert_code code , :and , [0x03,0x10,0x02,0xe0] #e0 01 10 03 end + def test_b + # the address is what an assembler calculates (a signed number for the amount of instructions), + # ie the relative (to pc) address -8 (pipeline) /4 so save space + # so the cpu adds the value*4 and starts loading that (load, decode, execute) + code = @generator.instance_eval { b -1 }.first #this jumps to the next instruction + assert_code code , :b , [0xff,0xff,0xff,0xea] #ea ff ff fe + end + def test_bl #see comment above. bx not implemented (as it means into thumb, and no thumb here) + code = @generator.instance_eval { bl -1 }.first #this jumps to the next instruction + assert_code code , :bl , [0xff,0xff,0xff,0xeb] #ea ff ff fe + end def test_bic code = @generator.instance_eval { bic r2 , r2 , r3 }.first assert_code code , :bic , [0x03,0x20,0xc2,0xe1] #e3 c2 20 44 @@ -69,18 +80,26 @@ class TestArmAsm < MiniTest::Test code = @generator.instance_eval { sbc r3, r4 , r5 }.first assert_code code , :sbc , [0x05,0x30,0xc4,0xe0]#e0 c4 30 05 end + def test_str + code = @generator.instance_eval { str r0, r0 }.first + assert_code code, :str , [0x00,0x00,0x80,0xe5] #e5 81 00 00 + end def test_sub code = @generator.instance_eval { sub r2, r0, 1 }.first - assert_code code, :sub , [0x01,0x20,0x40,0xe2] + assert_code code, :sub , [0x01,0x20,0x40,0xe2] #e2 40 20 01 end def test_swi code = @generator.instance_eval { swi 0x05 }.first assert_code code , :swi , [0x05,0x00,0x00,0xef]#ef 00 00 05 end def test_teq - code = @generator.teq( [:reg , 'r1'] , [:reg , 'r2'] ).first + code = @generator.instance_eval{ teq r1 , r2}.first assert_code code , :teq , [0x02,0x00,0x31,0xe1] #e1 31 00 02 end + def test_tst + code = @generator.instance_eval{ tst r1 , r2}.first + assert_code code , :tst , [0x02,0x00,0x11,0xe1] #e1 11 00 02 + end def test_mov code = @generator.instance_eval { mov r0, 5 }.first assert_code code , :mov , [0x05,0x00,0xa0,0xe3] #e3 a0 10 05 @@ -89,7 +108,6 @@ class TestArmAsm < MiniTest::Test code = @generator.instance_eval { mvn r1, 5 }.first assert_code code , :mvn , [0x05,0x10,0xe0,0xe3] #e3 e0 10 05 end - # tst b bl bx strb def saved_other @generator.instance_eval do mov r0, 5