require_relative '../helper' require "register/interpreter" require "rye" Rye::Cmd.add_command :ld, '/usr/bin/ld' Rye::Cmd.add_command :aout, './a.out' # machinery to run a soml program in 2 ways # - first by running it through the interpreter # - second by assembling to arm , pushing the binary to a remote machine and executing it there # # The second obviously takes a fair bit of time so it's only done when an REMOTE_PI is set # REMOTE_PI has to be set to user@machine:port or it will default to an emulator # the minimum is REMOTE_PI=username , and off course ssh keys have to be set up # btw can't test with ruby on a PI as code creation only works on 64bit # that's because ruby nibbles 2 bits from a word, and soml code doesn't work around that module RuntimeTests def setup @stdout = "" @machine = Register.machine.boot Soml::Compiler.load_parfait end def check ret = nil @machine.parse_and_compile main() @machine.collect @interpreter = Register::Interpreter.new @interpreter.start @machine.init count = 0 begin count += 1 #puts interpreter.instruction @interpreter.tick end while( ! @interpreter.instruction.nil?) assert_equal @stdout , @interpreter.stdout , "stdout wrong locally" if ret assert_equal Parfait::Message , @interpreter.get_register(:r0).class assert_equal ret , @interpreter.get_register(:r0).return_value , "exit wrong #{@string_input}" end check_remote ret end def connected return false if ENV["REMOTE_PI"].nil? or (ENV["REMOTE_PI"] == "") return @@conn if defined?(@@conn) puts "remote " + ENV["REMOTE_PI"] user , rest = ENV["REMOTE_PI"].split("@") machine , port = rest.to_s.split(":") @@conn = Rye::Box.new(machine || "localhost" , :port => (port || 2222) , :user => (user || "pi")) end def check_remote ret return unless box = connected file = write_object_file r_file = file.sub("./" , "salama/") box.file_upload file , r_file box.ld "-N", r_file begin #need to rescue here as rye throws if no return 0 ret = box.aout # and we use return to mean something rescue Rye::Err => e # so it's basically never 0 ret = e.rap end assert_equal @stdout , ret.stdout.join , "remote std was #{ret.stdout}" if @stdout assert_equal "" , ret.stderr.join , "remote had error" if ret and ret.is_a?(Numeric) should = @interpreter.get_register(:r0).return_value should &= 0xFF # don't knwo why exit codes are restricted but there you are assert_equal should , ret.exit_status.to_i , "remote exit failed for #{@string_input}" end end def write_object_file file_name = caller(4).first.split("in ").last.chop.sub("`","") return if file_name.include?("run") file_name = "./tmp/" + file_name + ".o" Register.machine.translate_arm writer = Elf::ObjectWriter.new writer.save file_name file_name end def check_return val check val end def check_return_class val check assert_equal val , @interpreter.get_register(:r0).return_value.class end end