a basic interpret command for cli

part of the benchmark effort
determine amount of objects
This commit is contained in:
Torsten 2019-07-25 21:23:55 +03:00
parent 00bf38a0e6
commit 14c965360d
2 changed files with 52 additions and 10 deletions

View File

@ -8,7 +8,8 @@ module Risc
# will be executed by method execute_SlotToReg # will be executed by method execute_SlotToReg
# #
# The Interpreter (a bit like a cpu) has a state flag, a current instruction and registers # The Interpreter (a bit like a cpu) has a state flag, a current instruction and registers
# We collect the stdout (as a hack not to interpret the OS) # We collect the stdout (as a hack not to interpret the OS) in a string. It can also be passed
# in to the init, as an IO
# #
class Interpreter class Interpreter
# fire events for changed pc and register contents # fire events for changed pc and register contents
@ -18,11 +19,13 @@ module Risc
attr_reader :instruction , :clock , :pc # current instruction and pc attr_reader :instruction , :clock , :pc # current instruction and pc
attr_reader :registers # the registers, 16 (a hash, sym -> contents) attr_reader :registers # the registers, 16 (a hash, sym -> contents)
attr_reader :stdout, :state , :flags # somewhat like the lags on a cpu, hash sym => bool (zero .. . ) attr_reader :stdout, :state , :flags # somewhat like the flags on a cpu, hash sym => bool (zero .. . )
#start in state :stopped and set registers to unknown # start in state :stopped and set registers to unknown
def initialize( linker ) # Linker gives the state of the program
@stdout , @clock , @pc , @state = "", 0 , 0 , :stopped # Passing a stdout in (an IO, only << called) can be used to get output immediately.
def initialize( linker , stdout = "")
@stdout , @clock , @pc , @state = stdout, 0 , 0 , :stopped
@registers = {} @registers = {}
@flags = { :zero => false , :plus => false , @flags = { :zero => false , :plus => false ,
:minus => false , :overflow => false } :minus => false , :overflow => false }
@ -32,8 +35,7 @@ module Risc
@linker = linker @linker = linker
end end
def start_program(linker = nil) def start_program()
initialize(linker || @linker)
init = @linker.cpu_init init = @linker.cpu_init
set_state(:running) set_state(:running)
set_pc( Position.get(init).at ) set_pc( Position.get(init).at )
@ -249,10 +251,12 @@ module Risc
str = get_register( :r1 ) # should test length, ie r2 str = get_register( :r1 ) # should test length, ie r2
case str case str
when Symbol when Symbol
@stdout += str.to_s @stdout << str.to_s
@stdout.flush if @stdout.respond_to?(:flush)
return str.to_s.length return str.to_s.length
when Parfait::Word when Parfait::Word
@stdout += str.to_string @stdout << str.to_string
@stdout.flush if @stdout.respond_to?(:flush)
return str.char_length return str.char_length
else else
raise "NO string for putstring #{str.class}:#{str.object_id}" unless str.is_a?(Symbol) raise "NO string for putstring #{str.class}:#{str.object_id}" unless str.is_a?(Symbol)

View File

@ -1,5 +1,6 @@
require "thor" require "thor"
require "rubyx" require "rubyx"
require "risc/interpreter"
class RubyXC < Thor class RubyXC < Thor
desc "compile FILE" , "Compile given FILE to binary" desc "compile FILE" , "Compile given FILE to binary"
@ -27,7 +28,44 @@ class RubyXC < Thor
outfile = file.split("/").last.gsub(".rb" , ".o") outfile = file.split("/").last.gsub(".rb" , ".o")
writer.save outfile writer.save outfile
end
desc "interpret FILE" , "Interpret given FILE "
long_desc <<-LONGDESC
Compiles the given file to an intermediate RISC format, and runs the
Interpreter.
RISC is the last abstract layer inside the compiler. It is in nature
very close to arm (without quirks and much smaller).
An interpreter was originally developed for the RISC layer for debugging purposes.
Running the interpreter is about 50k slower than binary, but it can be used
to veryfy simple programs.
No output file will be generated, the only output is generated by the
given program.
The program must define a main method on the Space class, which will be invoked.
LONGDESC
def interpret(file)
begin
ruby = File.read(file)
rescue
fail MalformattedArgumentError , "No such file #{file}"
end
options = {
parfait: { factory: 3*1024, },
load_parfait: false ,
}
compiler = RubyX::RubyXCompiler.new(options)
linker = compiler.ruby_to_binary(ruby, :interpreter)
puts "interpreting #{file}"
interpreter = Risc::Interpreter.new(linker , STDOUT )
interpreter.start_program
interpreter.tick while(interpreter.instruction)
return outfile
end end
end end