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 #include "pio_enums.h"
19 
20 struct src_item {
21     yy::location location;
22 
23     src_item() = default;
24 
src_itemsrc_item25     explicit src_item(const yy::location &location) : location(location) {}
26 };
27 
28 struct program;
29 struct pio_assembler;
30 
31 struct resolvable : public src_item {
resolvableresolvable32     resolvable(const yy::location &l) : src_item(l) {}
33 
34     int resolve(const program &program);
35 
resolveresolvable36     int resolve(pio_assembler *pioasm, const program *program) {
37         return resolve(pioasm, program, *this);
38     }
39 
40     virtual int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) = 0;
41 
42     virtual ~resolvable() = default;
43 };
44 
45 using rvalue = std::shared_ptr<resolvable>;
46 
47 enum struct inst_type {
48     jmp = 0x0,
49     wait = 0x1,
50     in = 0x2,
51     out = 0x3,
52     push_pull = 0x4,
53     mov = 0x5,
54     irq = 0x6,
55     set = 0x7,
56 };
57 
58 /* condition codes */
59 enum struct condition {
60     al = 0x0,
61     xz = 0x1,
62     xnz__ = 0x2,
63     yz = 0x3,
64     ynz__ = 0x4,
65     xney = 0x5,
66     pin = 0x6,
67     osrez = 0x7,
68 };
69 
70 /* in source / out / set target - not all valid */
71 enum struct in_out_set {
72     in_out_set_pins = 0x0,
73     in_out_set_x = 0x1,
74     in_out_set_y = 0x2,
75     in_out_null = 0x3,
76     in_out_set_pindirs = 0x4,
77     in_status = 0x5,
78     out_set_pc = 0x5,
79     in_out_isr = 0x6,
80     in_osr = 0x7,
81     out_exec = 0x7,
82 };
83 
84 enum struct irq {
85     set = 0x0,
86     set_wait = 0x1,
87     clear = 0x2,
88 };
89 
90 // mov src/dest (not all valid)
91 enum struct mov {
92     pins = 0x0,
93     x = 0x1,
94     y = 0x2,
95     null = 0x3,
96     pindirs = 0x3,
97     exec = 0x4,
98     pc = 0x5,
99     status = 0x5,
100     isr = 0x6,
101     osr = 0x7,
102     fifo_y = 0x8,
103     fifo_index = 0x9,
104 };
105 
106 enum struct mov_status_type {
107     unspecified = -1,
108     tx_lessthan = 0,
109     rx_lessthan = 1,
110     irq_set = 2,
111 };
112 
113 struct extended_mov {
114     mov loc;
115     rvalue fifo_index;
116 
extended_movextended_mov117     extended_mov() : loc(mov::pindirs), fifo_index(nullptr) {}
extended_movextended_mov118     extended_mov(mov _type) : loc(_type), fifo_index(nullptr) {}
extended_movextended_mov119     extended_mov(rvalue _fifo_index) : loc(mov::fifo_index), fifo_index(_fifo_index) {}
120 
uses_fifoextended_mov121     bool uses_fifo(void) const { return loc == mov::fifo_index || loc == mov::fifo_y; }
122 };
123 
124 enum struct mov_op {
125     none = 0x0,
126     invert = 0x1,
127     bit_reverse = 0x2,
128 };
129 
130 struct wait_source {
131     enum type {
132         gpio = 0x0,
133         pin = 0x1,
134         irq = 0x2,
135         jmppin = 0x3,
136     } target;
137     rvalue param;
138     int irq_type;
139 
targetwait_source140     wait_source(type target, rvalue param = 0, int irq_type = 0) : target(target), param(std::move(param)), irq_type(irq_type) {}
141 };
142 
143 struct name_ref : public resolvable {
144     std::string name;
145 
name_refname_ref146     name_ref(const yy::location &l, std::string name) : resolvable(l), name(std::move(name)) {}
147 
148     int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override;
149 };
150 
151 struct code_block : public resolvable {
152     std::string lang;
153     std::string contents;
154 
code_blockcode_block155     code_block(const yy::location &l, std::string lang, std::string contents) : resolvable(l), lang(std::move(lang)),
156                                                                                 contents(std::move(contents)) {}
157 
resolvecode_block158     int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override {
159         return 0;
160     }
161 };
162 
163 struct int_value : public resolvable {
164     int value;
165 
int_valueint_value166     int_value(const yy::location &l, int value) : resolvable(l), value(value) {}
167 
resolveint_value168     int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override {
169         return value;
170     }
171 };
172 
resolvable_int(const yy::location & l,int v)173 static inline rvalue resolvable_int(const yy::location &l, int v) {
174     return std::shared_ptr<resolvable>(new int_value(l, v));
175 }
176 
177 struct binary_operation : public resolvable {
178     enum op_type {
179         add,
180         subtract,
181         multiply,
182         divide,
183         and_, // pesky C++
184         or_,
185         xor_,
186         shl_,
187         shr_
188     };
189 
190     op_type op;
191     rvalue left, right;
192 
binary_operationbinary_operation193     binary_operation(const yy::location &l, op_type op, rvalue left, rvalue right) :
194             resolvable(l), op(op), left(std::move(left)), right(std::move(right)) {}
195 
196     int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override;
197 };
198 
199 struct unary_operation : public resolvable {
200     enum op_type {
201         negate,
202         reverse
203     };
204 
205     op_type op;
206     rvalue arg;
207 
unary_operationunary_operation208     unary_operation(const yy::location &l, op_type op, const rvalue &arg) :
209             resolvable(l), op(op), arg(arg) {}
210 
211     int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override;
212 };
213 
214 struct symbol : public src_item {
215     std::string name;
216     rvalue value;
217     bool is_public;
218     bool is_label;
219     int resolve_started;
220 
src_itemsymbol221     symbol(const yy::location &l, std::string name, bool is_extern = false) : src_item(l), name(std::move(name)),
222                                                                               is_public(is_extern), is_label(false),
223                                                                               resolve_started(false) {}
224 };
225 
226 struct raw_encoding {
227     enum inst_type type;
228     uint arg1;
229     uint arg2;
230 };
231 
232 struct instruction : public src_item {
233     rvalue sideset; // possibly null
234     rvalue delay;
235 
instructioninstruction236     instruction(const yy::location &l) : src_item(l) {}
237 
238     // validate while adding instruciton
pre_validateinstruction239     virtual void pre_validate(program &program) {}
240 
241     virtual uint encode(program &program);
242 
243     virtual raw_encoding raw_encode(program &program);
244 };
245 
246 struct pio_assembler;
247 
248 // rvalue with extra encompassing location
249 struct rvalue_loc {
250     rvalue value;
251     yy::location location;
252 
253     rvalue_loc() = default;
254 
rvalue_locrvalue_loc255     rvalue_loc(const rvalue &v, const yy::location &l) : value(v), location(l) {}
256 };
257 
258 struct in_out {
259     yy::location location;
260     rvalue pin_count;
261     bool right;
262     bool autop;
263     rvalue threshold;
264     int final_pin_count = -1; // not specified
265     int final_threshold;
266 };
267 
268 struct program : public src_item {
269     static const int MAX_INSTRUCTIONS = 32;
270 
271     pio_assembler *pioasm;
272     std::string name;
273     rvalue_loc origin;
274     rvalue_loc sideset;
275     rvalue_loc set_count;
276     in_out in;
277     in_out out;
278     bool sideset_opt;
279     bool sideset_pindirs;
280 
281     rvalue wrap_target;
282     rvalue wrap;
283 
284     int pio_version = 0;
285     uint clock_div_int = 1;
286     uint clock_div_frac = 0;
287     yy::location fifo_loc;
288     fifo_config fifo = fifo_config::txrx;
289     // 1 bit of bitmap per 16 pins used
290     uint8_t used_gpio_ranges = 0;
291 
292     std::map<std::string, std::shared_ptr<symbol>> symbols;
293     std::vector<std::shared_ptr<symbol>> ordered_symbols;
294     std::vector<std::shared_ptr<instruction>> instructions;
295     std::map<std::string, std::vector<code_block>> code_blocks;
296     std::map<std::string, std::vector<std::pair<std::string,std::string>>> lang_opts;
297     struct {
298         mov_status_type type = mov_status_type::unspecified;
299         rvalue n;
300         int param;
301         int final_n; // post finalization
302     } mov_status;
303 
304     // post finalization
305     int delay_max;
306     int sideset_bits_including_opt; // specified side set bits + 1 if we need presence flag
307     int sideset_max;
308     int final_set_count = -1;
309     int final_out_count = -1;
310     int final_in_count = -1;
311 
programprogram312     program(pio_assembler *pioasm, const yy::location &l, std::string name) :
313             src_item(l), pioasm(pioasm), name(std::move(name)), sideset_opt(true), sideset_pindirs(false) {}
314 
set_originprogram315     void set_origin(const yy::location &l, const rvalue &_origin) {
316         origin = rvalue_loc(_origin, l);
317     }
318 
319     void set_wrap_target(const yy::location &l);
320 
321     void set_wrap(const yy::location &l);
322 
set_sidesetprogram323     void set_sideset(const yy::location &l, rvalue _sideset, bool optional, bool pindirs) {
324         sideset = rvalue_loc(_sideset, l);
325         sideset_opt = optional;
326         sideset_pindirs = pindirs;
327     }
328 
set_outprogram329     void set_out(const yy::location &l, rvalue v, bool right, bool autop, rvalue threshold) {
330         out.location = l;
331         out.pin_count = std::move(v);
332         out.right = right;
333         out.autop = autop;
334         out.threshold = threshold;
335     }
336 
set_inprogram337     void set_in(const yy::location &l, rvalue v, bool right, bool autop, rvalue threshold) {
338         in.location = l;
339         in.pin_count = std::move(v);
340         in.right = right;
341         in.autop = autop;
342         in.threshold = threshold;
343     }
344 
set_set_countprogram345     void set_set_count(const yy::location &l, rvalue v) {
346         set_count = rvalue_loc(v, l);
347     }
348 
add_labelprogram349     void add_label(std::shared_ptr<symbol> label) {
350         label->value = resolvable_int(label->location, instructions.size());
351         add_symbol(label);
352     }
353 
354     void add_symbol(std::shared_ptr<symbol> symbol);
355 
356     void add_instruction(std::shared_ptr<instruction> inst);
357 
358     void add_code_block(const code_block &block);
359 
360     void add_lang_opt(std::string lang, std::string name, std::string value);
361 
362     void set_pio_version(const yy::location &l, int version);
363 
364     void set_clock_div(const yy::location &l, float clock_div);
365 
366     void set_fifo_config(const yy::location &l, fifo_config config);
367 
368     void set_mov_status(mov_status_type type, rvalue n, int param = 0) {
369         mov_status.type = type;
370         mov_status.n = n;
371         mov_status.param = param;
372     }
373 
374     void finalize();
375 protected:
376     void init_pio_version();
377 };
378 
379 struct instr_jmp : public instruction {
380     condition cond;
381     rvalue target;
382 
instr_jmpinstr_jmp383     instr_jmp(const yy::location &l, condition c, rvalue target) : instruction(l), cond(c), target(std::move(target)) { }
384 
385     raw_encoding raw_encode(program &program) override;
386 };
387 
388 struct instr_wait : public instruction {
389     rvalue polarity;
390     std::shared_ptr<wait_source> source;
391 
instr_waitinstr_wait392     instr_wait(const yy::location &l, rvalue polarity, std::shared_ptr<wait_source> source) : instruction(l), polarity(
393             std::move(polarity)), source(std::move(source)) {}
394 
395     raw_encoding raw_encode(program &program) override;
396 };
397 
398 struct instr_in : public instruction {
399     enum in_out_set src;
400     rvalue value;
401 
instr_ininstr_in402     instr_in(const yy::location &l, const enum in_out_set &src, rvalue value) : instruction(l), src(src),
403                                                                                 value(std::move(value)) {}
404 
405     raw_encoding raw_encode(program &program) override;
406 };
407 
408 struct instr_out : public instruction {
409     enum in_out_set dest;
410     rvalue value;
411 
instr_outinstr_out412     instr_out(const yy::location &l, const enum in_out_set &dest, rvalue value) : instruction(l), dest(dest),
413                                                                                   value(std::move(value)) {}
414 
415     raw_encoding raw_encode(program &program) override;
416 };
417 
418 struct instr_set : public instruction {
419     enum in_out_set dest;
420     rvalue value;
421 
instr_setinstr_set422     instr_set(const yy::location &l, const enum in_out_set &dest, rvalue value) : instruction(l), dest(dest),
423                                                                                   value(std::move(value)) {}
424 
425     raw_encoding raw_encode(program &program) override;
426 };
427 
428 
429 struct instr_push : public instruction {
430     bool if_full, blocking;
431 
instr_pushinstr_push432     instr_push(const yy::location &l, bool if_full, bool blocking) : instruction(l), if_full(if_full),
433                                                                      blocking(blocking) {}
434 
435 
436     void pre_validate(program& program) override;
raw_encodeinstr_push437     raw_encoding raw_encode(program &program) override {
438         uint arg1 = (blocking ? 1u : 0u) | (if_full ? 0x2u : 0);
439         return {inst_type::push_pull, arg1, 0};
440     }
441 };
442 
443 struct instr_pull : public instruction {
444     bool if_empty, blocking;
445 
instr_pullinstr_pull446     instr_pull(const yy::location &l, bool if_empty, bool blocking) : instruction(l), if_empty(if_empty),
447                                                                       blocking(blocking) {}
448 
raw_encodeinstr_pull449     raw_encoding raw_encode(program &program) override {
450         uint arg1 = (blocking ? 1u : 0u) | (if_empty ? 0x2u : 0) | 0x4u;
451         return {inst_type::push_pull, arg1, 0};
452     }
453 };
454 
455 struct instr_mov : public instruction {
456     extended_mov dest, src;
457     mov_op op;
458 
459     instr_mov(const yy::location &l, const extended_mov &dest, const extended_mov &src, const mov_op& op = mov_op::none) :
instructioninstr_mov460             instruction(l), dest(dest), src(src), op(op) {}
461 
462     uint get_push_get_index(const program &program, extended_mov index);
463     void pre_validate(program& program) override;
464     raw_encoding raw_encode(program &program) override;
465 };
466 
467 struct instr_irq : public instruction {
468     enum irq modifiers;
469     rvalue num;
470     int irq_type;
471 
472     instr_irq(const yy::location &l, const enum irq &modifiers, rvalue num, int irq_type = 0) :
instructioninstr_irq473             instruction(l), modifiers(modifiers), num(std::move(num)), irq_type(irq_type) {}
474 
475     raw_encoding raw_encode(program &program) override;
476 };
477 
478 
479 struct instr_nop : public instr_mov {
instr_nopinstr_nop480     instr_nop(const yy::location &l) : instr_mov(l, mov::y, mov::y) {}
481 };
482 
483 struct instr_word : public instruction {
484     rvalue encoding;
485 
instr_wordinstr_word486     instr_word(const yy::location &l, rvalue encoding) : instruction(l), encoding(std::move(encoding)) {}
487 
488     uint encode(program &program) override;
489 };
490 
491 #endif
492