started naming instruction arguments properly, starting with compare
This commit is contained in:
parent
f65ad813af
commit
6abd10f278
@ -2,22 +2,22 @@ module Arm
|
|||||||
class CompareInstruction < Vm::CompareInstruction
|
class CompareInstruction < Vm::CompareInstruction
|
||||||
include Arm::Constants
|
include Arm::Constants
|
||||||
|
|
||||||
def initialize(first , attributes)
|
def initialize(left , right , attributes)
|
||||||
super(first , attributes)
|
super(left , right, attributes)
|
||||||
@attributes[:condition_code] = :al if @attributes[:condition_code] == nil
|
@attributes[:condition_code] = :al if @attributes[:condition_code] == nil
|
||||||
@operand = 0
|
@operand = 0
|
||||||
@i = 0
|
@i = 0
|
||||||
@attributes[:update_status] = 1
|
@attributes[:update_status] = 1
|
||||||
@rn = first
|
@rn = left
|
||||||
@rd = :r0
|
@rd = :r0
|
||||||
end
|
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
|
def length
|
||||||
4
|
4
|
||||||
end
|
end
|
||||||
|
|
||||||
def build
|
def build
|
||||||
arg = @attributes[:right]
|
arg = @right
|
||||||
|
|
||||||
if arg.is_a?(Vm::StringConstant)
|
if arg.is_a?(Vm::StringConstant)
|
||||||
# do pc relative addressing with the difference to the instuction
|
# do pc relative addressing with the difference to the instuction
|
||||||
|
@ -45,28 +45,28 @@ module Vm
|
|||||||
# Derived machines may use own instructions and define functions for them if so desired
|
# Derived machines may use own instructions and define functions for them if so desired
|
||||||
def initialize
|
def initialize
|
||||||
[:push, :pop].each do |inst|
|
[:push, :pop].each do |inst|
|
||||||
define_instruction_for(inst , StackInstruction)
|
define_instruction_one(inst , StackInstruction)
|
||||||
end
|
end
|
||||||
[:adc, :add, :and, :bic, :eor, :orr, :rsb, :rsc, :sbc, :sub].each do |inst|
|
[:adc, :add, :and, :bic, :eor, :orr, :rsb, :rsc, :sbc, :sub].each do |inst|
|
||||||
define_instruction_for(inst , LogicInstruction)
|
define_instruction_one(inst , LogicInstruction)
|
||||||
end
|
end
|
||||||
[:mov, :mvn].each do |inst|
|
[:mov, :mvn].each do |inst|
|
||||||
define_instruction_for(inst , MoveInstruction)
|
define_instruction_one(inst , MoveInstruction)
|
||||||
end
|
end
|
||||||
[:cmn, :cmp, :teq, :tst].each do |inst|
|
[:cmn, :cmp, :teq, :tst].each do |inst|
|
||||||
define_instruction_for(inst , CompareInstruction)
|
define_instruction_two(inst , CompareInstruction)
|
||||||
end
|
end
|
||||||
[:strb, :str , :ldrb, :ldr].each do |inst|
|
[:strb, :str , :ldrb, :ldr].each do |inst|
|
||||||
define_instruction_for(inst , MemoryInstruction)
|
define_instruction_one(inst , MemoryInstruction)
|
||||||
end
|
end
|
||||||
[:b, :call , :swi].each do |inst|
|
[:b, :call , :swi].each do |inst|
|
||||||
define_instruction_for(inst , CallInstruction)
|
define_instruction_one(inst , CallInstruction)
|
||||||
end
|
end
|
||||||
# create all possible brach instructions, but the CallInstruction demangles the
|
# create all possible brach instructions, but the CallInstruction demangles the
|
||||||
# code, and has opcode set to :b and :condition_code set to the condition
|
# code, and has opcode set to :b and :condition_code set to the condition
|
||||||
CONDITIONS.each do |suffix|
|
CONDITIONS.each do |suffix|
|
||||||
define_instruction_for("b#{suffix}".to_sym , CallInstruction)
|
define_instruction_one("b#{suffix}".to_sym , CallInstruction)
|
||||||
define_instruction_for("call#{suffix}".to_sym , CallInstruction)
|
define_instruction_one("call#{suffix}".to_sym , CallInstruction)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -74,20 +74,6 @@ module Vm
|
|||||||
self.class.send(:define_method, name , &block)
|
self.class.send(:define_method, name , &block)
|
||||||
end
|
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
|
def self.instance
|
||||||
@@instance
|
@@instance
|
||||||
@ -105,7 +91,28 @@ module Vm
|
|||||||
# be used to define the mov on an arm machine.
|
# 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
|
# This methods picks up that derived class and calls a define_instruction methods that can
|
||||||
# be overriden in subclasses
|
# 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
|
c_name = clazz.name
|
||||||
my_module = self.class.name.split("::").first
|
my_module = self.class.name.split("::").first
|
||||||
clazz_name = clazz.name.split("::").last
|
clazz_name = clazz.name.split("::").last
|
||||||
@ -113,7 +120,7 @@ module Vm
|
|||||||
module_class = eval("#{my_module}::#{clazz_name}") rescue nil
|
module_class = eval("#{my_module}::#{clazz_name}") rescue nil
|
||||||
clazz = module_class if module_class
|
clazz = module_class if module_class
|
||||||
end
|
end
|
||||||
define_instruction(inst , clazz )
|
clazz
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -55,8 +55,9 @@ module Vm
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
class CompareInstruction < Instruction
|
class CompareInstruction < Instruction
|
||||||
def initialize first , options
|
def initialize left , right , options
|
||||||
@first = first
|
@left = left
|
||||||
|
@right = right
|
||||||
super(options)
|
super(options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,3 +2,4 @@ require_relative "test_arm"
|
|||||||
require_relative "test_logic"
|
require_relative "test_logic"
|
||||||
require_relative "test_move"
|
require_relative "test_move"
|
||||||
require_relative "test_memory"
|
require_relative "test_memory"
|
||||||
|
require_relative "test_compare"
|
||||||
|
@ -18,14 +18,6 @@ class TestArmAsm < MiniTest::Test
|
|||||||
code = @machine.bic :r2 , left: :r2 , right: :r3
|
code = @machine.bic :r2 , left: :r2 , right: :r3
|
||||||
assert_code code , :bic , [0x03,0x20,0xc2,0xe1] #e3 c2 20 44
|
assert_code code , :bic , [0x03,0x20,0xc2,0xe1] #e3 c2 20 44
|
||||||
end
|
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
|
def test_push
|
||||||
code = @machine.push [:lr] , {}
|
code = @machine.push [:lr] , {}
|
||||||
assert_code code , :push , [0x00,0x40,0x2d,0xe9] #e9 2d 40 00
|
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
|
assert_code code , :sbc , [0x05,0x30,0xc4,0xe0]#e0 c4 30 05
|
||||||
end
|
end
|
||||||
def test_swi
|
def test_swi
|
||||||
code = @machine.swi 0x05 , {}
|
code = @machine.swi 0x05
|
||||||
assert_code code , :swi , [0x05,0x00,0x00,0xef]#ef 00 00 05
|
assert_code code , :swi , [0x05,0x00,0x00,0xef]#ef 00 00 05
|
||||||
end
|
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
|
end
|
||||||
|
22
test/arm/test_compare.rb
Normal file
22
test/arm/test_compare.rb
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user