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