summaryrefslogtreecommitdiff
path: root/asm.rb
diff options
context:
space:
mode:
authorJulian Blake Kongslie2021-07-06 09:44:36 -0700
committerJulian Blake Kongslie2021-07-06 09:44:36 -0700
commit60e1775b874015a3451e4bde10a8eb30701b1165 (patch)
tree477a2835c0f7e616bdeeabe6aee85f8af8b79650 /asm.rb
downloadbreadboarding-60e1775b874015a3451e4bde10a8eb30701b1165.tar.xz
Initial commit.
Diffstat (limited to '')
-rwxr-xr-xasm.rb196
1 files changed, 196 insertions, 0 deletions
diff --git a/asm.rb b/asm.rb
new file mode 100755
index 0000000..2ca9155
--- /dev/null
+++ b/asm.rb
@@ -0,0 +1,196 @@
1#!/usr/bin/ruby -w
2
3$insts = {}
4
5$next_opcode = 0
6
7def inst(pattern, vector=false, &code)
8 return if vector
9 throw "instruction with this pattern already defined" if $insts.member?(pattern)
10 $insts[pattern] = $next_opcode
11 $next_opcode += 1
12end
13
14load "insts.rb"
15
16$labels = {}
17$pc = 0
18
19ARGF.each_line do | line |
20 line.chomp!
21 line.gsub!(/^\s+/, "")
22 line.gsub!(/#.*/, "")
23 line.gsub!(/\s+$/, "")
24
25 next if line == ""
26
27 if line =~ /^([a-zA-Z_][a-zA-Z0-9_]*):$/
28 $labels[$1] = $pc
29 $stdout.write("\t// #{line}\n")
30 next
31 elsif line =~ /^\.origin\s+((?:0x[0-9a-fA-F]+)?(?:\d+))$/
32 $pc = $1.to_i(0)
33 $stdout.write("@#{$pc.to_s(16)}\t// #{line}\n")
34 next
35 elsif line =~ /^\.bytes?\s+(.*)$/
36 data = $1.split(/\s+/)
37 data.map { | x | throw "invalid byte #{x}" unless x =~ /^-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+))$/ }
38 data = data.map { | x | x.to_i(0) }
39 data = data.map { | x | x < 0 ? x + 0x100 : x }
40 data.map { | x | throw "invalid byte 0x#{x.to_s(16)}" unless x >= 0 && x <= 0xff }
41 data = data.map { | x | x.to_s(16).rjust(2, "0") }
42 $pc += data.size
43 $stdout.write("#{data.join(" ")}\t// #{line}\n")
44 next
45 elsif line =~ /^\.shorts?\s+(.*)$/
46 data = $1.split(/\s+/)
47 data.map { | x | throw "invalid short #{x}" unless x =~ /^-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+))$/ }
48 data = data.map { | x | x.to_i(0) }
49 data = data.map { | x | x < 0 ? x + 0x10000 : x }
50 data.map { | x | throw "invalid short 0x#{x.to_s(16)}" unless x >= 0 && x <= 0xffff }
51 data = data.flat_map { | x | [x & 0xff, x >> 8] }
52 data = data.map { | x | x.to_s(16).rjust(2, "0") }
53 $pc += data.size
54 $stdout.write("#{data.join(" ")}\t// #{line}\n")
55 next
56 elsif line =~ /^\.longs?\s+(.*)$/
57 data = $1.split(/\s+/)
58 data.map { | x | throw "invalid long #{x}" unless x =~ /^-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+))$/ }
59 data = data.map { | x | x.to_i(0) }
60 data = data.map { | x | x < 0 ? x + 0x100000000 : x }
61 data.map { | x | throw "invalid long 0x#{x.to_s(16)}" unless x >= 0 && x <= 0xffffffff }
62 data = data.flat_map { | x | [x & 0xff, (x >> 8) & 0xff, (x >> 16) & 0xff, x >> 24] }
63 data = data.map { | x | x.to_s(16).rjust(2, "0") }
64 $pc += data.size
65 $stdout.write("#{data.join(" ")}\t// #{line}\n")
66 next
67 elsif line =~ /^\.quads?\s+(.*)$/
68 data = $1.split(/\s+/)
69 data.map { | x | throw "invalid quad #{x}" unless x =~ /^-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+))$/ }
70 data = data.map { | x | x.to_i(0) }
71 data = data.map { | x | x < 0 ? x + 0x10000000000000000 : x }
72 data.map { | x | throw "invalid quad 0x#{x.to_s(16)}" unless x >= 0 && x <= 0xffffffffffffffff }
73 data = data.flat_map { | x | [x & 0xff, (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff, (x >> 32) & 0xff, (x >> 40) & 0xff, (x >> 48) & 0xff, x >> 56] }
74 data = data.map { | x | x.to_s(16).rjust(2, "0") }
75 $pc += data.size
76 $stdout.write("#{data.join(" ")}\t// #{line}\n")
77 next
78 end
79
80 parts = line.split(/\s+/)
81
82 patterns = [parts.shift]
83 values = []
84 parts.each do | part |
85 case part
86 when /^(-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+)))$/
87 patterns << "#"
88 values << $1.to_i(0)
89 when /^([a-zA-Z_][a-zA-Z0-9_]+)$/
90 throw "unknown label #{$1}" unless $labels.member?($1)
91 patterns << "#"
92 values << $labels[$1]
93 when /^\$(-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+)))$/
94 patterns << "$"
95 values << $1.to_i(0)
96 when /^\[(-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+)))\]$/
97 patterns << "[#]"
98 values << $1.to_i(0)
99 when /^\[([a-zA-Z_][a-zA-Z0-9_]+)\]$/
100 throw "unknown label #{$1}" unless $labels.member?($1)
101 patterns << "[#]"
102 values << $labels[$1]
103 when /^\[\$(-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+)))\]$/
104 patterns << "[$]"
105 values << $1.to_i(0)
106 else
107 throw "invalid part #{part}"
108 end
109 end
110
111 pattern = patterns.join(" ")
112 throw "unknown instruction pattern #{pattern}" unless $insts.member?(pattern)
113 opcode = $insts[pattern]
114
115 # Encoding format:
116 # +-+-+-+-+-+-+-+-+
117 # |M|I|SEL| SHIFT |
118 # +-+-+-+-+-+-+-+-+
119 # M = More data after this
120 # I = Invert this field before shifting
121 # SEL = Field selector (0=opcode, 2=A, 3=B)
122 # SHIFT = Data to shift in
123
124 # This gives us these common first nibbles:
125 # 0 last opcode byte
126 # 8 extended opcode byte
127 # A operand A byte
128 # B operand B byte
129 # E operand A byte (with inversion)
130 # F operand B byte (with inversion)
131
132 space = false
133 values.each_with_index do | value, idx |
134 inverted = value < 0
135 if inverted
136 value *= -1
137 value -= 1
138 end
139 nibbles = []
140 while value != 0
141 nibbles << (value & 0xf).to_s(16)
142 value = value >> 4
143 end
144 if inverted and nibbles.empty?
145 nibbles << "f"
146 end
147 nibbles.reverse!
148 if idx == 0
149 if inverted
150 $stdout.write(" ") if space
151 $stdout.write("e#{nibbles.shift}")
152 $pc += 1
153 space = true
154 end
155 nibbles.each do | nibble |
156 $stdout.write(" ") if space
157 $stdout.write("a#{nibble}")
158 $pc += 1
159 space = true
160 end
161 elsif idx == 1
162 if inverted
163 $stdout.write(" ") if space
164 $stdout.write("f#{nibbles.shift}")
165 $pc += 1
166 space = true
167 end
168 nibbles.each do | nibble |
169 $stdout.write(" ") if space
170 $stdout.write("b#{nibble}")
171 $pc += 1
172 space = true
173 end
174 else
175 throw "don't know how to encode this many fields"
176 end
177 end
178
179 nibbles = []
180 while opcode != 0
181 nibbles << (opcode & 0xf).to_s(16)
182 opcode = opcode >> 4
183 end
184 nibbles << "0" if nibbles.empty?
185 last = nibbles.shift
186 nibbles.reverse!
187 nibbles.each do | nibble |
188 $stdout.write(" ") if space
189 $stdout.write("8#{nibble}")
190 $pc += 1
191 space = true
192 end
193 $stdout.write(" ") if space
194 $stdout.write("0#{last}\t// #{line}\n")
195 $pc += 1
196end