OR-1 dataflow CPU sketch
1"""Parser tests for the dataflow graph assembly grammar."""
2
3from textwrap import dedent
4
5import pytest
6from lark import exceptions, LarkError
7
8
9class TestInstDefs:
10 def test_basic_instructions(self, parser):
11 tree = parser.parse(dedent("""\
12 &my_add <| add
13 &my_sub <| sub
14 &my_const <| const, 10
15 &my_shift <| shiftl
16 &my_not <| not
17 """))
18 assert tree.data == "start"
19 assert len(tree.children) == 5
20 assert all(child.data == "inst_def" for child in tree.children)
21
22 def test_hex_const(self, parser):
23 tree = parser.parse(dedent("""\
24 &mask <| const, 0xFF
25 """))
26 assert tree.data == "start"
27 assert len(tree.children) == 1
28 assert tree.children[0].data == "inst_def"
29
30 def test_named_args(self, parser):
31 tree = parser.parse(dedent("""\
32 &serial <| ior, dest=0x45, addr=0x91, data=0x43
33 """))
34 assert tree.data == "start"
35 assert len(tree.children) == 1
36 assert tree.children[0].data == "inst_def"
37
38 def test_system_config(self, parser):
39 tree = parser.parse(dedent("""\
40 &loader <| load_inst, dest=0x01, addr=0x00, data_l=0xABCD, data_h=0x1234
41 """))
42 assert tree.data == "start"
43 assert len(tree.children) == 1
44 assert tree.children[0].data == "inst_def"
45
46
47class TestEdges:
48 def test_plain_edges(self, parser):
49 tree = parser.parse(dedent("""\
50 &a |> &b:L
51 &a |> &b:R
52 &c |> &d, &e
53 """))
54 assert tree.data == "start"
55 assert len(tree.children) == 3
56 assert all(child.data == "plain_edge" for child in tree.children)
57
58 def test_strong_inline_edge(self, parser):
59 tree = parser.parse(dedent("""\
60 add &a, &b |> &c, &d
61 """))
62 assert tree.data == "start"
63 assert len(tree.children) == 1
64 assert tree.children[0].data == "strong_edge"
65
66 def test_weak_inline_edge(self, parser):
67 tree = parser.parse(dedent("""\
68 &c, &d sub <| &a, &b
69 """))
70 assert tree.data == "start"
71 assert len(tree.children) == 1
72 assert tree.children[0].data == "weak_edge"
73
74 def test_fanout(self, parser):
75 tree = parser.parse(dedent("""\
76 &splitter <| pass
77 &input |> &splitter:L
78 &splitter |> &consumer_a:L, &consumer_b:R
79 """))
80 assert tree.data == "start"
81 assert len(tree.children) == 3
82 assert tree.children[0].data == "inst_def"
83 assert tree.children[1].data == "plain_edge"
84 assert tree.children[2].data == "plain_edge"
85
86
87class TestFunctions:
88 def test_fib_function(self, parser):
89 tree = parser.parse(dedent("""\
90 $fib |> {
91 &const_n <| const, 10
92 &sub1 <| sub
93 &sub2 <| sub
94 &branch <| sweq
95
96 &const_n |> &branch:L
97 &const_n |> &sub1:L
98 &const_n |> &sub1:R
99 &const_n |> &sub2:R
100 &sub1 |> &recurse_a:L
101 }
102 """))
103 assert tree.data == "start"
104 assert len(tree.children) == 1
105 assert tree.children[0].data == "func_def"
106
107
108class TestPlacement:
109 def test_pe_qualifiers(self, parser):
110 tree = parser.parse(dedent("""\
111 &my_add|pe0 <| add
112 &result|pe1 <| pass
113 &my_add|pe0 |> &result|pe1:L
114 """))
115 assert tree.data == "start"
116 assert len(tree.children) == 3
117 assert tree.children[0].data == "inst_def"
118 assert tree.children[1].data == "inst_def"
119 assert tree.children[2].data == "plain_edge"
120
121 def test_location_directive(self, parser):
122 tree = parser.parse(dedent("""\
123 @data_section|sm0
124 """))
125 assert tree.data == "start"
126 assert len(tree.children) == 1
127 assert tree.children[0].data == "location_dir"
128
129
130class TestDataDefs:
131 def test_hex_data(self, parser):
132 tree = parser.parse(dedent("""\
133 @hello|sm0:0 = 0x05
134 @hello|sm0:1 = 'h', 'e'
135 @hello|sm0:2 = 'l', 'l'
136 """))
137 assert tree.data == "start"
138 assert len(tree.children) == 3
139 assert all(child.data == "data_def" for child in tree.children)
140
141 def test_macro_invocation(self, parser):
142 tree = parser.parse(dedent("""\
143 @hello = #str "hello"
144 """))
145 assert tree.data == "start"
146 assert len(tree.children) == 1
147 assert tree.children[0].data == "data_def"
148
149 def test_multi_line_string(self, parser):
150 tree = parser.parse(dedent('''\
151 @msg = "hello
152world"
153 '''))
154 assert tree.data == "start"
155 assert len(tree.children) == 1
156 assert tree.children[0].data == "data_def"
157
158 def test_raw_string(self, parser):
159 tree = parser.parse(dedent("""\
160 @path = r"no\\escapes\\here"
161 """))
162 assert tree.data == "start"
163 assert len(tree.children) == 1
164 assert tree.children[0].data == "data_def"
165
166 def test_byte_string(self, parser):
167 tree = parser.parse(dedent("""\
168 @raw_data = b"\\x01\\x02\\x03"
169 """))
170 assert tree.data == "start"
171 assert len(tree.children) == 1
172 assert tree.children[0].data == "data_def"
173
174
175class TestComments:
176 def test_inline_comments(self, parser):
177 tree = parser.parse(dedent("""\
178 &my_add <| add ; this is a comment
179 &a |> &b:L ; wire a to b left port
180 """))
181 assert tree.data == "start"
182 assert len(tree.children) == 2
183 assert tree.children[0].data == "inst_def"
184 assert tree.children[1].data == "plain_edge"
185
186
187class TestMixedPrograms:
188 def test_mixed_program(self, parser):
189 tree = parser.parse(dedent("""\
190 @counter|sm0:0 = 0x00
191
192 $main |> {
193 &init <| const, 0
194 &loop_add <| add
195 &cmp <| lte
196 &branch <| breq
197 &output <| iow, dest=0x01
198
199 &init |> &loop_add:L
200 &loop_add |> &cmp:L
201 &loop_add |> &output:L
202 }
203 """))
204 assert tree.data == "start"
205 assert len(tree.children) == 2
206 assert tree.children[0].data == "data_def"
207 assert tree.children[1].data == "func_def"
208
209
210class TestSMOps:
211 def test_read_op(self, parser):
212 tree = parser.parse(dedent("""\
213 &cell <| read
214 """))
215 assert tree.data == "start"
216 assert len(tree.children) == 1
217 assert tree.children[0].data == "inst_def"
218
219 def test_write_op(self, parser):
220 tree = parser.parse(dedent("""\
221 &cell <| write
222 """))
223 assert tree.data == "start"
224 assert len(tree.children) == 1
225 assert tree.children[0].data == "inst_def"
226
227 def test_clear_op(self, parser):
228 tree = parser.parse(dedent("""\
229 &cell <| clear
230 """))
231 assert tree.data == "start"
232 assert len(tree.children) == 1
233 assert tree.children[0].data == "inst_def"
234
235 def test_alloc_op(self, parser):
236 tree = parser.parse(dedent("""\
237 &cell <| alloc
238 """))
239 assert tree.data == "start"
240 assert len(tree.children) == 1
241 assert tree.children[0].data == "inst_def"
242
243 def test_free_op(self, parser):
244 tree = parser.parse(dedent("""\
245 &cell <| free
246 """))
247 assert tree.data == "start"
248 assert len(tree.children) == 1
249 assert tree.children[0].data == "inst_def"
250
251 def test_rd_inc_op(self, parser):
252 tree = parser.parse(dedent("""\
253 &cell <| rd_inc
254 """))
255 assert tree.data == "start"
256 assert len(tree.children) == 1
257 assert tree.children[0].data == "inst_def"
258
259 def test_rd_dec_op(self, parser):
260 tree = parser.parse(dedent("""\
261 &cell <| rd_dec
262 """))
263 assert tree.data == "start"
264 assert len(tree.children) == 1
265 assert tree.children[0].data == "inst_def"
266
267 def test_cmp_sw_op(self, parser):
268 tree = parser.parse(dedent("""\
269 &cell <| cmp_sw
270 """))
271 assert tree.data == "start"
272 assert len(tree.children) == 1
273 assert tree.children[0].data == "inst_def"
274
275
276class TestSystemPragma:
277 def test_system_pragma_minimal(self, parser):
278 tree = parser.parse(dedent("""\
279 @system pe=4, sm=1
280 """))
281 assert tree.data == "start"
282 assert len(tree.children) == 1
283 assert tree.children[0].data == "system_pragma"
284
285 def test_system_pragma_full(self, parser):
286 tree = parser.parse(dedent("""\
287 @system pe=2, sm=1, iram=128, ctx=2
288 """))
289 assert tree.data == "start"
290 assert len(tree.children) == 1
291 assert tree.children[0].data == "system_pragma"
292
293 def test_system_pragma_with_hex(self, parser):
294 tree = parser.parse(dedent("""\
295 @system pe=0x04, sm=0x01
296 """))
297 assert tree.data == "start"
298 assert len(tree.children) == 1
299 assert tree.children[0].data == "system_pragma"
300
301
302class TestUnknownOpcodes:
303 def test_unknown_opcode_fails(self, parser):
304 with pytest.raises((exceptions.UnexpectedToken, exceptions.UnexpectedCharacters)):
305 parser.parse(dedent("""\
306 &unknown <| foobar
307 """))