diff --git a/lib/arm/compare_instruction.rb b/lib/arm/compare_instruction.rb index 0ffd86b8..543592d4 100644 --- a/lib/arm/compare_instruction.rb +++ b/lib/arm/compare_instruction.rb @@ -2,22 +2,22 @@ module Arm class CompareInstruction < Vm::CompareInstruction include Arm::Constants - def initialize(first , attributes) - super(first , attributes) + def initialize(left , right , attributes) + super(left , right, attributes) @attributes[:condition_code] = :al if @attributes[:condition_code] == nil @operand = 0 @i = 0 @attributes[:update_status] = 1 - @rn = first + @rn = left @rd = :r0 end - # arm intrucioons are pretty sensible, and always 4 bytes (thumb not supported) + # arm instructions are pretty sensible, and always 4 bytes (thumb not supported) def length 4 end def build - arg = @attributes[:right] + arg = @right if arg.is_a?(Vm::StringConstant) # do pc relative addressing with the difference to the instuction diff --git a/lib/vm/c_machine.rb b/lib/vm/c_machine.rb index dd2017be..5871d695 100644 --- a/lib/vm/c_machine.rb +++ b/lib/vm/c_machine.rb @@ -45,28 +45,28 @@ module Vm # Derived machines may use own instructions and define functions for them if so desired def initialize [:push, :pop].each do |inst| - define_instruction_for(inst , StackInstruction) + define_instruction_one(inst , StackInstruction) end [:adc, :add, :and, :bic, :eor, :orr, :rsb, :rsc, :sbc, :sub].each do |inst| - define_instruction_for(inst , LogicInstruction) + define_instruction_one(inst , LogicInstruction) end [:mov, :mvn].each do |inst| - define_instruction_for(inst , MoveInstruction) + define_instruction_one(inst , MoveInstruction) end [:cmn, :cmp, :teq, :tst].each do |inst| - define_instruction_for(inst , CompareInstruction) + define_instruction_two(inst , CompareInstruction) end [:strb, :str , :ldrb, :ldr].each do |inst| - define_instruction_for(inst , MemoryInstruction) + define_instruction_one(inst , MemoryInstruction) end [:b, :call , :swi].each do |inst| - define_instruction_for(inst , CallInstruction) + define_instruction_one(inst , CallInstruction) end # create all possible brach instructions, but the CallInstruction demangles the # code, and has opcode set to :b and :condition_code set to the condition CONDITIONS.each do |suffix| - define_instruction_for("b#{suffix}".to_sym , CallInstruction) - define_instruction_for("call#{suffix}".to_sym , CallInstruction) + define_instruction_one("b#{suffix}".to_sym , CallInstruction) + define_instruction_one("call#{suffix}".to_sym , CallInstruction) end end @@ -74,20 +74,6 @@ module Vm self.class.send(:define_method, name , &block) end - # define the instruction inst (given as a symbol) on this class as a methods - # As we define a standard set of instructions (or memnonics) , this turns this class into a kind of - # Assembler, in that you can write .mov() or .pop() and those functions mean the same as if they - # were in an assembler file (also options are the same) - # defaults gets merged into the instructions options hash, ie passed on to the (machine specific) - # Instruction constructor and as such can be used to influence that classes behaviour - def define_instruction(inst , clazz , defaults = {} ) - create_method(inst) do |first , options| - options = {} if options == nil - options.merge defaults - options[:opcode] = inst - clazz.new(first , options) - end - end def self.instance @@instance @@ -105,7 +91,28 @@ module Vm # be used to define the mov on an arm machine. # This methods picks up that derived class and calls a define_instruction methods that can # be overriden in subclasses - def define_instruction_for(inst , clazz ) + def define_instruction_one(inst , clazz , defaults = {} ) + clazz = class_for(clazz) + create_method(inst) do |first , options = nil| + options = {} if options == nil + options.merge defaults + options[:opcode] = inst + clazz.new(first , options) + end + end + + # same for two args (left right, from to etc) + def define_instruction_two(inst , clazz , defaults = {} ) + clazz = class_for(clazz) + create_method(inst) do |first ,second , options = nil| + options = {} if options == nil + options.merge defaults + options[:opcode] = inst + clazz.new(first , second ,options) + end + end + + def class_for clazz c_name = clazz.name my_module = self.class.name.split("::").first clazz_name = clazz.name.split("::").last @@ -113,7 +120,7 @@ module Vm module_class = eval("#{my_module}::#{clazz_name}") rescue nil clazz = module_class if module_class end - define_instruction(inst , clazz ) + clazz end end end diff --git a/lib/vm/instruction.rb b/lib/vm/instruction.rb index 7ad50ffc..98338f69 100644 --- a/lib/vm/instruction.rb +++ b/lib/vm/instruction.rb @@ -55,8 +55,9 @@ module Vm end end class CompareInstruction < Instruction - def initialize first , options - @first = first + def initialize left , right , options + @left = left + @right = right super(options) end end diff --git a/test/arm/test_all.rb b/test/arm/test_all.rb index f086bd4a..f6575565 100644 --- a/test/arm/test_all.rb +++ b/test/arm/test_all.rb @@ -2,3 +2,4 @@ require_relative "test_arm" require_relative "test_logic" require_relative "test_move" require_relative "test_memory" +require_relative "test_compare" diff --git a/test/arm/test_arm.rb b/test/arm/test_arm.rb index 24c1fc6b..b1aeb09c 100644 --- a/test/arm/test_arm.rb +++ b/test/arm/test_arm.rb @@ -18,14 +18,6 @@ class TestArmAsm < MiniTest::Test code = @machine.bic :r2 , left: :r2 , right: :r3 assert_code code , :bic , [0x03,0x20,0xc2,0xe1] #e3 c2 20 44 end - def test_cmn - code = @machine.cmn :r1 , right: :r2 - assert_code code , :cmn , [0x02,0x00,0x71,0xe1] #e1 71 00 02 - end - def test_cmp - code = @machine.cmp :r1 , right: :r2 - assert_code code , :cmp , [0x02,0x00,0x51,0xe1] #e1 51 00 02 - end def test_push code = @machine.push [:lr] , {} assert_code code , :push , [0x00,0x40,0x2d,0xe9] #e9 2d 40 00 @@ -47,15 +39,7 @@ class TestArmAsm < MiniTest::Test assert_code code , :sbc , [0x05,0x30,0xc4,0xe0]#e0 c4 30 05 end def test_swi - code = @machine.swi 0x05 , {} + code = @machine.swi 0x05 assert_code code , :swi , [0x05,0x00,0x00,0xef]#ef 00 00 05 end - def test_teq - code = @machine.teq :r1 , right: :r2 - assert_code code , :teq , [0x02,0x00,0x31,0xe1] #e1 31 00 02 - end - def test_tst - code = @machine.tst :r1 , right: :r2 - assert_code code , :tst , [0x02,0x00,0x11,0xe1] #e1 11 00 02 - end end diff --git a/test/arm/test_compare.rb b/test/arm/test_compare.rb new file mode 100644 index 00000000..9103da47 --- /dev/null +++ b/test/arm/test_compare.rb @@ -0,0 +1,22 @@ +require_relative 'helper' + +class TestArmAsm < MiniTest::Test + include ArmHelper + + def test_cmn + code = @machine.cmn :r1 , :r2 + assert_code code , :cmn , [0x02,0x00,0x71,0xe1] #e1 71 00 02 + end + def test_cmp + code = @machine.cmp :r1 , :r2 + assert_code code , :cmp , [0x02,0x00,0x51,0xe1] #e1 51 00 02 + end + def test_teq + code = @machine.teq :r1 , :r2 + assert_code code , :teq , [0x02,0x00,0x31,0xe1] #e1 31 00 02 + end + def test_tst + code = @machine.tst :r1 , :r2 + assert_code code , :tst , [0x02,0x00,0x11,0xe1] #e1 11 00 02 + end +end \ No newline at end of file