so close i can smell it, checkpoint
This commit is contained in:
@ -1,8 +1,35 @@
|
||||
require "vm/machine"
|
||||
require_relative "instruction"
|
||||
require_relative "stack_instruction"
|
||||
require_relative "logic_instruction"
|
||||
require_relative "memory_instruction"
|
||||
require_relative "call_instruction"
|
||||
|
||||
module Arm
|
||||
class ArmMachine < Vm::Machine
|
||||
|
||||
# defines a method in the current class, with the name inst (first erg)
|
||||
# the method instantiates an instruction of the given class which gets passed a single hash as arg
|
||||
|
||||
# gets called for every "standard" instruction.
|
||||
# may be used for machine specific ones too
|
||||
def define_instruction inst , clazz
|
||||
super
|
||||
return
|
||||
# need to use create_method and move to options hash
|
||||
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 |options|
|
||||
instruction clazz , inst , suffix , 0 , *args
|
||||
end
|
||||
define_method("#{inst}s#{suffix}") do |options|
|
||||
instruction clazz , inst , suffix , 1 , *args
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def word_load value
|
||||
"word"
|
||||
end
|
||||
@ -12,9 +39,17 @@ module Arm
|
||||
|
||||
def main_entry
|
||||
e = Vm::Block.new("main_entry")
|
||||
e.add_code( mov( :left => :fp , :right => 0 ))
|
||||
end
|
||||
def main_exit
|
||||
e = Vm::Block.new("main_exit")
|
||||
e.join( syscall(0) )
|
||||
end
|
||||
def syscall num
|
||||
e = Vm::Block.new("syscall")
|
||||
e.add_code( MoveInstruction.new( 7 , num ) )
|
||||
e.add_code( CallInstruction.new( :swi ) )
|
||||
e
|
||||
end
|
||||
end
|
||||
end
|
@ -1,6 +1,6 @@
|
||||
require_relative "instruction"
|
||||
|
||||
module Asm
|
||||
module Arm
|
||||
# There are only three call instructions in arm branch (b), call (bl) and syscall (swi)
|
||||
|
||||
# A branch could be called a jump as it has no notion of returning
|
||||
@ -13,7 +13,7 @@ module Asm
|
||||
# in Arm the register layout is different and so we have to place the syscall code into register 7
|
||||
# Registers 0-6 hold the call values as for a normal c call
|
||||
|
||||
class CallInstruction < Instruction
|
||||
class CallInstruction < Vm::CallInstruction
|
||||
|
||||
def assemble(io)
|
||||
case opcode
|
||||
|
82
lib/arm/constants.rb
Normal file
82
lib/arm/constants.rb
Normal file
@ -0,0 +1,82 @@
|
||||
module Arm
|
||||
|
||||
module Constants
|
||||
OPCODES = {
|
||||
:adc => 0b0101, :add => 0b0100,
|
||||
:and => 0b0000, :bic => 0b1110,
|
||||
:eor => 0b0001, :orr => 0b1100,
|
||||
:rsb => 0b0011, :rsc => 0b0111,
|
||||
:sbc => 0b0110, :sub => 0b0010,
|
||||
|
||||
# for these Rn is sbz (should be zero)
|
||||
:mov => 0b1101,
|
||||
:mvn => 0b1111,
|
||||
# for these Rd is sbz and S=1
|
||||
:cmn => 0b1011,
|
||||
:cmp => 0b1010,
|
||||
:teq => 0b1001,
|
||||
:tst => 0b1000,
|
||||
|
||||
:b => 0b1010,
|
||||
:bl => 0b1011,
|
||||
:bx => 0b00010010
|
||||
}
|
||||
#return the bit patter that the cpu uses for the current instruction @opcode
|
||||
def op_bit_code
|
||||
OPCODES[@opcode] or throw "no code found for #{@opcode.inspect}"
|
||||
end
|
||||
|
||||
#codition codes can be applied to many instructions and thus save branches
|
||||
# :al => always , :eq => equal and so on
|
||||
# eq mov if equal :moveq r1 r2 (also exists as function) will only execute if the last operation was 0
|
||||
COND_CODES = {
|
||||
:al => 0b1110, :eq => 0b0000,
|
||||
:ne => 0b0001, :cs => 0b0010,
|
||||
:mi => 0b0100, :hi => 0b1000,
|
||||
:cc => 0b0011, :pl => 0b0101,
|
||||
:ls => 0b1001, :vc => 0b0111,
|
||||
:lt => 0b1011, :le => 0b1101,
|
||||
:ge => 0b1010, :gt => 0b1100,
|
||||
:vs => 0b0110
|
||||
}
|
||||
#return the bit pattern for the @condition_code variable, which signals the conditional code
|
||||
def cond_bit_code
|
||||
COND_CODES[@condition_code] or throw "no code found for #{@condition_code}"
|
||||
end
|
||||
|
||||
REGISTERS = { 'r0' => 0, 'r1' => 1, 'r2' => 2, 'r3' => 3, 'r4' => 4, 'r5' => 5,
|
||||
'r6' => 6, 'r7' => 7, 'r8' => 8, 'r9' => 9, 'r10' => 10, 'r11' => 11,
|
||||
'r12' => 12, 'r13' => 13, 'r14' => 14, 'r15' => 15, 'a1' => 0, 'a2' => 1,
|
||||
'a3' => 2, 'a4' => 3, 'v1' => 4, 'v2' => 5, 'v3' => 6, 'v4' => 7, 'v5' => 8,
|
||||
'v6' => 9, 'rfp' => 9, 'sl' => 10, 'fp' => 11, 'ip' => 12, 'sp' => 13,
|
||||
'lr' => 14, 'pc' => 15 }
|
||||
def reg name
|
||||
raise "no such register #{reg}" unless REGISTERS[name]
|
||||
Asm::Register.new(name , REGISTERS[name])
|
||||
end
|
||||
|
||||
|
||||
|
||||
def calculate_u8_with_rr(arg)
|
||||
parts = arg.value.to_s(2).rjust(32,'0').scan(/^(0*)(.+?)0*$/).flatten
|
||||
pre_zeros = parts[0].length
|
||||
imm_len = parts[1].length
|
||||
if ((pre_zeros+imm_len) % 2 == 1)
|
||||
u8_imm = (parts[1]+'0').to_i(2)
|
||||
imm_len += 1
|
||||
else
|
||||
u8_imm = parts[1].to_i(2)
|
||||
end
|
||||
if (u8_imm.fits_u8?)
|
||||
# can do!
|
||||
rot_imm = (pre_zeros+imm_len) / 2
|
||||
if (rot_imm > 15)
|
||||
return nil
|
||||
end
|
||||
return u8_imm | (rot_imm << 8)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,24 +1,12 @@
|
||||
require_relative "assembly_error"
|
||||
require_relative "arm_machine"
|
||||
require "vm/instruction"
|
||||
require_relative "constants"
|
||||
|
||||
module Asm
|
||||
Vm::Instruction.class_eval do
|
||||
include Arm::Constants
|
||||
|
||||
class Code ; end
|
||||
|
||||
# Not surprisingly represents an cpu instruction.
|
||||
# This is an abstract base class, with derived classes
|
||||
# Logic / Move / Compare / Stack / Memory (see there)
|
||||
#
|
||||
# Opcode is a (<= three) letter accronym (same as in assembly code). Though in arm, suffixes can
|
||||
# make the opcode longer, we chop those off in the constructor
|
||||
# Argurments are registers or labels or string/num Literals
|
||||
|
||||
class Instruction < Code
|
||||
include ArmMachine
|
||||
COND_POSTFIXES = Regexp.union( Arm::Constants::COND_CODES.keys.collect{|k|k.to_s} ).source
|
||||
|
||||
COND_POSTFIXES = Regexp.union( COND_CODES.keys.collect{|k|k.to_s} ).source
|
||||
|
||||
def initialize(opcode , condition_code , update_status , args)
|
||||
def initializ(opcode , condition_code , update_status , args)
|
||||
@update_status_flag = update_status
|
||||
@condition_code = condition_code.to_sym
|
||||
@opcode = opcode
|
||||
@ -43,4 +31,3 @@ module Asm
|
||||
4
|
||||
end
|
||||
end
|
||||
end
|
@ -1,12 +1,12 @@
|
||||
require_relative "instruction"
|
||||
|
||||
module Asm
|
||||
module Arm
|
||||
# ADDRESSING MODE 1
|
||||
# Logic ,Maths, Move and compare instructions (last three below)
|
||||
|
||||
class LogicInstruction < Instruction
|
||||
class LogicInstruction < Vm::LogicInstruction
|
||||
|
||||
def initialize(opcode , condition_code , update_status , args)
|
||||
def initializ(opcode , condition_code , update_status , args)
|
||||
super(opcode , condition_code , update_status , args)
|
||||
@rn = nil
|
||||
@i = 0
|
||||
@ -84,7 +84,7 @@ module Asm
|
||||
io.write_uint32 val
|
||||
end
|
||||
end
|
||||
class CompareInstruction < LogicInstruction
|
||||
class CompareInstruction < Vm::CompareInstruction
|
||||
def initialize(opcode , condition_code , update_status , args)
|
||||
super(opcode , condition_code , update_status , args)
|
||||
@update_status_flag = 1
|
||||
@ -95,11 +95,12 @@ module Asm
|
||||
do_build args[1]
|
||||
end
|
||||
end
|
||||
class MoveInstruction < LogicInstruction
|
||||
def initialize(opcode , condition_code , update_status , args)
|
||||
class MoveInstruction < Vm::MoveInstruction
|
||||
def initializ(opcode , condition_code , update_status , args)
|
||||
super(opcode , condition_code , update_status , args)
|
||||
@rn = reg "r0" # register zero = zero bit pattern
|
||||
end
|
||||
|
||||
def build
|
||||
do_build args[1]
|
||||
end
|
||||
|
@ -1,10 +1,10 @@
|
||||
require "asm/nodes"
|
||||
require_relative "instruction"
|
||||
|
||||
module Asm
|
||||
module Arm
|
||||
# ADDRESSING MODE 2
|
||||
# Implemented: immediate offset with offset=0
|
||||
class MemoryInstruction < Instruction
|
||||
class MemoryInstruction < Vm::MemoryInstruction
|
||||
|
||||
def initialize(opcode , condition_code , update_status , args)
|
||||
super(opcode , condition_code , update_status , args)
|
||||
|
@ -1,10 +1,10 @@
|
||||
require_relative "instruction"
|
||||
|
||||
module Asm
|
||||
module Arm
|
||||
# ADDRESSING MODE 4
|
||||
class StackInstruction < Instruction
|
||||
class StackInstruction < Vm::StackInstruction
|
||||
|
||||
def initialize(opcode , condition_code , update_status , args)
|
||||
def initializ(opcode , condition_code , update_status , args)
|
||||
super(opcode , condition_code , update_status , args)
|
||||
@update_status_flag= 0
|
||||
@rn = reg "r0" # register zero = zero bit pattern
|
||||
|
Reference in New Issue
Block a user