removed the (too) fancy dsl. Also introduce register indirection

This commit is contained in:
Torsten Ruger 2014-06-07 17:59:44 +03:00
parent 6433a394e7
commit 36f237c633
26 changed files with 128 additions and 161 deletions

View File

@ -23,7 +23,7 @@ module Arm
immediate = @immediate immediate = @immediate
arg = @right arg = @right
if arg.is_a?(Vm::StringConstant) if arg.is_a?(Vm::ObjectConstant)
# do pc relative addressing with the difference to the instuction # 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) # 8 is for the funny pipeline adjustment (ie oc pointing to fetch and not execute)
arg = Vm::IntegerConstant.new( arg.position - self.position - 8 ) arg = Vm::IntegerConstant.new( arg.position - self.position - 8 )

View File

@ -50,20 +50,21 @@ module Arm
'a3' => 2, 'a4' => 3, 'v1' => 4, 'v2' => 5, 'v3' => 6, 'v4' => 7, 'v5' => 8, '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, 'v6' => 9, 'rfp' => 9, 'sl' => 10, 'fp' => 11, 'ip' => 12, 'sp' => 13,
'lr' => 14, 'pc' => 15 } 'lr' => 14, 'pc' => 15 }
def reg name def reg r_name
code = reg_code name code = reg_code r_name
raise "no such register #{name}" unless code raise "no such register #{r_name}" unless code
Arm::Register.new(name.to_sym , code ) Arm::Register.new(r_name.to_sym , code )
end end
def reg_code name def reg_code r_name
if name.is_a? Vm::Word raise "double r #{r_name}" if( :rr1 == r_name)
name = "r#{name.register}" if r_name.is_a? Vm::Word
r_name = r_name.register_symbol
end end
if name.is_a? Fixnum if r_name.is_a? Fixnum
name = "r#{name}" r_name = "r#{r_name}"
end end
r = REGISTERS[name.to_s] r = REGISTERS[r_name.to_s]
raise "no reg #{name}" if r == nil raise "no reg #{r_name}" if r == nil
r r
end end

View File

@ -25,7 +25,7 @@ module Arm
immediate = @immediate immediate = @immediate
right = @right right = @right
if @left.is_a?(Vm::StringConstant) if @left.is_a?(Vm::ObjectConstant)
# do pc relative addressing with the difference to the instuction # do pc relative addressing with the difference to the instuction
# 8 is for the funny pipeline adjustment (ie pointing to fetch and not execute) # 8 is for the funny pipeline adjustment (ie pointing to fetch and not execute)
right = @left.position - self.position - 8 right = @left.position - self.position - 8
@ -36,7 +36,7 @@ module Arm
right = Vm::IntegerConstant.new( right ) right = Vm::IntegerConstant.new( right )
end end
if (right.is_a?(Vm::IntegerConstant)) if (right.is_a?(Vm::IntegerConstant))
if (right.integer.fits_u8?) if true #TODO (right.integer.fits_u8?)
# no shifting needed # no shifting needed
operand = right.integer operand = right.integer
immediate = 1 immediate = 1

View File

@ -29,14 +29,14 @@ module Arm
add_offset = @add_offset add_offset = @add_offset
arg = @left 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 #str / ldr are _serious instructions. With BIG possibilities not half are implemented
if (arg.is_a?(Symbol)) #symbol is register if (arg.is_a?(Symbol)) #symbol is register
rn = arg rn = arg
if @right if @right
operand = @right operand = @right
#TODO better test, this operand integer (register) does not work. but sleep first #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) unless( operand.is_a? Symbol)
puts "operand #{operand.inspect}" puts "operand #{operand.inspect}"
if (operand < 0) if (operand < 0)
@ -51,7 +51,7 @@ module Arm
end end
end end
end end
elsif (arg.is_a?(Vm::StringConstant) ) #use pc relative elsif (arg.is_a?(Vm::ObjectConstant) ) #use pc relative
rn = :pc rn = :pc
operand = arg.position - self.position - 8 #stringtable is after code operand = arg.position - self.position - 8 #stringtable is after code
add_offset = 1 add_offset = 1

View File

@ -12,10 +12,11 @@ module Arm
@immediate = 0 @immediate = 0
@rn = :r0 # register zero = zero bit pattern @rn = :r0 # register zero = zero bit pattern
# raise inspect if to.is_a?(Vm::Value) and raise inspect if to.is_a?(Vm::Value) and
# from.is_a?(Vm::Value) and from.is_a?(Vm::Value) and
# !@attributes[:shift_lsr] and !@attributes[:shift_lsr] and
# to.register == from.register to.register_symbol == from.register_symbol
raise "uups " if @to.register_symbol == :rr1
end end
# arm intrucions are pretty sensible, and always 4 bytes (thumb not supported) # arm intrucions are pretty sensible, and always 4 bytes (thumb not supported)
@ -30,7 +31,7 @@ module Arm
immediate = @immediate immediate = @immediate
right = @from right = @from
if right.is_a?(Vm::StringConstant) if right.is_a?(Vm::ObjectConstant)
# do pc relative addressing with the difference to the instuction # 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) # 8 is for the funny pipeline adjustment (ie oc pointing to fetch and not execute)
right = Vm::IntegerConstant.new( right.position - self.position - 8 ) right = Vm::IntegerConstant.new( right.position - self.position - 8 )

View File

@ -9,6 +9,7 @@ module Ast
if receiver.name == :self if receiver.name == :self
function = context.current_class.get_or_create_function(name) function = context.current_class.get_or_create_function(name)
value = Vm::Integer.new(Vm::Function::RECEIVER_REG)
elsif receiver.is_a? ModuleName elsif receiver.is_a? ModuleName
c_name = receiver.name c_name = receiver.name
clazz = context.object_space.get_or_create_class c_name clazz = context.object_space.get_or_create_class c_name
@ -23,6 +24,7 @@ module Ast
else else
# should be case switch for basic tyes and dynamic dispatch for objects reference # should be case switch for basic tyes and dynamic dispatch for objects reference
value = context.locals[receiver.name] value = context.locals[receiver.name]
raise "no value" unless value
function = context.current_class.get_or_create_function(name) function = context.current_class.get_or_create_function(name)
end end
raise "No such method error #{clazz.to_s}:#{name}" if function == nil raise "No such method error #{clazz.to_s}:#{name}" if function == nil

View File

@ -12,13 +12,12 @@ module Ast
args << arg_value args << arg_value
end end
# class depends on receiver # class depends on receiver
me = Vm::Integer.new( Vm::Function::RECEIVER_REG )
if receiver.nil? if receiver.nil?
clazz = context.current_class clazz = context.current_class
me = Vm::Integer.new( Vm::Function::RECEIVER_REG )
else else
c = context.object_space.get_or_create_class receiver.name.to_sym c = context.object_space.get_or_create_class receiver.name.to_sym
clazz = c.meta_class clazz = c.meta_class
raise "get the constant loaded to 1"
end end
function = Vm::Function.new(name , me , args ) function = Vm::Function.new(name , me , args )
@ -38,10 +37,10 @@ module Ast
end end
return_reg = Vm::Integer.new(7) return_reg = Vm::Integer.new(7)
if last_compiled.is_a?(Vm::IntegerConstant) or last_compiled.is_a?(Vm::StringConstant) if last_compiled.is_a?(Vm::IntegerConstant) or last_compiled.is_a?(Vm::ObjectConstant)
return_reg.load into , last_compiled if last_compiled.register != return_reg.register return_reg.load into , last_compiled if last_compiled.register_symbol != return_reg.register_symbol
else 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 end
function.set_return return_reg function.set_return return_reg

View File

@ -18,8 +18,7 @@ module Ast
end end
l_val = left.compile(context , into) l_val = left.compile(context , into)
into = into.scope binding
case operator case operator
when ">" when ">"
code = l_val.greater_than into , r_val code = l_val.greater_than into , r_val
@ -33,7 +32,7 @@ module Ast
code = l_val.equals into , r_val code = l_val.equals into , r_val
when "+" when "+"
res = context.function.new_local res = context.function.new_local
into.res = l_val + r_val into.add res , l_val , r_val
code = res code = res
when "-" when "-"
res = context.function.new_local res = context.function.new_local

View File

@ -7,10 +7,10 @@ module Ast
# copied from function expression: TODO make function # copied from function expression: TODO make function
return_reg = Vm::Integer.new(7) 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 return_reg.load into , expression_value
else 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 end
#function.set_return return_reg #function.set_return return_reg
return return_reg return return_reg

View File

@ -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 # 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 def _get_instance_variable context , name = Vm::Integer
get_function = Vm::Function.new(:_get_instance_variable , Vm::Integer , [ Vm::Integer ] , Vm::Integer ) get_function = Vm::Function.new(:_get_instance_variable , Vm::Integer , [ Vm::Integer ] , Vm::Integer )
me = get_function.args[0] me = get_function.receiver
var_name = get_function.args[1] var_name = get_function.args.first
return_to = get_function.return_type return_to = get_function.return_type
index_function = context.object_space.get_or_create_class(:Object).get_or_create_function(:index_of) index_function = context.object_space.get_or_create_class(:Object).get_or_create_function(:index_of)
b = get_function.body b = get_function.body

View File

@ -36,7 +36,7 @@ module Core
putint_function = Vm::Function.new(:putint , Vm::Integer , [] , Vm::Integer ) putint_function = Vm::Function.new(:putint , Vm::Integer , [] , Vm::Integer )
buffer = Vm::StringConstant.new(" ") # create a buffer buffer = Vm::StringConstant.new(" ") # create a buffer
context.object_space.add_object buffer # and save it (function local variable: a no no) 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 moved_int = putint_function.new_local
utoa = context.object_space.get_or_create_class(:Object).get_or_create_function(:utoa) utoa = context.object_space.get_or_create_class(:Object).get_or_create_function(:utoa)
b = putint_function.body b = putint_function.body
@ -44,7 +44,7 @@ module Core
#b.a buffer => int # string to write to #b.a buffer => int # string to write to
b.add( int , buffer ,nil ) # 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 ) b.call( utoa )
# And now we "just" have to print it, using the write_stdout # And now we "just" have to print it, using the write_stdout
b.add( int , buffer , nil ) # string to write to b.add( int , buffer , nil ) # string to write to
@ -60,13 +60,13 @@ module Core
# arguments: string address , integer # arguments: string address , integer
def utoa context def utoa context
utoa_function = Vm::Function.new(:utoa , Vm::Integer , [ Vm::Integer ] , Vm::Integer ) utoa_function = Vm::Function.new(:utoa , Vm::Integer , [ Vm::Integer ] , Vm::Integer )
str_addr = utoa_function.args[0] str_addr = utoa_function.receiver
number = utoa_function.args[1] number = utoa_function.args.first
remainder = utoa_function.new_local remainder = utoa_function.new_local
Vm::RegisterMachine.instance.div10( utoa_function.body , number , remainder ) Vm::RegisterMachine.instance.div10( utoa_function.body , number , remainder )
# make char out of digit (by using ascii encoding) 48 == "0" # make char out of digit (by using ascii encoding) 48 == "0"
b = utoa_function.body.scope binding b = utoa_function.body
b.remainder = remainder + 48 b.add(remainder , remainder , 48)
b.strb( remainder, str_addr ) b.strb( remainder, str_addr )
b.sub( str_addr, str_addr , 1 ) b.sub( str_addr, str_addr , 1 )
b.cmp( number , 0 ) b.cmp( number , 0 )
@ -80,26 +80,26 @@ module Core
# not my hand off course, found in the net from a basic introduction # not my hand off course, found in the net from a basic introduction
def fibo context def fibo context
fibo_function = Vm::Function.new(:fibo , Vm::Integer , [] , Vm::Integer ) fibo_function = Vm::Function.new(:fibo , Vm::Integer , [] , Vm::Integer )
result = Vm::Integer.new(7) result = fibo_function.return_type
int = fibo_function.args[0] int = fibo_function.receiver
count = fibo_function.new_local count = fibo_function.new_local
f1 = fibo_function.new_local f1 = fibo_function.new_local
f2 = 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( result, int , condition_code: :le)
b.mov( :pc , :lr , condition_code: :le) b.mov( :pc , :lr , condition_code: :le)
b.push [ count , f1 , f2 , :lr] b.push [ count , f1 , f2 , :lr]
b.f1 = 1 b.mov f1 , 1
b.f2 = 0 b.mov f2 , 0
b.count = int - 2 b.sub count , int , 2
l = fibo_function.body.new_block("loop").scope binding l = fibo_function.body.new_block("loop")
l.f1 = f1 + f2 l.add f1 , f1 , f2
l.f2 = f1 - f2 l.sub f2 , f1 , f2
l.count = (count - 1).set_update_status l.sub count , count , 1 , set_update_status: 1
l.bpl( l ) l.bpl( l )
l.mov( result , f1 ) l.mov( result , f1 )
fibo_function.set_return result fibo_function.set_return result

View File

@ -24,14 +24,3 @@ module Support
end end
end 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

View File

@ -32,14 +32,8 @@ module Vm
attr_reader :name , :next , :codes , :function attr_reader :name , :next , :codes , :function
def add_code(kode) 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}" 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 @insert_at.codes << kode
self self
end end
@ -70,27 +64,8 @@ module Vm
self self
end end
# to use the assignment syntax (see method_missing) the scope must be set, so variables can be resolved # sugar to create instructions easily.
# The scope you set should be a binding (literally, the kernel.binding) # any method will be passed on to the RegisterMachine and the result added to the block
# 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
# With this trick we can write what looks like assembler, # With this trick we can write what looks like assembler,
# Example b.instance_eval # Example b.instance_eval
# mov( r1 , r2 ) # mov( r1 , r2 )
@ -98,16 +73,8 @@ module Vm
# end # end
# mov and add will be called on Machine and generate Inststuction that are then added # mov and add will be called on Machine and generate Inststuction that are then added
# to the block # to the block
# also symbols are supported and wrapped as register usages (for bare metal programming)
def method_missing(meth, *args, &block) 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) add_code RegisterMachine.instance.send(meth , *args)
end end

View File

@ -3,7 +3,7 @@ require_relative "meta_class"
module Vm module Vm
# class is mainly a list of functions with a name (for now) # class is mainly a list of functions with a name (for now)
# layout of object is seperated into Layout # layout of object is seperated into Layout
class BootClass < Code class BootClass < ObjectConstant
def initialize name , context , super_class = :Object def initialize name , context , super_class = :Object
super() super()
@context = context @context = context

View File

@ -9,15 +9,23 @@ module Vm
@value = value @value = value
@args = args @args = args
@function = function @function = function
raise "oh #{name} " unless value
end end
attr_reader :function , :args , :name , :value attr_reader :function , :args , :name , :value
def load_args into 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| args.each_with_index do |arg , index|
if arg.is_a?(IntegerConstant) or arg.is_a?(StringConstant) if arg.is_a?(IntegerConstant) or arg.is_a?(StringConstant)
function.args[index].load into , arg function.args[index].load into , arg
else 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 end
end end

View File

@ -43,5 +43,6 @@ module Vm
def assemble(io) def assemble(io)
raise "Not implemented #{self.inspect}" raise "Not implemented #{self.inspect}"
end end
end end
end end

View File

@ -9,6 +9,10 @@ module Vm
end 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 class IntegerConstant < Constant
def initialize int def initialize int
@ -25,7 +29,7 @@ module Vm
# Currently string are stored "inline" , ie in the code segment. # Currently string are stored "inline" , ie in the code segment.
# Mainly because that works an i aint no elf expert. # Mainly because that works an i aint no elf expert.
class StringConstant < Constant class StringConstant < ObjectConstant
attr_reader :string attr_reader :string
# currently aligned to 4 (ie padded with 0) and off course 0 at the end # currently aligned to 4 (ie padded with 0) and off course 0 at the end
def initialize str def initialize str

View File

@ -27,16 +27,16 @@ module Vm
class Function < Code class Function < Code
TYPE_REG = 0 TYPE_REG = :r0
RECEIVER_REG = 1 RECEIVER_REG = :r1
RETURN_REG = 7 RETURN_REG = :r7
def initialize(name , receiver = Vm::Integer , args = [] , return_type = Vm::Integer) def initialize(name , receiver = Vm::Integer , args = [] , return_type = Vm::Integer)
super() super()
@name = name.to_sym @name = name.to_sym
if receiver.is_a?(Value) if receiver.is_a?(Value)
@receiver = receiver @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 else
@receiver = receiver.new(RECEIVER_REG) @receiver = receiver.new(RECEIVER_REG)
end end
@ -45,9 +45,9 @@ module Vm
args.each_with_index do |arg , i| args.each_with_index do |arg , i|
if arg.is_a?(Value) if arg.is_a?(Value)
@args[i] = arg @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 else
@args[i] = arg.new(i+1+RECEIVER_REG) @args[i] = arg.new(RegisterUse.new(RECEIVER_REG).next_reg(i + 1))
end end
end end
set_return return_type set_return return_type
@ -59,12 +59,12 @@ module Vm
@blocks = [] @blocks = []
end 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 def set_return type_or_value
@return_type = type_or_value || Vm::Integer @return_type = type_or_value || Vm::Integer
if @return_type.is_a?(Value) 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 else
@return_type = @return_type.new(RETURN_REG) @return_type = @return_type.new(RETURN_REG)
end end
@ -76,7 +76,7 @@ module Vm
def new_local type = Vm::Integer def new_local type = Vm::Integer
register = args.length + 1 + @locals.length # one for the receiver implicit arg 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 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 # raise "Register overflow in function #{name}" if l.register > 6
@locals << l @locals << l
l l
@ -84,13 +84,13 @@ module Vm
#BUG - must save receiver #BUG - must save receiver
def save_locals context , into 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? into.push(save) unless save.empty?
end end
def restore_locals context , into def restore_locals context , into
#TODO assumes allocation in order, as the pop must be get regs in ascending order (also push) #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? into.pop(restore) unless restore.empty?
end end

View File

@ -68,16 +68,6 @@ module Vm
@right = right @right = right
super(options) super(options)
end 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 end
class MathInstruction < Instruction class MathInstruction < Instruction
def initialize first , options = {} def initialize first , options = {}
@ -96,7 +86,7 @@ module Vm
def initialize to , from , options = {} def initialize to , from , options = {}
@to = to @to = to
@from = from @from = from
raise inspect unless from raise "move must have from set #{inspect}" unless from
super(options) super(options)
end end
end end

View File

@ -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 # 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(...) # 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 # 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 # no name, nor nothing. as this is just the object really
def initialize(object) def initialize(object)

View File

@ -108,6 +108,7 @@ module Vm
options = {} if options == nil options = {} if options == nil
options.merge defaults options.merge defaults
options[:opcode] = inst options[:opcode] = inst
first = Vm::Integer.new(first) if first.is_a? Symbol
clazz.new(first , options) clazz.new(first , options)
end end
end end
@ -118,6 +119,8 @@ module Vm
create_method(inst) do |left ,right , options = nil| create_method(inst) do |left ,right , options = nil|
options = {} if options == nil options = {} if options == nil
options.merge defaults 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 options[:opcode] = inst
clazz.new(left , right ,options) clazz.new(left , right ,options)
end end
@ -130,6 +133,9 @@ module Vm
options = {} if options == nil options = {} if options == nil
options.merge defaults options.merge defaults
options[:opcode] = inst 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) clazz.new(result, left , right ,options)
end end
end end

View File

@ -53,9 +53,23 @@ module Vm
# but which register can be changed, and _all_ instructions sharing the RegisterUse then use that register # 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. # In other words a simple level of indirection, or change from value to reference sematics.
class RegisterUse class RegisterUse
attr_accessor :register attr_accessor :symbol
def initialize r 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
end end
@ -66,23 +80,21 @@ module Vm
attr_accessor :used_register attr_accessor :used_register
def register def register_symbol
@used_register.register @used_register.symbol
end end
def inspect def inspect
self.class.name + "(r#{used_register.register})" "#{self.class.name} (#{register_symbol})"
end end
def to_s def to_s
inspect inspect
end end
def initialize reg def initialize reg
if reg.is_a? Fixnum if reg.is_a? RegisterUse
@used_register = RegisterUse.new(reg)
else
@used_register = reg @used_register = reg
else
@used_register = RegisterUse.new(reg)
end end
raise inspect if reg == nil
end end
def length def length
4 4
@ -98,21 +110,6 @@ module Vm
class Integer < Word 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 def less_or_equal block , right
RegisterMachine.instance.integer_less_or_equal block , self , right RegisterMachine.instance.integer_less_or_equal block , self , right
end end
@ -155,7 +152,9 @@ module Vm
block.mov( self , right ) #move the value block.mov( self , right ) #move the value
elsif right.is_a? StringConstant elsif right.is_a? StringConstant
block.add( self , right , nil) #move the address, by "adding" to pc, ie pc relative 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 else
raise "unknown #{right.inspect}" raise "unknown #{right.inspect}"
end end

View File

@ -21,7 +21,8 @@ def minus(a,b)
end end
end end
putint(times(7,6)) tim = times(7,6)
tim.putint()
HERE 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] @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 " @output = " 42 "

View File

@ -5,7 +5,8 @@ class TestPutint < MiniTest::Test
def test_putint def test_putint
@string_input = <<HERE @string_input = <<HERE
putint( 42 ) fourty_two = 42
fourty_two.putint()
HERE 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] @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 " @output = " 42 "
@ -14,4 +15,3 @@ HERE
write "putint" write "putint"
end end
end end

View File

@ -14,8 +14,8 @@ def fibonaccir( n )
return a + b return a + b
end end
end end
fib = fibonaccir( 10 )
putint(fibonaccir( 10 )) fib.putint()
HERE 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] @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 " @output = " 55 "

View File

@ -16,8 +16,8 @@ def fibonaccit(n) # n == r0
end #r5 <- r0 - 1 n=n-1 through r5 tmp end #r5 <- r0 - 1 n=n-1 through r5 tmp
return b return b
end # r0 <- r5 end # r0 <- r5
fibo = fibonaccit( 10 )
putint(fibonaccit( 10 )) fibo.putint()
HERE 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] @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 " @output = " 55 "
@ -31,8 +31,8 @@ HERE
def test_kernel_fibo def test_kernel_fibo
int = Vm::Integer.new(1) int = Vm::Integer.new(1)
fibo = @object_space.get_or_create_class(:Object).get_or_create_function(:fibo) fibo = @object_space.get_or_create_class(:Object).get_or_create_function(:fibo)
main = @object_space.main.scope binding main = @object_space.main
main.int = 10 main.mov int , 10
ret = main.call( fibo ) ret = main.call( fibo )
main.mov( :r1 , :r7 ) main.mov( :r1 , :r7 )
putint = @object_space.get_or_create_class(:Object).get_or_create_function(:putint) putint = @object_space.get_or_create_class(:Object).get_or_create_function(:putint)