removed the (too) fancy dsl. Also introduce register indirection
This commit is contained in:
parent
6433a394e7
commit
36f237c633
@ -23,7 +23,7 @@ module Arm
|
||||
immediate = @immediate
|
||||
|
||||
arg = @right
|
||||
if arg.is_a?(Vm::StringConstant)
|
||||
if arg.is_a?(Vm::ObjectConstant)
|
||||
# do pc relative addressing with the difference to the instuction
|
||||
# 8 is for the funny pipeline adjustment (ie oc pointing to fetch and not execute)
|
||||
arg = Vm::IntegerConstant.new( arg.position - self.position - 8 )
|
||||
|
@ -50,20 +50,21 @@ module Arm
|
||||
'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
|
||||
code = reg_code name
|
||||
raise "no such register #{name}" unless code
|
||||
Arm::Register.new(name.to_sym , code )
|
||||
def reg r_name
|
||||
code = reg_code r_name
|
||||
raise "no such register #{r_name}" unless code
|
||||
Arm::Register.new(r_name.to_sym , code )
|
||||
end
|
||||
def reg_code name
|
||||
if name.is_a? Vm::Word
|
||||
name = "r#{name.register}"
|
||||
def reg_code r_name
|
||||
raise "double r #{r_name}" if( :rr1 == r_name)
|
||||
if r_name.is_a? Vm::Word
|
||||
r_name = r_name.register_symbol
|
||||
end
|
||||
if name.is_a? Fixnum
|
||||
name = "r#{name}"
|
||||
if r_name.is_a? Fixnum
|
||||
r_name = "r#{r_name}"
|
||||
end
|
||||
r = REGISTERS[name.to_s]
|
||||
raise "no reg #{name}" if r == nil
|
||||
r = REGISTERS[r_name.to_s]
|
||||
raise "no reg #{r_name}" if r == nil
|
||||
r
|
||||
end
|
||||
|
||||
|
@ -25,7 +25,7 @@ module Arm
|
||||
immediate = @immediate
|
||||
|
||||
right = @right
|
||||
if @left.is_a?(Vm::StringConstant)
|
||||
if @left.is_a?(Vm::ObjectConstant)
|
||||
# do pc relative addressing with the difference to the instuction
|
||||
# 8 is for the funny pipeline adjustment (ie pointing to fetch and not execute)
|
||||
right = @left.position - self.position - 8
|
||||
@ -36,7 +36,7 @@ module Arm
|
||||
right = Vm::IntegerConstant.new( right )
|
||||
end
|
||||
if (right.is_a?(Vm::IntegerConstant))
|
||||
if (right.integer.fits_u8?)
|
||||
if true #TODO (right.integer.fits_u8?)
|
||||
# no shifting needed
|
||||
operand = right.integer
|
||||
immediate = 1
|
||||
|
@ -29,14 +29,14 @@ module Arm
|
||||
add_offset = @add_offset
|
||||
|
||||
arg = @left
|
||||
arg = "r#{arg.register}".to_sym if( arg.is_a? Vm::Word )
|
||||
arg = arg.register_symbol if( arg.is_a? Vm::Word )
|
||||
#str / ldr are _serious instructions. With BIG possibilities not half are implemented
|
||||
if (arg.is_a?(Symbol)) #symbol is register
|
||||
rn = arg
|
||||
if @right
|
||||
operand = @right
|
||||
#TODO better test, this operand integer (register) does not work. but sleep first
|
||||
operand = operand.register if operand.is_a? Vm::Integer
|
||||
operand = operand.register_symbol if operand.is_a? Vm::Integer
|
||||
unless( operand.is_a? Symbol)
|
||||
puts "operand #{operand.inspect}"
|
||||
if (operand < 0)
|
||||
@ -51,7 +51,7 @@ module Arm
|
||||
end
|
||||
end
|
||||
end
|
||||
elsif (arg.is_a?(Vm::StringConstant) ) #use pc relative
|
||||
elsif (arg.is_a?(Vm::ObjectConstant) ) #use pc relative
|
||||
rn = :pc
|
||||
operand = arg.position - self.position - 8 #stringtable is after code
|
||||
add_offset = 1
|
||||
|
@ -12,10 +12,11 @@ module Arm
|
||||
|
||||
@immediate = 0
|
||||
@rn = :r0 # register zero = zero bit pattern
|
||||
# raise inspect if to.is_a?(Vm::Value) and
|
||||
# from.is_a?(Vm::Value) and
|
||||
# !@attributes[:shift_lsr] and
|
||||
# to.register == from.register
|
||||
raise inspect if to.is_a?(Vm::Value) and
|
||||
from.is_a?(Vm::Value) and
|
||||
!@attributes[:shift_lsr] and
|
||||
to.register_symbol == from.register_symbol
|
||||
raise "uups " if @to.register_symbol == :rr1
|
||||
end
|
||||
|
||||
# arm intrucions are pretty sensible, and always 4 bytes (thumb not supported)
|
||||
@ -30,7 +31,7 @@ module Arm
|
||||
immediate = @immediate
|
||||
|
||||
right = @from
|
||||
if right.is_a?(Vm::StringConstant)
|
||||
if right.is_a?(Vm::ObjectConstant)
|
||||
# do pc relative addressing with the difference to the instuction
|
||||
# 8 is for the funny pipeline adjustment (ie oc pointing to fetch and not execute)
|
||||
right = Vm::IntegerConstant.new( right.position - self.position - 8 )
|
||||
|
@ -9,6 +9,7 @@ module Ast
|
||||
|
||||
if receiver.name == :self
|
||||
function = context.current_class.get_or_create_function(name)
|
||||
value = Vm::Integer.new(Vm::Function::RECEIVER_REG)
|
||||
elsif receiver.is_a? ModuleName
|
||||
c_name = receiver.name
|
||||
clazz = context.object_space.get_or_create_class c_name
|
||||
@ -23,6 +24,7 @@ module Ast
|
||||
else
|
||||
# should be case switch for basic tyes and dynamic dispatch for objects reference
|
||||
value = context.locals[receiver.name]
|
||||
raise "no value" unless value
|
||||
function = context.current_class.get_or_create_function(name)
|
||||
end
|
||||
raise "No such method error #{clazz.to_s}:#{name}" if function == nil
|
||||
|
@ -12,13 +12,12 @@ module Ast
|
||||
args << arg_value
|
||||
end
|
||||
# class depends on receiver
|
||||
me = Vm::Integer.new( Vm::Function::RECEIVER_REG )
|
||||
if receiver.nil?
|
||||
clazz = context.current_class
|
||||
me = Vm::Integer.new( Vm::Function::RECEIVER_REG )
|
||||
else
|
||||
c = context.object_space.get_or_create_class receiver.name.to_sym
|
||||
clazz = c.meta_class
|
||||
raise "get the constant loaded to 1"
|
||||
end
|
||||
|
||||
function = Vm::Function.new(name , me , args )
|
||||
@ -38,10 +37,10 @@ module Ast
|
||||
end
|
||||
|
||||
return_reg = Vm::Integer.new(7)
|
||||
if last_compiled.is_a?(Vm::IntegerConstant) or last_compiled.is_a?(Vm::StringConstant)
|
||||
return_reg.load into , last_compiled if last_compiled.register != return_reg.register
|
||||
if last_compiled.is_a?(Vm::IntegerConstant) or last_compiled.is_a?(Vm::ObjectConstant)
|
||||
return_reg.load into , last_compiled if last_compiled.register_symbol != return_reg.register_symbol
|
||||
else
|
||||
return_reg.move( into, last_compiled ) if last_compiled.register != return_reg.register
|
||||
return_reg.move( into, last_compiled ) if last_compiled.register_symbol != return_reg.register_symbol
|
||||
end
|
||||
function.set_return return_reg
|
||||
|
||||
|
@ -18,8 +18,7 @@ module Ast
|
||||
end
|
||||
|
||||
l_val = left.compile(context , into)
|
||||
into = into.scope binding
|
||||
|
||||
|
||||
case operator
|
||||
when ">"
|
||||
code = l_val.greater_than into , r_val
|
||||
@ -33,7 +32,7 @@ module Ast
|
||||
code = l_val.equals into , r_val
|
||||
when "+"
|
||||
res = context.function.new_local
|
||||
into.res = l_val + r_val
|
||||
into.add res , l_val , r_val
|
||||
code = res
|
||||
when "-"
|
||||
res = context.function.new_local
|
||||
|
@ -7,10 +7,10 @@ module Ast
|
||||
# copied from function expression: TODO make function
|
||||
|
||||
return_reg = Vm::Integer.new(7)
|
||||
if expression_value.is_a?(Vm::IntegerConstant) or expression_value.is_a?(Vm::StringConstant)
|
||||
if expression_value.is_a?(Vm::IntegerConstant) or expression_value.is_a?(Vm::ObjectConstant)
|
||||
return_reg.load into , expression_value
|
||||
else
|
||||
return_reg.move( into, expression_value ) if expression_value.register != return_reg.register
|
||||
return_reg.move( into, expression_value ) if expression_value.register_symbol != return_reg.register_symbol
|
||||
end
|
||||
#function.set_return return_reg
|
||||
return return_reg
|
||||
|
@ -19,8 +19,8 @@ module Boot
|
||||
# The at_index is just "below" the api, somehting we need but don't want to expose, so we can't code the above in ruby
|
||||
def _get_instance_variable context , name = Vm::Integer
|
||||
get_function = Vm::Function.new(:_get_instance_variable , Vm::Integer , [ Vm::Integer ] , Vm::Integer )
|
||||
me = get_function.args[0]
|
||||
var_name = get_function.args[1]
|
||||
me = get_function.receiver
|
||||
var_name = get_function.args.first
|
||||
return_to = get_function.return_type
|
||||
index_function = context.object_space.get_or_create_class(:Object).get_or_create_function(:index_of)
|
||||
b = get_function.body
|
||||
|
@ -36,7 +36,7 @@ module Core
|
||||
putint_function = Vm::Function.new(:putint , Vm::Integer , [] , Vm::Integer )
|
||||
buffer = Vm::StringConstant.new(" ") # create a buffer
|
||||
context.object_space.add_object buffer # and save it (function local variable: a no no)
|
||||
int = putint_function.args.first
|
||||
int = putint_function.receiver
|
||||
moved_int = putint_function.new_local
|
||||
utoa = context.object_space.get_or_create_class(:Object).get_or_create_function(:utoa)
|
||||
b = putint_function.body
|
||||
@ -44,7 +44,7 @@ module Core
|
||||
#b.a buffer => int # string to write to
|
||||
|
||||
b.add( int , buffer ,nil ) # string to write to
|
||||
b.a int + (buffer.length-3) => int
|
||||
b.add(int , int , buffer.length - 3)
|
||||
b.call( utoa )
|
||||
# And now we "just" have to print it, using the write_stdout
|
||||
b.add( int , buffer , nil ) # string to write to
|
||||
@ -60,13 +60,13 @@ module Core
|
||||
# arguments: string address , integer
|
||||
def utoa context
|
||||
utoa_function = Vm::Function.new(:utoa , Vm::Integer , [ Vm::Integer ] , Vm::Integer )
|
||||
str_addr = utoa_function.args[0]
|
||||
number = utoa_function.args[1]
|
||||
str_addr = utoa_function.receiver
|
||||
number = utoa_function.args.first
|
||||
remainder = utoa_function.new_local
|
||||
Vm::RegisterMachine.instance.div10( utoa_function.body , number , remainder )
|
||||
# make char out of digit (by using ascii encoding) 48 == "0"
|
||||
b = utoa_function.body.scope binding
|
||||
b.remainder = remainder + 48
|
||||
b = utoa_function.body
|
||||
b.add(remainder , remainder , 48)
|
||||
b.strb( remainder, str_addr )
|
||||
b.sub( str_addr, str_addr , 1 )
|
||||
b.cmp( number , 0 )
|
||||
@ -80,26 +80,26 @@ module Core
|
||||
# not my hand off course, found in the net from a basic introduction
|
||||
def fibo context
|
||||
fibo_function = Vm::Function.new(:fibo , Vm::Integer , [] , Vm::Integer )
|
||||
result = Vm::Integer.new(7)
|
||||
int = fibo_function.args[0]
|
||||
result = fibo_function.return_type
|
||||
int = fibo_function.receiver
|
||||
count = fibo_function.new_local
|
||||
f1 = fibo_function.new_local
|
||||
f2 = fibo_function.new_local
|
||||
b = fibo_function.body.scope binding
|
||||
b = fibo_function.body
|
||||
|
||||
b.a int == 1
|
||||
b.cmp int , 1
|
||||
b.mov( result, int , condition_code: :le)
|
||||
b.mov( :pc , :lr , condition_code: :le)
|
||||
b.push [ count , f1 , f2 , :lr]
|
||||
b.f1 = 1
|
||||
b.f2 = 0
|
||||
b.count = int - 2
|
||||
b.mov f1 , 1
|
||||
b.mov f2 , 0
|
||||
b.sub count , int , 2
|
||||
|
||||
l = fibo_function.body.new_block("loop").scope binding
|
||||
|
||||
l.f1 = f1 + f2
|
||||
l.f2 = f1 - f2
|
||||
l.count = (count - 1).set_update_status
|
||||
l = fibo_function.body.new_block("loop")
|
||||
|
||||
l.add f1 , f1 , f2
|
||||
l.sub f2 , f1 , f2
|
||||
l.sub count , count , 1 , set_update_status: 1
|
||||
l.bpl( l )
|
||||
l.mov( result , f1 )
|
||||
fibo_function.set_return result
|
||||
|
@ -24,14 +24,3 @@ module Support
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Binding
|
||||
#these are defined in 2.1 and thus the definitions should be conditional. TODO
|
||||
def local_variable_defined? sym
|
||||
vars = eval("local_variables")
|
||||
vars.include? sym
|
||||
end
|
||||
def local_variable_get sym
|
||||
eval(sym.to_s)
|
||||
end
|
||||
end
|
||||
|
@ -32,14 +32,8 @@ module Vm
|
||||
attr_reader :name , :next , :codes , :function
|
||||
|
||||
def add_code(kode)
|
||||
if kode.is_a? Hash
|
||||
raise "Hack only for 1 element #{inspect} #{kode.inspect}" unless kode.length == 1
|
||||
instruction , result = kode.first
|
||||
instruction.assign result
|
||||
kode = instruction
|
||||
end
|
||||
raise "alarm #{kode}" if kode.is_a? Word
|
||||
raise "alarm #{kode}" unless kode.is_a? Code
|
||||
raise "alarm #{kode.class} #{kode}" unless kode.is_a? Code
|
||||
@insert_at.codes << kode
|
||||
self
|
||||
end
|
||||
@ -70,27 +64,8 @@ module Vm
|
||||
self
|
||||
end
|
||||
|
||||
# to use the assignment syntax (see method_missing) the scope must be set, so variables can be resolved
|
||||
# The scope you set should be a binding (literally, the kernel.binding)
|
||||
# The function return the block, so it can be chained into an assignment
|
||||
# Example (coding a function ) and having variable int defined
|
||||
# b = function.body.scope(binding)
|
||||
# b.int = 5 will create a mov instruction to set the register that int points to
|
||||
def scope where
|
||||
@scope = where
|
||||
self
|
||||
end
|
||||
|
||||
# sugar to create instructions easily. Actually just got double sweet with two versions:
|
||||
# 1 for any method that ends in = we evaluate the method name in the current scope (see scope())
|
||||
# for the result we call assign with the right value. The resulting instruction is added to
|
||||
# the block.
|
||||
# Thus we emulate assignment,
|
||||
# Example: block b
|
||||
# b.variable = value looks like what it does, but actually generates
|
||||
# an instruction for the block (mov or add)
|
||||
#
|
||||
# 2- any other method will be passed on to the RegisterMachine and the result added to the block
|
||||
# sugar to create instructions easily.
|
||||
# any method will be passed on to the RegisterMachine and the result added to the block
|
||||
# With this trick we can write what looks like assembler,
|
||||
# Example b.instance_eval
|
||||
# mov( r1 , r2 )
|
||||
@ -98,16 +73,8 @@ module Vm
|
||||
# end
|
||||
# mov and add will be called on Machine and generate Inststuction that are then added
|
||||
# to the block
|
||||
# also symbols are supported and wrapped as register usages (for bare metal programming)
|
||||
def method_missing(meth, *args, &block)
|
||||
var = meth.to_s[0 ... -1]
|
||||
if( args.length == 1) and ( meth.to_s[-1] == "=" )
|
||||
if @scope.local_variable_defined? var.to_sym
|
||||
l_val = @scope.local_variable_get var.to_sym
|
||||
return add_code l_val.assign(args[0])
|
||||
else
|
||||
return super
|
||||
end
|
||||
end
|
||||
add_code RegisterMachine.instance.send(meth , *args)
|
||||
end
|
||||
|
||||
|
@ -3,7 +3,7 @@ require_relative "meta_class"
|
||||
module Vm
|
||||
# class is mainly a list of functions with a name (for now)
|
||||
# layout of object is seperated into Layout
|
||||
class BootClass < Code
|
||||
class BootClass < ObjectConstant
|
||||
def initialize name , context , super_class = :Object
|
||||
super()
|
||||
@context = context
|
||||
|
@ -9,15 +9,23 @@ module Vm
|
||||
@value = value
|
||||
@args = args
|
||||
@function = function
|
||||
raise "oh #{name} " unless value
|
||||
end
|
||||
attr_reader :function , :args , :name , :value
|
||||
|
||||
def load_args into
|
||||
if value.is_a?(IntegerConstant) or value.is_a?(ObjectConstant)
|
||||
function.receiver.load into , value
|
||||
else
|
||||
raise "meta #{name} " if value.is_a? MetaClass
|
||||
function.receiver.move( into, value ) if value.register_symbol != function.receiver.register_symbol
|
||||
end
|
||||
raise "function call '#{name}' has #{args.length} arguments, but function has #{function.args.length}" if args.length != function.args.length
|
||||
args.each_with_index do |arg , index|
|
||||
if arg.is_a?(IntegerConstant) or arg.is_a?(StringConstant)
|
||||
function.args[index].load into , arg
|
||||
else
|
||||
function.args[index].move( into, arg ) if arg.register != function.args[index].register
|
||||
function.args[index].move( into, arg ) if arg.register_symbol != function.args[index].register_symbol
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -43,5 +43,6 @@ module Vm
|
||||
def assemble(io)
|
||||
raise "Not implemented #{self.inspect}"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -9,6 +9,10 @@ module Vm
|
||||
|
||||
end
|
||||
|
||||
# another abstract "marker" class (so we can check for it)
|
||||
# derived classes are Boot/Meta Clas and StringConstant
|
||||
class ObjectConstant < Constant
|
||||
end
|
||||
|
||||
class IntegerConstant < Constant
|
||||
def initialize int
|
||||
@ -25,7 +29,7 @@ module Vm
|
||||
# Currently string are stored "inline" , ie in the code segment.
|
||||
# Mainly because that works an i aint no elf expert.
|
||||
|
||||
class StringConstant < Constant
|
||||
class StringConstant < ObjectConstant
|
||||
attr_reader :string
|
||||
# currently aligned to 4 (ie padded with 0) and off course 0 at the end
|
||||
def initialize str
|
||||
|
@ -27,16 +27,16 @@ module Vm
|
||||
|
||||
class Function < Code
|
||||
|
||||
TYPE_REG = 0
|
||||
RECEIVER_REG = 1
|
||||
RETURN_REG = 7
|
||||
TYPE_REG = :r0
|
||||
RECEIVER_REG = :r1
|
||||
RETURN_REG = :r7
|
||||
|
||||
def initialize(name , receiver = Vm::Integer , args = [] , return_type = Vm::Integer)
|
||||
super()
|
||||
@name = name.to_sym
|
||||
if receiver.is_a?(Value)
|
||||
@receiver = receiver
|
||||
raise "arg in non std register #{arg.inspect}" unless RECEIVER_REG == receiver.register
|
||||
raise "arg in non std register #{arg.inspect}" unless RECEIVER_REG == receiver.register_symbol
|
||||
else
|
||||
@receiver = receiver.new(RECEIVER_REG)
|
||||
end
|
||||
@ -45,9 +45,9 @@ module Vm
|
||||
args.each_with_index do |arg , i|
|
||||
if arg.is_a?(Value)
|
||||
@args[i] = arg
|
||||
raise "arg in non std register #{arg.inspect}" unless (i+1+RECEIVER_REG) == arg.register
|
||||
raise "arg in non std register #{arg.inspect}" unless RECEIVER_REG == arg.used_register.next_reg(i - 1)
|
||||
else
|
||||
@args[i] = arg.new(i+1+RECEIVER_REG)
|
||||
@args[i] = arg.new(RegisterUse.new(RECEIVER_REG).next_reg(i + 1))
|
||||
end
|
||||
end
|
||||
set_return return_type
|
||||
@ -59,12 +59,12 @@ module Vm
|
||||
@blocks = []
|
||||
end
|
||||
|
||||
attr_reader :args , :entry , :exit , :body , :name , :return_type , :revceiver
|
||||
attr_reader :args , :entry , :exit , :body , :name , :return_type , :receiver
|
||||
|
||||
def set_return type_or_value
|
||||
@return_type = type_or_value || Vm::Integer
|
||||
if @return_type.is_a?(Value)
|
||||
raise "return in non std register #{@return_type.inspect}" unless RETURN_REG == @return_type.register
|
||||
raise "return in non std register #{@return_type.inspect}" unless RETURN_REG == @return_type.register_symbol
|
||||
else
|
||||
@return_type = @return_type.new(RETURN_REG)
|
||||
end
|
||||
@ -76,7 +76,7 @@ module Vm
|
||||
def new_local type = Vm::Integer
|
||||
register = args.length + 1 + @locals.length # one for the receiver implicit arg
|
||||
l = type.new(register + 1) # one for the type register 0, TODO add type as arg0 implicitly
|
||||
puts "new local #{l.register}"
|
||||
puts "new local #{l.register_symbol}"
|
||||
# raise "Register overflow in function #{name}" if l.register > 6
|
||||
@locals << l
|
||||
l
|
||||
@ -84,13 +84,13 @@ module Vm
|
||||
#BUG - must save receiver
|
||||
|
||||
def save_locals context , into
|
||||
save = args.collect{|a| a.register } + @locals.collect{|l| l.register}
|
||||
save = args.collect{|a| a.register_symbol } + @locals.collect{|l| l.register_symbol}
|
||||
into.push(save) unless save.empty?
|
||||
end
|
||||
|
||||
def restore_locals context , into
|
||||
#TODO assumes allocation in order, as the pop must be get regs in ascending order (also push)
|
||||
restore = args.collect{|a| a.register } + @locals.collect{|l| l.register}
|
||||
restore = args.collect{|a| a.register_symbol } + @locals.collect{|l| l.register_symbol}
|
||||
into.pop(restore) unless restore.empty?
|
||||
end
|
||||
|
||||
|
@ -68,16 +68,6 @@ module Vm
|
||||
@right = right
|
||||
super(options)
|
||||
end
|
||||
# this is used to write code that looks like assignment
|
||||
# So instructions can be created without the result (register) set, and this assigns where
|
||||
# the reuslt after the fact, but usually in the same line
|
||||
# Example (with block b, and variables int,a,b): b.int = a + b
|
||||
# a + b actually creates an add instruction while the b.int= assigns the result to int
|
||||
# b.add( int , a , b) is an alternative (assmbler style) way of writing the same.
|
||||
def assign left
|
||||
@result = left
|
||||
self
|
||||
end
|
||||
end
|
||||
class MathInstruction < Instruction
|
||||
def initialize first , options = {}
|
||||
@ -96,7 +86,7 @@ module Vm
|
||||
def initialize to , from , options = {}
|
||||
@to = to
|
||||
@from = from
|
||||
raise inspect unless from
|
||||
raise "move must have from set #{inspect}" unless from
|
||||
super(options)
|
||||
end
|
||||
end
|
||||
|
@ -8,7 +8,7 @@ module Vm
|
||||
# PS: can't say i fancy the << self syntax and am considerernig adding a keyword for it, like meta
|
||||
# In effect it is a very similar construct to def self.function(...)
|
||||
# So one could write def meta.function(...) and thus define on the meta-class
|
||||
class MetaClass < Code
|
||||
class MetaClass < ObjectConstant
|
||||
# no name, nor nothing. as this is just the object really
|
||||
|
||||
def initialize(object)
|
||||
|
@ -108,6 +108,7 @@ module Vm
|
||||
options = {} if options == nil
|
||||
options.merge defaults
|
||||
options[:opcode] = inst
|
||||
first = Vm::Integer.new(first) if first.is_a? Symbol
|
||||
clazz.new(first , options)
|
||||
end
|
||||
end
|
||||
@ -118,6 +119,8 @@ module Vm
|
||||
create_method(inst) do |left ,right , options = nil|
|
||||
options = {} if options == nil
|
||||
options.merge defaults
|
||||
left = Vm::Integer.new(left) if left.is_a? Symbol
|
||||
right = Vm::Integer.new(right) if right.is_a? Symbol
|
||||
options[:opcode] = inst
|
||||
clazz.new(left , right ,options)
|
||||
end
|
||||
@ -130,6 +133,9 @@ module Vm
|
||||
options = {} if options == nil
|
||||
options.merge defaults
|
||||
options[:opcode] = inst
|
||||
result = Vm::Integer.new(result) if result.is_a? Symbol
|
||||
left = Vm::Integer.new(left) if left.is_a? Symbol
|
||||
right = Vm::Integer.new(right) if right.is_a? Symbol
|
||||
clazz.new(result, left , right ,options)
|
||||
end
|
||||
end
|
||||
|
@ -53,9 +53,23 @@ module Vm
|
||||
# but which register can be changed, and _all_ instructions sharing the RegisterUse then use that register
|
||||
# In other words a simple level of indirection, or change from value to reference sematics.
|
||||
class RegisterUse
|
||||
attr_accessor :register
|
||||
attr_accessor :symbol
|
||||
def initialize r
|
||||
@register = r
|
||||
if( r.is_a? Fixnum)
|
||||
r = "r#{r}".to_sym
|
||||
end
|
||||
raise "wrong type for register init #{r}" unless r.is_a? Symbol
|
||||
raise "double r #{r}" if r == :rr1
|
||||
@symbol = r
|
||||
end
|
||||
|
||||
#helper methods to calculate with register symbols
|
||||
def next_reg by = 1
|
||||
int = @symbol[1,3].to_i
|
||||
"r#{int + by}".to_sym
|
||||
end
|
||||
def next_reg_use by = 1
|
||||
RegisterUse.new( next_reg(by) )
|
||||
end
|
||||
end
|
||||
|
||||
@ -66,23 +80,21 @@ module Vm
|
||||
|
||||
attr_accessor :used_register
|
||||
|
||||
def register
|
||||
@used_register.register
|
||||
def register_symbol
|
||||
@used_register.symbol
|
||||
end
|
||||
|
||||
def inspect
|
||||
self.class.name + "(r#{used_register.register})"
|
||||
"#{self.class.name} (#{register_symbol})"
|
||||
end
|
||||
def to_s
|
||||
inspect
|
||||
end
|
||||
def initialize reg
|
||||
if reg.is_a? Fixnum
|
||||
@used_register = RegisterUse.new(reg)
|
||||
else
|
||||
if reg.is_a? RegisterUse
|
||||
@used_register = reg
|
||||
else
|
||||
@used_register = RegisterUse.new(reg)
|
||||
end
|
||||
raise inspect if reg == nil
|
||||
end
|
||||
def length
|
||||
4
|
||||
@ -98,21 +110,6 @@ module Vm
|
||||
|
||||
class Integer < Word
|
||||
|
||||
# part of the dsl.
|
||||
# Gets called with either fixnum/IntegerConstant or an Instruction (usually logic, iw add...)
|
||||
# For instructions we flip, ie call the assign on the instruction
|
||||
# but for constants we have to create instruction first (mov)
|
||||
def assign other
|
||||
other = Vm::IntegerConstant.new(other) if other.is_a? Fixnum
|
||||
if other.is_a?(Vm::IntegerConstant) or other.is_a?(Vm::Integer)
|
||||
class_for(MoveInstruction).new( self , other , :opcode => :mov)
|
||||
elsif other.is_a?(Vm::StringConstant) # pc relative addressing
|
||||
class_for(LogicInstruction).new(self , other , nil , opcode: :add)
|
||||
else
|
||||
other.assign(self)
|
||||
end
|
||||
end
|
||||
|
||||
def less_or_equal block , right
|
||||
RegisterMachine.instance.integer_less_or_equal block , self , right
|
||||
end
|
||||
@ -155,7 +152,9 @@ module Vm
|
||||
block.mov( self , right ) #move the value
|
||||
elsif right.is_a? StringConstant
|
||||
block.add( self , right , nil) #move the address, by "adding" to pc, ie pc relative
|
||||
block.mov( Integer.new(register+1) , right.length ) #and the length HACK TODO
|
||||
block.mov( Integer.new(self.used_register.next_reg) , right.length ) #and the length HACK TODO
|
||||
elsif right.is_a?(BootClass) or right.is_a?(MetaClass)
|
||||
block.add( self , right , nil) #move the address, by "adding" to pc, ie pc relative
|
||||
else
|
||||
raise "unknown #{right.inspect}"
|
||||
end
|
||||
|
@ -21,7 +21,8 @@ def minus(a,b)
|
||||
end
|
||||
end
|
||||
|
||||
putint(times(7,6))
|
||||
tim = times(7,6)
|
||||
tim.putint()
|
||||
HERE
|
||||
@should = [0x0,0x40,0x2d,0xe9,0x2,0x30,0x41,0xe0,0x3,0x70,0xa0,0xe1,0x0,0x80,0xbd,0xe8,0x0,0x40,0x2d,0xe9,0x2,0x30,0x41,0xe0,0x3,0x70,0xa0,0xe1,0x0,0x80,0xbd,0xe8]
|
||||
@output = " 42 "
|
||||
|
@ -5,7 +5,8 @@ class TestPutint < MiniTest::Test
|
||||
|
||||
def test_putint
|
||||
@string_input = <<HERE
|
||||
putint( 42 )
|
||||
fourty_two = 42
|
||||
fourty_two.putint()
|
||||
HERE
|
||||
@should = [0x0,0x40,0x2d,0xe9,0x1,0x20,0xa0,0xe1,0x20,0x10,0x8f,0xe2,0x9,0x10,0x81,0xe2,0xe9,0xff,0xff,0xeb,0x14,0x10,0x8f,0xe2,0xc,0x20,0xa0,0xe3,0x1,0x0,0xa0,0xe3,0x4,0x70,0xa0,0xe3,0x0,0x0,0x0,0xef,0x0,0x70,0xa0,0xe1,0x0,0x80,0xbd,0xe8,0x0,0x40,0x2d,0xe9,0x1,0x20,0xa0,0xe1,0x20,0x10,0x8f,0xe2,0x9,0x10,0x81,0xe2,0xe9,0xff,0xff,0xeb,0x14,0x10,0x8f,0xe2,0xc,0x20,0xa0,0xe3,0x1,0x0,0xa0,0xe3,0x4,0x70,0xa0,0xe3,0x0,0x0,0x0,0xef,0x0,0x70,0xa0,0xe1,0x0,0x80,0xbd,0xe8]
|
||||
@output = " 42 "
|
||||
@ -14,4 +15,3 @@ HERE
|
||||
write "putint"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -14,8 +14,8 @@ def fibonaccir( n )
|
||||
return a + b
|
||||
end
|
||||
end
|
||||
|
||||
putint(fibonaccir( 10 ))
|
||||
fib = fibonaccir( 10 )
|
||||
fib.putint()
|
||||
HERE
|
||||
@should = [0x0,0x40,0x2d,0xe9,0x1,0x0,0x51,0xe3,0xe,0x0,0x0,0xda,0x1,0x20,0x41,0xe2,0x6,0x0,0x2d,0xe9,0x2,0x10,0xa0,0xe1,0xf8,0xff,0xff,0xeb,0x6,0x0,0xbd,0xe8,0x7,0x30,0xa0,0xe1,0x2,0x40,0x41,0xe2,0x1e,0x0,0x2d,0xe9,0x4,0x10,0xa0,0xe1,0xf2,0xff,0xff,0xeb,0x1e,0x0,0xbd,0xe8,0x7,0x50,0xa0,0xe1,0x5,0x60,0x83,0xe0,0x6,0x70,0xa0,0xe1,0x0,0x0,0x0,0xea,0x1,0x70,0xa0,0xe1,0x0,0x80,0xbd,0xe8,0x0,0x40,0x2d,0xe9,0x1,0x0,0x51,0xe3,0xe,0x0,0x0,0xda,0x1,0x20,0x41,0xe2,0x6,0x0,0x2d,0xe9,0x2,0x10,0xa0,0xe1,0xf8,0xff,0xff,0xeb,0x6,0x0,0xbd,0xe8,0x7,0x30,0xa0,0xe1,0x2,0x40,0x41,0xe2,0x1e,0x0,0x2d,0xe9,0x4,0x10,0xa0,0xe1,0xf2,0xff,0xff,0xeb,0x1e,0x0,0xbd,0xe8,0x7,0x50,0xa0,0xe1,0x5,0x60,0x83,0xe0,0x6,0x70,0xa0,0xe1,0x0,0x0,0x0,0xea,0x1,0x70,0xa0,0xe1,0x0,0x80,0xbd,0xe8]
|
||||
@output = " 55 "
|
||||
|
@ -16,8 +16,8 @@ def fibonaccit(n) # n == r0
|
||||
end #r5 <- r0 - 1 n=n-1 through r5 tmp
|
||||
return b
|
||||
end # r0 <- r5
|
||||
|
||||
putint(fibonaccit( 10 ))
|
||||
fibo = fibonaccit( 10 )
|
||||
fibo.putint()
|
||||
HERE
|
||||
@should = [0x0,0x40,0x2d,0xe9,0x0,0x20,0xa0,0xe3,0x1,0x30,0xa0,0xe3,0x1,0x0,0x51,0xe3,0x6,0x0,0x0,0xda,0x2,0x40,0xa0,0xe1,0x3,0x20,0xa0,0xe1,0x3,0x50,0x84,0xe0,0x5,0x30,0xa0,0xe1,0x1,0x60,0x41,0xe2,0x6,0x10,0xa0,0xe1,0xf6,0xff,0xff,0xea,0x3,0x70,0xa0,0xe1,0x0,0x80,0xbd,0xe8,0x0,0x40,0x2d,0xe9,0x0,0x20,0xa0,0xe3,0x1,0x30,0xa0,0xe3,0x1,0x0,0x51,0xe3,0x6,0x0,0x0,0xda,0x2,0x40,0xa0,0xe1,0x3,0x20,0xa0,0xe1,0x3,0x50,0x84,0xe0,0x5,0x30,0xa0,0xe1,0x1,0x60,0x41,0xe2,0x6,0x10,0xa0,0xe1,0xf6,0xff,0xff,0xea,0x3,0x70,0xa0,0xe1,0x0,0x80,0xbd,0xe8]
|
||||
@output = " 55 "
|
||||
@ -31,8 +31,8 @@ HERE
|
||||
def test_kernel_fibo
|
||||
int = Vm::Integer.new(1)
|
||||
fibo = @object_space.get_or_create_class(:Object).get_or_create_function(:fibo)
|
||||
main = @object_space.main.scope binding
|
||||
main.int = 10
|
||||
main = @object_space.main
|
||||
main.mov int , 10
|
||||
ret = main.call( fibo )
|
||||
main.mov( :r1 , :r7 )
|
||||
putint = @object_space.get_or_create_class(:Object).get_or_create_function(:putint)
|
||||
|
Loading…
Reference in New Issue
Block a user