2014-05-03 21:18:04 +02:00
|
|
|
require_relative "code"
|
|
|
|
require "support/hash_attributes"
|
2014-05-02 07:02:25 +02:00
|
|
|
module Vm
|
2014-05-03 14:13:44 +02:00
|
|
|
|
2014-05-03 21:18:04 +02:00
|
|
|
# Because the idea of what one instruction does, does not always map one to one to real machine
|
2014-05-03 14:13:44 +02:00
|
|
|
# instructions, and instruction may link to another instruction thus creating an arbitrary list
|
|
|
|
# to get the job (the original instruciton) done
|
2014-05-03 21:18:04 +02:00
|
|
|
|
2014-05-03 14:13:44 +02:00
|
|
|
# Admittately it would be simpler just to create the (abstract) instructions and let the machine
|
|
|
|
# encode them into what-ever is neccessary, but this approach leaves more possibility to
|
|
|
|
# optimize the actual instruction stream (not just the crystal instruction stream). Makes sense?
|
|
|
|
|
|
|
|
# We have basic classes (literally) of instructions
|
|
|
|
# - Memory
|
|
|
|
# - Stack
|
|
|
|
# - Logic
|
|
|
|
# - Math
|
|
|
|
# - Control/Compare
|
|
|
|
# - Move
|
|
|
|
# - Call
|
|
|
|
|
|
|
|
# Instruction derives from Code, for the assembly api
|
2014-05-03 21:18:04 +02:00
|
|
|
|
2014-05-19 10:28:13 +02:00
|
|
|
class Instruction < Code
|
2014-05-18 09:27:35 +02:00
|
|
|
def initialize options
|
2014-05-05 14:59:29 +02:00
|
|
|
@attributes = options
|
2014-05-03 21:18:04 +02:00
|
|
|
end
|
2014-05-19 10:28:13 +02:00
|
|
|
def opcode
|
|
|
|
@attributes[:opcode]
|
|
|
|
end
|
2014-05-02 07:02:25 +02:00
|
|
|
end
|
|
|
|
|
2014-05-03 14:13:44 +02:00
|
|
|
class StackInstruction < Instruction
|
2014-05-19 10:28:13 +02:00
|
|
|
def initialize first , options = {}
|
2014-05-18 09:27:35 +02:00
|
|
|
@first = first
|
|
|
|
super(options)
|
|
|
|
end
|
2014-05-03 14:13:44 +02:00
|
|
|
end
|
|
|
|
class MemoryInstruction < Instruction
|
2014-05-19 10:28:13 +02:00
|
|
|
def initialize first , options = {}
|
2014-05-18 09:27:35 +02:00
|
|
|
@first = first
|
|
|
|
super(options)
|
|
|
|
end
|
2014-05-03 14:13:44 +02:00
|
|
|
end
|
|
|
|
class LogicInstruction < Instruction
|
2014-05-19 10:28:13 +02:00
|
|
|
def initialize result , left , right , options = {}
|
2014-05-18 11:18:57 +02:00
|
|
|
@result = result
|
|
|
|
@left = left
|
|
|
|
@right = right
|
2014-05-18 09:27:35 +02:00
|
|
|
super(options)
|
|
|
|
end
|
2014-05-19 10:28:13 +02:00
|
|
|
attr_accessor :result
|
2014-05-03 14:13:44 +02:00
|
|
|
end
|
|
|
|
class MathInstruction < Instruction
|
2014-05-19 10:28:13 +02:00
|
|
|
def initialize first , options = {}
|
2014-05-18 09:27:35 +02:00
|
|
|
@first = first
|
|
|
|
super(options)
|
|
|
|
end
|
2014-05-03 14:13:44 +02:00
|
|
|
end
|
|
|
|
class CompareInstruction < Instruction
|
2014-05-19 10:28:13 +02:00
|
|
|
def initialize left , right , options = {}
|
2014-05-18 10:11:26 +02:00
|
|
|
@left = left
|
|
|
|
@right = right
|
2014-05-18 09:27:35 +02:00
|
|
|
super(options)
|
|
|
|
end
|
2014-05-03 14:13:44 +02:00
|
|
|
end
|
|
|
|
class MoveInstruction < Instruction
|
2014-05-19 10:28:13 +02:00
|
|
|
def initialize to , from , options = {}
|
2014-05-18 11:30:49 +02:00
|
|
|
@to = to
|
|
|
|
@from = from
|
2014-05-19 10:28:13 +02:00
|
|
|
raise inspect unless from
|
2014-05-18 09:27:35 +02:00
|
|
|
super(options)
|
|
|
|
end
|
2014-05-03 14:13:44 +02:00
|
|
|
end
|
|
|
|
class CallInstruction < Instruction
|
2014-05-19 10:28:13 +02:00
|
|
|
def initialize first , options = {}
|
2014-05-18 09:27:35 +02:00
|
|
|
@first = first
|
|
|
|
super(options)
|
2014-05-14 09:47:30 +02:00
|
|
|
opcode = @attributes[:opcode].to_s
|
|
|
|
if opcode.length == 3 and opcode[0] == "b"
|
|
|
|
@attributes[:condition_code] = opcode[1,2].to_sym
|
|
|
|
@attributes[:opcode] = :b
|
|
|
|
end
|
2014-05-15 15:54:23 +02:00
|
|
|
if opcode.length == 6 and opcode[0] == "c"
|
|
|
|
@attributes[:condition_code] = opcode[4,2].to_sym
|
|
|
|
@attributes[:opcode] = :call
|
|
|
|
end
|
2014-05-14 09:47:30 +02:00
|
|
|
end
|
2014-05-03 14:13:44 +02:00
|
|
|
end
|
2014-05-02 07:02:25 +02:00
|
|
|
end
|