adds code class as base for anything that can be assembled
This commit is contained in:
parent
d08e6702f0
commit
6261451c4b
46
lib/asm/code.rb
Normal file
46
lib/asm/code.rb
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
module Asm
|
||||||
|
# Base class for anything that we can assemble
|
||||||
|
|
||||||
|
# Derived classes include instrucitons, blocks and data(strings)
|
||||||
|
|
||||||
|
# The commonality abstracted here is the length and position
|
||||||
|
# and the ability to assemble itself into the stream
|
||||||
|
|
||||||
|
# All code is position independant once assembled.
|
||||||
|
# But for jumps and calls two passes are neccessary.
|
||||||
|
# The first setting the position, the second assembling
|
||||||
|
class Code
|
||||||
|
|
||||||
|
# just sets position to nil, so we can sell that it has not been set
|
||||||
|
def initialize
|
||||||
|
@position = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# the position in the stream. Think of it as an address if you want. The difference is small.
|
||||||
|
# Especially since we produce _only_ position independant code
|
||||||
|
# in other words, during assembly the position _must_ be resolved into a pc relative address
|
||||||
|
# and not used as is
|
||||||
|
def position
|
||||||
|
throw "Not set" unless @address
|
||||||
|
@address
|
||||||
|
end
|
||||||
|
|
||||||
|
# The containing class (assembler/function) call this to tell the instruction/data where it is in the
|
||||||
|
# stream. During assembly the position is then used to calculate pc relative addresses.
|
||||||
|
def at address
|
||||||
|
@address = address
|
||||||
|
end
|
||||||
|
|
||||||
|
# length for this code in bytes
|
||||||
|
def length
|
||||||
|
throw "Not implemented #{self}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# so currently the interface passes the io (usually string_io) in for the code to assemble itself.
|
||||||
|
# this may change as the writing is still done externally (or that will change)
|
||||||
|
def assemble(io)
|
||||||
|
throw "Not implemented #{self}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1,10 +1,18 @@
|
|||||||
require "asm/assembly_error"
|
require_relative "label"
|
||||||
require "asm/instruction_tools"
|
require_relative "assembly_error"
|
||||||
require "asm/label"
|
require_relative "instruction_tools"
|
||||||
|
|
||||||
module Asm
|
module Asm
|
||||||
|
|
||||||
class Instruction
|
# 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 InstructionTools
|
include InstructionTools
|
||||||
|
|
||||||
COND_POSTFIXES = Regexp.union( COND_CODES.keys.collect{|k|k.to_s} ).source
|
COND_POSTFIXES = Regexp.union( COND_CODES.keys.collect{|k|k.to_s} ).source
|
||||||
@ -31,17 +39,10 @@ module Asm
|
|||||||
def affect_status
|
def affect_status
|
||||||
@s
|
@s
|
||||||
end
|
end
|
||||||
|
|
||||||
def at position
|
|
||||||
@position = position
|
|
||||||
end
|
|
||||||
|
|
||||||
|
# arm intrucioons are pretty sensible, and always 4 bytes (thumb not supported)
|
||||||
def length
|
def length
|
||||||
4
|
4
|
||||||
end
|
end
|
||||||
|
|
||||||
def assemble(io)
|
|
||||||
raise "Abstract class, should not be called/instantiated #{self.inspect}"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -1,35 +1,34 @@
|
|||||||
module Asm
|
require_relative "code"
|
||||||
|
|
||||||
class Label
|
module Asm
|
||||||
|
|
||||||
|
# Labels are, like in assembler, a point to jump/branch to. An address in the stream.
|
||||||
|
# To allow for forward branches creation does not fix the position. Set does that.
|
||||||
|
class Label < Code
|
||||||
def initialize(name , asm)
|
def initialize(name , asm)
|
||||||
|
super
|
||||||
@name = name
|
@name = name
|
||||||
@asm = asm
|
@asm = asm
|
||||||
@position = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_writer :position , :name
|
|
||||||
|
|
||||||
def position
|
|
||||||
if (@position.nil?)
|
|
||||||
raise 'Tried to use label object that has not been set'
|
|
||||||
end
|
|
||||||
@position
|
|
||||||
end
|
|
||||||
def at pos
|
|
||||||
@position = pos
|
|
||||||
end
|
|
||||||
def length
|
|
||||||
0
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def assemble(io)
|
# setting a label fixes it's position in the stream.
|
||||||
self.position = io.tell
|
# For backwards jumps, positions of labels are known at creation, but for forward off course not.
|
||||||
end
|
# So then one can create a label, branch to it and set it later.
|
||||||
def set!
|
def set!
|
||||||
@asm.add_value self
|
@asm.add_value self
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Label has no length , 0
|
||||||
|
def length
|
||||||
|
0
|
||||||
|
end
|
||||||
|
|
||||||
|
# nothing to write, we check that the position is what was set
|
||||||
|
def assemble(io)
|
||||||
|
raise "Hmm hmm hmm, me thinks i should be somewhere else" if self.position != io.tell
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
@ -1,7 +1,15 @@
|
|||||||
|
require_relative "code"
|
||||||
|
|
||||||
module Asm
|
module Asm
|
||||||
|
# The name really says it all.
|
||||||
|
# The only interesting thing is storage.
|
||||||
|
# Currently string are stored "inline" , ie in the code segment.
|
||||||
|
# Mainly because that works an i aint no elf expert.
|
||||||
|
|
||||||
class StringLiteral
|
class StringLiteral
|
||||||
|
|
||||||
|
# currently aligned to 4 (ie padded with 0) and off course 0 at the end
|
||||||
def initialize(str)
|
def initialize(str)
|
||||||
#align
|
|
||||||
length = str.length
|
length = str.length
|
||||||
# rounding up to the next 4 (always adding one for zero pad)
|
# rounding up to the next 4 (always adding one for zero pad)
|
||||||
pad = ((length / 4 ) + 1 ) * 4 - length
|
pad = ((length / 4 ) + 1 ) * 4 - length
|
||||||
@ -9,16 +17,12 @@ module Asm
|
|||||||
@string = str + "\x00" * pad
|
@string = str + "\x00" * pad
|
||||||
end
|
end
|
||||||
|
|
||||||
def position
|
# the strings length plus padding
|
||||||
throw "Not set" unless @address
|
|
||||||
@address
|
|
||||||
end
|
|
||||||
def at address
|
|
||||||
@address = address
|
|
||||||
end
|
|
||||||
def length
|
def length
|
||||||
@string.length
|
@string.length
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# just writing the string
|
||||||
def assemble(io)
|
def assemble(io)
|
||||||
io << @string
|
io << @string
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user