mips_tester 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +54 -0
- data/Gemfile.lock +1 -1
- data/README.md +5 -9
- data/lib/mips_tester.rb +90 -38
- data/spec/mips_spec.rb +55 -10
- metadata +3 -3
data/.gitignore
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# Compiled source #
|
2
|
+
###################
|
3
|
+
*.com
|
4
|
+
*.class
|
5
|
+
*.dll
|
6
|
+
*.exe
|
7
|
+
*.o
|
8
|
+
*.so
|
9
|
+
|
10
|
+
# Packages #
|
11
|
+
############
|
12
|
+
# it's better to unpack these files and commit the raw source
|
13
|
+
# git has its own built in compression methods
|
14
|
+
*.7z
|
15
|
+
*.dmg
|
16
|
+
*.gz
|
17
|
+
*.iso
|
18
|
+
*.jar
|
19
|
+
*.rar
|
20
|
+
*.tar
|
21
|
+
*.zip
|
22
|
+
|
23
|
+
# Logs and databases #
|
24
|
+
######################
|
25
|
+
*.log
|
26
|
+
*.sql
|
27
|
+
*.sqlite
|
28
|
+
|
29
|
+
# OS generated files #
|
30
|
+
######################
|
31
|
+
.DS_Store?
|
32
|
+
ehthumbs.db
|
33
|
+
Icon?
|
34
|
+
Thumbs.db
|
35
|
+
|
36
|
+
coverage
|
37
|
+
rdoc
|
38
|
+
pkg
|
39
|
+
test/tmp
|
40
|
+
test/version_tmp
|
41
|
+
tmp
|
42
|
+
pkg
|
43
|
+
*.gem
|
44
|
+
*.rbc
|
45
|
+
lib/bundler/man
|
46
|
+
spec/reports
|
47
|
+
.config
|
48
|
+
InstalledFiles
|
49
|
+
.bundle
|
50
|
+
|
51
|
+
# YARD artifacts
|
52
|
+
.yardoc
|
53
|
+
_yardoc
|
54
|
+
doc/
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -19,14 +19,10 @@ It relies on MARS (it's ugly I know, but SPIM's cli doesn't work with automated
|
|
19
19
|
$> irb
|
20
20
|
$irb :001> require 'mips_tester'
|
21
21
|
$irb :002> tester = MIPSTester::MIPS.new :mars_path => "/Applications/MARS_4_1.jar"
|
22
|
-
$irb :003> tester.
|
23
|
-
$irb :004>
|
24
|
-
$irb :005>
|
25
|
-
$irb :006>
|
22
|
+
$irb :003> tester.test "test.asm" do
|
23
|
+
$irb :004> set :s0 => 0x01
|
24
|
+
$irb :005> set '0x10010004' => 45
|
25
|
+
$irb :006> expect :s0 => 0x01, :s1 => 0x45
|
26
26
|
$irb :007> verbose! # Optional verbosity!
|
27
27
|
$irb :008> end
|
28
|
-
=> true
|
29
|
-
|
30
|
-
## TO-DOs
|
31
|
-
* Ability to input memory address and expect their results
|
32
|
-
* Better failing messages
|
28
|
+
=> true
|
data/lib/mips_tester.rb
CHANGED
@@ -1,47 +1,88 @@
|
|
1
1
|
require 'tempfile' unless defined? Tempfile
|
2
|
-
require 'pp'
|
3
2
|
|
3
|
+
# Main MIPSTester module
|
4
4
|
module MIPSTester
|
5
|
-
|
5
|
+
# Library version
|
6
|
+
VERSION = "0.1.0"
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
# MIPSFileError Exception, raised when test file is not valid or non-existent
|
9
|
+
class MIPSFileError < Exception; end
|
10
|
+
|
11
|
+
# MIPSInvalidBlockError Exception, raised when no block is given to test method
|
12
|
+
class MIPSInvalidBlockError < Exception; end
|
13
|
+
|
14
|
+
# MIPSMarsError Exception, raised when MARS installation path is not valid.
|
15
|
+
class MIPSMarsError < Exception; end
|
10
16
|
|
17
|
+
# Main MIPS tester class.
|
18
|
+
# It provides the methods to test MIPS ASMs files
|
19
|
+
class MIPS
|
20
|
+
# Register validation
|
21
|
+
REGISTER_REGEX = /^(at|v[01]|a[0-3]|s[0-7]|t\d|[2-9]|1[0-9]|2[0-5])$/
|
22
|
+
|
23
|
+
# Memory address validation
|
24
|
+
ADDRESS_REGEX = /^0x[\da-f]{8}$/
|
25
|
+
|
26
|
+
# MARS jar path
|
27
|
+
attr_reader :mars_path
|
28
|
+
|
29
|
+
# Create a new MIPSTester::MIPS object
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
# MIPSTester::MIPS.new :mars_path => 'path/to/mars.jar'
|
33
|
+
#
|
34
|
+
# @return [MIPSTester::MIPS] The MIPSTester::MIPS object
|
11
35
|
def initialize(params = {})
|
12
36
|
@mars_path = params.delete(:mars_path)
|
13
|
-
raise
|
37
|
+
raise MIPSMarsError.new("Provide valid Mars jar.") if not @mars_path or not File.exists? @mars_path
|
14
38
|
end
|
15
39
|
|
16
|
-
|
17
|
-
|
18
|
-
|
40
|
+
# Run a given file in the emulator. *A provided block is mandatory*, with starter registers
|
41
|
+
# and expected values.
|
42
|
+
# A simple DSL is provided:
|
43
|
+
# * set [Hash] => set initial registers or memory addresses
|
44
|
+
# * expect [Hash] => expect values of registers or memory addresses
|
45
|
+
# * verbose! => optional, if given prints on STDOUT set registers and expected ones
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# test "file.asm" do
|
49
|
+
# set :s1 => 6, '0x10010000' => 0xFF
|
50
|
+
# expect :s5 => 6
|
51
|
+
# verbose!
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# @param file [String] The path to the file to run
|
55
|
+
# @param block The block to provide info on what to test
|
56
|
+
#
|
57
|
+
# @return [Boolean] True if the test went well, False if not.
|
58
|
+
def test(file, &block)
|
59
|
+
raise MIPSFileError.new("Provide valid file.") if not file or not File.exists? file
|
60
|
+
raise MIPSInvalidBlockError.new("Provide block.") if not block
|
19
61
|
|
20
62
|
reset!
|
21
63
|
|
22
64
|
instance_eval(&block)
|
23
65
|
|
24
66
|
asm = Tempfile.new "temp.asm"
|
25
|
-
asm.write
|
26
|
-
asm.write File.read(file)
|
67
|
+
asm.write(prep_params + File.read(file))
|
27
68
|
asm.close
|
28
69
|
|
29
|
-
cli = `#{["java -jar",
|
30
|
-
|
70
|
+
cli = `#{["java -jar",
|
71
|
+
@mars_path,
|
72
|
+
@regs.empty? ? "" : @regs.keys.join(" "),
|
73
|
+
@addresses.empty? ? "" : [@addresses.keys.min, @addresses.keys.max].join("-"),
|
74
|
+
"nc dec",
|
75
|
+
asm.path].join(" ")}`
|
76
|
+
|
31
77
|
begin
|
32
78
|
results = parse_results cli
|
33
79
|
|
34
|
-
if @verbose
|
35
|
-
puts "\nExpected:"
|
36
|
-
pp @exp
|
37
|
-
puts "\nResults:"
|
38
|
-
pp results
|
39
|
-
end
|
80
|
+
puts "Expected:\n#{@exp}\nResults:\n#{results}" if @verbose
|
40
81
|
|
41
82
|
return compare_hashes(@exp, results)
|
42
83
|
rescue Exception => ex
|
43
84
|
puts ex.message
|
44
|
-
return
|
85
|
+
return false
|
45
86
|
ensure
|
46
87
|
asm.unlink
|
47
88
|
end
|
@@ -50,39 +91,50 @@ module MIPSTester
|
|
50
91
|
private
|
51
92
|
|
52
93
|
def verbose!; @verbose = true; end
|
53
|
-
|
54
|
-
def
|
94
|
+
|
95
|
+
def set hash
|
96
|
+
hash.each_pair do |key, value|
|
97
|
+
case key
|
98
|
+
when REGISTER_REGEX then @regs.merge! key => value
|
99
|
+
when ADDRESS_REGEX then @addresses.merge! key => value
|
100
|
+
else puts "Warning: #{key} not recognized as register or memory address. Discarded."
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def expect hash; @exp.merge! hash; end
|
55
106
|
|
56
107
|
def reset!
|
57
|
-
@regs = {}; @exp = {}; @verbose = false
|
108
|
+
@regs = {}; @addresses = {}; @exp = {}; @verbose = false
|
58
109
|
end
|
59
110
|
|
60
111
|
def parse_results(results)
|
61
|
-
if results =~ /^Error/
|
62
|
-
throw Exception.new "Error in file\nReason: #{results}\n\n"
|
63
|
-
end
|
112
|
+
raise Exception.new "Error in given file!\nReason: #{results}\n\n" if results =~ /^Error/
|
64
113
|
|
65
114
|
out = {}
|
66
115
|
|
67
|
-
results.split("\n")[1..-1].
|
68
|
-
|
69
|
-
|
116
|
+
results.split("\n")[1..-1].each do |reg|
|
117
|
+
key, value = reg.strip.split("\t")
|
118
|
+
|
119
|
+
if key =~ /^Mem/
|
120
|
+
out.merge! key[4..-2] => value.to_i
|
121
|
+
else
|
122
|
+
out.merge! key[1..-1] => value.to_i
|
123
|
+
end
|
70
124
|
end
|
71
125
|
|
72
126
|
out
|
73
127
|
end
|
74
128
|
|
75
|
-
def
|
129
|
+
def prep_params
|
76
130
|
out = ""
|
77
|
-
regs.each_pair
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
out << "li\t\t$t1, 0x#{value.to_s(16)}\n"
|
83
|
-
out << "sb\t\t$t1, ($t0)\n"
|
84
|
-
end
|
131
|
+
@regs.each_pair {|key, value| out << "li\t\t$#{key}, #{value}\n" }
|
132
|
+
@addresses.each_pair do |key, value|
|
133
|
+
out << "li\t\t$t0, #{key}\n"
|
134
|
+
out << "li\t\t$t1, 0x#{value.to_s(16)}\n"
|
135
|
+
out << "sb\t\t$t1, ($t0)\n"
|
85
136
|
end
|
137
|
+
|
86
138
|
out
|
87
139
|
end
|
88
140
|
|
data/spec/mips_spec.rb
CHANGED
@@ -1,16 +1,61 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
include MIPSTester
|
2
3
|
|
3
|
-
describe
|
4
|
-
|
5
|
-
|
4
|
+
describe MIPS do
|
5
|
+
context 'passing wrong parameters' do
|
6
|
+
it 'should raise exception if not valid MARS path is given' do
|
7
|
+
expect do
|
8
|
+
MIPS.new :mars_path => '/tmp/MARS.jar'
|
9
|
+
end.to raise_error(::MIPSMarsError)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should raise exception if not valid file path is given' do
|
13
|
+
mips = MIPS.new :mars_path => "/Applications/MARS_4_1.jar"
|
14
|
+
expect do
|
15
|
+
mips.test fixture_path("non-existing.asm") {}
|
16
|
+
end.to raise_error(::MIPSFileError)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should raise exception if no block is given on test method' do
|
20
|
+
mips = MIPS.new :mars_path => "/Applications/MARS_4_1.jar"
|
21
|
+
expect do
|
22
|
+
mips.test fixture_path("empty.asm")
|
23
|
+
end.to raise_error(::MIPSInvalidBlockError)
|
24
|
+
end
|
6
25
|
end
|
7
26
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
27
|
+
|
28
|
+
context 'work on empty file' do
|
29
|
+
let :mips do
|
30
|
+
MIPS.new :mars_path => "/Applications/MARS_4_1.jar"
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should expect given register values' do
|
34
|
+
mips.test fixture_path("empty.asm") do
|
35
|
+
set :s0 => 0x0C, :s1 => 0x3F
|
36
|
+
expect :s0 => 0x0C, :s1 => 0x3F
|
37
|
+
end.should be_true
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should fail with expected results different from set results' do
|
41
|
+
mips.test fixture_path("empty.asm") do
|
42
|
+
set :s0 => 0x0D, :s1 => 0x3E
|
43
|
+
expect :s0 => 0x0C, :s1 => 0x3F
|
44
|
+
end.should be_false
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should expect given memory address values' do
|
48
|
+
mips.test fixture_path("empty.asm") do
|
49
|
+
set '0x10010000' => 45, '0x10010010' => 32, '0x10010020' => 0xFF
|
50
|
+
expect '0x10010000' => 45, '0x10010010' => 32, '0x10010020' => 0xFF
|
51
|
+
end.should be_true
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should expect mixed parameters' do
|
55
|
+
mips.test fixture_path("empty.asm") do
|
56
|
+
set '0x10010000' => 45, :s0 => 32
|
57
|
+
expect '0x10010000' => 45, :s0 => 32
|
58
|
+
end.should be_true
|
59
|
+
end
|
15
60
|
end
|
16
61
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: mips_tester
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0
|
5
|
+
version: 0.1.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Federico Ravasio
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-04-
|
13
|
+
date: 2011-04-25 00:00:00 +02:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -34,13 +34,13 @@ extensions: []
|
|
34
34
|
extra_rdoc_files: []
|
35
35
|
|
36
36
|
files:
|
37
|
+
- .gitignore
|
37
38
|
- Gemfile
|
38
39
|
- Gemfile.lock
|
39
40
|
- LICENSE
|
40
41
|
- README.md
|
41
42
|
- Rakefile
|
42
43
|
- lib/mips_tester.rb
|
43
|
-
- mips_tester-0.0.1.gem
|
44
44
|
- mips_tester.gemspec
|
45
45
|
- spec/fixtures/empty.asm
|
46
46
|
- spec/mips_spec.rb
|