2014-05-05 10:03:43 +02:00
|
|
|
require_relative "code"
|
|
|
|
|
2014-04-28 21:08:09 +02:00
|
|
|
module Vm
|
2014-05-02 07:02:25 +02:00
|
|
|
|
|
|
|
# Values represent the information as it is processed. Different subclasses for different types,
|
|
|
|
# each type with different operations.
|
2014-05-21 18:41:51 +02:00
|
|
|
# The oprerations on values is what makes a machine do things. Operations are captured as
|
|
|
|
# subclasses of Instruction and saved to Blocks
|
2014-05-02 07:02:25 +02:00
|
|
|
|
|
|
|
# Values are immutable! (that's why they are called values)
|
|
|
|
# Operations on values _always_ produce new values (conceptionally)
|
|
|
|
|
2014-05-03 14:13:44 +02:00
|
|
|
# Values are a way to reason about (create/validate) instructions.
|
|
|
|
# In fact a linked lists of values is created by invoking instructions
|
|
|
|
# the linked list goes from value to instruction to value, backwards
|
2014-05-02 07:02:25 +02:00
|
|
|
|
|
|
|
# Word Values are what fits in a register. Derived classes
|
|
|
|
# Float, Reference , Integer(s) must fit the same registers
|
|
|
|
|
2014-05-05 10:03:43 +02:00
|
|
|
# just a base class for data. not sure how this will be usefull (may just have read too much llvm)
|
2014-05-21 18:41:51 +02:00
|
|
|
class Value
|
|
|
|
def class_for clazz
|
2014-05-21 18:43:46 +02:00
|
|
|
RegisterMachine.instance.class_for(clazz)
|
2014-05-10 09:59:56 +02:00
|
|
|
end
|
2014-05-02 07:02:25 +02:00
|
|
|
end
|
|
|
|
|
2014-05-13 17:21:24 +02:00
|
|
|
# Just a nice way to write branches
|
2014-05-22 20:38:57 +02:00
|
|
|
class BranchCondition < Value
|
2014-05-13 17:21:24 +02:00
|
|
|
|
2014-05-22 20:38:57 +02:00
|
|
|
def initialize operator
|
|
|
|
@operator = operator
|
|
|
|
end
|
|
|
|
attr_accessor :operator
|
|
|
|
#needed to check the opposite, ie not true
|
|
|
|
def not_operator
|
|
|
|
case @operator
|
|
|
|
when :le
|
|
|
|
:gt
|
|
|
|
when :gt
|
|
|
|
:le
|
2014-05-24 09:41:57 +02:00
|
|
|
when :lt
|
|
|
|
:ge
|
2014-05-25 07:43:07 +02:00
|
|
|
when :eq
|
|
|
|
:ne
|
2014-05-22 20:38:57 +02:00
|
|
|
else
|
|
|
|
raise "no implemented #{@operator}"
|
|
|
|
end
|
|
|
|
end
|
2014-05-13 17:21:24 +02:00
|
|
|
end
|
|
|
|
|
2014-06-06 20:49:03 +02:00
|
|
|
# RegisterUSe is _not_ the name for a register, "only" for a certain use of it.
|
|
|
|
# In a way it is like a variable name, a storage location. The location is a register off course,
|
|
|
|
# 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
|
2014-06-07 16:59:44 +02:00
|
|
|
attr_accessor :symbol
|
2014-06-06 20:49:03 +02:00
|
|
|
def initialize r
|
2014-06-07 16:59:44 +02:00
|
|
|
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) )
|
2014-06-06 20:49:03 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# This is what it is when we don't know what it is. #TODO, better if it were explicitly a different type, not the base
|
|
|
|
# Must be promoted to A Word-Value to to anything makes is_a chaecking easier
|
2014-05-13 15:24:19 +02:00
|
|
|
# remembering that our oo machine is typed, no overloading or stuff
|
2014-05-02 07:02:25 +02:00
|
|
|
class Word < Value
|
2014-05-13 15:24:19 +02:00
|
|
|
|
2014-06-06 20:49:03 +02:00
|
|
|
attr_accessor :used_register
|
|
|
|
|
2014-06-07 16:59:44 +02:00
|
|
|
def register_symbol
|
|
|
|
@used_register.symbol
|
2014-06-06 20:49:03 +02:00
|
|
|
end
|
2014-05-13 17:21:24 +02:00
|
|
|
def inspect
|
2014-06-07 16:59:44 +02:00
|
|
|
"#{self.class.name} (#{register_symbol})"
|
2014-05-20 10:03:18 +02:00
|
|
|
end
|
|
|
|
def to_s
|
|
|
|
inspect
|
2014-05-13 17:21:24 +02:00
|
|
|
end
|
2014-05-13 15:24:19 +02:00
|
|
|
def initialize reg
|
2014-06-07 16:59:44 +02:00
|
|
|
if reg.is_a? RegisterUse
|
2014-06-06 20:49:03 +02:00
|
|
|
@used_register = reg
|
2014-06-07 16:59:44 +02:00
|
|
|
else
|
|
|
|
@used_register = RegisterUse.new(reg)
|
2014-06-06 20:49:03 +02:00
|
|
|
end
|
2014-05-05 08:35:40 +02:00
|
|
|
end
|
2014-05-10 14:24:56 +02:00
|
|
|
def length
|
|
|
|
4
|
|
|
|
end
|
2014-04-28 21:08:09 +02:00
|
|
|
end
|
|
|
|
|
2014-05-02 07:02:25 +02:00
|
|
|
class Unsigned < Word
|
|
|
|
|
2014-05-13 17:21:24 +02:00
|
|
|
def plus block , unsigned
|
2014-05-21 18:43:46 +02:00
|
|
|
RegisterMachine.instance.unsigned_plus self , unsigned
|
2014-05-02 07:02:25 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-05-13 15:24:19 +02:00
|
|
|
class Integer < Word
|
2014-05-02 07:02:25 +02:00
|
|
|
|
2014-05-13 17:21:24 +02:00
|
|
|
def less_or_equal block , right
|
2014-05-21 18:43:46 +02:00
|
|
|
RegisterMachine.instance.integer_less_or_equal block , self , right
|
2014-05-06 20:36:28 +02:00
|
|
|
end
|
2014-05-28 19:10:16 +02:00
|
|
|
def greater_or_equal block , right
|
|
|
|
RegisterMachine.instance.integer_greater_or_equal block , self , right
|
|
|
|
end
|
2014-05-22 20:38:57 +02:00
|
|
|
def greater_than block , right
|
|
|
|
RegisterMachine.instance.integer_greater_than block , self , right
|
|
|
|
end
|
2014-05-24 09:41:57 +02:00
|
|
|
def less_than block , right
|
|
|
|
RegisterMachine.instance.integer_less_than block , self , right
|
|
|
|
end
|
2014-05-28 19:10:16 +02:00
|
|
|
def equals block , right
|
|
|
|
RegisterMachine.instance.integer_equals block , self , right
|
|
|
|
end
|
2014-05-21 11:42:54 +02:00
|
|
|
def == other
|
|
|
|
code = class_for(CompareInstruction).new(self , other , opcode: :cmp)
|
|
|
|
end
|
2014-05-19 10:28:13 +02:00
|
|
|
def + other
|
2014-05-20 10:54:59 +02:00
|
|
|
class_for(LogicInstruction).new(nil , self , other , opcode: :add)
|
|
|
|
end
|
|
|
|
def - other
|
2014-05-21 11:42:54 +02:00
|
|
|
class_for(LogicInstruction).new(nil , self , other , opcode: :sub )#, update_status: 1 )
|
2014-05-19 10:28:13 +02:00
|
|
|
end
|
2014-06-01 20:03:08 +02:00
|
|
|
def at_index block , left , right
|
|
|
|
RegisterMachine.instance.integer_at_index block , self , left , right
|
|
|
|
end
|
2014-05-16 09:42:25 +02:00
|
|
|
def plus block , first , right
|
2014-05-21 18:43:46 +02:00
|
|
|
RegisterMachine.instance.integer_plus block , self , first , right
|
2014-05-13 17:21:24 +02:00
|
|
|
end
|
2014-05-16 09:42:25 +02:00
|
|
|
def minus block , first , right
|
2014-05-21 18:43:46 +02:00
|
|
|
RegisterMachine.instance.integer_minus block , self , first , right
|
2014-05-14 10:33:23 +02:00
|
|
|
end
|
2014-06-02 14:11:48 +02:00
|
|
|
def left_shift block , first , right
|
|
|
|
RegisterMachine.instance.integer_left_shift block , self , first , right
|
|
|
|
end
|
2014-05-13 17:21:24 +02:00
|
|
|
|
|
|
|
def load block , right
|
2014-05-21 20:27:05 +02:00
|
|
|
if(right.is_a? IntegerConstant)
|
|
|
|
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
|
2014-06-07 16:59:44 +02:00
|
|
|
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
|
2014-05-21 20:27:05 +02:00
|
|
|
else
|
|
|
|
raise "unknown #{right.inspect}"
|
|
|
|
end
|
2014-05-21 20:15:23 +02:00
|
|
|
self
|
2014-05-03 14:13:44 +02:00
|
|
|
end
|
2014-05-14 11:02:54 +02:00
|
|
|
|
|
|
|
def move block , right
|
2014-05-21 20:15:23 +02:00
|
|
|
block.mov( self , right )
|
|
|
|
self
|
2014-05-14 11:02:54 +02:00
|
|
|
end
|
|
|
|
|
2014-05-02 07:02:25 +02:00
|
|
|
end
|
|
|
|
end
|
2014-05-13 15:24:19 +02:00
|
|
|
require_relative "constants"
|