1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _PIO_TYPES_H
8 #define _PIO_TYPES_H
9 
10 #include <string>
11 #include <map>
12 #include <set>
13 #include <utility>
14 #include <vector>
15 #include <memory>
16 
17 #include "location.h"
18 
19 typedef unsigned int uint;
20 
21 enum struct inst_type {
22     jmp = 0x0,
23     wait = 0x1,
24     in = 0x2,
25     out = 0x3,
26     push_pull = 0x4,
27     mov = 0x5,
28     irq = 0x6,
29     set = 0x7,
30 };
31 
32 /* condition codes */
33 enum struct condition {
34     al = 0x0,
35     xz = 0x1,
36     xnz__ = 0x2,
37     yz = 0x3,
38     ynz__ = 0x4,
39     xney = 0x5,
40     pin = 0x6,
41     osrez = 0x7,
42 };
43 
44 /* in source / out / set target - not all valid */
45 enum struct in_out_set {
46     in_out_set_pins = 0x0,
47     in_out_set_x = 0x1,
48     in_out_set_y = 0x2,
49     in_out_null = 0x3,
50     in_out_set_pindirs = 0x4,
51     in_status = 0x5,
52     out_set_pc = 0x5,
53     in_out_isr = 0x6,
54     in_osr = 0x7,
55     out_exec = 0x7,
56 };
57 
58 enum struct irq {
59     set = 0x0,
60     set_wait = 0x1,
61     clear = 0x2,
62 };
63 
64 // mov src/dest (not all valid)
65 enum struct mov {
66     pins = 0x0,
67     x = 0x1,
68     y = 0x2,
69     null = 0x3,
70     exec = 0x4,
71     pc = 0x5,
72     status = 0x5,
73     isr = 0x6,
74     osr = 0x7,
75 };
76 
77 enum struct mov_op {
78     none = 0x0,
79     invert = 0x1,
80     bit_reverse = 0x2,
81 };
82 
83 struct src_item {
84     yy::location location;
85 
86     src_item() = default;
87 
src_itemsrc_item88     explicit src_item(const yy::location &location) : location(location) {}
89 };
90 
91 struct program;
92 struct pio_assembler;
93 
94 struct resolvable : public src_item {
resolvableresolvable95     resolvable(const yy::location &l) : src_item(l) {}
96 
97     int resolve(const program &program);
98 
resolveresolvable99     int resolve(pio_assembler *pioasm, const program *program) {
100         return resolve(pioasm, program, *this);
101     }
102 
103     virtual int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) = 0;
104 };
105 
106 using rvalue = std::shared_ptr<resolvable>;
107 
108 struct wait_source {
109     enum type {
110         gpio = 0x0,
111         pin = 0x1,
112         irq = 0x2
113     } target;
114     rvalue param;
115     bool flag;
116 
targetwait_source117     wait_source(type target, rvalue param, bool flag = false) : target(target), param(std::move(param)), flag(flag) {}
118 };
119 
120 struct name_ref : public resolvable {
121     std::string name;
122 
name_refname_ref123     name_ref(const yy::location &l, std::string name) : resolvable(l), name(std::move(name)) {}
124 
125     int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override;
126 };
127 
128 struct code_block : public resolvable {
129     std::string lang;
130     std::string contents;
131 
code_blockcode_block132     code_block(const yy::location &l, std::string lang, std::string contents) : resolvable(l), lang(std::move(lang)),
133                                                                                 contents(std::move(contents)) {}
134 
resolvecode_block135     int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override {
136         return 0;
137     }
138 };
139 
140 struct int_value : public resolvable {
141     int value;
142 
int_valueint_value143     int_value(const yy::location &l, int value) : resolvable(l), value(value) {}
144 
resolveint_value145     int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override {
146         return value;
147     }
148 };
149 
resolvable_int(const yy::location & l,int v)150 static inline rvalue resolvable_int(const yy::location &l, int v) {
151     return std::shared_ptr<resolvable>(new int_value(l, v));
152 }
153 
154 struct binary_operation : public resolvable {
155     enum op_type {
156         add,
157         subtract,
158         multiply,
159         divide,
160         and_, // pesky C++
161         or_,
162         xor_
163     };
164 
165     op_type op;
166     rvalue left, right;
167 
binary_operationbinary_operation168     binary_operation(const yy::location &l, op_type op, rvalue left, rvalue right) :
169             resolvable(l), op(op), left(std::move(left)), right(std::move(right)) {}
170 
171     int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override;
172 };
173 
174 struct unary_operation : public resolvable {
175     enum op_type {
176         negate,
177         reverse
178     };
179 
180     op_type op;
181     rvalue arg;
182 
unary_operationunary_operation183     unary_operation(const yy::location &l, op_type op, const rvalue &arg) :
184             resolvable(l), op(op), arg(arg) {}
185 
186     int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override;
187 };
188 
189 struct symbol : public src_item {
190     std::string name;
191     rvalue value;
192     bool is_public;
193     bool is_label;
194     int resolve_started;
195 
src_itemsymbol196     symbol(const yy::location &l, std::string name, bool is_extern = false) : src_item(l), name(std::move(name)),
197                                                                               is_public(is_extern), is_label(false),
198                                                                               resolve_started(false) {}
199 };
200 
201 struct raw_encoding {
202     enum inst_type type;
203     uint arg1;
204     uint arg2;
205 };
206 
207 struct instruction : public src_item {
208     rvalue sideset; // possibly null
209     rvalue delay;
210 
instructioninstruction211     instruction(const yy::location &l) : src_item(l) {}
212 
213     virtual uint encode(const program &program);
214 
215     virtual raw_encoding raw_encode(const program &program);
216 };
217 
218 struct pio_assembler;
219 
220 // rvalue with extra encompassing location
221 struct rvalue_loc {
222     rvalue value;
223     yy::location location;
224 
225     rvalue_loc() = default;
226 
rvalue_locrvalue_loc227     rvalue_loc(const rvalue &v, const yy::location &l) : value(v), location(l) {}
228 };
229 
230 struct program : public src_item {
231     static const int MAX_INSTRUCTIONS = 32;
232 
233     pio_assembler *pioasm;
234     std::string name;
235     rvalue_loc origin;
236     rvalue_loc sideset;
237     bool sideset_opt;
238     bool sideset_pindirs;
239 
240     rvalue wrap_target;
241     rvalue wrap;
242 
243     std::map<std::string, std::shared_ptr<symbol>> symbols;
244     std::vector<std::shared_ptr<symbol>> ordered_symbols;
245     std::vector<std::shared_ptr<instruction>> instructions;
246     std::map<std::string, std::vector<code_block>> code_blocks;
247     std::map<std::string, std::vector<std::pair<std::string,std::string>>> lang_opts;
248 
249     // post finalization
250     int delay_max;
251     int sideset_bits_including_opt; // specified side set bits + 1 if we need presence flag
252     int sideset_max;
253 
programprogram254     program(pio_assembler *pioasm, const yy::location &l, std::string name) :
255             src_item(l), pioasm(pioasm), name(std::move(name)), sideset_opt(true), sideset_pindirs(false) {}
256 
set_originprogram257     void set_origin(const yy::location &l, const rvalue &_origin) {
258         origin = rvalue_loc(_origin, l);
259     }
260 
261     void set_wrap_target(const yy::location &l);
262 
263     void set_wrap(const yy::location &l);
264 
set_sidesetprogram265     void set_sideset(const yy::location &l, rvalue _sideset, bool optional, bool pindirs) {
266         sideset = rvalue_loc(_sideset, l);
267         sideset_opt = optional;
268         sideset_pindirs = pindirs;
269     }
270 
add_labelprogram271     void add_label(std::shared_ptr<symbol> label) {
272         label->value = resolvable_int(label->location, instructions.size());
273         add_symbol(label);
274     }
275 
276     void add_symbol(std::shared_ptr<symbol> symbol);
277 
278     void add_instruction(std::shared_ptr<instruction> inst);
279 
280     void add_code_block(const code_block &block);
281 
282     void add_lang_opt(std::string lang, std::string name, std::string value);
283     void finalize();
284 };
285 
286 struct instr_jmp : public instruction {
287     condition cond;
288     rvalue target;
289 
instr_jmpinstr_jmp290     instr_jmp(const yy::location &l, condition c, rvalue target) : instruction(l), cond(c), target(std::move(target)) { }
291 
292     raw_encoding raw_encode(const program &program) override;
293 };
294 
295 struct instr_wait : public instruction {
296     rvalue polarity;
297     std::shared_ptr<wait_source> source;
298 
instr_waitinstr_wait299     instr_wait(const yy::location &l, rvalue polarity, std::shared_ptr<wait_source> source) : instruction(l), polarity(
300             std::move(polarity)), source(std::move(source)) {}
301 
302     raw_encoding raw_encode(const program &program) override;
303 };
304 
305 struct instr_in : public instruction {
306     enum in_out_set src;
307     rvalue value;
308 
instr_ininstr_in309     instr_in(const yy::location &l, const enum in_out_set &src, rvalue value) : instruction(l), src(src),
310                                                                                 value(std::move(value)) {}
311 
312     raw_encoding raw_encode(const program &program) override;
313 };
314 
315 struct instr_out : public instruction {
316     enum in_out_set dest;
317     rvalue value;
318 
instr_outinstr_out319     instr_out(const yy::location &l, const enum in_out_set &dest, rvalue value) : instruction(l), dest(dest),
320                                                                                   value(std::move(value)) {}
321 
322     raw_encoding raw_encode(const program &program) override;
323 };
324 
325 struct instr_set : public instruction {
326     enum in_out_set dest;
327     rvalue value;
328 
instr_setinstr_set329     instr_set(const yy::location &l, const enum in_out_set &dest, rvalue value) : instruction(l), dest(dest),
330                                                                                   value(std::move(value)) {}
331 
332     raw_encoding raw_encode(const program &program) override;
333 };
334 
335 
336 struct instr_push : public instruction {
337     bool if_full, blocking;
338 
instr_pushinstr_push339     instr_push(const yy::location &l, bool if_full, bool blocking) : instruction(l), if_full(if_full),
340                                                                      blocking(blocking) {}
341 
raw_encodeinstr_push342     raw_encoding raw_encode(const program &program) override {
343         uint arg1 = (blocking ? 1u : 0u) | (if_full ? 0x2u : 0);
344         return {inst_type::push_pull, arg1, 0};
345     }
346 };
347 
348 struct instr_pull : public instruction {
349     bool if_empty, blocking;
350 
instr_pullinstr_pull351     instr_pull(const yy::location &l, bool if_empty, bool blocking) : instruction(l), if_empty(if_empty),
352                                                                       blocking(blocking) {}
353 
raw_encodeinstr_pull354     raw_encoding raw_encode(const program &program) override {
355         uint arg1 = (blocking ? 1u : 0u) | (if_empty ? 0x2u : 0) | 0x4u;
356         return {inst_type::push_pull, arg1, 0};
357     }
358 };
359 
360 struct instr_mov : public instruction {
361     enum mov dest, src;
362     mov_op op;
363 
364     instr_mov(const yy::location &l, const enum mov &dest, const enum mov &src, const mov_op& op = mov_op::none) :
instructioninstr_mov365             instruction(l), dest(dest), src(src), op(op) {}
366 
raw_encodeinstr_mov367     raw_encoding raw_encode(const program &program) override {
368         return {inst_type::mov, (uint) dest, (uint)src | ((uint)op << 3u)};
369     }
370 };
371 
372 struct instr_irq : public instruction {
373     enum irq modifiers;
374     rvalue num;
375     bool relative;
376 
377     instr_irq(const yy::location &l, const enum irq &modifiers, rvalue num, bool relative = false) :
instructioninstr_irq378             instruction(l), modifiers(modifiers), num(std::move(num)), relative(relative) {}
379 
380     raw_encoding raw_encode(const program &program) override;
381 };
382 
383 
384 struct instr_nop : public instr_mov {
instr_nopinstr_nop385     instr_nop(const yy::location &l) : instr_mov(l, mov::y, mov::y) {}
386 };
387 
388 struct instr_word : public instruction {
389     rvalue encoding;
390 
instr_wordinstr_word391     instr_word(const yy::location &l, rvalue encoding) : instruction(l), encoding(std::move(encoding)) {}
392 
393     uint encode(const program &program) override;
394 };
395 
396 #endif