rips 0.0.8 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +52 -3
- data/bin/rips +3 -1
- data/examples/calc.rips +55 -0
- data/{example.rips → examples/example.rips} +0 -0
- data/lib/rips.rb +54 -25
- data/lib/rips/assembler.rb +98 -113
- data/lib/rips/error.rb +3 -2
- data/lib/rips/formats/format.rb +0 -4
- data/lib/rips/instructions/instruction.rb +18 -9
- data/lib/rips/utils.rb +4 -18
- data/lib/rips/utils/array.rb +12 -0
- data/lib/rips/utils/integer.rb +15 -0
- data/lib/rips/utils/string_assembler.rb +62 -0
- data/lib/rips/utils/string_variable.rb +41 -0
- data/lib/rips/variables/address.rb +4 -9
- data/lib/rips/variables/inmediate.rb +3 -8
- data/lib/rips/variables/port.rb +3 -9
- data/lib/rips/variables/register.rb +3 -8
- data/lib/rips/variables/variable.rb +4 -26
- data/lib/rips/version.rb +1 -1
- data/rips.gemspec +1 -1
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fff3963bd941c448681cc84b7866aef618c72d9
|
4
|
+
data.tar.gz: 1f77e7972c43bcc523a10f749b4cfc7c3bc04d67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0bb9c555874d3bdfac873b7cec8add0b1f05007684f5406158420cb76e2ca84352b3d2f2c258faadfc466b62a09d18c31173b65c75a9970fe427b182b1040b2
|
7
|
+
data.tar.gz: febd89dee2a4629452838ade172abde29357d6c1f14bad915cdcc9dcaccd15ea92452ff617f3c2d11ffef5ab8aaf37a655454ea21b77a5063310bab2183f525e
|
data/README.md
CHANGED
@@ -1,14 +1,63 @@
|
|
1
1
|
# Rips
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/rips.svg)](http://badge.fury.io/rb/rips)
|
3
|
+
[![Dependency Status](https://gemnasium.com/Madh93/rips.svg)](https://gemnasium.com/Madh93/rips)
|
2
4
|
|
3
|
-
Simple assembler written in Ruby for a simple 16-bit CPU written in Verilog.
|
5
|
+
Simple assembler written in Ruby for a simple 16-bit CPU written in Verilog. Based in MIPS syntax with next features:
|
6
|
+
|
7
|
+
- 18 basic instructions
|
8
|
+
- 16 registers ($0-$15)
|
9
|
+
- 4 I/O ports (@0-@3)
|
10
|
+
- Support labels
|
11
|
+
- Support comments
|
12
|
+
|
13
|
+
## Requirements
|
14
|
+
|
15
|
+
Ruby >=1.9.3
|
4
16
|
|
5
17
|
## Installation
|
6
18
|
|
7
19
|
$ gem install rips
|
20
|
+
|
21
|
+
or download from [RubyGems](https://rubygems.org/gems/rips).
|
22
|
+
|
23
|
+
**Optional:** [Rips syntax highlightning package for sublime text 2/3](https://github.com/Madh93/rips-syntax/)
|
8
24
|
|
9
25
|
## Usage
|
10
26
|
|
11
|
-
$ rips instructions.rips
|
27
|
+
$ rips [OPTIONS] instructions.rips
|
28
|
+
|
29
|
+
Examples:
|
30
|
+
|
31
|
+
$ rips --debug instructions.rips
|
32
|
+
$ rips -d instructions.rips -o instructions
|
33
|
+
|
34
|
+
## Options
|
35
|
+
|
36
|
+
-d, --debug Show trace in console
|
37
|
+
-o FILE Output file with binary instructions (by default: progfile.dat)
|
38
|
+
|
39
|
+
## Instruction Set
|
40
|
+
|
41
|
+
| Name | MNENOMIC | FORMAT | OPERATION | OPCODE |
|
42
|
+
|--------------------|----------|--------|----------------|--------|
|
43
|
+
| Move | move | C | move $1, $0 | 0000 |
|
44
|
+
| Not | not | C | not $1, $0 | 0001 |
|
45
|
+
| Add | add | D | add $2, $0, $1 | 0010 |
|
46
|
+
| Subtract | sub | D | sub $2, $0, $1 | 0011 |
|
47
|
+
| And | and | D | and $2, $0, $1 | 0100 |
|
48
|
+
| Or | or | D | or $2, $0, $1 | 0101 |
|
49
|
+
| Sign negation | neg | C | neg $1, $0 | 0110 |
|
50
|
+
| Jump | j | B | j label | 1001 |
|
51
|
+
| Load Inmediate | li | C | li $0, 10 | 1010 |
|
52
|
+
| Load from I/O | lesr | C | lesr $0, @0 | 1011 |
|
53
|
+
| Store I/O from Reg | sesr | C | sesr @0, $0 | 1101 |
|
54
|
+
| Store I/O from Mem | sesm | C | sesm @0, 10 | 1110 |
|
55
|
+
| Relative Jump | ji | B | ji 10 | 011000 |
|
56
|
+
| Jump and Link | jal | B | jal label | 101000 |
|
57
|
+
| Jump Register | jr | A | jr | 111000 |
|
58
|
+
| Branch z!=0 | bnez | B | bnez label | 001111 |
|
59
|
+
| Branch z==0 | beqz | B | beqz label | 011111 |
|
60
|
+
| No Operation | nop | A | nop | 111111 |
|
12
61
|
|
13
62
|
## Contributing
|
14
63
|
|
@@ -16,4 +65,4 @@ Simple assembler written in Ruby for a simple 16-bit CPU written in Verilog.
|
|
16
65
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
17
66
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
18
67
|
4. Push to the branch (`git push origin my-new-feature`)
|
19
|
-
5. Create a new Pull Request
|
68
|
+
5. Create a new Pull Request
|
data/bin/rips
CHANGED
data/examples/calc.rips
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#### Simple calculator ###
|
2
|
+
|
3
|
+
# Assign opcodes to add, sub and mul
|
4
|
+
define:
|
5
|
+
li $5, 8 # add (1000)
|
6
|
+
li $6, 4 # sub (0100)
|
7
|
+
li $7, 2 # mul(0010)
|
8
|
+
|
9
|
+
main:
|
10
|
+
|
11
|
+
# Load from I/O to registers
|
12
|
+
lesr $1, @0
|
13
|
+
lesr $2, @1
|
14
|
+
lesr $3, @2
|
15
|
+
|
16
|
+
# Check input is add, sub or mul
|
17
|
+
sub $4, $3, $5
|
18
|
+
beqz op_add
|
19
|
+
|
20
|
+
sub $4, $3, $6
|
21
|
+
beqz op_sub
|
22
|
+
|
23
|
+
sub $4, $3, $7
|
24
|
+
beqz op_mul
|
25
|
+
|
26
|
+
j main # Infinite loop
|
27
|
+
|
28
|
+
op_add:
|
29
|
+
|
30
|
+
add $4, $1, $2
|
31
|
+
j store
|
32
|
+
|
33
|
+
op_sub:
|
34
|
+
|
35
|
+
sub $4, $1, $2
|
36
|
+
j store
|
37
|
+
|
38
|
+
op_mul:
|
39
|
+
|
40
|
+
li $8, 1 # Count
|
41
|
+
move $4, $0
|
42
|
+
add $1, $1, $0 # IF $1==0 -> finish loop
|
43
|
+
beqz store
|
44
|
+
|
45
|
+
loop:
|
46
|
+
|
47
|
+
add $4, $4, $2 # Repeat $1 times
|
48
|
+
sub $1, $1, $8
|
49
|
+
bnez loop
|
50
|
+
|
51
|
+
store:
|
52
|
+
|
53
|
+
# Store in I/O from register
|
54
|
+
sesr @0, $4
|
55
|
+
j main
|
File without changes
|
data/lib/rips.rb
CHANGED
@@ -3,34 +3,63 @@ require "rips/assembler"
|
|
3
3
|
require "rips/error"
|
4
4
|
|
5
5
|
module Rips
|
6
|
+
class RipsLauncher
|
6
7
|
|
7
|
-
|
8
|
+
# @argv: input's arguments
|
9
|
+
# @debug: switch to show trace in console
|
10
|
+
# @source: source file with Rips instructions
|
11
|
+
# @output: output file with binary instructions
|
12
|
+
def initialize
|
13
|
+
@argv = ARGV
|
14
|
+
@debug = debug_mode?
|
15
|
+
@source = source_file
|
16
|
+
@output = output_file
|
8
17
|
|
9
|
-
|
10
|
-
|
11
|
-
debug = true
|
12
|
-
ARGV.delete("-d")
|
13
|
-
elsif ARGV.include?("--debug")
|
14
|
-
debug = true
|
15
|
-
ARGV.delete("--debug")
|
16
|
-
end
|
17
|
-
|
18
|
-
Error::message(1) if ARGV.empty?
|
19
|
-
|
20
|
-
# Check for a valid file
|
21
|
-
if !File.exist? ARGV[0]
|
22
|
-
Error::message(2)
|
23
|
-
elsif !File.readable? ARGV[0]
|
24
|
-
Error::message(3)
|
25
|
-
end
|
18
|
+
run
|
19
|
+
end
|
26
20
|
|
27
|
-
|
21
|
+
private
|
28
22
|
|
29
|
-
|
30
|
-
|
31
|
-
|
23
|
+
# Check debug mode
|
24
|
+
def debug_mode?
|
25
|
+
@argv.include?("-d") || @argv.include?("--debug")
|
32
26
|
end
|
33
|
-
end
|
34
27
|
|
35
|
-
|
36
|
-
|
28
|
+
# Check if it's a valid input file
|
29
|
+
def source_file
|
30
|
+
source = @argv.find{|x| /\.rips$/ =~ x }
|
31
|
+
Error::message(1) if source.nil?
|
32
|
+
Error::message(2) if !File.exist?(source)
|
33
|
+
Error::message(3) if !File.readable?(source)
|
34
|
+
return source
|
35
|
+
end
|
36
|
+
|
37
|
+
# Check cmdline options (now only output)
|
38
|
+
def output_file
|
39
|
+
if @argv.include?("-o")
|
40
|
+
out = @argv[(@argv.index("-o"))+1]
|
41
|
+
Error::message(9) if out.nil? || out == @source || out == "-d" || out == "--debug"
|
42
|
+
return out
|
43
|
+
else
|
44
|
+
return "progfile.dat"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Read input file
|
49
|
+
def read
|
50
|
+
File.open(@source, "r") do |f|
|
51
|
+
f.each_line do |line|
|
52
|
+
@rips << line
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Launch Rips assembler
|
58
|
+
def run
|
59
|
+
@rips = Assembler.new(@debug)
|
60
|
+
read
|
61
|
+
@rips.run(@output)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
data/lib/rips/assembler.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
require "rips/instructions"
|
2
2
|
|
3
|
+
class String
|
4
|
+
include Rips::Utils::StringAssemblerExtension
|
5
|
+
end
|
6
|
+
|
7
|
+
class Array
|
8
|
+
include Rips::Utils::ArrayExtension
|
9
|
+
end
|
10
|
+
|
3
11
|
module Rips
|
4
12
|
class Assembler
|
5
13
|
|
@@ -22,120 +30,62 @@ module Rips
|
|
22
30
|
@line = 1
|
23
31
|
end
|
24
32
|
|
25
|
-
|
26
|
-
def find_labels
|
27
|
-
|
28
|
-
@input.each_with_index do |line, i|
|
29
|
-
if !line.empty?
|
30
|
-
label = line.scan(/\w+:/)
|
31
|
-
if (label.size == 1)
|
32
|
-
|
33
|
-
if !@labels.include?(label[0].to_s.split(":").first)
|
34
|
-
@labels[label[0].to_s.split(":").first] = [*@instructions.each_with_index].bsearch{|x, _| x >= i}.last
|
35
|
-
else
|
36
|
-
Error::message(7, i+1, label[0].to_s.split(":").first)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
33
|
+
private
|
42
34
|
|
43
35
|
# Store number line for each instruction
|
44
36
|
def find_instructions
|
45
|
-
|
46
37
|
@input.each_with_index do |line,i|
|
47
|
-
if
|
38
|
+
if line.instruction?
|
48
39
|
@instructions << i+1
|
49
40
|
end
|
50
41
|
end
|
51
42
|
end
|
52
43
|
|
53
|
-
#
|
54
|
-
def
|
55
|
-
@input
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
find_labels
|
63
|
-
|
64
|
-
@input.each do |line|
|
65
|
-
|
66
|
-
# If line is empty -> next line
|
67
|
-
# Or if not is a label
|
68
|
-
if (!line.empty?) && (line.scan(/\w+:/).empty?)
|
69
|
-
|
70
|
-
parse_input(line)
|
71
|
-
@instruction = nil
|
72
|
-
|
73
|
-
# If it's a comment -> show but not work with it
|
74
|
-
if line[0] != "#"
|
75
|
-
|
76
|
-
exists_instruction
|
77
|
-
@instruction = get_instruction
|
78
|
-
|
79
|
-
parse_label
|
80
|
-
|
81
|
-
argument_size
|
82
|
-
argument_syntax
|
83
|
-
|
84
|
-
@instruction.set_arguments(@cmd[:arguments])
|
85
|
-
@output << @instruction.code
|
44
|
+
# Store labels and number line
|
45
|
+
def find_labels
|
46
|
+
@input.each_with_index do |line, i|
|
47
|
+
if line.label?(i)
|
48
|
+
label = line.split(":")[0]
|
49
|
+
if !@labels.include?(label)
|
50
|
+
@labels[label] = [*@instructions.each_with_index].search{|x, _| x >= i}.last
|
51
|
+
else
|
52
|
+
Error::message(7, i+1, line)
|
86
53
|
end
|
87
|
-
|
88
|
-
end
|
89
|
-
@line += 1
|
90
|
-
end
|
91
|
-
|
92
|
-
generate
|
93
|
-
end
|
94
|
-
|
95
|
-
# Codification log of instruction
|
96
|
-
def show
|
97
|
-
|
98
|
-
# If line was a comment -> @instruction should be nil
|
99
|
-
if @instruction.nil?
|
100
|
-
codification = ""
|
101
|
-
else
|
102
|
-
codification = @instruction.code.scan(/.{4}|.+/).join("_")
|
54
|
+
end
|
103
55
|
end
|
104
|
-
|
105
|
-
puts "@#{@line}:" \
|
106
|
-
"\t#{codification}" \
|
107
|
-
"\t#{@cmd[:comments]}"
|
108
56
|
end
|
109
57
|
|
110
|
-
# Generate output in "progfile.dat"
|
111
|
-
def generate
|
112
|
-
File.open("progfile.dat", "w") do |f|
|
113
|
-
@output.each do |line|
|
114
|
-
f.puts line
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
58
|
# Split on tokens
|
120
59
|
def parse_input (line)
|
121
60
|
|
122
|
-
if line
|
61
|
+
if line.comment?
|
123
62
|
@cmd[:comments] = line
|
124
63
|
else
|
125
|
-
@cmd[:name] = line.
|
126
|
-
@cmd[:
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
if @cmd[:arguments].first == "jr" ||
|
131
|
-
@cmd[:arguments].first == "nop"
|
132
|
-
@cmd[:arguments] = []
|
64
|
+
@cmd[:name] = line.instruction_name
|
65
|
+
if (@cmd[:name] == "jr ") || (@cmd[:name] == "nop ")
|
66
|
+
@cmd[:arguments] = []
|
67
|
+
else
|
68
|
+
@cmd[:arguments] = line.instruction_arguments(@cmd[:name])
|
133
69
|
end
|
134
|
-
@cmd[:comments] = line.
|
70
|
+
@cmd[:comments] = line.instruction_comments
|
135
71
|
@cmd[:comments].insert(0,"#") if !@cmd[:comments].empty?
|
136
72
|
end
|
137
73
|
end
|
138
74
|
|
75
|
+
# Obtain instruction's instance object
|
76
|
+
def get_instruction
|
77
|
+
Rips::Instructions.const_get("#{@cmd[:name].capitalize}").new
|
78
|
+
end
|
79
|
+
|
80
|
+
# Exists instruction in Instruction Set?
|
81
|
+
def exists_instruction?
|
82
|
+
if Instructions::SET.include? (@cmd[:name])
|
83
|
+
@instruction = get_instruction
|
84
|
+
else
|
85
|
+
Error::message(4, @line, @cmd[:name] )
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
139
89
|
# Translate label's name to instruction's number
|
140
90
|
def parse_label
|
141
91
|
if (@instruction.is_a? Rips::Instructions::Beqz) ||
|
@@ -146,23 +96,9 @@ module Rips
|
|
146
96
|
@cmd[:arguments] = [@labels[@cmd[:arguments].first].to_s]
|
147
97
|
end
|
148
98
|
end
|
149
|
-
|
150
|
-
# Obtain instruction's instance object
|
151
|
-
def get_instruction
|
152
|
-
Object.const_get("Rips::Instructions::#{@cmd[:name].capitalize}").new
|
153
|
-
end
|
154
|
-
|
155
|
-
# Exists instruction in Instruction Set?
|
156
|
-
def exists_instruction
|
157
|
-
if !Instructions::SET.include? (@cmd[:name])
|
158
|
-
Error::message( 4,
|
159
|
-
@line,
|
160
|
-
@cmd[:name] )
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
99
|
+
|
164
100
|
# Check number of arguments given with expected by instruction
|
165
|
-
def argument_size
|
101
|
+
def argument_size?
|
166
102
|
if @cmd[:arguments].size != @instruction.args_number
|
167
103
|
Error::message( 5,
|
168
104
|
@line,
|
@@ -173,16 +109,65 @@ module Rips
|
|
173
109
|
end
|
174
110
|
|
175
111
|
# Check if arguments are the same variable type of instruction
|
176
|
-
def argument_syntax
|
112
|
+
def argument_syntax?
|
177
113
|
@instruction.variables.each_with_index do |var,i|
|
178
|
-
if var.
|
179
|
-
@cmd[:arguments][i] =
|
114
|
+
if var.valid_syntax? @cmd[:arguments][i]
|
115
|
+
@cmd[:arguments][i] = @cmd[:arguments][i].arg_to_i
|
180
116
|
else
|
181
|
-
Error::message(
|
182
|
-
@line,
|
183
|
-
var.error(@cmd[:arguments][i]) )
|
117
|
+
Error::message(6, @line, var.error(@cmd[:arguments][i]) )
|
184
118
|
end
|
185
119
|
end
|
186
120
|
end
|
121
|
+
|
122
|
+
# Codification log of instruction
|
123
|
+
def show (i)
|
124
|
+
puts "@#{@line}:" \
|
125
|
+
"\t#{@output[i].scan(/.{4}|.+/).join("_") unless @instruction.nil?}" \
|
126
|
+
"\t#{@cmd[:comments]}"
|
127
|
+
end
|
128
|
+
|
129
|
+
# Generate output in "progfile.dat"
|
130
|
+
def generate (path)
|
131
|
+
File.open(path, "w") do |f|
|
132
|
+
@output.each do |line|
|
133
|
+
f.puts line
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
public
|
139
|
+
|
140
|
+
# Stores each new line of file
|
141
|
+
def << (value)
|
142
|
+
@input << value.strip
|
143
|
+
end
|
144
|
+
|
145
|
+
# Analyze and translate each instruction
|
146
|
+
def run (path = "progfile.dat")
|
147
|
+
find_instructions
|
148
|
+
find_labels
|
149
|
+
|
150
|
+
@input.each do |line|
|
151
|
+
if (line.instruction?) || (line.comment?)
|
152
|
+
parse_input(line)
|
153
|
+
@instruction = nil
|
154
|
+
# If it's a comment -> show but not work with it
|
155
|
+
if line.instruction?
|
156
|
+
|
157
|
+
exists_instruction?
|
158
|
+
parse_label
|
159
|
+
argument_size?
|
160
|
+
argument_syntax?
|
161
|
+
|
162
|
+
@instruction.set_arguments(@cmd[:arguments])
|
163
|
+
@output << @instruction.code
|
164
|
+
end
|
165
|
+
show(@output.size-1) if @debug
|
166
|
+
end
|
167
|
+
@line += 1
|
168
|
+
end
|
169
|
+
generate(path)
|
170
|
+
end
|
171
|
+
|
187
172
|
end
|
188
173
|
end
|
data/lib/rips/error.rb
CHANGED
@@ -3,14 +3,15 @@ module Rips
|
|
3
3
|
|
4
4
|
MESSAGES =
|
5
5
|
[ "RIPS ERROR (0). Unknown problem.",
|
6
|
-
"RIPS ERROR (1).
|
6
|
+
"RIPS ERROR (1). Invalid input file (try `rips file.rips`).",
|
7
7
|
"RIPS ERROR (2). Doesn't exist file or directory.",
|
8
8
|
"RIPS ERROR (3). Permission denied to read file.",
|
9
9
|
"RIPS ERROR (4). In line %d: doesn't exist `%s` instruction in Instruction Set.",
|
10
10
|
"RIPS ERROR (5). In line %d: for `%s` instruction wrong number of arguments (%d for %d).",
|
11
11
|
"RIPS ERROR (6). In line %d: syntax error, %s.",
|
12
12
|
"RIPS ERROR (7). In line %d: There is already a label called `%s`.",
|
13
|
-
"RIPS ERROR (8). In line %d: Unknown syntax for label `%s` (try `labelname:`)."
|
13
|
+
"RIPS ERROR (8). In line %d: Unknown syntax for label `%s` (try `labelname:`).",
|
14
|
+
"RIPS ERROR (9). Invalid output file." ]
|
14
15
|
|
15
16
|
def self.message (num, *args)
|
16
17
|
puts MESSAGES[num] % args
|
data/lib/rips/formats/format.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
require "rips/instructions/set"
|
2
2
|
require "rips/formats"
|
3
3
|
require "rips/variables"
|
4
|
+
require "rips/utils"
|
5
|
+
|
6
|
+
class Integer
|
7
|
+
include Rips::Utils::IntegerExtension
|
8
|
+
end
|
4
9
|
|
5
10
|
module Rips
|
6
11
|
module Instructions
|
@@ -16,15 +21,7 @@ module Rips
|
|
16
21
|
@output = []
|
17
22
|
end
|
18
23
|
|
19
|
-
|
20
|
-
def args_number
|
21
|
-
@format.args_number
|
22
|
-
end
|
23
|
-
|
24
|
-
# Pass all arguments at once
|
25
|
-
def set_arguments (args)
|
26
|
-
@format.set_arguments(args)
|
27
|
-
end
|
24
|
+
private
|
28
25
|
|
29
26
|
# Add blanks (0 values) for instructions with free space
|
30
27
|
def add_blank
|
@@ -37,6 +34,18 @@ module Rips
|
|
37
34
|
end
|
38
35
|
end
|
39
36
|
|
37
|
+
public
|
38
|
+
|
39
|
+
# Return number of arguments
|
40
|
+
def args_number
|
41
|
+
@format.args_number
|
42
|
+
end
|
43
|
+
|
44
|
+
# Pass all arguments at once
|
45
|
+
def set_arguments (args)
|
46
|
+
@format.set_arguments(args)
|
47
|
+
end
|
48
|
+
|
40
49
|
# Coding to Machine Code
|
41
50
|
def code
|
42
51
|
|
data/lib/rips/utils.rb
CHANGED
@@ -1,18 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
else
|
6
|
-
'%0*b' % [width, self]
|
7
|
-
end
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
class String
|
12
|
-
def del(regexp)
|
13
|
-
gsub(regexp,'')
|
14
|
-
end
|
15
|
-
def del!(regexp)
|
16
|
-
gsub!(regexp,'')
|
17
|
-
end
|
18
|
-
end
|
1
|
+
require "rips/utils/array"
|
2
|
+
require "rips/utils/integer"
|
3
|
+
require "rips/utils/string_variable"
|
4
|
+
require "rips/utils/string_assembler"
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require "rips/error"
|
2
|
+
|
3
|
+
module Rips
|
4
|
+
module Utils
|
5
|
+
module StringAssemblerExtension
|
6
|
+
|
7
|
+
# Delete spaces and tabs
|
8
|
+
def del(regexp)
|
9
|
+
gsub(regexp,'')
|
10
|
+
end
|
11
|
+
|
12
|
+
# Delete spaces and tabs
|
13
|
+
def del!(regexp)
|
14
|
+
gsub!(regexp,'')
|
15
|
+
end
|
16
|
+
|
17
|
+
# Return integer part of arguments of an instruction
|
18
|
+
def arg_to_i
|
19
|
+
(/\A[-]?\d+\z/ === self) ? self.to_i : self.slice(1..-1).to_i
|
20
|
+
end
|
21
|
+
|
22
|
+
# Check if string is a comment
|
23
|
+
def comment?
|
24
|
+
self[0] == "#"
|
25
|
+
end
|
26
|
+
|
27
|
+
# Check if string is a label
|
28
|
+
def label?(line)
|
29
|
+
if (!self.empty?) && (self[0] != "#") && (self[-1] == ":")
|
30
|
+
label = self.scan(/\w+:/)
|
31
|
+
if (label.size == 1)
|
32
|
+
return true
|
33
|
+
elsif (label.size > 1)
|
34
|
+
Error::message(8, line+1, self)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Check if string is a instruction
|
40
|
+
def instruction?
|
41
|
+
(!self.empty?) && (self[0] != "#") && (self.scan(/\w+:/).empty?)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Get intruction's name of string
|
45
|
+
def instruction_name
|
46
|
+
self.split("#").first.split(" ").first.downcase
|
47
|
+
end
|
48
|
+
|
49
|
+
# Get intruction's arguments of string
|
50
|
+
def instruction_arguments(instruction)
|
51
|
+
args = self.split("#").first.split("#{instruction} ")
|
52
|
+
args.pop.split("#").first.del(/\s+|\t+/).split(",") unless args.empty?
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get intruction's comments of string
|
56
|
+
def instruction_comments
|
57
|
+
self.split("#").slice(1..-1).join
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Rips
|
2
|
+
module Utils
|
3
|
+
module StringVariableExtension
|
4
|
+
|
5
|
+
# Check if value is a valid number (...,-1,0,1...)
|
6
|
+
def number? (value)
|
7
|
+
/\A[-]?\d+\z/ === value
|
8
|
+
end
|
9
|
+
|
10
|
+
# Check if value is between in permitted range
|
11
|
+
def valid_range? (range)
|
12
|
+
if number?(self.slice(1..-1))
|
13
|
+
self.to_i.between?(range[0], range[1])
|
14
|
+
else
|
15
|
+
self.slice(1..-1).to_i.between?(range[0], range[1])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Check if value is a valid inmediate (...,-1,0,1...)
|
20
|
+
def inmediate?
|
21
|
+
number?(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Check if value is a register ($0..15)
|
25
|
+
def register?
|
26
|
+
(self[0] == "$") && number?(self.slice(1..-1))
|
27
|
+
end
|
28
|
+
|
29
|
+
# Check if value is a port (@0..3)
|
30
|
+
def port?
|
31
|
+
(self[0] == "@") && number?(self.slice(1..-1))
|
32
|
+
end
|
33
|
+
|
34
|
+
# Check if value is an address (0..127 | label)
|
35
|
+
def address? (range)
|
36
|
+
(self.is_a?(String)) || (number?(self.slice(1..-1)) && valid_range?(range))
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -16,16 +16,11 @@ module Rips
|
|
16
16
|
end
|
17
17
|
|
18
18
|
# Check input variable syntax
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
true
|
23
|
-
elsif value.is_a?(String)
|
24
|
-
true
|
25
|
-
else
|
26
|
-
false
|
27
|
-
end
|
19
|
+
def valid_syntax? (value)
|
20
|
+
value.extend(Rips::Utils::StringVariableExtension)
|
21
|
+
value.address?(@range)
|
28
22
|
end
|
23
|
+
|
29
24
|
end
|
30
25
|
end
|
31
26
|
end
|
@@ -16,14 +16,9 @@ module Rips
|
|
16
16
|
end
|
17
17
|
|
18
18
|
# Check input variable syntax
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
if number?(value) && between?(value, @range)
|
23
|
-
true
|
24
|
-
else
|
25
|
-
false
|
26
|
-
end
|
19
|
+
def valid_syntax? (value)
|
20
|
+
value.extend(Rips::Utils::StringVariableExtension)
|
21
|
+
value.inmediate? && value.valid_range?(@range)
|
27
22
|
end
|
28
23
|
|
29
24
|
end
|
data/lib/rips/variables/port.rb
CHANGED
@@ -11,20 +11,14 @@ module Rips
|
|
11
11
|
# @range: bit's range for variable
|
12
12
|
def initialize(size = 2)
|
13
13
|
super(size)
|
14
|
-
@syntax = "@0-3"
|
15
14
|
@range = [0, 2**@length-1]
|
16
15
|
@syntax = "@#{@range[0]}-#{@range[1]}"
|
17
16
|
end
|
18
17
|
|
19
18
|
# Check input variable syntax
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
if port?(value) && between?(value, @range)
|
24
|
-
true
|
25
|
-
else
|
26
|
-
false
|
27
|
-
end
|
19
|
+
def valid_syntax? (value)
|
20
|
+
value.extend(Rips::Utils::StringVariableExtension)
|
21
|
+
value.port? && value.valid_range?(@range)
|
28
22
|
end
|
29
23
|
|
30
24
|
end
|
@@ -16,14 +16,9 @@ module Rips
|
|
16
16
|
end
|
17
17
|
|
18
18
|
# Check input variable syntax
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
if register?(value) && between?(value, @range)
|
23
|
-
true
|
24
|
-
else
|
25
|
-
false
|
26
|
-
end
|
19
|
+
def valid_syntax? (value)
|
20
|
+
value.extend(Rips::Utils::StringVariableExtension)
|
21
|
+
value.register? && value.valid_range?(@range)
|
27
22
|
end
|
28
23
|
|
29
24
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "rips/utils"
|
2
|
+
|
1
3
|
module Rips
|
2
4
|
module Variables
|
3
5
|
|
@@ -10,35 +12,11 @@ module Rips
|
|
10
12
|
@length = length
|
11
13
|
end
|
12
14
|
|
13
|
-
# Check if value is a register ($0..15)
|
14
|
-
def register? (value)
|
15
|
-
(value[0] == "$") && number?(value.slice(1..-1))
|
16
|
-
end
|
17
|
-
|
18
|
-
# Check if value is a port (@0..3)
|
19
|
-
def port? (value)
|
20
|
-
(value[0] == "@") && number?(value.slice(1..-1))
|
21
|
-
end
|
22
|
-
|
23
|
-
# Check if value is a valid number (...,-1,0,1...)
|
24
|
-
def number? (value)
|
25
|
-
/\A[-]?\d+\z/ === value
|
26
|
-
end
|
27
|
-
|
28
|
-
# Check if value is between in permitted range
|
29
|
-
def between? (value, range)
|
30
|
-
to_i(value).between?(range[0], range[1])
|
31
|
-
end
|
32
|
-
|
33
|
-
# Return integer part of value
|
34
|
-
def to_i (value)
|
35
|
-
number?(value) ? value.to_i : value.slice(1..-1).to_i
|
36
|
-
end
|
37
|
-
|
38
15
|
# Return error message about incorrent syntax
|
39
16
|
def error (value)
|
40
17
|
"unexpected `#{value}` (expected a `#{self.class.to_s.split(':').last}` argument like `#{@syntax}`)"
|
41
|
-
end
|
18
|
+
end
|
19
|
+
|
42
20
|
end
|
43
21
|
end
|
44
22
|
end
|
data/lib/rips/version.rb
CHANGED
data/rips.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rips
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Madh93
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -67,7 +67,8 @@ files:
|
|
67
67
|
- README.md
|
68
68
|
- Rakefile
|
69
69
|
- bin/rips
|
70
|
-
-
|
70
|
+
- examples/calc.rips
|
71
|
+
- examples/example.rips
|
71
72
|
- lib/rips.rb
|
72
73
|
- lib/rips/assembler.rb
|
73
74
|
- lib/rips/error.rb
|
@@ -99,6 +100,10 @@ files:
|
|
99
100
|
- lib/rips/instructions/set.rb
|
100
101
|
- lib/rips/instructions/sub.rb
|
101
102
|
- lib/rips/utils.rb
|
103
|
+
- lib/rips/utils/array.rb
|
104
|
+
- lib/rips/utils/integer.rb
|
105
|
+
- lib/rips/utils/string_assembler.rb
|
106
|
+
- lib/rips/utils/string_variable.rb
|
102
107
|
- lib/rips/variables.rb
|
103
108
|
- lib/rips/variables/address.rb
|
104
109
|
- lib/rips/variables/inmediate.rb
|
@@ -121,7 +126,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
121
126
|
requirements:
|
122
127
|
- - ">="
|
123
128
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
129
|
+
version: 1.9.3
|
125
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
131
|
requirements:
|
127
132
|
- - ">="
|