2015-11-18 12:04:57 +01:00
|
|
|
require_relative '../helper'
|
|
|
|
require "register/interpreter"
|
|
|
|
require "rye"
|
|
|
|
Rye::Cmd.add_command :ld, '/usr/bin/ld'
|
|
|
|
Rye::Cmd.add_command :aout, './a.out'
|
|
|
|
|
2016-12-11 11:55:03 +01:00
|
|
|
# machinery to run a typed program in 2 ways
|
2015-11-18 12:04:57 +01:00
|
|
|
# - first by running it through the interpreter
|
|
|
|
# - second by assembling to arm , pushing the binary to a remote machine and executing it there
|
|
|
|
#
|
2015-11-18 12:42:07 +01:00
|
|
|
# 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
|
2015-11-18 12:04:57 +01:00
|
|
|
|
2015-11-18 12:27:20 +01:00
|
|
|
# btw can't test with ruby on a PI as code creation only works on 64bit
|
2016-12-11 11:55:03 +01:00
|
|
|
# that's because ruby nibbles 2 bits from a word, and typed code doesn't work around that
|
2015-11-18 12:04:57 +01:00
|
|
|
module RuntimeTests
|
|
|
|
|
|
|
|
def setup
|
|
|
|
@stdout = ""
|
2015-11-20 12:27:31 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def load_program
|
2015-11-18 12:04:57 +01:00
|
|
|
@machine = Register.machine.boot
|
2015-11-20 12:27:31 +01:00
|
|
|
@machine.parse_and_compile main()
|
|
|
|
@machine.collect
|
2015-11-18 12:04:57 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check ret = nil
|
2015-11-21 13:19:07 +01:00
|
|
|
i = check_local
|
2015-11-21 15:33:43 +01:00
|
|
|
check_r ret
|
2015-11-21 13:19:07 +01:00
|
|
|
i
|
|
|
|
end
|
|
|
|
|
|
|
|
def check_local ret = nil
|
|
|
|
load_program
|
2015-11-20 12:27:31 +01:00
|
|
|
interpreter = Register::Interpreter.new
|
|
|
|
interpreter.start @machine.init
|
2015-11-18 12:04:57 +01:00
|
|
|
count = 0
|
|
|
|
begin
|
|
|
|
count += 1
|
|
|
|
#puts interpreter.instruction
|
2015-11-20 12:27:31 +01:00
|
|
|
interpreter.tick
|
|
|
|
end while( ! interpreter.instruction.nil?)
|
|
|
|
assert_equal @stdout , interpreter.stdout , "stdout wrong locally"
|
2015-11-18 12:04:57 +01:00
|
|
|
if ret
|
2015-11-20 12:27:31 +01:00
|
|
|
assert_equal Parfait::Message , interpreter.get_register(:r0).class
|
|
|
|
assert_equal ret , interpreter.get_register(:r0).return_value , "exit wrong #{@string_input}"
|
2015-11-18 12:04:57 +01:00
|
|
|
end
|
2015-11-20 13:37:26 +01:00
|
|
|
interpreter
|
2015-11-18 12:04:57 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def connected
|
2015-11-18 12:50:38 +01:00
|
|
|
return false if ENV["REMOTE_PI"].nil? or (ENV["REMOTE_PI"] == "")
|
2015-11-18 14:18:56 +01:00
|
|
|
return @@conn if defined?(@@conn)
|
2015-11-18 12:50:38 +01:00
|
|
|
puts "remote " + ENV["REMOTE_PI"]
|
2015-11-18 12:42:07 +01:00
|
|
|
user , rest = ENV["REMOTE_PI"].split("@")
|
2015-11-18 12:17:49 +01:00
|
|
|
machine , port = rest.to_s.split(":")
|
2015-11-30 15:09:55 +01:00
|
|
|
make_box machine , port , user
|
|
|
|
end
|
2016-12-08 19:13:08 +01:00
|
|
|
|
2015-11-30 15:09:55 +01:00
|
|
|
def make_box machine = nil , port = nil , user = nil
|
2015-11-18 12:17:49 +01:00
|
|
|
@@conn = Rye::Box.new(machine || "localhost" , :port => (port || 2222) , :user => (user || "pi"))
|
2015-11-18 12:04:57 +01:00
|
|
|
end
|
|
|
|
|
2015-11-21 15:33:43 +01:00
|
|
|
def check_r ret_val , dont_run = false
|
2015-11-18 12:04:57 +01:00
|
|
|
return unless box = connected
|
2015-11-20 12:27:31 +01:00
|
|
|
load_program
|
2015-11-18 12:04:57 +01:00
|
|
|
file = write_object_file
|
|
|
|
r_file = file.sub("./" , "salama/")
|
|
|
|
box.file_upload file , r_file
|
2015-11-20 22:51:58 +01:00
|
|
|
print "\nfile #{file} "
|
2015-11-21 15:33:43 +01:00
|
|
|
return if dont_run
|
2015-11-18 12:04:57 +01:00
|
|
|
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"
|
2015-11-20 12:27:31 +01:00
|
|
|
if ret_val
|
|
|
|
ret_val &= 0xFF # don't knwo why exit codes are restricted but there you are
|
|
|
|
assert_equal ret_val , ret.exit_status.to_i , "remote exit failed for #{@string_input}"
|
2015-11-18 12:04:57 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def write_object_file
|
2015-11-20 12:27:31 +01:00
|
|
|
file_name = caller(3).first.split("in ").last.chop.sub("`","")
|
2015-11-18 12:04:57 +01:00
|
|
|
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
|
|
|
|
|
|
|
|
end
|