better logic with new block class
This commit is contained in:
parent
7af46d210b
commit
92beb638de
107
lib/asm/block.rb
107
lib/asm/block.rb
@ -1,32 +1,111 @@
|
|||||||
require_relative "code"
|
require_relative 'call_instruction'
|
||||||
|
require_relative 'stack_instruction'
|
||||||
|
require_relative 'logic_instruction'
|
||||||
|
require_relative 'memory_instruction'
|
||||||
|
|
||||||
module Asm
|
module Asm
|
||||||
|
|
||||||
# Labels are, like in assembler, a point to jump/branch to. An address in the stream.
|
class Code ; end
|
||||||
# To allow for forward branches creation does not fix the position. Set does that.
|
|
||||||
class Label < Code
|
# A Block is the smalles unit of code, a list of instructions as it were
|
||||||
def initialize(name , asm)
|
# It is also a point to jump/branch to. An address in the final stream.
|
||||||
super
|
# To allow for forward branches creation does not fix the position. Either set or assembling does that.
|
||||||
@name = name
|
|
||||||
|
# Blocks are also used to create instructions, and so Block has functions for every cpu instruction
|
||||||
|
# and to make using the apu function easier, there are functions that create registers as well
|
||||||
|
class Block < Code
|
||||||
|
|
||||||
|
def initialize(asm)
|
||||||
|
super()
|
||||||
|
@codes = []
|
||||||
|
@position = 0
|
||||||
@asm = asm
|
@asm = asm
|
||||||
end
|
end
|
||||||
|
|
||||||
# setting a label fixes it's position in the stream.
|
ArmMachine::REGISTERS.each do |reg , number|
|
||||||
# For backwards jumps, positions of labels are known at creation, but for forward off course not.
|
define_method(reg) { Asm::Register.new(reg , number) }
|
||||||
# So then one can create a label, branch to it and set it later.
|
end
|
||||||
|
|
||||||
|
def instruction(clazz, opcode , condition_code , update_status , *args)
|
||||||
|
arg_nodes = []
|
||||||
|
args.each do |arg|
|
||||||
|
if (arg.is_a?(Asm::Register))
|
||||||
|
arg_nodes << arg
|
||||||
|
elsif (arg.is_a?(Integer))
|
||||||
|
arg_nodes << Asm::NumLiteral.new(arg)
|
||||||
|
elsif (arg.is_a?(String))
|
||||||
|
arg_nodes << @asm.add_string(arg)
|
||||||
|
elsif (arg.is_a?(Asm::Label))
|
||||||
|
arg_nodes << arg
|
||||||
|
else
|
||||||
|
raise "Invalid argument #{arg.inspect} for instruction"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
add_code clazz.new(opcode , condition_code , update_status , arg_nodes)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def self.define_instruction(inst , clazz )
|
||||||
|
define_method(inst) do |*args|
|
||||||
|
instruction clazz , inst , :al , 0 , *args
|
||||||
|
end
|
||||||
|
define_method("#{inst}s") do |*args|
|
||||||
|
instruction clazz , inst , :al , 1 , *args
|
||||||
|
end
|
||||||
|
ArmMachine::COND_CODES.keys.each do |suffix|
|
||||||
|
define_method("#{inst}#{suffix}") do |*args|
|
||||||
|
instruction clazz , inst , suffix , 0 , *args
|
||||||
|
end
|
||||||
|
define_method("#{inst}s#{suffix}") do |*args|
|
||||||
|
instruction clazz , inst , suffix , 1 , *args
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
[:push, :pop].each do |inst|
|
||||||
|
define_instruction(inst , StackInstruction)
|
||||||
|
end
|
||||||
|
|
||||||
|
[:adc, :add, :and, :bic, :eor, :orr, :rsb, :rsc, :sbc, :sub].each do |inst|
|
||||||
|
define_instruction(inst , LogicInstruction)
|
||||||
|
end
|
||||||
|
[:mov, :mvn].each do |inst|
|
||||||
|
define_instruction(inst , MoveInstruction)
|
||||||
|
end
|
||||||
|
[:cmn, :cmp, :teq, :tst].each do |inst|
|
||||||
|
define_instruction(inst , CompareInstruction)
|
||||||
|
end
|
||||||
|
[:strb, :str , :ldrb, :ldr].each do |inst|
|
||||||
|
define_instruction(inst , MemoryInstruction)
|
||||||
|
end
|
||||||
|
[:b, :bl , :swi].each do |inst|
|
||||||
|
define_instruction(inst , CallInstruction)
|
||||||
|
end
|
||||||
|
|
||||||
|
# setting a block fixes it's position in the stream.
|
||||||
|
# For backwards jumps, positions of blocks are known at creation, but for forward off course not.
|
||||||
|
# So then one can create a block, branch to it and set it later.
|
||||||
def set!
|
def set!
|
||||||
@asm.add_value self
|
@asm.add_block self
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
# Label has no length , 0
|
# Label has no length , 0
|
||||||
def length
|
def length
|
||||||
0
|
@codes.sum :length
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_code(kode)
|
||||||
|
kode.at(@position)
|
||||||
|
length = kode.length
|
||||||
|
@position += length
|
||||||
|
@codes << kode
|
||||||
end
|
end
|
||||||
|
|
||||||
# nothing to write, we check that the position is what was set
|
|
||||||
def assemble(io)
|
def assemble(io)
|
||||||
raise "Hmm hmm hmm, me thinks i should be somewhere else" if self.position != io.tell
|
@codes.each do |obj|
|
||||||
|
obj.assemble io
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
require_relative "instruction"
|
||||||
|
|
||||||
module Asm
|
module Asm
|
||||||
# There are only three call instructions in arm branch (b), call (bl) and syscall (swi)
|
# There are only three call instructions in arm branch (b), call (bl) and syscall (swi)
|
||||||
|
|
||||||
@ -17,7 +19,7 @@ module Asm
|
|||||||
case opcode
|
case opcode
|
||||||
when :b, :bl
|
when :b, :bl
|
||||||
arg = args[0]
|
arg = args[0]
|
||||||
if arg.is_a? Label
|
if arg.is_a? Block
|
||||||
diff = arg.position - self.position - 8
|
diff = arg.position - self.position - 8
|
||||||
arg = NumLiteral.new(diff)
|
arg = NumLiteral.new(diff)
|
||||||
end
|
end
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
require_relative "label"
|
|
||||||
require_relative "assembly_error"
|
require_relative "assembly_error"
|
||||||
require_relative "arm_machine"
|
require_relative "arm_machine"
|
||||||
|
|
||||||
module Asm
|
module Asm
|
||||||
|
|
||||||
|
class Code ; end
|
||||||
|
|
||||||
# Not surprisingly represents an cpu instruction.
|
# Not surprisingly represents an cpu instruction.
|
||||||
# This is an abstract base class, with derived classes
|
# This is an abstract base class, with derived classes
|
||||||
# Logic / Move / Compare / Stack / Memory (see there)
|
# Logic / Move / Compare / Stack / Memory (see there)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
require_relative "instruction"
|
||||||
|
|
||||||
module Asm
|
module Asm
|
||||||
# ADDRESSING MODE 1
|
# ADDRESSING MODE 1
|
||||||
# Logic ,Maths, Move and compare instructions (last three below)
|
# Logic ,Maths, Move and compare instructions (last three below)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
require "asm/nodes"
|
require "asm/nodes"
|
||||||
|
require_relative "instruction"
|
||||||
|
|
||||||
module Asm
|
module Asm
|
||||||
# ADDRESSING MODE 2
|
# ADDRESSING MODE 2
|
||||||
|
@ -1,125 +1,90 @@
|
|||||||
require 'asm/call_instruction'
|
|
||||||
require 'asm/stack_instruction'
|
|
||||||
require 'asm/logic_instruction'
|
|
||||||
require 'asm/memory_instruction'
|
|
||||||
require 'asm/nodes'
|
require 'asm/nodes'
|
||||||
|
require 'asm/block'
|
||||||
require 'stream_reader'
|
require 'stream_reader'
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
require "asm/string_literal"
|
require "asm/string_literal"
|
||||||
|
|
||||||
module Asm
|
module Asm
|
||||||
|
|
||||||
class ArmAssembler
|
# Program is the the top-level of the code hierachy, except it is not derived from code
|
||||||
|
# instead a Program is a list of blocks (and string constants)
|
||||||
ArmMachine::REGISTERS.each do |reg , number|
|
|
||||||
define_method(reg) { Asm::Register.new(reg , number) }
|
# All code is created in blocks (see there) and there are two styles for that, for forward of backward
|
||||||
end
|
# referencing. Read function block and add_block and Block.set
|
||||||
|
|
||||||
|
|
||||||
|
class Program
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@codes = []
|
@blocks = []
|
||||||
@position = 0 # marks not set
|
|
||||||
@labels = []
|
|
||||||
@string_table = {}
|
@string_table = {}
|
||||||
end
|
end
|
||||||
attr_reader :codes , :position
|
|
||||||
|
|
||||||
def instruction(clazz, opcode , condition_code , update_status , *args)
|
attr_reader :blocks
|
||||||
arg_nodes = []
|
|
||||||
args.each do |arg|
|
|
||||||
if (arg.is_a?(Asm::Register))
|
|
||||||
arg_nodes << arg
|
|
||||||
elsif (arg.is_a?(Integer))
|
|
||||||
arg_nodes << Asm::NumLiteral.new(arg)
|
|
||||||
elsif (arg.is_a?(String))
|
|
||||||
arg_nodes << add_string(arg)
|
|
||||||
elsif (arg.is_a?(Asm::Label))
|
|
||||||
arg_nodes << arg
|
|
||||||
else
|
|
||||||
raise "Invalid argument #{arg.inspect} for instruction"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
add_code clazz.new(opcode , condition_code , update_status , arg_nodes)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def self.define_instruction(inst , clazz )
|
|
||||||
define_method(inst) do |*args|
|
|
||||||
instruction clazz , inst , :al , 0 , *args
|
|
||||||
end
|
|
||||||
define_method("#{inst}s") do |*args|
|
|
||||||
instruction clazz , inst , :al , 1 , *args
|
|
||||||
end
|
|
||||||
ArmMachine::COND_CODES.keys.each do |suffix|
|
|
||||||
define_method("#{inst}#{suffix}") do |*args|
|
|
||||||
instruction clazz , inst , suffix , 0 , *args
|
|
||||||
end
|
|
||||||
define_method("#{inst}s#{suffix}") do |*args|
|
|
||||||
instruction clazz , inst , suffix , 1 , *args
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
[:push, :pop].each do |inst|
|
# Assembling to string will return a binary string of the whole program, ie all blocks and the
|
||||||
define_instruction(inst , StackInstruction)
|
# strings they use
|
||||||
end
|
# As a memory reference this would be callable, but more likely you will hand it over to
|
||||||
|
# an ObjectWriter as the .text section and then link it. And then execute it :-)
|
||||||
[:adc, :add, :and, :bic, :eor, :orr, :rsb, :rsc, :sbc, :sub].each do |inst|
|
|
||||||
define_instruction(inst , LogicInstruction)
|
|
||||||
end
|
|
||||||
[:mov, :mvn].each do |inst|
|
|
||||||
define_instruction(inst , MoveInstruction)
|
|
||||||
end
|
|
||||||
[:cmn, :cmp, :teq, :tst].each do |inst|
|
|
||||||
define_instruction(inst , CompareInstruction)
|
|
||||||
end
|
|
||||||
[:strb, :str , :ldrb, :ldr].each do |inst|
|
|
||||||
define_instruction(inst , MemoryInstruction)
|
|
||||||
end
|
|
||||||
[:b, :bl , :swi].each do |inst|
|
|
||||||
define_instruction(inst , CallInstruction)
|
|
||||||
end
|
|
||||||
|
|
||||||
def assemble_to_string
|
def assemble_to_string
|
||||||
#put the strings at the end of the assembled code.
|
#put the strings at the end of the assembled code.
|
||||||
# adding them will fix their position and make them assemble after
|
# adding them will fix their position and make them assemble after
|
||||||
@string_table.values.each do |data|
|
@string_table.values.each do |data|
|
||||||
add_code data
|
add_block data
|
||||||
end
|
end
|
||||||
io = StringIO.new
|
io = StringIO.new
|
||||||
assemble(io)
|
assemble(io)
|
||||||
io.string
|
io.string
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Add a string to the string table. Strings are global and constant. So only one copy of each
|
||||||
|
# string exists
|
||||||
|
# Internally StringLiterals are created and stored and during assembly written after the blocks
|
||||||
def add_string str
|
def add_string str
|
||||||
code = @string_table[str]
|
code = @string_table[str]
|
||||||
return code if code
|
return code if code
|
||||||
data = Asm::StringLiteral.new(str)
|
data = Asm::StringLiteral.new(str)
|
||||||
@string_table[str] = data
|
@string_table[str] = data
|
||||||
end
|
end
|
||||||
|
|
||||||
def strings
|
# Length of all blocks. Does not take strings into account as they are added after all blocks.
|
||||||
@string_table.values
|
# This is used to determine where a block when it is added after creation (see add_block)
|
||||||
end
|
def length
|
||||||
|
@blocks.inject(0) {| sum , item | sum + item.length}
|
||||||
def add_code(kode)
|
|
||||||
kode.at(@position)
|
|
||||||
length = kode.length
|
|
||||||
@position += length
|
|
||||||
@codes << kode
|
|
||||||
end
|
|
||||||
|
|
||||||
def label name
|
|
||||||
label = Label.new(name , self)
|
|
||||||
@labels << label
|
|
||||||
label
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# call block to create a new (code) block. The simple way is to do this with a block and
|
||||||
|
# use the yielded block to add code, ie something like:
|
||||||
|
# prog.block do |loop|
|
||||||
|
# loop.instance_eval do #this part you can acheive with calls too
|
||||||
|
# mov r0 , 10
|
||||||
|
# subs r0 , 1
|
||||||
|
# bne block
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# Easy, because it's a backward jump. For forward branches that doesn't work and so you have to
|
||||||
|
# create the block without a ruby block. You can then jumpt to it immediately
|
||||||
|
# But the block is not part of the program (since we don't know where) and so you have to add it later
|
||||||
|
def block
|
||||||
|
block = Block.new(self)
|
||||||
|
yield block.set! if block_given? #yield the block (which set returns)
|
||||||
|
block
|
||||||
|
end
|
||||||
|
|
||||||
|
# This is how you add a forward declared block. This is called automatically when you
|
||||||
|
# call block with ruby block, but has to be done manually if not
|
||||||
|
def add_block block
|
||||||
|
block.at self.length
|
||||||
|
@blocks << block
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
def assemble(io)
|
def assemble(io)
|
||||||
@codes.each do |obj|
|
@blocks.each do |obj|
|
||||||
obj.assemble io
|
obj.assemble io
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
require "asm/instruction"
|
require_relative "instruction"
|
||||||
|
|
||||||
module Asm
|
module Asm
|
||||||
# ADDRESSING MODE 4
|
# ADDRESSING MODE 4
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', ".." , "parslet",'lib'))
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', ".." , "parslet",'lib'))
|
||||||
require 'parslet'
|
require 'parslet'
|
||||||
|
|
||||||
require "asm/stack_instruction"
|
require "asm/program"
|
||||||
require "asm/arm_assembler"
|
|
||||||
require "elf/object_writer"
|
require "elf/object_writer"
|
||||||
require 'vm/parser'
|
require 'vm/parser'
|
||||||
require 'vm/nodes'
|
require 'vm/nodes'
|
||||||
|
@ -6,17 +6,20 @@ require_relative 'helper'
|
|||||||
# adc add and bic eor orr rsb rsc sbc sub mov mvn cmn cmp teq tst b bl bx swi strb
|
# adc add and bic eor orr rsb rsc sbc sub mov mvn cmn cmp teq tst b bl bx swi strb
|
||||||
|
|
||||||
class TestArmAsm < MiniTest::Test
|
class TestArmAsm < MiniTest::Test
|
||||||
# need a code generator, for arm
|
# need Program and a block (see those classes)
|
||||||
def setup
|
def setup
|
||||||
@assembler = Asm::ArmAssembler.new
|
@program = Asm::Program.new
|
||||||
|
#no ruby block given, ie need to add this block later by hand
|
||||||
|
@block = @program.block
|
||||||
end
|
end
|
||||||
|
|
||||||
# code is what the generator spits out, at least one instruction worth (.first)
|
# code is what the generator spits out, at least one instruction worth (.first)
|
||||||
# the op code is wat was witten as assembler in the first place and the binary result
|
# the op code is wat was witten as assembler in the first place and the binary result
|
||||||
# is reversed and in 4 bytes as ruby can only do 31 bits and so we can't test with just one int (?)
|
# is reversed and in 4 bytes as ruby can only do 31 bits and so we can't test with just one int (?)
|
||||||
def assert_code code , op , should
|
def assert_code code , op , should
|
||||||
|
@program.add_block @block #assume not added before
|
||||||
assert_equal op , code.opcode
|
assert_equal op , code.opcode
|
||||||
binary = @assembler.assemble_to_string
|
binary = @program.assemble_to_string
|
||||||
assert_equal 4 , binary.length
|
assert_equal 4 , binary.length
|
||||||
index = 0
|
index = 0
|
||||||
binary.each_byte do |byte |
|
binary.each_byte do |byte |
|
||||||
@ -25,111 +28,111 @@ class TestArmAsm < MiniTest::Test
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
def test_adc
|
def test_adc
|
||||||
code = @assembler.instance_eval { adc r1, r3, r5}.first
|
code = @block.instance_eval { adc r1, r3, r5}.first
|
||||||
assert_code code , :adc , [0x05,0x10,0xa3,0xe0] #e0 a3 10 05
|
assert_code code , :adc , [0x05,0x10,0xa3,0xe0] #e0 a3 10 05
|
||||||
end
|
end
|
||||||
def test_add
|
def test_add
|
||||||
code = @assembler.instance_eval { add r1 , r1, r3}.first
|
code = @block.instance_eval { add r1 , r1, r3}.first
|
||||||
assert_code code , :add , [0x03,0x10,0x81,0xe0] #e0 81 10 03
|
assert_code code , :add , [0x03,0x10,0x81,0xe0] #e0 81 10 03
|
||||||
end
|
end
|
||||||
def test_and # inst eval doesn't really work with and
|
def test_and # inst eval doesn't really work with and
|
||||||
code = @assembler.and( @assembler.r1 , @assembler.r2 , @assembler.r3).first
|
code = @block.and( @block.r1 , @block.r2 , @block.r3).first
|
||||||
assert_code code , :and , [0x03,0x10,0x02,0xe0] #e0 01 10 03
|
assert_code code , :and , [0x03,0x10,0x02,0xe0] #e0 01 10 03
|
||||||
end
|
end
|
||||||
def test_b
|
def test_b
|
||||||
# the address is what an assembler calculates (a signed number for the amount of instructions),
|
# 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
|
# 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)
|
# so the cpu adds the value*4 and starts loading that (load, decode, execute)
|
||||||
code = @assembler.instance_eval { b -1 }.first #this jumps to the next instruction
|
code = @block.instance_eval { b -1 }.first #this jumps to the next instruction
|
||||||
assert_code code , :b , [0xff,0xff,0xff,0xea] #ea ff ff fe
|
assert_code code , :b , [0xff,0xff,0xff,0xea] #ea ff ff fe
|
||||||
end
|
end
|
||||||
def test_bl #see comment above. bx not implemented (as it means into thumb, and no thumb here)
|
def test_bl #see comment above. bx not implemented (as it means into thumb, and no thumb here)
|
||||||
code = @assembler.instance_eval { bl -1 }.first #this jumps to the next instruction
|
code = @block.instance_eval { bl -1 }.first #this jumps to the next instruction
|
||||||
assert_code code , :bl , [0xff,0xff,0xff,0xeb] #ea ff ff fe
|
assert_code code , :bl , [0xff,0xff,0xff,0xeb] #ea ff ff fe
|
||||||
end
|
end
|
||||||
def test_bic
|
def test_bic
|
||||||
code = @assembler.instance_eval { bic r2 , r2 , r3 }.first
|
code = @block.instance_eval { bic r2 , r2 , r3 }.first
|
||||||
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
|
def test_cmn
|
||||||
code = @assembler.instance_eval { cmn r1 , r2 }.first
|
code = @block.instance_eval { cmn r1 , r2 }.first
|
||||||
assert_code code , :cmn , [0x02,0x00,0x71,0xe1] #e1 71 00 02
|
assert_code code , :cmn , [0x02,0x00,0x71,0xe1] #e1 71 00 02
|
||||||
end
|
end
|
||||||
def test_cmp
|
def test_cmp
|
||||||
code = @assembler.instance_eval { cmp r1 , r2 }.first
|
code = @block.instance_eval { cmp r1 , r2 }.first
|
||||||
assert_code code , :cmp , [0x02,0x00,0x51,0xe1] #e1 51 00 02
|
assert_code code , :cmp , [0x02,0x00,0x51,0xe1] #e1 51 00 02
|
||||||
end
|
end
|
||||||
def test_eor
|
def test_eor
|
||||||
code = @assembler.instance_eval { eor r2 , r2 , r3 }.first
|
code = @block.instance_eval { eor r2 , r2 , r3 }.first
|
||||||
assert_code code , :eor , [0x03,0x20,0x22,0xe0] #e0 22 20 03
|
assert_code code , :eor , [0x03,0x20,0x22,0xe0] #e0 22 20 03
|
||||||
end
|
end
|
||||||
def test_ldr
|
def test_ldr
|
||||||
code = @assembler.instance_eval { ldr r0, r0 }.first
|
code = @block.instance_eval { ldr r0, r0 }.first
|
||||||
assert_code code, :ldr , [0x00,0x00,0x90,0xe5] #e5 90 00 00
|
assert_code code, :ldr , [0x00,0x00,0x90,0xe5] #e5 90 00 00
|
||||||
end
|
end
|
||||||
def test_ldr2
|
def test_ldr2
|
||||||
code = @assembler.instance_eval { ldr r0, r0 + 4 }.first
|
code = @block.instance_eval { ldr r0, r0 + 4 }.first
|
||||||
assert_code code, :ldr , [0x04,0x00,0x90,0xe5] #e5 90 00 04
|
assert_code code, :ldr , [0x04,0x00,0x90,0xe5] #e5 90 00 04
|
||||||
end
|
end
|
||||||
def test_ldrb
|
def test_ldrb
|
||||||
code = @assembler.instance_eval { ldrb r0, r0 }.first
|
code = @block.instance_eval { ldrb r0, r0 }.first
|
||||||
assert_code code, :ldrb , [0x00,0x00,0xd0,0xe5] #e5 d0 00 00
|
assert_code code, :ldrb , [0x00,0x00,0xd0,0xe5] #e5 d0 00 00
|
||||||
end
|
end
|
||||||
def test_orr
|
def test_orr
|
||||||
code = @assembler.instance_eval { orr r2 , r2 , r3 }.first
|
code = @block.instance_eval { orr r2 , r2 , r3 }.first
|
||||||
assert_code code , :orr , [0x03,0x20,0x82,0xe1] #e1 82 20 03
|
assert_code code , :orr , [0x03,0x20,0x82,0xe1] #e1 82 20 03
|
||||||
end
|
end
|
||||||
def test_push
|
def test_push
|
||||||
code = @assembler.instance_eval { push lr }.first
|
code = @block.instance_eval { push lr }.first
|
||||||
assert_code code , :push , [0x00,0x40,0x2d,0xe9] #e9 2d 40 00
|
assert_code code , :push , [0x00,0x40,0x2d,0xe9] #e9 2d 40 00
|
||||||
end
|
end
|
||||||
def test_pop
|
def test_pop
|
||||||
code = @assembler.instance_eval { pop pc }.first
|
code = @block.instance_eval { pop pc }.first
|
||||||
assert_code code , :pop , [0x00,0x80,0xbd,0xe8] #e8 bd 80 00
|
assert_code code , :pop , [0x00,0x80,0xbd,0xe8] #e8 bd 80 00
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_rsb
|
def test_rsb
|
||||||
code = @assembler.instance_eval { rsb r1 , r2 , r3 }.first
|
code = @block.instance_eval { rsb r1 , r2 , r3 }.first
|
||||||
assert_code code , :rsb , [0x03,0x10,0x62,0xe0]#e0 62 10 03
|
assert_code code , :rsb , [0x03,0x10,0x62,0xe0]#e0 62 10 03
|
||||||
end
|
end
|
||||||
def test_rsc
|
def test_rsc
|
||||||
code = @assembler.instance_eval { rsc r2 , r3 , r4 }.first
|
code = @block.instance_eval { rsc r2 , r3 , r4 }.first
|
||||||
assert_code code , :rsc , [0x04,0x20,0xe3,0xe0]#e0 e3 20 04
|
assert_code code , :rsc , [0x04,0x20,0xe3,0xe0]#e0 e3 20 04
|
||||||
end
|
end
|
||||||
def test_sbc
|
def test_sbc
|
||||||
code = @assembler.instance_eval { sbc r3, r4 , r5 }.first
|
code = @block.instance_eval { sbc r3, r4 , r5 }.first
|
||||||
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_str
|
def test_str
|
||||||
code = @assembler.instance_eval { str r0, r0 }.first
|
code = @block.instance_eval { str r0, r0 }.first
|
||||||
assert_code code, :str , [0x00,0x00,0x80,0xe5] #e5 81 00 00
|
assert_code code, :str , [0x00,0x00,0x80,0xe5] #e5 81 00 00
|
||||||
end
|
end
|
||||||
def test_strb
|
def test_strb
|
||||||
code = @assembler.instance_eval { strb r0, r0 }.first
|
code = @block.instance_eval { strb r0, r0 }.first
|
||||||
assert_code code, :strb , [0x00,0x00,0xc0,0xe5] #e5 c0 00 00
|
assert_code code, :strb , [0x00,0x00,0xc0,0xe5] #e5 c0 00 00
|
||||||
end
|
end
|
||||||
def test_sub
|
def test_sub
|
||||||
code = @assembler.instance_eval { sub r2, r0, 1 }.first
|
code = @block.instance_eval { sub r2, r0, 1 }.first
|
||||||
assert_code code, :sub , [0x01,0x20,0x40,0xe2] #e2 40 20 01
|
assert_code code, :sub , [0x01,0x20,0x40,0xe2] #e2 40 20 01
|
||||||
end
|
end
|
||||||
def test_swi
|
def test_swi
|
||||||
code = @assembler.instance_eval { swi 0x05 }.first
|
code = @block.instance_eval { swi 0x05 }.first
|
||||||
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
|
def test_teq
|
||||||
code = @assembler.instance_eval{ teq r1 , r2}.first
|
code = @block.instance_eval{ teq r1 , r2}.first
|
||||||
assert_code code , :teq , [0x02,0x00,0x31,0xe1] #e1 31 00 02
|
assert_code code , :teq , [0x02,0x00,0x31,0xe1] #e1 31 00 02
|
||||||
end
|
end
|
||||||
def test_tst
|
def test_tst
|
||||||
code = @assembler.instance_eval{ tst r1 , r2}.first
|
code = @block.instance_eval{ tst r1 , r2}.first
|
||||||
assert_code code , :tst , [0x02,0x00,0x11,0xe1] #e1 11 00 02
|
assert_code code , :tst , [0x02,0x00,0x11,0xe1] #e1 11 00 02
|
||||||
end
|
end
|
||||||
def test_mov
|
def test_mov
|
||||||
code = @assembler.instance_eval { mov r0, 5 }.first
|
code = @block.instance_eval { mov r0, 5 }.first
|
||||||
assert_code code , :mov , [0x05,0x00,0xa0,0xe3] #e3 a0 10 05
|
assert_code code , :mov , [0x05,0x00,0xa0,0xe3] #e3 a0 10 05
|
||||||
end
|
end
|
||||||
def test_mvn
|
def test_mvn
|
||||||
code = @assembler.instance_eval { mvn r1, 5 }.first
|
code = @block.instance_eval { mvn r1, 5 }.first
|
||||||
assert_code code , :mvn , [0x05,0x10,0xe0,0xe3] #e3 e0 10 05
|
assert_code code , :mvn , [0x05,0x10,0xe0,0xe3] #e3 e0 10 05
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user