Squashed 'third_party/pico-sdk/' content from commit 2062372d2
Change-Id: Ic20f199d3ed0ea8d3a6a1bbf513f875ec7500cc6
git-subtree-dir: third_party/pico-sdk
git-subtree-split: 2062372d203b372849d573f252cf7c6dc2800c0a
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/tools/pioasm/parser.yy b/tools/pioasm/parser.yy
new file mode 100644
index 0000000..467ca89
--- /dev/null
+++ b/tools/pioasm/parser.yy
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+%skeleton "lalr1.cc" /* -*- C++ -*- */
+%require "3.4.2"
+%defines
+
+%define api.token.constructor
+%define api.value.type variant
+/*%define parse.assert*/
+%define api.location.file "location.h"
+%define parse.lac full
+/* define parse.trace*/
+%define parse.error verbose
+%no-lines
+%locations
+
+%code requires {
+ #include <string>
+ #include <fstream>
+ #include <sstream>
+ #include "pio_types.h"
+ struct pio_assembler;
+
+ #ifdef _MSC_VER
+ #pragma warning(disable : 4065) // default only switch statement
+ #endif
+}
+
+// The parsing context.
+%param { pio_assembler& pioasm }
+
+%code {
+ #include "pio_assembler.h"
+ #ifdef _MSC_VER
+ #pragma warning(disable : 4244) // possible loss of data (valid warning, but there is a software check / missing cast)
+ #endif
+}
+
+%define api.token.prefix {TOK_}
+
+%token
+ END 0 "end of file"
+
+ NEWLINE "end of line"
+ COMMA ","
+ COLON ":"
+
+ LPAREN "("
+ RPAREN ")"
+ LBRACKET "["
+ RBRACKET "]"
+ PLUS "+"
+ MINUS "-"
+ MULTIPLY "*"
+ DIVIDE "/"
+ OR "|"
+ AND "&"
+ XOR "^"
+ POST_DECREMENT "--"
+ NOT_EQUAL "!="
+ NOT "!"
+ REVERSE "::"
+ EQUAL "="
+
+ PROGRAM ".program"
+ WRAP_TARGET ".wrap_target"
+ WRAP ".wrap"
+ DEFINE ".define"
+ SIDE_SET ".side_set"
+ WORD ".word"
+ ORIGIN ".origin"
+ LANG_OPT ".lang_opt"
+
+ JMP "jmp"
+ WAIT "wait"
+ IN "in"
+ OUT "out"
+ PUSH "push"
+ PULL "pull"
+ MOV "mov"
+ IRQ "irq"
+ SET "set"
+ NOP "nop"
+
+ PIN "pin"
+ GPIO "gpio"
+ OSRE "osre"
+
+ PINS "pins"
+ NULL "null"
+ PINDIRS "pindirs"
+ BLOCK "block"
+ NOBLOCK "noblock"
+ IFEMPTY "ifempty"
+ IFFULL "iffull"
+ NOWAIT "nowait"
+ CLEAR "clear"
+ REL "rel"
+ X "x"
+ Y "y"
+ EXEC "exec"
+ PC "pc"
+ ISR "isr"
+ OSR "osr"
+ OPTIONAL "opt"
+ SIDE "side"
+ STATUS "status"
+ PUBLIC "public"
+;
+
+%token
+ <std::string> ID "identifier"
+ <std::string> STRING "string"
+ <std::string> NON_WS "text"
+ <std::string> CODE_BLOCK_START "code block"
+ <std::string> CODE_BLOCK_CONTENTS "%}" // bit ugly but if there is no end this is what we will be missing
+ <std::string> UNKNOWN_DIRECTIVE
+ <int> INT "integer"
+;
+
+
+%left REVERSE
+%left PLUS MINUS
+%left MULTIPLY DIVIDE
+%left AND OR XOR
+
+%printer { yyo << "..."; } <*>;
+
+%%
+
+file:
+ lines END { if (pioasm.error_count || pioasm.write_output()) YYABORT; }
+ ;
+
+lines:
+ line
+ | lines NEWLINE line;
+
+line:
+ PROGRAM ID { if (!pioasm.add_program(@$, $2)) { std::stringstream msg; msg << "program " << $2 << " already exists"; error(@$, msg.str()); abort(); } }
+ | directive
+ | instruction { pioasm.get_current_program(@1, "instruction").add_instruction($1); }
+ | label_decl instruction { auto &p = pioasm.get_current_program(@2, "instruction"); p.add_label($1); p.add_instruction($2); }
+ | label_decl { pioasm.get_current_program(@1, "label").add_label($1); }
+ | code_block
+ | %empty
+ | error { if (pioasm.error_count > 6) { std::cerr << "\ntoo many errors; aborting.\n"; YYABORT; } }
+ ;
+
+code_block:
+ CODE_BLOCK_START CODE_BLOCK_CONTENTS { std::string of = $1; if (of.empty()) of = output_format::default_name; pioasm.get_current_program(@$, "code block", false, false).add_code_block( code_block(@$, of, $2)); }
+
+%type <std::shared_ptr<symbol>> label_decl;
+label_decl:
+ symbol_def COLON { $1->is_label = true; $$ = $1; }
+
+directive:
+ DEFINE symbol_def expression { $2->is_label = false; $2->value = $3; pioasm.get_current_program(@1, ".define", false, false).add_symbol($2); }
+ | ORIGIN value { pioasm.get_current_program(@1, ".origin", true).set_origin(@$, $2); }
+ | SIDE_SET value OPTIONAL PINDIRS { pioasm.get_current_program(@1, ".side_set", true).set_sideset(@$, $2, true, true); }
+ | SIDE_SET value OPTIONAL { pioasm.get_current_program(@1, ".side_set", true).set_sideset(@$, $2, true, false); }
+ | SIDE_SET value PINDIRS { pioasm.get_current_program(@1, ".side_set", true).set_sideset(@$, $2, false, true); }
+ | SIDE_SET value { pioasm.get_current_program(@1, ".side_set", true).set_sideset(@$, $2, false, false); }
+ | WRAP_TARGET { pioasm.get_current_program(@1, ".wrap_target").set_wrap_target(@$); }
+ | WRAP { pioasm.get_current_program(@1, ".wrap").set_wrap(@$); }
+ | WORD value { pioasm.get_current_program(@1, "instruction").add_instruction(std::shared_ptr<instruction>(new instr_word(@$, $2))); }
+ | LANG_OPT NON_WS NON_WS EQUAL INT { pioasm.get_current_program(@1, ".lang_opt").add_lang_opt($2, $3, std::to_string($5)); }
+ | LANG_OPT NON_WS NON_WS EQUAL STRING { pioasm.get_current_program(@1, ".lang_opt").add_lang_opt($2, $3, $5); }
+ | LANG_OPT NON_WS NON_WS EQUAL NON_WS { pioasm.get_current_program(@1, ".lang_opt").add_lang_opt($2, $3, $5); }
+ | LANG_OPT error { error(@$, "expected format is .lang_opt language option_name = option_value"); }
+ | UNKNOWN_DIRECTIVE { std::stringstream msg; msg << "unknown directive " << $1; throw syntax_error(@$, msg.str()); }
+ ;
+
+/* value is a more limited top level expression... requiring parenthesis */
+%type <std::shared_ptr<resolvable>> value;
+value: INT { $$ = resolvable_int(@$, $1); }
+ | ID { $$ = std::shared_ptr<resolvable>(new name_ref(@$, $1)); }
+ | LPAREN expression RPAREN { $$ = $2; }
+
+%type <std::shared_ptr<resolvable>> expression;
+expression:
+ value
+ | expression PLUS expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::add, $1, $3)); }
+ | expression MINUS expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::subtract, $1, $3)); }
+ | expression MULTIPLY expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::multiply, $1, $3)); }
+ | expression DIVIDE expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::divide, $1, $3)); }
+ | expression OR expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::or_, $1, $3)); }
+ | expression AND expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::and_, $1, $3)); }
+ | expression XOR expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::xor_, $1, $3)); }
+ | MINUS expression { $$ = std::shared_ptr<unary_operation>(new unary_operation(@$, unary_operation::negate, $2)); }
+ | REVERSE expression { $$ = std::shared_ptr<unary_operation>(new unary_operation(@$, unary_operation::reverse, $2)); }
+
+%type <std::shared_ptr<instruction>> instruction;
+instruction:
+ base_instruction sideset delay { $$ = $1; $$->sideset = $2; $$->delay = $3; }
+ | base_instruction delay sideset { $$ = $1; $$->delay = $2; $$->sideset = $3; }
+ | base_instruction sideset { $$ = $1; $$->sideset = $2; $$->delay = resolvable_int(@$, 0); }
+ | base_instruction delay { $$ = $1; $$->delay = $2; }
+ | base_instruction { $$ = $1; $$->delay = resolvable_int(@$, 0); }
+
+%type <std::shared_ptr<instruction>> base_instruction;
+base_instruction:
+ NOP { $$ = std::shared_ptr<instruction>(new instr_nop(@$)); }
+ | JMP condition comma expression { $$ = std::shared_ptr<instruction>(new instr_jmp(@$, $2, $4)); }
+ | WAIT value wait_source { $$ = std::shared_ptr<instruction>(new instr_wait(@$, $2, $3)); }
+ | WAIT value COMMA value { std::stringstream msg; location l; l.begin = @2.end; l.end = @3.end; msg << "expected irq, gpio or pin after the polarity value and before the \",\""; throw yy::parser::syntax_error(l, msg.str()); }
+ | WAIT wait_source { $$ = std::shared_ptr<instruction>(new instr_wait(@$, resolvable_int(@$, 1), $2)); }
+ | IN in_source comma value { $$ = std::shared_ptr<instruction>(new instr_in(@$, $2, $4)); }
+ | OUT out_target comma value { $$ = std::shared_ptr<instruction>(new instr_out(@$, $2, $4)); }
+ | PUSH if_full blocking { $$ = std::shared_ptr<instruction>(new instr_push(@$, $2, $3)); }
+ | PULL if_empty blocking { $$ = std::shared_ptr<instruction>(new instr_pull(@$, $2, $3)); }
+ | MOV mov_target comma mov_op mov_source { $$ = std::shared_ptr<instruction>(new instr_mov(@$, $2, $5, $4)); }
+ | IRQ irq_modifiers value REL { $$ = std::shared_ptr<instruction>(new instr_irq(@$, $2, $3, true)); }
+ | IRQ irq_modifiers value { $$ = std::shared_ptr<instruction>(new instr_irq(@$, $2, $3)); }
+ | SET set_target comma value { $$ = std::shared_ptr<instruction>(new instr_set(@$, $2, $4)); }
+;
+
+%type <std::shared_ptr<resolvable>> delay;
+delay:
+ LBRACKET expression RBRACKET { $$ = $2; }
+
+%type <std::shared_ptr<resolvable>> sideset;
+sideset:
+ SIDE value { $$ = $2; }
+
+%type <enum condition> condition;
+condition:
+ NOT X { $$ = condition::xz; }
+ | X POST_DECREMENT { $$ = condition::xnz__; }
+ | NOT Y { $$ = condition::yz; }
+ | Y POST_DECREMENT { $$ = condition::ynz__; }
+ | X NOT_EQUAL Y { $$ = condition::xney; }
+ | PIN { $$ = condition::pin; }
+ | NOT OSRE { $$ = condition::osrez; }
+ | %empty { $$ = condition::al; }
+
+%type <std::shared_ptr<wait_source>> wait_source;
+wait_source:
+ IRQ comma value REL { $$ = std::shared_ptr<wait_source>(new wait_source(wait_source::irq, $3, true)); }
+ | IRQ comma value { $$ = std::shared_ptr<wait_source>(new wait_source(wait_source::irq, $3, false)); }
+ | GPIO comma value { $$ = std::shared_ptr<wait_source>(new wait_source(wait_source::gpio, $3)); }
+ | PIN comma value { $$ = std::shared_ptr<wait_source>(new wait_source(wait_source::pin, $3)); }
+
+comma: COMMA | %empty /* not a huge fan of forcing commas */
+
+%type <enum in_out_set> in_source;
+in_source: PINS { $$ = in_out_set::in_out_set_pins; }
+ | X { $$ = in_out_set::in_out_set_x; }
+ | Y { $$ = in_out_set::in_out_set_y; }
+ | NULL { $$ = in_out_set::in_out_null; }
+ | ISR { $$ = in_out_set::in_out_isr; }
+ | OSR { $$ = in_out_set::in_osr; }
+ | STATUS { $$ = in_out_set::in_status; }
+
+%type <enum in_out_set> out_target;
+out_target: PINS { $$ = in_out_set::in_out_set_pins; }
+ | X { $$ = in_out_set::in_out_set_x; }
+ | Y { $$ = in_out_set::in_out_set_y; }
+ | NULL { $$ = in_out_set::in_out_null; }
+ | PINDIRS { $$ = in_out_set::in_out_set_pindirs; }
+ | ISR { $$ = in_out_set::in_out_isr; }
+ | PC { $$ = in_out_set::out_set_pc; }
+ | EXEC { $$ = in_out_set::out_exec; }
+
+%type <enum mov> mov_target;
+mov_target: PINS { $$ = mov::pins; }
+ | X { $$ = mov::x; }
+ | Y { $$ = mov::y; }
+ | EXEC { $$ = mov::exec; }
+ | PC { $$ = mov::pc; }
+ | ISR { $$ = mov::isr; }
+ | OSR { $$ = mov::osr; }
+
+%type <enum mov> mov_source;
+mov_source: PINS { $$ = mov::pins; }
+ | X { $$ = mov::x; }
+ | Y { $$ = mov::y; }
+ | NULL { $$ = mov::null; }
+ | STATUS { $$ = mov::status; }
+ | ISR { $$ = mov::isr; }
+ | OSR { $$ = mov::osr; }
+
+%type <enum mov_op> mov_op;
+mov_op:
+ NOT { $$ = mov_op::invert; }
+ | REVERSE { $$ = mov_op::bit_reverse; }
+ | %empty { $$ = mov_op::none; }
+
+%type <enum in_out_set> set_target;
+set_target:
+ PINS { $$ = in_out_set::in_out_set_pins; }
+ | X { $$ = in_out_set::in_out_set_x; }
+ | Y { $$ = in_out_set::in_out_set_y; }
+ | PINDIRS { $$ = in_out_set::in_out_set_pindirs; }
+
+%type <bool> if_full;
+if_full:
+ IFFULL { $$ = true; }
+ | %empty { $$ = false; }
+
+%type <bool> if_empty;
+if_empty:
+ IFEMPTY { $$ = true; }
+ | %empty { $$ = false; }
+
+%type <bool> blocking;
+blocking:
+ BLOCK { $$ = true; }
+ | NOBLOCK { $$ = false; }
+ | %empty { $$ = true; }
+
+%type <enum irq> irq_modifiers;
+irq_modifiers:
+ CLEAR { $$ = irq::clear; }
+ | WAIT { $$ = irq::set_wait; }
+ | NOWAIT { $$ = irq::set; }
+ | SET { $$ = irq::set; }
+ | %empty { $$ = irq::set; }
+
+%type <std::shared_ptr<symbol>> symbol_def;
+symbol_def:
+ ID { $$ = std::shared_ptr<symbol>(new symbol(@$, $1)); }
+ | PUBLIC ID { $$ = std::shared_ptr<symbol>(new symbol(@$, $2, true)); }
+ | MULTIPLY ID { $$ = std::shared_ptr<symbol>(new symbol(@$, $2, true)); }
+
+%%
+void yy::parser::error(const location_type& l, const std::string& m)
+{
+ if (l.begin.filename) {
+ std::cerr << l << ": " << m << '\n';
+ pioasm.error_count++;
+ if (l.begin.line == l.end.line && *l.begin.filename == *l.end.filename) {
+ std::ifstream file(l.begin.filename->c_str());
+ std::string line;
+ for(int i = 0; i < l.begin.line; ++i) {
+ std::getline(file, line);
+ }
+ fprintf(stderr, "%5d | %s\n", l.begin.line, line.c_str());
+ fprintf(stderr, "%5s | %*s", "", l.begin.column, "^");
+ for (int i = l.begin.column; i < l.end.column - 1; i++) {
+ putc ('~', stderr);
+ }
+ putc ('\n', stderr);
+ }
+ } else {
+ std::cerr << m << '\n';
+ }
+}
+