rubyx/lib/risc/instructions/instruction.rb
Torsten 06ade75593 Fix non ssa issue
register instances were being shared across instructions
causing the setting to have side-effects
Fixed this by copying the register on write
(fixing the symptom rather than the cause, i'll make an issue)
2020-03-22 14:31:43 +02:00

105 lines
3.3 KiB
Ruby

require "util/list"
module Risc
# the register machine has at least 8 registers, named r0-r5 , :lr and :pc
# (for historical reasons , r for register, pc for ProgramCounter ie next instruction address
# and lr means LinkRegister, ie the location where to return to when in a function)
#
# We can load and store their contents, move data between them and
# access (get/set) memory at a constant offset from a register
# While SlotMachine works with objects, the register machine has registers,
# but we keep the names for better understanding, r2-5 are temporary/scratch
# There is no direct memory access, only through registers
# Constants can/must be loaded into registers before use
# At compile time, Instructions form a linked list (:next attribute is the link)
# At run time Instructions are traversesed as a graph
#
# Branches fan out, Labels collect
# Labels are the only valid branch targets
#
class Instruction
include Util::List
def initialize( source , nekst = nil )
@source = source
@next = nekst
return unless source
raise "Source must be string or Instruction, not #{source.class}" unless source.is_a?(String) or
source.is_a?(SlotMachine::Instruction) or source.is_a?(Parfait::Callable)
end
attr_reader :source
def to_arr
ret = []
self.each {|ins| ret << ins}
ret
end
# just part of the protocol, noop in this case
def precheck
end
# return an array of names of registers that is used by the instruction
def register_attributes
raise "Not implemented in #{self.class}"
end
# return an array of names of registers that is used by the instruction
def register_names
register_attributes.collect {|attr| get_register(attr)}
end
# get the register value that has the name (ie attribute by that name)
# return the registers name ie RegisterValue's symbol
def get_register(name)
instance_variable_get("@#{name}".to_sym).symbol
end
# set all registers that has the name "name"
# going through the register_names and setting all where the
# get_register would return name
# Create new RegisterValue with new name and swap the variable out
def set_registers(name , value)
register_attributes.each do |attr|
reg = instance_variable_get("@#{attr}".to_sym)
next unless reg.symbol == name
new_reg = reg.dup(value)
instance_variable_set("@#{attr}".to_sym , new_reg)
end
end
def to_cpu( translator )
translator.translate( self )
end
def class_source( derived)
"#{self.class.name.split("::").last}: #{derived} #{source_mini}"
end
def source_mini
return "(no source)" unless source
return "(from: #{source[0..50]})" if source.is_a?(String)
"(from: #{source.class.name.split("::").last})"
end
end
end
require_relative "setter"
require_relative "getter"
require_relative "reg_to_slot"
require_relative "slot_to_reg"
require_relative "reg_to_byte"
require_relative "byte_to_reg"
require_relative "load_constant"
require_relative "load_data"
require_relative "syscall"
require_relative "function_call"
require_relative "function_return"
require_relative "transfer"
require_relative "label"
require_relative "branch"
require_relative "dynamic_jump"
require_relative "operator_instruction"