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