rubyx/lib/risc/instruction.rb

133 lines
3.9 KiB
Ruby
Raw Normal View History

module Risc
2014-05-03 14:13:44 +02:00
# the register machine has at least 8 registers, named r0-r5 , :lr and :pc (for historical reasons)
# we can load and store their contents and
# access (get/set) memory at a constant offset from a register
2015-05-24 19:00:11 +02:00
# while the vm works with objects, the register machine has registers,
# but we keep the names for better understanding, r4/5 are temporary/scratch
# there is no direct memory access, only through registers
# constants can/must be loaded into registers before use
# Instructions form a graph.
# Linear instructions form a linked list
# Branches fan out, Labels collect
# Labels are the only valid branch targets
class Instruction
def initialize source , nekst = nil
2015-10-28 20:38:23 +01:00
@source = source
@next = nekst
return unless source
raise "Source must be string or ast node, not #{source.class}" unless source.is_a?(String) or source.is_a?(Mom::Instruction)
2015-07-18 10:21:49 +02:00
end
attr_reader :source
2015-07-18 10:21:49 +02:00
# set the next instruction (also aliased as <<)
# throw an error if that is set, use insert for that use case
# return the instruction, so chaining works as one wants (not backwards)
def set_next nekst
raise "Next already set #{@next}" if @next
@next = nekst
nekst
end
alias :<< :set_next
# during translation we replace one by one
def replace_next nekst
old = @next
@next = nekst
@next.append old.next if old
end
# get the next instruction (without arg given )
# when given an interger, advance along the line that many time and return.
def next( amount = 1)
(amount == 1) ? @next : @next.next(amount-1)
end
# set the give instruction as the next, while moving any existing
# instruction along to the given ones's next.
# ie insert into the linked list that the instructions form
def insert instruction
2018-03-14 13:09:31 +01:00
instruction.last.set_next @next
@next = instruction
end
# return last set instruction. ie follow the linked list until it stops
def last
code = self
code = code.next while( code.next )
return code
end
# set next for the last (see last)
# so append the given code to the linked list at the end
def append code
last.set_next code
end
def length labels = []
ret = 1
ret += self.next.length( labels ) if self.next
ret
end
2017-01-04 20:32:09 +01:00
def to_arr labels = []
ret = [self.class]
2017-01-04 20:32:09 +01:00
ret += self.next.to_arr(labels) if self.next
ret
end
# derived classes must provide a byte_length
def byte_length
raise "Abstract called on #{self}"
end
def assemble_all io , labels = []
self.assemble(io)
self.next.assemble_all(io, labels) if self.next
end
def assemble io
raise "Abstract called on #{self}"
end
def total_byte_length labels = []
ret = self.byte_length
ret += self.next.total_byte_length(labels) if self.next
#puts "#{self.class.name} return #{ret}"
ret
end
def set_position position , labels = []
2017-01-01 20:52:35 +01:00
Positioned.set_position(self,position)
position += byte_length
if self.next
self.next.set_position(position , labels)
else
position
end
end
2015-10-25 11:03:31 +01:00
def each_label labels =[] , &block
self.next.each_label(labels , &block) if self.next
end
2014-05-02 07:02:25 +02:00
end
2015-05-24 19:00:11 +02:00
2014-05-02 07:02:25 +02:00
end
require_relative "instructions/setter"
require_relative "instructions/getter"
require_relative "instructions/reg_to_slot"
require_relative "instructions/slot_to_reg"
2016-12-25 17:11:58 +01:00
require_relative "instructions/reg_to_byte"
require_relative "instructions/byte_to_reg"
require_relative "instructions/load_constant"
2015-06-22 21:48:42 +02:00
require_relative "instructions/syscall"
2014-10-04 11:52:47 +02:00
require_relative "instructions/function_call"
require_relative "instructions/function_return"
require_relative "instructions/register_transfer"
require_relative "instructions/label"
require_relative "instructions/branch"
2015-08-04 21:01:20 +02:00
require_relative "instructions/operator_instruction"