From ddf46ce8fd860ce5b4ab67079a78f510be3c9048 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sun, 3 Sep 2023 04:46:34 +0000 Subject: [PATCH] stmt_ins: refactor The overall intent is to make writing a decompiler require less code duplication. "bits.hpp" and "stmt_enum.hpp" are replaced with "stmt_ins.hpp" which is generated directly from dsp-notes.csv. --- .gitignore | 3 +- Makefile | 2 +- ast_emitter.cpp | 58 +- ast_emitter.hpp | 15 +- ast_printer.cpp | 108 +- ast_printer.hpp | 14 +- ast_resolver.cpp | 54 +- ast_resolver.hpp | 13 +- bits.hpp | 222 --- control_word.hpp | 84 ++ dsp-notes.csv | 158 +++ dsp-notes.ods | Bin 44902 -> 36041 bytes error.hpp | 6 + .../build_radix_tree.py | 0 gen/generate.py | 24 + gen/generate_notes.py | 241 ++++ gen/parse_notes.py | 128 ++ gen/template.cpp | 187 +++ imm.hpp | 47 + ins.hpp | 45 + parser.cpp | 215 +-- parser.hpp | 12 +- stmt.hpp | 387 +---- stmt_base.hpp | 25 + stmt_enum.hpp | 102 -- stmt_ins.hpp | 1264 +++++++++++++++++ stmt_string.cpp | 125 +- stmt_string.hpp | 7 +- test/Makefile | 12 +- token.hpp | 4 +- visitable.hpp | 14 +- visitor.hpp | 14 +- 32 files changed, 2683 insertions(+), 907 deletions(-) delete mode 100644 bits.hpp create mode 100644 control_word.hpp create mode 100644 dsp-notes.csv rename build_radix_tree.py => gen/build_radix_tree.py (100%) create mode 100644 gen/generate.py create mode 100644 gen/generate_notes.py create mode 100644 gen/parse_notes.py create mode 100644 gen/template.cpp create mode 100644 imm.hpp create mode 100644 ins.hpp create mode 100644 stmt_base.hpp delete mode 100644 stmt_enum.hpp create mode 100644 stmt_ins.hpp diff --git a/.gitignore b/.gitignore index dd411da..ff325b4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ scu-dsp-asm.* *.d test/*.s test/*.txt -*.bin \ No newline at end of file +*.bin +__pycache__ \ No newline at end of file diff --git a/Makefile b/Makefile index 824bebf..99aa9f9 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CXXFLAGS = -Og -g -Wall -Wextra -Werror -Wfatal-errors -Wno-c99-designator -std= LDFLAGS = TARGET ?= -CXX = $(TARGET)g++ +CXX = $(TARGET)clang++ SRC = main.cpp SRC += lexer.cpp diff --git a/ast_emitter.cpp b/ast_emitter.cpp index 1d660ee..f3556c7 100644 --- a/ast_emitter.cpp +++ b/ast_emitter.cpp @@ -89,9 +89,59 @@ uint32_t emitter_t::visit(const unary_t * unary) const // instructions -uint32_t emitter_t::visit(const op::alu_t * alu) const +uint32_t emitter_t::visit(const op::andl_t * andl) const { - return alu->code() | alu->bits(); + return andl->code() | andl->bits(); +} + +uint32_t emitter_t::visit(const op::orl_t * orl) const +{ + return orl->code() | orl->bits(); +} + +uint32_t emitter_t::visit(const op::xorl_t * xorl) const +{ + return xorl->code() | xorl->bits(); +} + +uint32_t emitter_t::visit(const op::add_t * add) const +{ + return add->code() | add->bits(); +} + +uint32_t emitter_t::visit(const op::sub_t * sub) const +{ + return sub->code() | sub->bits(); +} + +uint32_t emitter_t::visit(const op::ad2_t * ad2) const +{ + return ad2->code() | ad2->bits(); +} + +uint32_t emitter_t::visit(const op::sr_t * sr) const +{ + return sr->code() | sr->bits(); +} + +uint32_t emitter_t::visit(const op::rr_t * rr) const +{ + return rr->code() | rr->bits(); +} + +uint32_t emitter_t::visit(const op::sl_t * sl) const +{ + return sl->code() | sl->bits(); +} + +uint32_t emitter_t::visit(const op::rl_t * rl) const +{ + return rl->code() | rl->bits(); +} + +uint32_t emitter_t::visit(const op::rl8_t * rl8) const +{ + return rl8->code() | rl8->bits(); } uint32_t emitter_t::visit(const op::mov_ram_x_t * mov_ram_x) const @@ -146,7 +196,9 @@ uint32_t emitter_t::visit(const op::mov_ram_d1_t * mov_ram_d1) const uint32_t emitter_t::visit(const op::control_word_t * control_word) const { uint32_t word = control_word->code() | control_word->bits(); - for (auto& op : control_word->ops) { word |= dynamic_cast(op)->accept(this); } + for (const auto& op : control_word->ops) { + word |= std::visit([*this](auto&& arg) -> uint32_t { return (arg).accept(this); }, op); + } return word; } diff --git a/ast_emitter.hpp b/ast_emitter.hpp index 61a179a..b5615ef 100644 --- a/ast_emitter.hpp +++ b/ast_emitter.hpp @@ -7,6 +7,8 @@ #include "visitor.hpp" #include "expr.hpp" #include "stmt.hpp" +#include "stmt_ins.hpp" +#include "control_word.hpp" #include "ast.hpp" namespace dsp { @@ -33,7 +35,18 @@ struct emitter_t : visitor_t uint32_t visit(const literal_t * literal) const; uint32_t visit(const unary_t * unary) const; - uint32_t visit(const op::alu_t * alu) const; + uint32_t visit(const op::andl_t * andl) const; + uint32_t visit(const op::orl_t * orl) const; + uint32_t visit(const op::xorl_t * xorl) const; + uint32_t visit(const op::add_t * add) const; + uint32_t visit(const op::sub_t * sub) const; + uint32_t visit(const op::ad2_t * ad2) const; + uint32_t visit(const op::sr_t * sr) const; + uint32_t visit(const op::rr_t * rr) const; + uint32_t visit(const op::sl_t * sl) const; + uint32_t visit(const op::rl_t * rl) const; + uint32_t visit(const op::rl8_t * rl8) const; + uint32_t visit(const op::mov_ram_x_t * mov_ram_x) const; uint32_t visit(const op::mov_mul_p_t * mov_mul_p) const; uint32_t visit(const op::mov_ram_p_t * mov_ram_p) const; diff --git a/ast_printer.cpp b/ast_printer.cpp index 06c73ce..7da7a01 100644 --- a/ast_printer.cpp +++ b/ast_printer.cpp @@ -1,5 +1,6 @@ #include "ast_printer.hpp" #include "stmt_string.hpp" +#include "control_word.hpp" namespace dsp { @@ -96,14 +97,75 @@ void printer_t::parenthesize(const std::string_view s, const expr_t * a, const e // instructions -void printer_t::visit(const op::alu_t * alu) const +void printer_t::visit(const op::andl_t * andl) const { - parenthesize(op::alu_type_string[static_cast(alu->type)]); + (void)andl; + parenthesize("andl"); +} + +void printer_t::visit(const op::orl_t * orl) const +{ + (void)orl; + parenthesize("orl"); +} + +void printer_t::visit(const op::xorl_t * xorl) const +{ + (void)xorl; + parenthesize("xorl"); +} + +void printer_t::visit(const op::add_t * add) const +{ + (void)add; + parenthesize("add"); +} + +void printer_t::visit(const op::sub_t * sub) const +{ + (void)sub; + parenthesize("sub"); +} + +void printer_t::visit(const op::ad2_t * ad2) const +{ + (void)ad2; + parenthesize("ad2"); +} + +void printer_t::visit(const op::sr_t * sr) const +{ + (void)sr; + parenthesize("sr"); +} + +void printer_t::visit(const op::rr_t * rr) const +{ + (void)rr; + parenthesize("rr"); +} + +void printer_t::visit(const op::sl_t * sl) const +{ + (void)sl; + parenthesize("sl"); +} + +void printer_t::visit(const op::rl_t * rl) const +{ + (void)rl; + parenthesize("rl"); +} + +void printer_t::visit(const op::rl8_t * rl8) const +{ + (void)rl8; + parenthesize("rl8"); } void printer_t::visit(const op::mov_ram_x_t * mov_ram_x) const { - parenthesize("mov", op::xy_src_string[static_cast(mov_ram_x->src)], "x"); + parenthesize("mov", op::x_src_string[static_cast(mov_ram_x->src.value)], "x"); } void printer_t::visit(const op::mov_mul_p_t * mov_mul_p) const @@ -114,12 +176,12 @@ void printer_t::visit(const op::mov_mul_p_t * mov_mul_p) const void printer_t::visit(const op::mov_ram_p_t * mov_ram_p) const { - parenthesize("mov", op::xy_src_string[static_cast(mov_ram_p->src)], "p"); + parenthesize("mov", op::x_src_string[static_cast(mov_ram_p->src.value)], "p"); } void printer_t::visit(const op::mov_ram_y_t * mov_ram_y) const { - parenthesize("mov", op::xy_src_string[static_cast(mov_ram_y->src)], "y"); + parenthesize("mov", op::y_src_string[static_cast(mov_ram_y->src.value)], "y"); } void printer_t::visit(const op::clr_a_t * clr_a) const @@ -136,28 +198,28 @@ void printer_t::visit(const op::mov_alu_a_t * mov_alu_a) const void printer_t::visit(const op::mov_ram_a_t * mov_ram_a) const { - parenthesize("mov", op::xy_src_string[static_cast(mov_ram_a->src)], "a"); + parenthesize("mov", op::y_src_string[static_cast(mov_ram_a->src.value)], "a"); } void printer_t::visit(const op::mov_imm_d1_t * mov_imm_d1) const { parenthesize("mov", mov_imm_d1->imm.expr, - op::d1_dest_string[static_cast(mov_imm_d1->dest)]); + op::d1_dst_string[static_cast(mov_imm_d1->dst.value)]); } void printer_t::visit(const op::mov_ram_d1_t * mov_ram_d1) const { parenthesize("mov", - op::d1_src_string[static_cast(mov_ram_d1->src)], - op::d1_dest_string[static_cast(mov_ram_d1->dest)]); + op::d1_src_string[static_cast(mov_ram_d1->src.value)], + op::d1_dst_string[static_cast(mov_ram_d1->dst.value)]); } void printer_t::visit(const op::control_word_t * control_word) const { os << "(control_word "; for (const auto& op : control_word->ops) { - dynamic_cast(op)->accept(this); + std::visit([*this](auto&& arg){ (arg).accept(this); }, op); os << ' '; } os << ')'; @@ -165,27 +227,27 @@ void printer_t::visit(const op::control_word_t * control_word) const void printer_t::visit(const load::mvi_t * mvi) const { - parenthesize("mvi", mvi->imm.expr, load::dest_string[static_cast(mvi->dest)]); + parenthesize("mvi", mvi->imm.expr, load::dst_string[static_cast(mvi->dst.value)]); } void printer_t::visit(const load::mvi_cond_t * mvi_cond) const { parenthesize("mvi", mvi_cond->imm.expr, - load::dest_string[static_cast(mvi_cond->dest)], - load::cond_string[static_cast(mvi_cond->cond)]); + load::dst_string[static_cast(mvi_cond->dst.value)], + load::cond_string[static_cast(mvi_cond->cond.value)]); } -static std::string dma_hold_add(bool hold, dma::add_mode_t add) +static std::string dma_hold_add(dma::hold_t hold, dma::add_t add) { - return dma::hold_mode_string[static_cast(hold)] - + dma::add_mode_string[static_cast(add)]; + return dma::hold_mode_string[static_cast(hold.value)] + + dma::add_mode_string[static_cast(add.value)]; } void printer_t::visit(const dma::src_d0_imm_t * src_d0_imm) const { parenthesize(dma_hold_add(src_d0_imm->hold, src_d0_imm->add), - dma::src_string[static_cast(src_d0_imm->src)], + dma::src_string[static_cast(src_d0_imm->src.value)], "d0", src_d0_imm->imm.expr); } @@ -194,24 +256,24 @@ void printer_t::visit(const dma::d0_dst_imm_t * d0_dst_imm) const { parenthesize(dma_hold_add(d0_dst_imm->hold, d0_dst_imm->add), "d0", - dma::dst_string[static_cast(d0_dst_imm->dst)], + dma::dst_string[static_cast(d0_dst_imm->dst.value)], d0_dst_imm->imm.expr); } void printer_t::visit(const dma::src_d0_ram_t * src_d0_ram) const { parenthesize(dma_hold_add(src_d0_ram->hold, src_d0_ram->add), - dma::src_string[static_cast(src_d0_ram->src)], + dma::src_string[static_cast(src_d0_ram->src.value)], "d0", - dma::length_ram_string[static_cast(src_d0_ram->ram)]); + dma::length_ram_string[static_cast(src_d0_ram->ram.value)]); } void printer_t::visit(const dma::d0_dst_ram_t * d0_dst_ram) const { parenthesize(dma_hold_add(d0_dst_ram->hold, d0_dst_ram->add), "d0", - dma::dst_string[static_cast(d0_dst_ram->dst)], - dma::length_ram_string[static_cast(d0_dst_ram->ram)]); + dma::dst_string[static_cast(d0_dst_ram->dst.value)], + dma::length_ram_string[static_cast(d0_dst_ram->ram.value)]); } void printer_t::visit(const jump::jmp_t * jmp) const @@ -222,7 +284,7 @@ void printer_t::visit(const jump::jmp_t * jmp) const void printer_t::visit(const jump::jmp_cond_t * jmp_cond) const { parenthesize("jmp", - jump::cond_string[static_cast(jmp_cond->cond)], + jump::cond_string[static_cast(jmp_cond->cond.value)], jmp_cond->imm.expr); } diff --git a/ast_printer.hpp b/ast_printer.hpp index 5f76ae2..e762228 100644 --- a/ast_printer.hpp +++ b/ast_printer.hpp @@ -7,6 +7,7 @@ #include "expr.hpp" #include "num.hpp" #include "stmt.hpp" +#include "stmt_ins.hpp" namespace dsp { @@ -25,7 +26,18 @@ struct printer_t : visitor_t void visit(const literal_t * literal) const; void visit(const unary_t * unary) const; - void visit(const op::alu_t * alu) const; + void visit(const op::andl_t * andl) const; + void visit(const op::orl_t * orl) const; + void visit(const op::xorl_t * xorl) const; + void visit(const op::add_t * add) const; + void visit(const op::sub_t * sub) const; + void visit(const op::ad2_t * ad2) const; + void visit(const op::sr_t * sr) const; + void visit(const op::rr_t * rr) const; + void visit(const op::sl_t * sl) const; + void visit(const op::rl_t * rl) const; + void visit(const op::rl8_t * rl8) const; + void visit(const op::mov_ram_x_t * mov_ram_x) const; void visit(const op::mov_mul_p_t * mov_mul_p) const; void visit(const op::mov_ram_p_t * mov_ram_p) const; diff --git a/ast_resolver.cpp b/ast_resolver.cpp index e9ace90..47d97e4 100644 --- a/ast_resolver.cpp +++ b/ast_resolver.cpp @@ -33,9 +33,59 @@ void resolver_t::visit(const unary_t * unary) const // instructions -void resolver_t::visit(const op::alu_t * alu) const +void resolver_t::visit(const op::andl_t * andl) const { - (void)alu; + (void)andl; +} + +void resolver_t::visit(const op::orl_t * orl) const +{ + (void)orl; +} + +void resolver_t::visit(const op::xorl_t * xorl) const +{ + (void)xorl; +} + +void resolver_t::visit(const op::add_t * add) const +{ + (void)add; +} + +void resolver_t::visit(const op::sub_t * sub) const +{ + (void)sub; +} + +void resolver_t::visit(const op::ad2_t * ad2) const +{ + (void)ad2; +} + +void resolver_t::visit(const op::sr_t * sr) const +{ + (void)sr; +} + +void resolver_t::visit(const op::rr_t * rr) const +{ + (void)rr; +} + +void resolver_t::visit(const op::sl_t * sl) const +{ + (void)sl; +} + +void resolver_t::visit(const op::rl_t * rl) const +{ + (void)rl; +} + +void resolver_t::visit(const op::rl8_t * rl8) const +{ + (void)rl8; } void resolver_t::visit(const op::mov_ram_x_t * mov_ram_x) const diff --git a/ast_resolver.hpp b/ast_resolver.hpp index 82cb7ae..1cacc90 100644 --- a/ast_resolver.hpp +++ b/ast_resolver.hpp @@ -37,7 +37,18 @@ struct resolver_t : visitor_t void visit(const literal_t * literal) const; void visit(const unary_t * unary) const; - void visit(const op::alu_t * alu) const; + void visit(const op::andl_t * andl) const; + void visit(const op::orl_t * orl) const; + void visit(const op::xorl_t * xorl) const; + void visit(const op::add_t * add) const; + void visit(const op::sub_t * sub) const; + void visit(const op::ad2_t * ad2) const; + void visit(const op::sr_t * sr) const; + void visit(const op::rr_t * rr) const; + void visit(const op::sl_t * sl) const; + void visit(const op::rl_t * rl) const; + void visit(const op::rl8_t * rl8) const; + void visit(const op::mov_ram_x_t * mov_ram_x) const; void visit(const op::mov_mul_p_t * mov_mul_p) const; void visit(const op::mov_ram_p_t * mov_ram_p) const; diff --git a/bits.hpp b/bits.hpp deleted file mode 100644 index cc6f34d..0000000 --- a/bits.hpp +++ /dev/null @@ -1,222 +0,0 @@ -namespace dsp { - -namespace op { - -static uint32_t alu_bits(alu_type_t type) -{ - using enum alu_type_t; - switch (type) { - case alu_type_t::andl: return 0b0001 << 26; - case alu_type_t::orl: return 0b0010 << 26; - case alu_type_t::xorl: return 0b0011 << 26; - case alu_type_t::add: return 0b0100 << 26; - case alu_type_t::sub: return 0b0101 << 26; - case alu_type_t::ad2: return 0b0110 << 26; - case alu_type_t::sr: return 0b1000 << 26; - case alu_type_t::rr: return 0b1001 << 26; - case alu_type_t::sl: return 0b1010 << 26; - case alu_type_t::rl: return 0b1011 << 26; - case alu_type_t::rl8: return 0b1111 << 26; - default: __builtin_unreachable(); - } -} - -static uint32_t xy_src_bits(xy_src_t src, int shift) -{ - using enum xy_src_t; - - switch (src) { - case m0: return 0b000 << shift; - case m1: return 0b001 << shift; - case m2: return 0b010 << shift; - case m3: return 0b011 << shift; - case mc0: return 0b100 << shift; - case mc1: return 0b101 << shift; - case mc2: return 0b110 << shift; - case mc3: return 0b111 << shift; - default: __builtin_unreachable(); - } -} - -static uint32_t d1_dest_bits(d1_dest_t dest) -{ - using enum d1_dest_t; - - switch (dest) { - case mc0: return 0b0000 << 8; - case mc1: return 0b0001 << 8; - case mc2: return 0b0010 << 8; - case mc3: return 0b0011 << 8; - case rx: return 0b0100 << 8; - case pl: return 0b0101 << 8; - case ra0: return 0b0110 << 8; - case wa0: return 0b0111 << 8; - case lop: return 0b1010 << 8; - case top: return 0b1011 << 8; - case ct0: return 0b1100 << 8; - case ct1: return 0b1101 << 8; - case ct2: return 0b1110 << 8; - case ct3: return 0b1111 << 8; - default: __builtin_unreachable(); - } -} - -static uint32_t d1_src_bits(d1_src_t src) -{ - using enum d1_src_t; - - switch (src) { - case m0: return 0b0000 << 0; - case m1: return 0b0001 << 0; - case m2: return 0b0010 << 0; - case m3: return 0b0011 << 0; - case mc0: return 0b0100 << 0; - case mc1: return 0b0101 << 0; - case mc2: return 0b0110 << 0; - case mc3: return 0b0111 << 0; - case all: return 0b1001 << 0; - case alh: return 0b1010 << 0; - default: __builtin_unreachable(); - } -} - -} // op - -namespace load { - -static uint32_t dest_bits(dest_t dest) -{ - using enum dest_t; - - switch (dest) { - case mc0: return 0b0000 << 26; - case mc1: return 0b0001 << 26; - case mc2: return 0b0010 << 26; - case mc3: return 0b0011 << 26; - case rx: return 0b0100 << 26; - case pl: return 0b0101 << 26; - case ra0: return 0b0110 << 26; - case wa0: return 0b0111 << 26; - case lop: return 0b1010 << 26; - case pc: return 0b1100 << 26; - default: __builtin_unreachable(); - } -} - -static uint32_t cond_bits(cond_t cond) -{ - using enum cond_t; - - switch (cond) { - case z: return 0b1'0'0001 << 19; - case nz: return 0b0'0'0001 << 19; - case s: return 0b1'0'0010 << 19; - case ns: return 0b0'0'0010 << 19; - case c: return 0b1'0'0100 << 19; - case nc: return 0b0'0'0100 << 19; - case t0: return 0b1'0'1000 << 19; - case nt0: return 0b0'0'1000 << 19; - case zs: return 0b1'0'0011 << 19; - case nzs: return 0b0'0'0011 << 19; - default: __builtin_unreachable(); - } -} - -} // load - -namespace dma { - -static uint32_t add_mode_bits(add_mode_t add) -{ - using enum add_mode_t; - - switch (add) { - case _0 : return 0b000 << 15; - case _1 : return 0b001 << 15; - case _2 : return 0b010 << 15; - case _4 : return 0b011 << 15; - case _8 : return 0b100 << 15; - case _16: return 0b101 << 15; - case _32: return 0b110 << 15; - case _64: return 0b111 << 15; - default: __builtin_unreachable(); - } -} - -static uint32_t hold_bits(bool hold) -{ - return hold ? (1 << 14) - : (0 << 14) - ; -} - -static uint32_t src_bits(src_t src) -{ - using enum src_t; - - switch (src) { - case mc0: return 0b000 << 8; - case mc1: return 0b001 << 8; - case mc2: return 0b010 << 8; - case mc3: return 0b011 << 8; - default: __builtin_unreachable(); - } -} - -static uint32_t dst_bits(dst_t dst) -{ - using enum dst_t; - - switch (dst) { - case mc0: return 0b000 << 8; - case mc1: return 0b001 << 8; - case mc2: return 0b010 << 8; - case mc3: return 0b011 << 8; - case prg: return 0b100 << 8; - default: __builtin_unreachable(); - } -} - -static uint32_t length_ram_bits(length_ram_t ram) -{ - using enum length_ram_t; - - switch (ram) { - case m0 : return 0b000 << 0; - case m1 : return 0b001 << 0; - case m2 : return 0b010 << 0; - case m3 : return 0b011 << 0; - case mc0: return 0b100 << 0; - case mc1: return 0b101 << 0; - case mc2: return 0b110 << 0; - case mc3: return 0b111 << 0; - default: __builtin_unreachable(); - } -} - -} // dma - -namespace jump { - -static uint32_t cond_bits(cond_t cond) -{ - using enum cond_t; - - switch (cond) { - case z : return 0b100'001 << 19; - case nz : return 0b000'001 << 19; - case s : return 0b100'010 << 19; - case ns : return 0b000'010 << 19; - case c : return 0b100'100 << 19; - case nc : return 0b000'100 << 19; - case t0 : return 0b101'000 << 19; - case nt0: return 0b001'000 << 19; - case zs : return 0b100'011 << 19; - case nzs: return 0b000'011 << 19; - default: __builtin_unreachable(); - } -} - -} // jump - -} // dsp diff --git a/control_word.hpp b/control_word.hpp new file mode 100644 index 0000000..c58f773 --- /dev/null +++ b/control_word.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include +#include +#include +#include + +#include "stmt_base.hpp" +#include "stmt_ins.hpp" + +namespace dsp { + +namespace op { +using op_t = std::variant; + +struct control_word_t : stmt_accept_t +{ + control_word_t(std::vector ops) + : ops(ops) + { + } + + std::vector build_ops(uint32_t code) + { + std::vector ops; + if (andl_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (orl_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (xorl_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (add_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (sub_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (ad2_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (sr_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (rr_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (sl_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (rl_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (rl8_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (mov_ram_x_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (mov_mul_p_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (mov_ram_p_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (mov_ram_y_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (clr_a_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (mov_alu_a_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (mov_ram_a_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (mov_imm_d1_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else if (mov_ram_d1_t::pred(code)) ops.emplace_back(op_t{std::in_place_type, code}); + else { + std::cerr << "invalid control word code: " << (code) << std::endl; + throw std::runtime_error("invalid control word code"); + } + return ops; + } + + control_word_t(uint32_t code) + : ops(build_ops(code)) {} + + const std::vector ops; + + uint32_t mask() const { return 0b11 << 30; } + uint32_t code() const { return 0b00 << 30; } + uint32_t bits() const { return 0; } +}; + +} + +} diff --git a/dsp-notes.csv b/dsp-notes.csv new file mode 100644 index 0000000..d40b7bf --- /dev/null +++ b/dsp-notes.csv @@ -0,0 +1,158 @@ +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0, +"OP",,,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,"ALU",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"struct andl",,,0,0,0,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1 +,,"struct orl",,,0,0,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,2 +,,"struct xorl",,,0,0,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,3 +,,"struct add",,,0,1,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,4 +,,"struct sub",,,0,1,0,1,,,,,,,,,,,,,,,,,,,,,,,,,,,5 +,,"struct ad2",,,0,1,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,6 +,,"struct sr",,,1,0,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,8 +,,"struct rr",,,1,0,0,1,,,,,,,,,,,,,,,,,,,,,,,,,,,9 +,,"struct sl",,,1,0,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,10 +,,"struct rl",,,1,0,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,11 +,,"struct rl8",,,1,1,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,15 +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,"X-bus","enum x_src",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"m0",,,,,,,,,,0,0,0,,,,,,,,,,,,,,,,,,,,, +,,"m1",,,,,,,,,,0,0,1,,,,,,,,,,,,,,,,,,,,, +,,"m2",,,,,,,,,,0,1,0,,,,,,,,,,,,,,,,,,,,, +,,"m3",,,,,,,,,,0,1,1,,,,,,,,,,,,,,,,,,,,, +,,"mc0",,,,,,,,,,1,0,0,,,,,,,,,,,,,,,,,,,,, +,,"mc1",,,,,,,,,,1,0,1,,,,,,,,,,,,,,,,,,,,, +,,"mc2",,,,,,,,,,1,1,0,,,,,,,,,,,,,,,,,,,,, +,,"mc3",,,,,,,,,,1,1,1,,,,,,,,,,,,,,,,,,,,, +,,"struct mov_ram_x",,,,,,,1,,,"x_src",,,,,,,,,,,,,,,,,,,,,,, +,,"struct mov_mul_p",,,,,,,,1,0,,,,,,,,,,,,,,,,,,,,,,,, +,,"struct mov_ram_p",,,,,,,,1,1,"x_src",,,,,,,,,,,,,,,,,,,,,,, +,"Y-bus","enum y_src",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"m0",,,,,,,,,,,,,,,,0,0,0,,,,,,,,,,,,,,, +,,"m1",,,,,,,,,,,,,,,,0,0,1,,,,,,,,,,,,,,, +,,"m2",,,,,,,,,,,,,,,,0,1,0,,,,,,,,,,,,,,, +,,"m3",,,,,,,,,,,,,,,,0,1,1,,,,,,,,,,,,,,, +,,"mc0",,,,,,,,,,,,,,,,1,0,0,,,,,,,,,,,,,,, +,,"mc1",,,,,,,,,,,,,,,,1,0,1,,,,,,,,,,,,,,, +,,"mc2",,,,,,,,,,,,,,,,1,1,0,,,,,,,,,,,,,,, +,,"mc3",,,,,,,,,,,,,,,,1,1,1,,,,,,,,,,,,,,, +,,"struct mov_ram_y",,,,,,,,,,,,,1,,,"y_src",,,,,,,,,,,,,,,,, +,,"struct clr_a",,,,,,,,,,,,,,0,1,,,,,,,,,,,,,,,,,, +,,"struct mov_alu_a",,,,,,,,,,,,,,1,0,,,,,,,,,,,,,,,,,, +,,"struct mov_ram_a",,,,,,,,,,,,,,1,1,"y_src",,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0, +,"D1-bus","enum d1_src",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"m0",,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,0,0,0,0 +,,"m1",,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,0,0,1,1 +,,"m2",,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,0,1,0,2 +,,"m3",,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,0,1,1,3 +,,"mc0",,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,1,0,0,4 +,,"mc1",,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,1,0,1,5 +,,"mc2",,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,1,1,0,6 +,,"mc3",,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,1,1,1,7 +,,"all",,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,0,0,1,9 +,,"alh",,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,0,1,0,10 +,,"enum d1_dst",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"mc0",,,,,,,,,,,,,,,,,,,,,0,0,0,0,,,,,,,,,0 +,,"mc1",,,,,,,,,,,,,,,,,,,,,0,0,0,1,,,,,,,,,1 +,,"mc2",,,,,,,,,,,,,,,,,,,,,0,0,1,0,,,,,,,,,2 +,,"mc3",,,,,,,,,,,,,,,,,,,,,0,0,1,1,,,,,,,,,3 +,,"rx",,,,,,,,,,,,,,,,,,,,,0,1,0,0,,,,,,,,,4 +,,"pl",,,,,,,,,,,,,,,,,,,,,0,1,0,1,,,,,,,,,5 +,,"ra0",,,,,,,,,,,,,,,,,,,,,0,1,1,0,,,,,,,,,6 +,,"wa0",,,,,,,,,,,,,,,,,,,,,0,1,1,1,,,,,,,,,7 +,,"lop",,,,,,,,,,,,,,,,,,,,,1,0,1,0,,,,,,,,,10 +,,"top",,,,,,,,,,,,,,,,,,,,,1,0,1,1,,,,,,,,,11 +,,"ct0",,,,,,,,,,,,,,,,,,,,,1,1,0,0,,,,,,,,,12 +,,"ct1",,,,,,,,,,,,,,,,,,,,,1,1,0,1,,,,,,,,,13 +,,"ct2",,,,,,,,,,,,,,,,,,,,,1,1,1,0,,,,,,,,,14 +,,"ct3",,,,,,,,,,,,,,,,,,,,,1,1,1,1,,,,,,,,,15 +,,"struct mov_imm_d1",,,,,,,,,,,,,,,,,,,0,1,"d1_dst",,,,"imm",,,,,,,, +,,"struct mov_ram_d1",,,,,,,,,,,,,,,,,,,1,1,"d1_dst",,,,,,,,"d1_src",,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0, +"LOAD",,"struct mvi",1,0,"dst",,,,0,"imm",,,,,,,,,,,,,,,,,,,,,,,,, +,"conditional","struct mvi_cond",1,0,"dst",,,,1,"cond",,,,,,"imm",,,,,,,,,,,,,,,,,,, +,,"enum cond",,,,,,,,"N",,"T0","C","S","Z",,,,,,,,,,,,,,,,,,,, +,,"z",,,,,,,,1,0,0,0,0,1,,,,,,,,,,,,,,,,,,,, +,,"nz",,,,,,,,0,0,0,0,0,1,,,,,,,,,,,,,,,,,,,, +,,"s",,,,,,,,1,0,0,0,1,0,,,,,,,,,,,,,,,,,,,, +,,"ns",,,,,,,,0,0,0,0,1,0,,,,,,,,,,,,,,,,,,,, +,,"c",,,,,,,,1,0,0,1,0,0,,,,,,,,,,,,,,,,,,,, +,,"nc",,,,,,,,0,0,0,1,0,0,,,,,,,,,,,,,,,,,,,, +,,"t0",,,,,,,,1,0,1,0,0,0,,,,,,,,,,,,,,,,,,,, +,,"nt0",,,,,,,,0,0,1,0,0,0,,,,,,,,,,,,,,,,,,,, +,,"zs",,,,,,,,1,0,0,0,1,1,,,,,,,,,,,,,,,,,,,, +,,"nzs",,,,,,,,0,0,0,0,1,1,,,,,,,,,,,,,,,,,,,, +,,"enum dst",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"mc0",,,0,0,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,0 +,,"mc1",,,0,0,0,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1 +,,"mc2",,,0,0,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,2 +,,"mc3",,,0,0,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,3 +,,"rx",,,0,1,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,4 +,,"pl",,,0,1,0,1,,,,,,,,,,,,,,,,,,,,,,,,,,,5 +,,"ra0",,,0,1,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,6 +,,"wa0",,,0,1,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,7 +,,"lop",,,1,0,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,10 +,,"pc",,,1,1,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,12 +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0, +"DMA",,,,,,,,,,,,,,,,,,,,"H","L","D",,,,,,,,,,,,, +,"imm","struct d0_dst_imm",1,1,0,0,,,,,,,,,,,"add",,,"hold",0,0,,"dst",,,"imm",,,,,,,, +,,"struct src_d0_imm",1,1,0,0,,,,,,,,,,,"add",,,"hold",0,1,,"src",,,"imm",,,,,,,, +,"ram","struct d0_dst_ram",1,1,0,0,,,,,,,,,,,"add",,,"hold",1,0,,"dst",,,,,,,,"ram",,, +,,"struct src_d0_ram",1,1,0,0,,,,,,,,,,,"add",,,"hold",1,1,,"src",,,,,,,,"ram",,, +,,"enum ram",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"m0",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,0,0,0 +,,"m1",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,0,1,1 +,,"m2",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,1,0,2 +,,"m3",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,1,1,3 +,,"mc0",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,0,0,4 +,,"mc1",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,0,1,5 +,,"mc2",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,0,6 +,,"mc3",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,7 +,,"enum src",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"mc0",,,,,,,,,,,,,,,,,,,,,,0,0,0,,,,,,,,, +,,"mc1",,,,,,,,,,,,,,,,,,,,,,0,0,1,,,,,,,,, +,,"mc2",,,,,,,,,,,,,,,,,,,,,,0,1,0,,,,,,,,, +,,"mc3",,,,,,,,,,,,,,,,,,,,,,0,1,1,,,,,,,,, +,,"enum dst",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"mc0",,,,,,,,,,,,,,,,,,,,,,0,0,0,,,,,,,,, +,,"mc1",,,,,,,,,,,,,,,,,,,,,,0,0,1,,,,,,,,, +,,"mc2",,,,,,,,,,,,,,,,,,,,,,0,1,0,,,,,,,,, +,,"mc3",,,,,,,,,,,,,,,,,,,,,,0,1,1,,,,,,,,, +,,"prg",,,,,,,,,,,,,,,,,,,,,,1,0,0,,,,,,,,, +,,"enum hold",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"_false",,,,,,,,,,,,,,,,,,0,,,,,,,,,,,,,,, +,,"_true",,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,, +,,"enum add",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"_0",,,,,,,,,,,,,,,0,0,0,,,,,,,,,,,,,,,,0 +,,"_1",,,,,,,,,,,,,,,0,0,1,,,,,,,,,,,,,,,,1 +,,"_2",,,,,,,,,,,,,,,0,1,0,,,,,,,,,,,,,,,,2 +,,"_4",,,,,,,,,,,,,,,0,1,1,,,,,,,,,,,,,,,,3 +,,"_8",,,,,,,,,,,,,,,1,0,0,,,,,,,,,,,,,,,,4 +,,"_16",,,,,,,,,,,,,,,1,0,1,,,,,,,,,,,,,,,,5 +,,"_32",,,,,,,,,,,,,,,1,1,0,,,,,,,,,,,,,,,,6 +,,"_64",,,,,,,,,,,,,,,1,1,1,,,,,,,,,,,,,,,,7 +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0, +"JUMP",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"struct jmp",1,1,0,1,,,0,"imm",,,,,,,,,,,,,,,,,,,,,,,,, +,"conditional","struct jmp_cond",1,1,0,1,,,1,"cond",,,,,,"imm",,,,,,,,,,,,,,,,,,, +,,"enum cond",,,,,,,"F","N",,"T0","C","S","Z",,,,,,,,,,,,,,,,,,,, +,,"z",,,,,,,,1,0,0,0,0,1,,,,,,,,,,,,,,,,,,,, +,,"nz",,,,,,,,0,0,0,0,0,1,,,,,,,,,,,,,,,,,,,, +,,"s",,,,,,,,1,0,0,0,1,0,,,,,,,,,,,,,,,,,,,, +,,"ns",,,,,,,,0,0,0,0,1,0,,,,,,,,,,,,,,,,,,,, +,,"c",,,,,,,,1,0,0,1,0,0,,,,,,,,,,,,,,,,,,,, +,,"nc",,,,,,,,0,0,0,1,0,0,,,,,,,,,,,,,,,,,,,, +,,"t0",,,,,,,,1,0,1,0,0,0,,,,,,,,,,,,,,,,,,,, +,,"nt0",,,,,,,,0,0,1,0,0,0,,,,,,,,,,,,,,,,,,,, +,,"zs",,,,,,,,1,0,0,0,1,1,,,,,,,,,,,,,,,,,,,, +,,"nzs",,,,,,,,0,0,0,0,1,1,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +"LOOP",,"struct btm",1,1,1,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"struct lps",1,1,1,0,1,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +"END",,"struct end",1,1,1,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,"struct endi",1,1,1,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/dsp-notes.ods b/dsp-notes.ods index fd2c836fa2385909174a05b8f5ec068caae3c145..15224e02a94928e5b589e644e883f8607782e3ae 100644 GIT binary patch delta 34341 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 W0p6^@D_$8G1c5LWXrNyQhz9_|J=Ev` delta 43233 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 l|BF-yf`c=E=j3MT= 0, out.getvalue() + + out.write(indent * level + l + "\n") + + if l and (l[-1] == "{" or l[-1] == "("): + level += 2 + + if level == 0 and l and l[-1] == ";": + out.write("\n") + return out + +def renderer(): + out = io.StringIO() + def render(lines): + return _render(out, lines) + return render, out diff --git a/gen/generate_notes.py b/gen/generate_notes.py new file mode 100644 index 0000000..66b7c60 --- /dev/null +++ b/gen/generate_notes.py @@ -0,0 +1,241 @@ +import sys +from generate import renderer +from parse_notes import parse, read, X, Bits, Enum, Struct, Namespace + +def bits_mask_literal(bits, start, end) -> str: + b_str = lambda b: '1' if b is not X else '0' + s = ''.join(map(b_str, reversed(bits[start:end]))) + return s + +def bits_literal(bits, start, end) -> str: + b_str = lambda b: str(b) if b is not X else '0' + s = ''.join(map(b_str, reversed(bits[start:end]))) + return s + +def bits_start_end(bits): + start = 0 + while bits[start] is X: + start += 1 + + ix = start + 1 + end = ix + while ix < 32: + if bits[ix] is not X: + end = ix + 1 + ix += 1 + + return start, end + +def bits_to_shift(bits) -> str: + start, end = bits_start_end(bits) + literal = bits_literal(bits, start, end) + return f"0b{literal} << {start}" + +def bits_to_mask(bits) -> str: + start, end = bits_start_end(bits) + mask = bits_mask_literal(bits, start, end) + return f"0b{mask} << {start}" + +def enum_consts_to_value(namespace_name, enum_name, consts): + yield "static constexpr value_t to_value(uint32_t code)" + yield "{" + yield "using enum value_t;" + yield "" + yield "switch (code & mask()) {" + for const in consts: + shift = bits_to_shift(const.bits) + yield f"case {shift}: return {const.name};" + yield "default:" + yield f' std::cerr << "invalid {namespace_name} {enum_name} code: " << (code & mask()) << std::endl;' + yield ' throw std::runtime_error("invalid code");' + yield "}" + yield "}" + +def enum_consts_bits(consts): + yield "uint32_t bits() const" + yield "{" + yield "using enum value_t;" + yield "" + yield "switch (value) {" + for const in consts: + shift = bits_to_shift(const.bits) + yield f"case {const.name}: return {shift};" + yield "default: __builtin_unreachable();" + yield "}" + yield "}" + +def enum_value_t(consts): + yield "enum value_t {" + for const in consts: + yield f"{const.name}," + yield "};" + +def enum_struct(namespace, enum): + yield f"struct {enum.name}_t {{" + yield from enum_value_t(enum.consts) + yield "" + yield "const value_t value;" + yield "" + yield f"constexpr {enum.name}_t(value_t value)" + yield " : value(value) {}" + yield "" + yield f"constexpr {enum.name}_t(uint32_t code)" + yield " : value(to_value(code)) {}" + yield "" + mask = bits_to_mask(enum.consts[0].bits) + yield f"static constexpr uint32_t mask() {{ return {mask}; }}" + yield "" + yield from enum_consts_to_value(namespace.name, enum.name, enum.consts) + yield "" + yield from enum_consts_bits(enum.consts) + yield "};" + +def has_imm(struct): + return 'imm' in {name for _i, name in struct.fields} + +def imm_length(struct): + imm_length, = [i for i, name in struct.fields if name == 'imm'] + return imm_length + 1 + +def f_name(name): + return name.split('_', maxsplit=1)[-1] + +def struct_struct(namespace, struct): + if has_imm(struct): + length = imm_length(struct) + yield f"struct {struct.name}_t : stmt_accept_t<{struct.name}_t>, ins_imm_t<{struct.name}_t, {length}>" + yield "{" + yield f"using imm_type = uimm_t<{length}>;" + else: + yield f"struct {struct.name}_t : stmt_accept_t<{struct.name}_t>, ins_t<{struct.name}_t>" + yield "{" + yield "" + + + field_decls = [f"{name}_t {f_name(name)}" for _, name in struct.fields if name != 'imm'] + field_inits = [f"{f_name(name)}({f_name(name)})" for _, name in struct.fields if name != 'imm'] + if has_imm(struct): + field_decls.insert(0, "imm_type imm") + field_inits.insert(0, "ins_imm_t(imm)") + field_inits = ", ".join(field_inits) + field_decls = ", ".join(field_decls) + yield f"{struct.name}_t({field_decls})" + if field_inits.strip(): + yield f" : {field_inits} {{}}" + else: + yield "{}" + yield "" + yield f"{struct.name}_t(uint32_t code)" + code_inits = [f"{f_name(name)}(code)" for _, name in struct.fields if name != 'imm'] + if has_imm(struct): + code_inits.insert(0, "ins_imm_t(code)") + code_inits = ", ".join(code_inits) + if code_inits.strip(): + yield f" : {code_inits} {{ (void)code; }}" + else: + yield "{ (void)code; }" + yield "" + + for _, name in struct.fields: + if name == 'imm': + pass + else: + yield f"const {name}_t {f_name(name)};" + yield "" + + start, end = bits_start_end(struct.bits) + mask_literal = bits_mask_literal(struct.bits, start, end) + literal = bits_literal(struct.bits, start, end) + + yield f"static uint32_t mask() {{ return 0b{mask_literal} << {start}; }}" + yield f"static uint32_t code() {{ return 0b{literal} << {start}; }}" + bits_return = " | ".join(f"{f_name(name)}.bits()" for _, name in struct.fields if name != 'imm') + if not bits_return.strip(): + bits_return = "0" + yield f"uint32_t bits() const {{ return {bits_return}; }}" + + yield "};" + +def sort_events(events): + enums = [] + structs = [] + namespace = None + def do_yield(): + nonlocal enums, structs, namespace + + yield namespace + #yield from sorted(enums, key=lambda e: e.name) + yield from enums + assert structs, structs + yield from structs + #yield from sorted(structs, key=lambda e: e.name) + + for event in events: + if type(event) is Namespace: + if namespace is not None: + yield from do_yield() + else: + assert not enums + assert not structs + namespace = event + enums = [] + structs = [] + elif type(event) is Enum: + assert namespace is not None + enums.append(event) + elif type(event) is Struct: + assert namespace is not None + structs.append(event) + else: + assert False + assert namespace is not None + yield from do_yield() + +def generate_header_namespaces(events): + namespace = None + yield "namespace dsp {" + for event in events: + if type(event) is Namespace: + if namespace is not None: + yield "" + yield f"}} // {namespace.name}" + yield "" + yield f"namespace {event.name} {{" + yield "" + namespace = event + elif type(event) is Enum: + yield from enum_struct(namespace, event) + yield "" + elif type(event) is Struct: + yield from struct_struct(namespace, event) + yield "" + else: + assert False + assert namespace is not None + yield f"}} // namespace {namespace.name}" + yield "" + yield "} // namespace dsp" + +def generate_includes(): + yield "#pragma once" + yield "" + yield "#include " + yield "#include " + yield "" + yield '#include "imm.hpp"' + yield '#include "ins.hpp"' + yield '#include "stmt_base.hpp"' + yield "" + +def generate_header(): + events = list(sort_events(parse(read(sys.argv[1])))) + render, out = renderer() + render(generate_includes()) + render(generate_header_namespaces(events)) + return out + +print(generate_header().getvalue()) + +#consts=[Const(name='z', bits=xxxxxxx100001xxxxxxxxxxxxxxxxxxx), + +b = Bits(bits=[X,X,1,1,0,0,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X]) diff --git a/gen/parse_notes.py b/gen/parse_notes.py new file mode 100644 index 0000000..4afa2e1 --- /dev/null +++ b/gen/parse_notes.py @@ -0,0 +1,128 @@ +import csv +import sys +from dataclasses import dataclass +from typing import Union + +class _X: + def __repr__(self): + return 'x' + +X = _X() + +bit = Union[int, _X] + +@dataclass +class Bits: + bits: tuple[bit, bit, bit, bit, bit, bit, bit, bit, + bit, bit, bit, bit, bit, bit, bit, bit, + bit, bit, bit, bit, bit, bit, bit, bit, + bit, bit, bit, bit, bit, bit, bit, bit] + + def __repr__(self): + return ''.join(repr(i) for i in self.bits) + + def __getitem__(self, key): + return list(reversed(self.bits))[key] + +@dataclass +class Const: + name: str + bits: Bits + +@dataclass +class Enum: + name: str + consts: list[Const] + +@dataclass +class Struct: + name: str + bits: Bits + fields: list[tuple[int, str]] + +@dataclass +class Namespace: + name: str + +def read(path): + with open(path, newline='') as f: + reader = csv.reader(f, delimiter=',', quotechar='"') + return list(reader) + +label_col = 2 +bits_col = 3 + +def parse_struct(rows, ix): + return None, ix + 1 + +def validate_consts(consts): + by_index = set([ + frozenset([ix for ix, bit in enumerate(const.bits) if bit is not X]) + for const in consts + ]) + assert len(by_index) == 1 + +def get_bits(row): + return [ + int(i) if i in {"0", "1"} else X + for i in row[bits_col:bits_col+32] + ] + +def get_nonbits(row): + return [ + (31-ix, i) + for ix, i in enumerate(row[bits_col:bits_col+32]) + if i and i not in {"0", "1"} + ] + +def get_name(row, key): + label0 = row[label_col] + assert label0.startswith(f'{key} '), label0 + _, name = label0.split(' ', maxsplit=1) + return name + +def parse_enum(rows, ix): + enum_name = get_name(rows[ix], "enum") + ix += 1 + consts = [] + + while ix < len(rows): + label = rows[ix][label_col] + if not label or ' ' in label: + validate_consts(consts) + return Enum(enum_name, consts), ix + else: + const_name = label + bits = get_bits(rows[ix]) + assert len(bits) == 32 + consts.append(Const(const_name, Bits(bits))) + ix += 1 + +def parse_struct(rows, ix): + struct_name = get_name(rows[ix], "struct") + bits = get_bits(rows[ix]) + fields = get_nonbits(rows[ix]) + ix += 1 + + struct = Struct(struct_name, Bits(bits), fields) + return struct, ix + +def parse(rows): + ix = 0 + while ix < len(rows): + if rows[ix][0].strip(): + yield Namespace(rows[ix][0].lower()) + + label = rows[ix][label_col] + if label.startswith('struct'): + ret, ix = parse_struct(rows, ix) + yield ret + elif label.startswith('enum' ): + ret, ix = parse_enum(rows, ix) + yield ret + else: + ix += 1 + +#events = list(parse(read(sys.argv[1]))) +#from pprint import pprint +#pprint(events) diff --git a/gen/template.cpp b/gen/template.cpp new file mode 100644 index 0000000..3a2122e --- /dev/null +++ b/gen/template.cpp @@ -0,0 +1,187 @@ +#include + +#include "imm.hpp" +#include "stmt_base.hpp" + +namespace dsp { + +template +struct ins_t +{ + virtual uint32_t bits() const; + + uint32_t render() const + { + return T::code() | bits(); + } + + constexpr bool pred(uint32_t ins) const + { + return (ins & T::mask()) == T::code(); + } +}; + +template +struct ins_imm_t : ins_t +{ + ins_imm_t(uimm_t imm) + : imm(imm) {} + + const uimm_t imm; + + uint32_t render(visitor_t * visitor) + { + num_t value = imm.normalize(imm.expr->accept(visitor)); + if (imm.in_range(value)) + return render() | value; + else + throw imm_out_of_range(imm, value); + } +}; + +namespace load { + +struct dest_t { + enum value_t { + mc0, mc1, mc2, mc3, + rx , pl , + ra0, wa0, + lop, pc , + }; + + const value_t value; + + constexpr dest_t(value_t value) + : value(value) {} + + constexpr dest_t(uint32_t code) + : value(to_value(code)) { } + + static constexpr uint32_t mask() { return 0b1111 << 26; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b0000 << 26: return mc0; + case 0b0001 << 26: return mc1; + case 0b0010 << 26: return mc2; + case 0b0011 << 26: return mc3; + case 0b0100 << 26: return rx; + case 0b0101 << 26: return pl; + case 0b0110 << 26: return ra0; + case 0b0111 << 26: return wa0; + case 0b1010 << 26: return lop; + case 0b1100 << 26: return pc; + default: + std::cerr << "invalid load dest code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case mc0: return 0b0000 << 26; + case mc1: return 0b0001 << 26; + case mc2: return 0b0010 << 26; + case mc3: return 0b0011 << 26; + case rx: return 0b0100 << 26; + case pl: return 0b0101 << 26; + case ra0: return 0b0110 << 26; + case wa0: return 0b0111 << 26; + case lop: return 0b1010 << 26; + case pc: return 0b1100 << 26; + default: __builtin_unreachable(); + } + } +}; + +struct cond_t { + enum value_t { + z , nz , + s , ns , + c , nc , + t0, nt0, + zs, nzs, + }; + + const value_t value; + + constexpr cond_t(value_t value) + : value(value) {} + + constexpr cond_t(uint32_t code) + : value(to_value(code)) { } + + static constexpr uint32_t mask() { return 0b1'0'1111 << 19; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b1'0'0001 << 19: return z; + case 0b0'0'0001 << 19: return nz; + case 0b1'0'0010 << 19: return s; + case 0b0'0'0010 << 19: return ns; + case 0b1'0'0100 << 19: return c; + case 0b0'0'0100 << 19: return nc; + case 0b1'0'1000 << 19: return t0; + case 0b0'0'1000 << 19: return nt0; + case 0b1'0'0011 << 19: return zs; + case 0b0'0'0011 << 19: return nzs; + default: + std::cerr << "invalid load cond code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case z: return 0b1'0'0001 << 19; + case nz: return 0b0'0'0001 << 19; + case s: return 0b1'0'0010 << 19; + case ns: return 0b0'0'0010 << 19; + case c: return 0b1'0'0100 << 19; + case nc: return 0b0'0'0100 << 19; + case t0: return 0b1'0'1000 << 19; + case nt0: return 0b0'0'1000 << 19; + case zs: return 0b1'0'0011 << 19; + case nzs: return 0b0'0'0011 << 19; + default: __builtin_unreachable(); + } + } +}; + +struct mvi_cond_t : stmt_accept_t, ins_imm_t +{ + using imm_type = uimm_t<19>; + + mvi_cond_t(dest_t dest, cond_t cond, imm_type imm) + : dest(dest), cond(cond), ins_imm_t(imm) + { } + + mvi_cond_t(uint32_t code) + : dest(code), cond(code), ins_imm_t(code) + { } + + const dest_t dest; + const cond_t cond; + + static uint32_t mask() { return 0b11'0000'1 << 25; } + static uint32_t code() { return 0b10'0000'1 << 25; } + uint32_t bits() const { return dest.bits() + | cond.bits(); + } +}; + +} + +} diff --git a/imm.hpp b/imm.hpp new file mode 100644 index 0000000..ce65060 --- /dev/null +++ b/imm.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include "expr.hpp" + +namespace dsp { + +static const token_t null_token; + +template +struct imm_t { + imm_t(const token_t& token, const expr_t * expr) + : token(token), expr(expr) {} + + imm_t(const uint32_t code) + : token(null_token), expr(new literal_t(code & mask)) {} + + const token_t& token; + const expr_t * expr; + + static constexpr bool sign = S; + static constexpr int bits = N; + static constexpr num_t max = (1L << (bits - static_cast(sign))) - 1; + static constexpr num_t min = sign ? -(max + 1) : 0; + static constexpr num_t mask = (1L << bits) - 1; + + num_t normalize(num_t value) const + { + if (!S && value > 2147483648) { // fixme: hack + return value & max; + } else { + return value; + } + } + + bool in_range(num_t value) const + { + return value <= max && value >= min; + } +}; + +template +using simm_t = imm_t; + +template +using uimm_t = imm_t; + +} diff --git a/ins.hpp b/ins.hpp new file mode 100644 index 0000000..d6a4604 --- /dev/null +++ b/ins.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include + +#include "imm.hpp" + +namespace dsp { + +template +struct ins_t +{ + /* + virtual uint32_t bits() const; + + uint32_t render() const + { + return T::code() | bits(); + } + */ + + static bool pred(uint32_t ins) + { + return (ins & T::mask()) == T::code(); + } +}; + +template +struct ins_imm_t : ins_t +{ + ins_imm_t(uimm_t imm) + : imm(imm) {} + + const uimm_t imm; + + uint32_t render(visitor_t * visitor) + { + num_t value = imm.normalize(imm.expr->accept(visitor)); + if (imm.in_range(value)) + return render() | value; + else + throw imm_out_of_range(imm, value); + } +}; + +} diff --git a/parser.cpp b/parser.cpp index b1856f8..d66737b 100644 --- a/parser.cpp +++ b/parser.cpp @@ -173,21 +173,22 @@ void parser_t::synchronize() } */ -std::optional parser_t::alu() +std::optional parser_t::alu() { using namespace dsp::op; - if (match(_and)) return {new alu_t(alu_type_t::andl)}; - else if (match(_or )) return {new alu_t(alu_type_t::orl)}; - else if (match(_xor)) return {new alu_t(alu_type_t::xorl)}; - else if (match(_add)) return {new alu_t(alu_type_t::add)}; - else if (match(_sub)) return {new alu_t(alu_type_t::sub)}; - else if (match(_ad2)) return {new alu_t(alu_type_t::ad2)}; - else if (match(_sr )) return {new alu_t(alu_type_t::sr)}; - else if (match(_rr )) return {new alu_t(alu_type_t::rr)}; - else if (match(_sl )) return {new alu_t(alu_type_t::sl)}; - else if (match(_rl )) return {new alu_t(alu_type_t::rl)}; - else if (match(_rl8)) return {new alu_t(alu_type_t::rl8)}; + + if (match(_and)) return {op_t{std::in_place_type}}; + else if (match(_or )) return {op_t{std::in_place_type}}; + else if (match(_xor)) return {op_t{std::in_place_type}}; + else if (match(_add)) return {op_t{std::in_place_type}}; + else if (match(_sub)) return {op_t{std::in_place_type}}; + else if (match(_ad2)) return {op_t{std::in_place_type}}; + else if (match(_sr )) return {op_t{std::in_place_type}}; + else if (match(_rr )) return {op_t{std::in_place_type}}; + else if (match(_sl )) return {op_t{std::in_place_type}}; + else if (match(_rl )) return {op_t{std::in_place_type}}; + else if (match(_rl8)) return {op_t{std::in_place_type}}; else return {}; } @@ -199,41 +200,58 @@ bool parser_t::xyd1_src() return mc || m || al; } -static op::xy_src_t xy_src(const token_t& token) +static op::x_src_t x_src(const token_t& token) { using namespace dsp::op; switch (token.type) { - case _m0: return xy_src_t::m0; - case _m1: return xy_src_t::m1; - case _m2: return xy_src_t::m2; - case _m3: return xy_src_t::m3; - case _mc0: return xy_src_t::mc0; - case _mc1: return xy_src_t::mc1; - case _mc2: return xy_src_t::mc2; - case _mc3: return xy_src_t::mc3; + case _m0: return x_src_t::m0; + case _m1: return x_src_t::m1; + case _m2: return x_src_t::m2; + case _m3: return x_src_t::m3; + case _mc0: return x_src_t::mc0; + case _mc1: return x_src_t::mc1; + case _mc2: return x_src_t::mc2; + case _mc3: return x_src_t::mc3; default: assert(false); __builtin_unreachable(); } } -std::optional parser_t::d1_dest() +static op::y_src_t y_src(const token_t& token) { using namespace dsp::op; - if (match(_mc0)) return {d1_dest_t::mc0}; - else if (match(_mc1)) return {d1_dest_t::mc1}; - else if (match(_mc2)) return {d1_dest_t::mc2}; - else if (match(_mc3)) return {d1_dest_t::mc3}; - else if (match(_rx)) return {d1_dest_t::rx}; - else if (match(_pl)) return {d1_dest_t::pl}; - else if (match(_ra0)) return {d1_dest_t::ra0}; - else if (match(_wa0)) return {d1_dest_t::wa0}; - else if (match(_lop)) return {d1_dest_t::lop}; - else if (match(_top)) return {d1_dest_t::top}; - else if (match(_ct0)) return {d1_dest_t::ct0}; - else if (match(_ct1)) return {d1_dest_t::ct1}; - else if (match(_ct2)) return {d1_dest_t::ct2}; - else if (match(_ct3)) return {d1_dest_t::ct3}; + switch (token.type) { + case _m0: return y_src_t::m0; + case _m1: return y_src_t::m1; + case _m2: return y_src_t::m2; + case _m3: return y_src_t::m3; + case _mc0: return y_src_t::mc0; + case _mc1: return y_src_t::mc1; + case _mc2: return y_src_t::mc2; + case _mc3: return y_src_t::mc3; + default: assert(false); __builtin_unreachable(); + } +} + +std::optional parser_t::d1_dst() +{ + using namespace dsp::op; + + if (match(_mc0)) return {d1_dst_t::mc0}; + else if (match(_mc1)) return {d1_dst_t::mc1}; + else if (match(_mc2)) return {d1_dst_t::mc2}; + else if (match(_mc3)) return {d1_dst_t::mc3}; + else if (match(_rx)) return {d1_dst_t::rx}; + else if (match(_pl)) return {d1_dst_t::pl}; + else if (match(_ra0)) return {d1_dst_t::ra0}; + else if (match(_wa0)) return {d1_dst_t::wa0}; + else if (match(_lop)) return {d1_dst_t::lop}; + else if (match(_top)) return {d1_dst_t::top}; + else if (match(_ct0)) return {d1_dst_t::ct0}; + else if (match(_ct1)) return {d1_dst_t::ct1}; + else if (match(_ct2)) return {d1_dst_t::ct2}; + else if (match(_ct3)) return {d1_dst_t::ct3}; else return {}; } @@ -256,55 +274,60 @@ static op::d1_src_t d1_src(const token_t& token) } } -std::optional parser_t::xyd1_bus() +std::optional parser_t::xyd1_bus() { if (match(_mov)) { if (match(_alu)) { consume(comma, "expected `,` after `mov alu`"); consume(_a, "expected `a` after `mov alu,`"); - return {new op::mov_alu_a_t()}; + return {op::mov_alu_a_t()}; } else if (match(_mul)) { consume(comma, "expected ',' after `mov mul`"); consume(_p, "expected 'p' after `mov mul,`"); - return {new op::mov_mul_p_t()}; + return {op::mov_mul_p_t()}; } else if (xyd1_src()) { const token_t& src_token = previous(); consume(comma, "expected `,` after mov src operand"); // this is starting to feel a bit ugly... bool d1 = src_token.type == _alh || src_token.type == _alh; - if (!d1 && match(_y)) return {new op::mov_ram_y_t(xy_src(src_token))}; - else if (!d1 && match(_a)) return {new op::mov_ram_a_t(xy_src(src_token))}; - else if (!d1 && match(_x)) return {new op::mov_ram_x_t(xy_src(src_token))}; - else if (!d1 && match(_p)) return {new op::mov_ram_p_t(xy_src(src_token))}; - else if (auto dest_o = d1_dest()) return {new op::mov_ram_d1_t(d1_src(src_token), *dest_o)}; + if (!d1 && match(_y)) return {op::mov_ram_y_t(y_src(src_token))}; + else if (!d1 && match(_a)) return {op::mov_ram_a_t(y_src(src_token))}; + else if (!d1 && match(_x)) return {op::mov_ram_x_t(x_src(src_token))}; + else if (!d1 && match(_p)) return {op::mov_ram_p_t(x_src(src_token))}; + else if (auto dst_o = d1_dst()) return {op::mov_ram_d1_t(*dst_o, d1_src(src_token))}; else throw error(peek(), "expected x-bus, y-bus, or d-bus destination operand"); } else { uimm_t<8> imm = uimm_t<8>(peek(), immediate()); consume(comma, "expected `,`"); - if (auto dest_o = d1_dest()) - return {new op::mov_imm_d1_t(imm, *dest_o)}; + if (auto dst_o = d1_dst()) + return {op::mov_imm_d1_t(imm, *dst_o)}; else throw error(peek(), "expected d1 destination operand"); } } else if (match(_clr)) { consume(_a, "expected `a` after `clr`"); - return {new op::clr_a_t()}; + return {op::clr_a_t()}; } else { return {}; } } +static uint32_t op_mask(const op::op_t& op) +{ + return std::visit([](auto&& arg) -> uint32_t { return arg.mask(); }, op); +} + std::optional parser_t::op() { bool saw_nop = false; - std::vector ops; + std::vector ops; std::vector tokens; - auto emplace_op = [&](const token_t& token, const op::op_t * a) { - for (std::vector::size_type i = 0; i < ops.size(); i++) { - const op::op_t * b = ops[i]; - if ((a->mask() & b->mask() & ~(0b11 << 30)) != 0) { + auto emplace_op = [&](const token_t& token, const op::op_t& a) { + for (decltype(ops)::size_type i = 0; i < ops.size(); i++) { + const op::op_t& b = ops[i]; + if ((op_mask(a) & op_mask(b)) != 0) { dsp::error(*tokens[i], "conflict"); throw error(token, "conflict"); } @@ -319,7 +342,7 @@ std::optional parser_t::op() if (match(_nop)) saw_nop = 1; else if (auto op_o = alu() ) emplace_op(token, *op_o); else if (auto op_o = xyd1_bus()) emplace_op(token, *op_o); - else break; + else break; } if (ops.size() != 0 || saw_nop) return {new op::control_word_t(ops)}; @@ -327,20 +350,20 @@ std::optional parser_t::op() return {}; } -load::dest_t parser_t::load_dest() +load::dst_t parser_t::load_dst() { using namespace dsp::load; - if (match(_mc0)) return dest_t::mc0; - else if (match(_mc1)) return dest_t::mc1; - else if (match(_mc2)) return dest_t::mc2; - else if (match(_mc3)) return dest_t::mc3; - else if (match(_rx)) return dest_t::rx; - else if (match(_pl)) return dest_t::pl; - else if (match(_ra0)) return dest_t::ra0; - else if (match(_wa0)) return dest_t::wa0; - else if (match(_lop)) return dest_t::lop; - else if (match(_pc)) return dest_t::pc; + if (match(_mc0)) return dst_t::mc0; + else if (match(_mc1)) return dst_t::mc1; + else if (match(_mc2)) return dst_t::mc2; + else if (match(_mc3)) return dst_t::mc3; + else if (match(_rx)) return dst_t::rx; + else if (match(_pl)) return dst_t::pl; + else if (match(_ra0)) return dst_t::ra0; + else if (match(_wa0)) return dst_t::wa0; + else if (match(_lop)) return dst_t::lop; + else if (match(_pc)) return dst_t::pc; else throw error(peek(), "expected mvi destination"); } @@ -371,14 +394,14 @@ std::optional parser_t::load() const token_t& expr_token = peek(); expr_t * expr = immediate(); consume(comma, "expected `,`"); - load::dest_t dest = parser_t::load_dest(); + load::dst_t dst = parser_t::load_dst(); if (match(comma)) { load::cond_t cond = load_cond(); uimm_t<19> imm = uimm_t<19>(expr_token, expr); - return {new load::mvi_cond_t(imm, dest, cond)}; + return {new load::mvi_cond_t(imm, dst, cond)}; } else { uimm_t<25> imm = uimm_t<25>(expr_token, expr); - return {new load::mvi_t(imm, dest)}; + return {new load::mvi_t(imm, dst)}; } } else return {}; @@ -434,29 +457,29 @@ static bool dma_hold_p(const token_t& token) } } -static dma::add_mode_t dma_add(const token_t& token) +static dma::add_t dma_add(const token_t& token) { using namespace dsp::dma; switch (token.type) { case _dma: [[fallthrough]]; - case _dmah: return add_mode_t::_2; + case _dmah: return add_t::_2; case _dma0: [[fallthrough]]; - case _dmah0: return add_mode_t::_0; + case _dmah0: return add_t::_0; case _dma1: [[fallthrough]]; - case _dmah1: return add_mode_t::_1; + case _dmah1: return add_t::_1; case _dma2: [[fallthrough]]; - case _dmah2: return add_mode_t::_2; + case _dmah2: return add_t::_2; case _dma4: [[fallthrough]]; - case _dmah4: return add_mode_t::_4; + case _dmah4: return add_t::_4; case _dma8: [[fallthrough]]; - case _dmah8: return add_mode_t::_8; + case _dmah8: return add_t::_8; case _dma16: [[fallthrough]]; - case _dmah16: return add_mode_t::_16; + case _dmah16: return add_t::_16; case _dma32: [[fallthrough]]; - case _dmah32: return add_mode_t::_32; + case _dmah32: return add_t::_32; case _dma64: [[fallthrough]]; - case _dmah64: return add_mode_t::_64; + case _dmah64: return add_t::_64; default: assert(false); } } @@ -486,18 +509,18 @@ dma::dst_t parser_t::dma_dst() } } -std::optional parser_t::dma_length_ram() +std::optional parser_t::dma_ram() { using namespace dsp::dma; - if (match(_m0)) return length_ram_t::m0; - else if (match(_m1)) return length_ram_t::m1; - else if (match(_m2)) return length_ram_t::m2; - else if (match(_m3)) return length_ram_t::m3; - else if (match(_mc0)) return length_ram_t::mc0; - else if (match(_mc1)) return length_ram_t::mc1; - else if (match(_mc2)) return length_ram_t::mc2; - else if (match(_mc3)) return length_ram_t::mc3; + if (match(_m0)) return ram_t::m0; + else if (match(_m1)) return ram_t::m1; + else if (match(_m2)) return ram_t::m2; + else if (match(_m3)) return ram_t::m3; + else if (match(_mc0)) return ram_t::mc0; + else if (match(_mc1)) return ram_t::mc1; + else if (match(_mc2)) return ram_t::mc2; + else if (match(_mc3)) return ram_t::mc3; else return {}; } @@ -506,27 +529,27 @@ std::optional parser_t::dma() if (dma_p(peek())) { const token_t& token = advance(); bool hold = dma_hold_p(token); - dma::add_mode_t add = dma_add(token); + dma::add_t add = dma_add(token); if (match(_d0)) { consume(comma, "expected `,`"); dma::dst_t dst = dma_dst(); consume(comma, "expected `,`"); - if (auto length_ram_o = dma_length_ram()) { - return {new dma::d0_dst_ram_t(hold, add, dst, *length_ram_o)}; + if (auto ram_o = dma_ram()) { + return {new dma::d0_dst_ram_t(add, hold, dst, *ram_o)}; } else { uimm_t<8> imm = uimm_t<8>(peek(), immediate()); - return {new dma::d0_dst_imm_t(hold, add, dst, imm)}; + return {new dma::d0_dst_imm_t(imm, add, hold, dst)}; } } else { dma::src_t src = dma_src(); consume(comma, "expected `,`"); consume(_d0, "expected `d0`"); consume(comma, "expected `,`"); - if (auto length_ram_o = dma_length_ram()) { - return {new dma::src_d0_ram_t(hold, add, src, *length_ram_o)}; + if (auto ram_o = dma_ram()) { + return {new dma::src_d0_ram_t(add, hold, src, *ram_o)}; } else { uimm_t<8> imm = uimm_t<8>(peek(), immediate()); - return {new dma::src_d0_imm_t(hold, add, src, imm)}; + return {new dma::src_d0_imm_t(imm, add, hold, src)}; } } } else @@ -555,10 +578,10 @@ std::optional parser_t::jump() if (match(_jmp)) { if (auto cond_o = jump_cond()) { consume(comma, "expected `,` after jump condition"); - uimm_t<8> imm = uimm_t<8>(peek(), immediate()); - return {new jump::jmp_cond_t(*cond_o, imm)}; + uimm_t<19> imm = uimm_t<19>(peek(), immediate()); + return {new jump::jmp_cond_t(imm, *cond_o)}; } else { - uimm_t<8> imm = uimm_t<8>(peek(), immediate()); + uimm_t<25> imm = uimm_t<25>(peek(), immediate()); return {new jump::jmp_t(imm)}; } } else diff --git a/parser.hpp b/parser.hpp index 58e6468..b2e412d 100644 --- a/parser.hpp +++ b/parser.hpp @@ -6,6 +6,8 @@ #include "token.hpp" #include "expr.hpp" #include "stmt.hpp" +#include "stmt_ins.hpp" +#include "control_word.hpp" namespace dsp { @@ -49,17 +51,17 @@ struct parser_t expr_t * orl(); expr_t * primary(); - std::optional alu(); + std::optional alu(); bool xyd1_src(); - std::optional d1_dest(); - std::optional xyd1_bus(); + std::optional d1_dst(); + std::optional xyd1_bus(); std::optional op(); - load::dest_t load_dest(); + load::dst_t load_dst(); load::cond_t load_cond(); std::optional load(); dma::src_t dma_src(); dma::dst_t dma_dst(); - std::optional dma_length_ram(); + std::optional dma_ram(); std::optional dma(); std::optional jump_cond(); std::optional jump(); diff --git a/stmt.hpp b/stmt.hpp index a22c807..823403a 100644 --- a/stmt.hpp +++ b/stmt.hpp @@ -1,393 +1,30 @@ #pragma once -#include -#include #include -#include "stmt_enum.hpp" -#include "expr.hpp" -#include "bits.hpp" +#include "ins.hpp" +#include "stmt_base.hpp" namespace dsp { -struct stmt_t -{ - virtual void accept(visitor_t const * visitor) const = 0; - virtual uint32_t accept(visitor_t const * visitor) const = 0; -}; - -template -struct stmt_accept_t : stmt_t { - virtual void accept(visitor_t const * visitor) const { - return visitor->visit(static_cast(this)); - } - - virtual uint32_t accept(visitor_t const * visitor) const - { - return visitor->visit(static_cast(this)); - } -}; - -template -struct imm_t { - imm_t(const token_t& token, const expr_t * expr) - : token(token), expr(expr) {} - - const token_t& token; - const expr_t * expr; - - static constexpr bool sign = S; - static constexpr int bits = N; - static constexpr num_t max = (1L << (bits - static_cast(sign))) - 1; - static constexpr num_t min = sign ? -(max + 1) : 0; - - num_t normalize(num_t value) const - { - if (!S && value > 2147483648) { // fixme: hack - return value & max; - } else { - return value; - } - } - - bool in_range(num_t value) const - { - return value <= max && value >= min; - } -}; - -template -using simm_t = imm_t; - -template -using uimm_t = imm_t; - -namespace op { - -struct op_t -{ - virtual uint32_t mask() const = 0; - virtual uint32_t code() const = 0; - virtual uint32_t bits() const = 0; -}; - -struct alu_t : op_t, stmt_accept_t -{ - alu_t(alu_type_t type) - : type(type) {} - - const alu_type_t type; - - uint32_t mask() const { return 0b1111 << 26; } - uint32_t code() const { return 0b0000 << 26; } - uint32_t bits() const { return alu_bits(type); } -}; - -struct mov_ram_x_t : op_t, stmt_accept_t -{ - mov_ram_x_t(xy_src_t src) - : src(src) {} - - const xy_src_t src; - - uint32_t mask() const { return 0b100'111 << 20; } - uint32_t code() const { return 0b100'000 << 20; } - uint32_t bits() const { return xy_src_bits(src, 20); } -}; - -struct mov_mul_p_t : op_t, stmt_accept_t -{ - mov_mul_p_t() {} - - uint32_t mask() const { return 0b011'000 << 20; } - uint32_t code() const { return 0b010'000 << 20; } - uint32_t bits() const { return 0; } -}; - -struct mov_ram_p_t : op_t, stmt_accept_t -{ - mov_ram_p_t(xy_src_t src) - : src(src) {} - - const xy_src_t src; - - uint32_t mask() const { return 0b011'111 << 20; } - uint32_t code() const { return 0b011'000 << 20; } - uint32_t bits() const { return xy_src_bits(src, 20); } -}; - -struct mov_ram_y_t : op_t, stmt_accept_t -{ - mov_ram_y_t(xy_src_t src) - : src(src) {} - - const xy_src_t src; - - uint32_t mask() const { return 0b100'111 << 14; } - uint32_t code() const { return 0b100'000 << 14; } - uint32_t bits() const { return xy_src_bits(src, 14); } -}; - -struct clr_a_t : op_t, stmt_accept_t -{ - clr_a_t() {} - - uint32_t mask() const { return 0b011'000 << 14; } - uint32_t code() const { return 0b001'000 << 14; } - uint32_t bits() const { return 0; } -}; - -struct mov_alu_a_t : op_t, stmt_accept_t -{ - mov_alu_a_t() {} - - uint32_t mask() const { return 0b011'000 << 14; } - uint32_t code() const { return 0b010'000 << 14; } - uint32_t bits() const { return 0; } -}; - -struct mov_ram_a_t : op_t, stmt_accept_t -{ - mov_ram_a_t(xy_src_t src) - : src(src) {} - - const xy_src_t src; - - uint32_t mask() const { return 0b011'111 << 14; } - uint32_t code() const { return 0b011'000 << 14; } - uint32_t bits() const { return xy_src_bits(src, 14); } -}; - -struct mov_imm_d1_t : op_t, stmt_accept_t -{ - mov_imm_d1_t(uimm_t<8> imm, d1_dest_t dest) - : imm(imm), dest(dest) {} - - const uimm_t<8> imm; - const d1_dest_t dest; - - uint32_t mask() const { return 0b11'1111'1111'1111 << 0; } - uint32_t code() const { return 0b01'0000'0000'0000 << 0; } - uint32_t bits() const { return d1_dest_bits(dest); } -}; - -struct mov_ram_d1_t : op_t, stmt_accept_t -{ - mov_ram_d1_t(d1_src_t src, d1_dest_t dest) - : src(src), dest(dest) {} - - const d1_src_t src; - const d1_dest_t dest; - - uint32_t mask() const { return 0b11'1111'0000'1111 << 0; } - uint32_t code() const { return 0b11'0000'0000'0000 << 0; } - uint32_t bits() const { return d1_dest_bits(dest) | d1_src_bits(src); } -}; - -struct control_word_t : stmt_accept_t -{ - control_word_t(std::vector ops) - : ops(ops) - { - } - - const std::vector ops; - - uint32_t mask() const { return 0b11 << 30; } - uint32_t code() const { return 0b00 << 30; } - uint32_t bits() const { return 0; } -}; - -} // op - -namespace load { - -struct mvi_t : stmt_accept_t -{ - mvi_t(uimm_t<25> imm, dest_t dest) - : imm(imm), dest(dest) {} - - uint32_t mask() const { return 0xffff'ffff; } - uint32_t code() const { return 0b10'0000'0 << 25; } - uint32_t bits() const { return dest_bits(dest); } - - const uimm_t<25> imm; - const dest_t dest; -}; - -struct mvi_cond_t : stmt_accept_t -{ - mvi_cond_t(uimm_t<19> imm, dest_t dest, cond_t cond) - : imm(imm), dest(dest), cond(cond) {} - - const uimm_t<19> imm; - const dest_t dest; - const cond_t cond; - - uint32_t mask() const { return 0xffff'ffff; } - uint32_t code() const { return 0b10'0000'1 << 25; } - uint32_t bits() const { return dest_bits(dest) - | cond_bits(cond); - } -}; - -} // load - -namespace dma { - -struct d0_dst_imm_t : stmt_accept_t -{ - d0_dst_imm_t(bool hold, add_mode_t add, dst_t dst, uimm_t<8> imm) - : hold(hold), add(add), dst(dst), imm(imm) {} - - const bool hold; - const add_mode_t add; - const dst_t dst; - const uimm_t<8> imm; - - uint32_t mask() const { return 0xffff'ffff; } - uint32_t code() const { return 0b1100 << 28 | 0b00 << 12; } - uint32_t bits() const { return add_mode_bits(add) - | hold_bits(hold) - | dst_bits(dst); - } -}; - -struct src_d0_imm_t : stmt_accept_t -{ - src_d0_imm_t(bool hold, add_mode_t add, src_t src, uimm_t<8> imm) - : hold(hold), add(add), src(src), imm(imm) {} - - const bool hold; - const add_mode_t add; - const src_t src; - const uimm_t<8> imm; - - uint32_t mask() const { return 0xffff'ffff; } - uint32_t code() const { return 0b1100 << 28 | 0b01 << 12; } - uint32_t bits() const { return add_mode_bits(add) - | hold_bits(hold) - | src_bits(src); - } -}; - -struct d0_dst_ram_t : stmt_accept_t -{ - d0_dst_ram_t(bool hold, add_mode_t add, dst_t dst, length_ram_t ram) - : hold(hold), add(add), dst(dst), ram(ram) {} - - const bool hold; - const add_mode_t add; - const dst_t dst; - const length_ram_t ram; - - uint32_t mask() const { return 0xffff'ffff; } - uint32_t code() const { return 0b1100 << 28 | 0b10 << 12; } - uint32_t bits() const { return add_mode_bits(add) - | hold_bits(hold) - | dst_bits(dst) - | length_ram_bits(ram); - } -}; - -struct src_d0_ram_t : stmt_accept_t -{ - // from src to d0 - src_d0_ram_t(bool hold, add_mode_t add, src_t src, length_ram_t ram) - : hold(hold), add(add), src(src), ram(ram) {} - - const bool hold; - const add_mode_t add; - const src_t src; - const length_ram_t ram; - - uint32_t mask() const { return 0xffff'ffff; } - uint32_t code() const { return 0b1100 << 28 | 0b11 << 12; } - uint32_t bits() const { return add_mode_bits(add) - | hold_bits(hold) - | src_bits(src) - | length_ram_bits(ram); - } -}; - -} // dma - -namespace jump -{ - -struct jmp_t : stmt_accept_t -{ - jmp_t(uimm_t<8> imm) - : imm(imm) {} - - const uimm_t<8> imm; - - uint32_t mask() const { return 0xffff'ffff; } - uint32_t code() const { return 0b1101'00'0 << 25; } - uint32_t bits() const { return 0; } -}; - -struct jmp_cond_t : stmt_accept_t -{ - jmp_cond_t(cond_t cond, uimm_t<8> imm) - : cond(cond), imm(imm) {} - - const cond_t cond; - const uimm_t<8> imm; - - uint32_t mask() const { return 0xffff'ffff; } - uint32_t code() const { return 0b1101'00'1 << 25; } - uint32_t bits() const { return cond_bits(cond); } -}; - -} // jump - -namespace loop { - -struct btm_t : stmt_accept_t -{ - uint32_t mask() const { return 0xffff'ffff; } - uint32_t code() const { return 0b1110'0 << 27; } - uint32_t bits() const { return 0; } -}; - -struct lps_t : stmt_accept_t -{ - uint32_t mask() const { return 0xffff'ffff; } - uint32_t code() const { return 0b1110'1 << 27; } - uint32_t bits() const { return 0; } -}; - -} // loop - -namespace end { - -struct end_t : stmt_accept_t -{ - uint32_t mask() const { return 0xffff'ffff; } - uint32_t code() const { return 0b1111'0 << 27; } - uint32_t bits() const { return 0; } -}; - -struct endi_t : stmt_accept_t -{ - uint32_t mask() const { return 0xffff'ffff; } - uint32_t code() const { return 0b1111'1 << 27; } - uint32_t bits() const { return 0; } -}; - -} // end - namespace nop { -struct nop_t : stmt_accept_t +struct nop_t : stmt_accept_t, ins_t { + nop_t() + {} + + nop_t(uint32_t code) + { + (void)code; + } + uint32_t mask() const { return 0xffff'ffff; } uint32_t code() const { return 0x0000'0000; } uint32_t bits() const { return 0; } }; -} +} // namespace nop struct assign_t : stmt_accept_t { diff --git a/stmt_base.hpp b/stmt_base.hpp new file mode 100644 index 0000000..068fcb2 --- /dev/null +++ b/stmt_base.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "visitor.hpp" + +namespace dsp { + +struct stmt_t +{ + virtual void accept(visitor_t const * visitor) const = 0; + virtual uint32_t accept(visitor_t const * visitor) const = 0; +}; + +template +struct stmt_accept_t : stmt_t { + virtual void accept(visitor_t const * visitor) const { + return visitor->visit(static_cast(this)); + } + + virtual uint32_t accept(visitor_t const * visitor) const + { + return visitor->visit(static_cast(this)); + } +}; + +} diff --git a/stmt_enum.hpp b/stmt_enum.hpp deleted file mode 100644 index 7afb8db..0000000 --- a/stmt_enum.hpp +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once - -namespace dsp { - -namespace op { - -enum struct alu_type_t : int { - andl, - orl, - xorl, - add, - sub, - ad2, - sr, - rr, - sl, - rl, - rl8, -}; - -enum struct xy_src_t { - m0 , m1 , m2 , m3 , - mc0, mc1, mc2, mc3, -}; - -enum struct d1_dest_t { - mc0, mc1, mc2, mc3, - rx , pl , - ra0, wa0, - lop, top, - ct0, ct1, ct2, ct3, -}; - -enum struct d1_src_t { - m0 , m1 , m2 , m3 , - mc0, mc1, mc2, mc3, - all, alh, -}; - -} - -namespace load { - -enum struct dest_t { - mc0, mc1, mc2, mc3, - rx , pl , - ra0, wa0, - lop, pc , -}; - -enum struct cond_t { - z , nz , - s , ns , - c , nc , - t0, nt0, - zs, nzs, -}; - -} // load - -namespace dma { - -enum struct add_mode_t { - _0 , - _1 , - _2 , - _4 , - _8 , - _16, - _32, - _64, -}; - -enum struct src_t { - mc0, mc1, mc2, mc3, -}; - -enum struct dst_t { - mc0, mc1, mc2, mc3, - prg, -}; - -enum struct length_ram_t { - m0 , m1 , m2 , m3 , - mc0, mc1, mc2, mc3, -}; - -} // dma - -namespace jump { - -enum struct cond_t { - z , nz , - s , ns , - c , nc , - t0, nt0, - zs, nzs, -}; - -} // jump - -} diff --git a/stmt_ins.hpp b/stmt_ins.hpp new file mode 100644 index 0000000..45299db --- /dev/null +++ b/stmt_ins.hpp @@ -0,0 +1,1264 @@ +#pragma once + +#include +#include + +#include "imm.hpp" +#include "ins.hpp" +#include "stmt_base.hpp" + +namespace dsp { + namespace op { + + struct x_src_t { + enum value_t { + m0, + m1, + m2, + m3, + mc0, + mc1, + mc2, + mc3, + }; + + const value_t value; + + constexpr x_src_t(value_t value) + : value(value) {} + + constexpr x_src_t(uint32_t code) + : value(to_value(code)) {} + + static constexpr uint32_t mask() { return 0b111 << 20; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b000 << 20: return m0; + case 0b001 << 20: return m1; + case 0b010 << 20: return m2; + case 0b011 << 20: return m3; + case 0b100 << 20: return mc0; + case 0b101 << 20: return mc1; + case 0b110 << 20: return mc2; + case 0b111 << 20: return mc3; + default: + std::cerr << "invalid op x_src code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case m0: return 0b000 << 20; + case m1: return 0b001 << 20; + case m2: return 0b010 << 20; + case m3: return 0b011 << 20; + case mc0: return 0b100 << 20; + case mc1: return 0b101 << 20; + case mc2: return 0b110 << 20; + case mc3: return 0b111 << 20; + default: __builtin_unreachable(); + } + } + }; + + struct y_src_t { + enum value_t { + m0, + m1, + m2, + m3, + mc0, + mc1, + mc2, + mc3, + }; + + const value_t value; + + constexpr y_src_t(value_t value) + : value(value) {} + + constexpr y_src_t(uint32_t code) + : value(to_value(code)) {} + + static constexpr uint32_t mask() { return 0b111 << 14; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b000 << 14: return m0; + case 0b001 << 14: return m1; + case 0b010 << 14: return m2; + case 0b011 << 14: return m3; + case 0b100 << 14: return mc0; + case 0b101 << 14: return mc1; + case 0b110 << 14: return mc2; + case 0b111 << 14: return mc3; + default: + std::cerr << "invalid op y_src code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case m0: return 0b000 << 14; + case m1: return 0b001 << 14; + case m2: return 0b010 << 14; + case m3: return 0b011 << 14; + case mc0: return 0b100 << 14; + case mc1: return 0b101 << 14; + case mc2: return 0b110 << 14; + case mc3: return 0b111 << 14; + default: __builtin_unreachable(); + } + } + }; + + struct d1_src_t { + enum value_t { + m0, + m1, + m2, + m3, + mc0, + mc1, + mc2, + mc3, + all, + alh, + }; + + const value_t value; + + constexpr d1_src_t(value_t value) + : value(value) {} + + constexpr d1_src_t(uint32_t code) + : value(to_value(code)) {} + + static constexpr uint32_t mask() { return 0b1111 << 0; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b0000 << 0: return m0; + case 0b0001 << 0: return m1; + case 0b0010 << 0: return m2; + case 0b0011 << 0: return m3; + case 0b0100 << 0: return mc0; + case 0b0101 << 0: return mc1; + case 0b0110 << 0: return mc2; + case 0b0111 << 0: return mc3; + case 0b1001 << 0: return all; + case 0b1010 << 0: return alh; + default: + std::cerr << "invalid op d1_src code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case m0: return 0b0000 << 0; + case m1: return 0b0001 << 0; + case m2: return 0b0010 << 0; + case m3: return 0b0011 << 0; + case mc0: return 0b0100 << 0; + case mc1: return 0b0101 << 0; + case mc2: return 0b0110 << 0; + case mc3: return 0b0111 << 0; + case all: return 0b1001 << 0; + case alh: return 0b1010 << 0; + default: __builtin_unreachable(); + } + } + }; + + struct d1_dst_t { + enum value_t { + mc0, + mc1, + mc2, + mc3, + rx, + pl, + ra0, + wa0, + lop, + top, + ct0, + ct1, + ct2, + ct3, + }; + + const value_t value; + + constexpr d1_dst_t(value_t value) + : value(value) {} + + constexpr d1_dst_t(uint32_t code) + : value(to_value(code)) {} + + static constexpr uint32_t mask() { return 0b1111 << 8; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b0000 << 8: return mc0; + case 0b0001 << 8: return mc1; + case 0b0010 << 8: return mc2; + case 0b0011 << 8: return mc3; + case 0b0100 << 8: return rx; + case 0b0101 << 8: return pl; + case 0b0110 << 8: return ra0; + case 0b0111 << 8: return wa0; + case 0b1010 << 8: return lop; + case 0b1011 << 8: return top; + case 0b1100 << 8: return ct0; + case 0b1101 << 8: return ct1; + case 0b1110 << 8: return ct2; + case 0b1111 << 8: return ct3; + default: + std::cerr << "invalid op d1_dst code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case mc0: return 0b0000 << 8; + case mc1: return 0b0001 << 8; + case mc2: return 0b0010 << 8; + case mc3: return 0b0011 << 8; + case rx: return 0b0100 << 8; + case pl: return 0b0101 << 8; + case ra0: return 0b0110 << 8; + case wa0: return 0b0111 << 8; + case lop: return 0b1010 << 8; + case top: return 0b1011 << 8; + case ct0: return 0b1100 << 8; + case ct1: return 0b1101 << 8; + case ct2: return 0b1110 << 8; + case ct3: return 0b1111 << 8; + default: __builtin_unreachable(); + } + } + }; + + struct andl_t : stmt_accept_t, ins_t + { + + andl_t() + {} + + andl_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b1111 << 26; } + static uint32_t code() { return 0b0001 << 26; } + uint32_t bits() const { return 0; } + }; + + struct orl_t : stmt_accept_t, ins_t + { + + orl_t() + {} + + orl_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b1111 << 26; } + static uint32_t code() { return 0b0010 << 26; } + uint32_t bits() const { return 0; } + }; + + struct xorl_t : stmt_accept_t, ins_t + { + + xorl_t() + {} + + xorl_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b1111 << 26; } + static uint32_t code() { return 0b0011 << 26; } + uint32_t bits() const { return 0; } + }; + + struct add_t : stmt_accept_t, ins_t + { + + add_t() + {} + + add_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b1111 << 26; } + static uint32_t code() { return 0b0100 << 26; } + uint32_t bits() const { return 0; } + }; + + struct sub_t : stmt_accept_t, ins_t + { + + sub_t() + {} + + sub_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b1111 << 26; } + static uint32_t code() { return 0b0101 << 26; } + uint32_t bits() const { return 0; } + }; + + struct ad2_t : stmt_accept_t, ins_t + { + + ad2_t() + {} + + ad2_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b1111 << 26; } + static uint32_t code() { return 0b0110 << 26; } + uint32_t bits() const { return 0; } + }; + + struct sr_t : stmt_accept_t, ins_t + { + + sr_t() + {} + + sr_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b1111 << 26; } + static uint32_t code() { return 0b1000 << 26; } + uint32_t bits() const { return 0; } + }; + + struct rr_t : stmt_accept_t, ins_t + { + + rr_t() + {} + + rr_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b1111 << 26; } + static uint32_t code() { return 0b1001 << 26; } + uint32_t bits() const { return 0; } + }; + + struct sl_t : stmt_accept_t, ins_t + { + + sl_t() + {} + + sl_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b1111 << 26; } + static uint32_t code() { return 0b1010 << 26; } + uint32_t bits() const { return 0; } + }; + + struct rl_t : stmt_accept_t, ins_t + { + + rl_t() + {} + + rl_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b1111 << 26; } + static uint32_t code() { return 0b1011 << 26; } + uint32_t bits() const { return 0; } + }; + + struct rl8_t : stmt_accept_t, ins_t + { + + rl8_t() + {} + + rl8_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b1111 << 26; } + static uint32_t code() { return 0b1111 << 26; } + uint32_t bits() const { return 0; } + }; + + struct mov_ram_x_t : stmt_accept_t, ins_t + { + + mov_ram_x_t(x_src_t src) + : src(src) {} + + mov_ram_x_t(uint32_t code) + : src(code) { (void)code; } + + const x_src_t src; + + static uint32_t mask() { return 0b1 << 25; } + static uint32_t code() { return 0b1 << 25; } + uint32_t bits() const { return src.bits(); } + }; + + struct mov_mul_p_t : stmt_accept_t, ins_t + { + + mov_mul_p_t() + {} + + mov_mul_p_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b11 << 23; } + static uint32_t code() { return 0b10 << 23; } + uint32_t bits() const { return 0; } + }; + + struct mov_ram_p_t : stmt_accept_t, ins_t + { + + mov_ram_p_t(x_src_t src) + : src(src) {} + + mov_ram_p_t(uint32_t code) + : src(code) { (void)code; } + + const x_src_t src; + + static uint32_t mask() { return 0b11 << 23; } + static uint32_t code() { return 0b11 << 23; } + uint32_t bits() const { return src.bits(); } + }; + + struct mov_ram_y_t : stmt_accept_t, ins_t + { + + mov_ram_y_t(y_src_t src) + : src(src) {} + + mov_ram_y_t(uint32_t code) + : src(code) { (void)code; } + + const y_src_t src; + + static uint32_t mask() { return 0b1 << 19; } + static uint32_t code() { return 0b1 << 19; } + uint32_t bits() const { return src.bits(); } + }; + + struct clr_a_t : stmt_accept_t, ins_t + { + + clr_a_t() + {} + + clr_a_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b11 << 17; } + static uint32_t code() { return 0b01 << 17; } + uint32_t bits() const { return 0; } + }; + + struct mov_alu_a_t : stmt_accept_t, ins_t + { + + mov_alu_a_t() + {} + + mov_alu_a_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b11 << 17; } + static uint32_t code() { return 0b10 << 17; } + uint32_t bits() const { return 0; } + }; + + struct mov_ram_a_t : stmt_accept_t, ins_t + { + + mov_ram_a_t(y_src_t src) + : src(src) {} + + mov_ram_a_t(uint32_t code) + : src(code) { (void)code; } + + const y_src_t src; + + static uint32_t mask() { return 0b11 << 17; } + static uint32_t code() { return 0b11 << 17; } + uint32_t bits() const { return src.bits(); } + }; + + struct mov_imm_d1_t : stmt_accept_t, ins_imm_t + { + using imm_type = uimm_t<8>; + + mov_imm_d1_t(imm_type imm, d1_dst_t dst) + : ins_imm_t(imm), dst(dst) {} + + mov_imm_d1_t(uint32_t code) + : ins_imm_t(code), dst(code) { (void)code; } + + const d1_dst_t dst; + + static uint32_t mask() { return 0b11 << 12; } + static uint32_t code() { return 0b01 << 12; } + uint32_t bits() const { return dst.bits(); } + }; + + struct mov_ram_d1_t : stmt_accept_t, ins_t + { + + mov_ram_d1_t(d1_dst_t dst, d1_src_t src) + : dst(dst), src(src) {} + + mov_ram_d1_t(uint32_t code) + : dst(code), src(code) { (void)code; } + + const d1_dst_t dst; + const d1_src_t src; + + static uint32_t mask() { return 0b11 << 12; } + static uint32_t code() { return 0b11 << 12; } + uint32_t bits() const { return dst.bits() | src.bits(); } + }; + + + } // op + + namespace load { + + struct cond_t { + enum value_t { + z, + nz, + s, + ns, + c, + nc, + t0, + nt0, + zs, + nzs, + }; + + const value_t value; + + constexpr cond_t(value_t value) + : value(value) {} + + constexpr cond_t(uint32_t code) + : value(to_value(code)) {} + + static constexpr uint32_t mask() { return 0b111111 << 19; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b100001 << 19: return z; + case 0b000001 << 19: return nz; + case 0b100010 << 19: return s; + case 0b000010 << 19: return ns; + case 0b100100 << 19: return c; + case 0b000100 << 19: return nc; + case 0b101000 << 19: return t0; + case 0b001000 << 19: return nt0; + case 0b100011 << 19: return zs; + case 0b000011 << 19: return nzs; + default: + std::cerr << "invalid load cond code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case z: return 0b100001 << 19; + case nz: return 0b000001 << 19; + case s: return 0b100010 << 19; + case ns: return 0b000010 << 19; + case c: return 0b100100 << 19; + case nc: return 0b000100 << 19; + case t0: return 0b101000 << 19; + case nt0: return 0b001000 << 19; + case zs: return 0b100011 << 19; + case nzs: return 0b000011 << 19; + default: __builtin_unreachable(); + } + } + }; + + struct dst_t { + enum value_t { + mc0, + mc1, + mc2, + mc3, + rx, + pl, + ra0, + wa0, + lop, + pc, + }; + + const value_t value; + + constexpr dst_t(value_t value) + : value(value) {} + + constexpr dst_t(uint32_t code) + : value(to_value(code)) {} + + static constexpr uint32_t mask() { return 0b1111 << 26; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b0000 << 26: return mc0; + case 0b0001 << 26: return mc1; + case 0b0010 << 26: return mc2; + case 0b0011 << 26: return mc3; + case 0b0100 << 26: return rx; + case 0b0101 << 26: return pl; + case 0b0110 << 26: return ra0; + case 0b0111 << 26: return wa0; + case 0b1010 << 26: return lop; + case 0b1100 << 26: return pc; + default: + std::cerr << "invalid load dst code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case mc0: return 0b0000 << 26; + case mc1: return 0b0001 << 26; + case mc2: return 0b0010 << 26; + case mc3: return 0b0011 << 26; + case rx: return 0b0100 << 26; + case pl: return 0b0101 << 26; + case ra0: return 0b0110 << 26; + case wa0: return 0b0111 << 26; + case lop: return 0b1010 << 26; + case pc: return 0b1100 << 26; + default: __builtin_unreachable(); + } + } + }; + + struct mvi_t : stmt_accept_t, ins_imm_t + { + using imm_type = uimm_t<25>; + + mvi_t(imm_type imm, dst_t dst) + : ins_imm_t(imm), dst(dst) {} + + mvi_t(uint32_t code) + : ins_imm_t(code), dst(code) { (void)code; } + + const dst_t dst; + + static uint32_t mask() { return 0b1100001 << 25; } + static uint32_t code() { return 0b1000000 << 25; } + uint32_t bits() const { return dst.bits(); } + }; + + struct mvi_cond_t : stmt_accept_t, ins_imm_t + { + using imm_type = uimm_t<19>; + + mvi_cond_t(imm_type imm, dst_t dst, cond_t cond) + : ins_imm_t(imm), dst(dst), cond(cond) {} + + mvi_cond_t(uint32_t code) + : ins_imm_t(code), dst(code), cond(code) { (void)code; } + + const dst_t dst; + const cond_t cond; + + static uint32_t mask() { return 0b1100001 << 25; } + static uint32_t code() { return 0b1000001 << 25; } + uint32_t bits() const { return dst.bits() | cond.bits(); } + }; + + + } // load + + namespace dma { + + struct ram_t { + enum value_t { + m0, + m1, + m2, + m3, + mc0, + mc1, + mc2, + mc3, + }; + + const value_t value; + + constexpr ram_t(value_t value) + : value(value) {} + + constexpr ram_t(uint32_t code) + : value(to_value(code)) {} + + static constexpr uint32_t mask() { return 0b111 << 0; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b000 << 0: return m0; + case 0b001 << 0: return m1; + case 0b010 << 0: return m2; + case 0b011 << 0: return m3; + case 0b100 << 0: return mc0; + case 0b101 << 0: return mc1; + case 0b110 << 0: return mc2; + case 0b111 << 0: return mc3; + default: + std::cerr << "invalid dma ram code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case m0: return 0b000 << 0; + case m1: return 0b001 << 0; + case m2: return 0b010 << 0; + case m3: return 0b011 << 0; + case mc0: return 0b100 << 0; + case mc1: return 0b101 << 0; + case mc2: return 0b110 << 0; + case mc3: return 0b111 << 0; + default: __builtin_unreachable(); + } + } + }; + + struct src_t { + enum value_t { + mc0, + mc1, + mc2, + mc3, + }; + + const value_t value; + + constexpr src_t(value_t value) + : value(value) {} + + constexpr src_t(uint32_t code) + : value(to_value(code)) {} + + static constexpr uint32_t mask() { return 0b111 << 8; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b000 << 8: return mc0; + case 0b001 << 8: return mc1; + case 0b010 << 8: return mc2; + case 0b011 << 8: return mc3; + default: + std::cerr << "invalid dma src code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case mc0: return 0b000 << 8; + case mc1: return 0b001 << 8; + case mc2: return 0b010 << 8; + case mc3: return 0b011 << 8; + default: __builtin_unreachable(); + } + } + }; + + struct dst_t { + enum value_t { + mc0, + mc1, + mc2, + mc3, + prg, + }; + + const value_t value; + + constexpr dst_t(value_t value) + : value(value) {} + + constexpr dst_t(uint32_t code) + : value(to_value(code)) {} + + static constexpr uint32_t mask() { return 0b111 << 8; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b000 << 8: return mc0; + case 0b001 << 8: return mc1; + case 0b010 << 8: return mc2; + case 0b011 << 8: return mc3; + case 0b100 << 8: return prg; + default: + std::cerr << "invalid dma dst code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case mc0: return 0b000 << 8; + case mc1: return 0b001 << 8; + case mc2: return 0b010 << 8; + case mc3: return 0b011 << 8; + case prg: return 0b100 << 8; + default: __builtin_unreachable(); + } + } + }; + + struct hold_t { + enum value_t { + _false, + _true, + }; + + const value_t value; + + constexpr hold_t(value_t value) + : value(value) {} + + constexpr hold_t(uint32_t code) + : value(to_value(code)) {} + + static constexpr uint32_t mask() { return 0b1 << 14; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b0 << 14: return _false; + case 0b1 << 14: return _true; + default: + std::cerr << "invalid dma hold code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case _false: return 0b0 << 14; + case _true: return 0b1 << 14; + default: __builtin_unreachable(); + } + } + }; + + struct add_t { + enum value_t { + _0, + _1, + _2, + _4, + _8, + _16, + _32, + _64, + }; + + const value_t value; + + constexpr add_t(value_t value) + : value(value) {} + + constexpr add_t(uint32_t code) + : value(to_value(code)) {} + + static constexpr uint32_t mask() { return 0b111 << 15; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b000 << 15: return _0; + case 0b001 << 15: return _1; + case 0b010 << 15: return _2; + case 0b011 << 15: return _4; + case 0b100 << 15: return _8; + case 0b101 << 15: return _16; + case 0b110 << 15: return _32; + case 0b111 << 15: return _64; + default: + std::cerr << "invalid dma add code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case _0: return 0b000 << 15; + case _1: return 0b001 << 15; + case _2: return 0b010 << 15; + case _4: return 0b011 << 15; + case _8: return 0b100 << 15; + case _16: return 0b101 << 15; + case _32: return 0b110 << 15; + case _64: return 0b111 << 15; + default: __builtin_unreachable(); + } + } + }; + + struct d0_dst_imm_t : stmt_accept_t, ins_imm_t + { + using imm_type = uimm_t<8>; + + d0_dst_imm_t(imm_type imm, add_t add, hold_t hold, dst_t dst) + : ins_imm_t(imm), add(add), hold(hold), dst(dst) {} + + d0_dst_imm_t(uint32_t code) + : ins_imm_t(code), add(code), hold(code), dst(code) { (void)code; } + + const add_t add; + const hold_t hold; + const dst_t dst; + + static uint32_t mask() { return 0b11110000000000000011 << 12; } + static uint32_t code() { return 0b11000000000000000000 << 12; } + uint32_t bits() const { return add.bits() | hold.bits() | dst.bits(); } + }; + + struct src_d0_imm_t : stmt_accept_t, ins_imm_t + { + using imm_type = uimm_t<8>; + + src_d0_imm_t(imm_type imm, add_t add, hold_t hold, src_t src) + : ins_imm_t(imm), add(add), hold(hold), src(src) {} + + src_d0_imm_t(uint32_t code) + : ins_imm_t(code), add(code), hold(code), src(code) { (void)code; } + + const add_t add; + const hold_t hold; + const src_t src; + + static uint32_t mask() { return 0b11110000000000000011 << 12; } + static uint32_t code() { return 0b11000000000000000001 << 12; } + uint32_t bits() const { return add.bits() | hold.bits() | src.bits(); } + }; + + struct d0_dst_ram_t : stmt_accept_t, ins_t + { + + d0_dst_ram_t(add_t add, hold_t hold, dst_t dst, ram_t ram) + : add(add), hold(hold), dst(dst), ram(ram) {} + + d0_dst_ram_t(uint32_t code) + : add(code), hold(code), dst(code), ram(code) { (void)code; } + + const add_t add; + const hold_t hold; + const dst_t dst; + const ram_t ram; + + static uint32_t mask() { return 0b11110000000000000011 << 12; } + static uint32_t code() { return 0b11000000000000000010 << 12; } + uint32_t bits() const { return add.bits() | hold.bits() | dst.bits() | ram.bits(); } + }; + + struct src_d0_ram_t : stmt_accept_t, ins_t + { + + src_d0_ram_t(add_t add, hold_t hold, src_t src, ram_t ram) + : add(add), hold(hold), src(src), ram(ram) {} + + src_d0_ram_t(uint32_t code) + : add(code), hold(code), src(code), ram(code) { (void)code; } + + const add_t add; + const hold_t hold; + const src_t src; + const ram_t ram; + + static uint32_t mask() { return 0b11110000000000000011 << 12; } + static uint32_t code() { return 0b11000000000000000011 << 12; } + uint32_t bits() const { return add.bits() | hold.bits() | src.bits() | ram.bits(); } + }; + + + } // dma + + namespace jump { + + struct cond_t { + enum value_t { + z, + nz, + s, + ns, + c, + nc, + t0, + nt0, + zs, + nzs, + }; + + const value_t value; + + constexpr cond_t(value_t value) + : value(value) {} + + constexpr cond_t(uint32_t code) + : value(to_value(code)) {} + + static constexpr uint32_t mask() { return 0b111111 << 19; } + + static constexpr value_t to_value(uint32_t code) + { + using enum value_t; + + switch (code & mask()) { + case 0b100001 << 19: return z; + case 0b000001 << 19: return nz; + case 0b100010 << 19: return s; + case 0b000010 << 19: return ns; + case 0b100100 << 19: return c; + case 0b000100 << 19: return nc; + case 0b101000 << 19: return t0; + case 0b001000 << 19: return nt0; + case 0b100011 << 19: return zs; + case 0b000011 << 19: return nzs; + default: + std::cerr << "invalid jump cond code: " << (code & mask()) << std::endl; + throw std::runtime_error("invalid code"); + } + } + + uint32_t bits() const + { + using enum value_t; + + switch (value) { + case z: return 0b100001 << 19; + case nz: return 0b000001 << 19; + case s: return 0b100010 << 19; + case ns: return 0b000010 << 19; + case c: return 0b100100 << 19; + case nc: return 0b000100 << 19; + case t0: return 0b101000 << 19; + case nt0: return 0b001000 << 19; + case zs: return 0b100011 << 19; + case nzs: return 0b000011 << 19; + default: __builtin_unreachable(); + } + } + }; + + struct jmp_t : stmt_accept_t, ins_imm_t + { + using imm_type = uimm_t<25>; + + jmp_t(imm_type imm) + : ins_imm_t(imm) {} + + jmp_t(uint32_t code) + : ins_imm_t(code) { (void)code; } + + + static uint32_t mask() { return 0b1111001 << 25; } + static uint32_t code() { return 0b1101000 << 25; } + uint32_t bits() const { return 0; } + }; + + struct jmp_cond_t : stmt_accept_t, ins_imm_t + { + using imm_type = uimm_t<19>; + + jmp_cond_t(imm_type imm, cond_t cond) + : ins_imm_t(imm), cond(cond) {} + + jmp_cond_t(uint32_t code) + : ins_imm_t(code), cond(code) { (void)code; } + + const cond_t cond; + + static uint32_t mask() { return 0b1111001 << 25; } + static uint32_t code() { return 0b1101001 << 25; } + uint32_t bits() const { return cond.bits(); } + }; + + + } // jump + + namespace loop { + + struct btm_t : stmt_accept_t, ins_t + { + + btm_t() + {} + + btm_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b11111 << 27; } + static uint32_t code() { return 0b11100 << 27; } + uint32_t bits() const { return 0; } + }; + + struct lps_t : stmt_accept_t, ins_t + { + + lps_t() + {} + + lps_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b11111 << 27; } + static uint32_t code() { return 0b11101 << 27; } + uint32_t bits() const { return 0; } + }; + + + } // loop + + namespace end { + + struct end_t : stmt_accept_t, ins_t + { + + end_t() + {} + + end_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b11111 << 27; } + static uint32_t code() { return 0b11110 << 27; } + uint32_t bits() const { return 0; } + }; + + struct endi_t : stmt_accept_t, ins_t + { + + endi_t() + {} + + endi_t(uint32_t code) + { (void)code; } + + + static uint32_t mask() { return 0b11111 << 27; } + static uint32_t code() { return 0b11111 << 27; } + uint32_t bits() const { return 0; } + }; + + } // namespace end + +} // namespace dsp + diff --git a/stmt_string.cpp b/stmt_string.cpp index 8d17d0b..479cf81 100644 --- a/stmt_string.cpp +++ b/stmt_string.cpp @@ -1,5 +1,5 @@ #include "stmt_string.hpp" -#include "stmt_enum.hpp" +#include "stmt_ins.hpp" #define i(v) (static_cast(v)) @@ -7,46 +7,43 @@ namespace dsp { namespace op { -const std::string alu_type_string[] = { - [i(alu_type_t::andl)] = "andl", - [i(alu_type_t::orl )] = "orl", - [i(alu_type_t::xorl)] = "xorl", - [i(alu_type_t::add )] = "add", - [i(alu_type_t::sub )] = "sub", - [i(alu_type_t::ad2 )] = "ad2", - [i(alu_type_t::sr )] = "sr", - [i(alu_type_t::rr )] = "rr", - [i(alu_type_t::sl )] = "sl", - [i(alu_type_t::rl )] = "rl", - [i(alu_type_t::rl8 )] = "rl8", +const std::string x_src_string[] = { + [i(x_src_t::m0 )] = "m0" , + [i(x_src_t::m1 )] = "m1" , + [i(x_src_t::m2 )] = "m2" , + [i(x_src_t::m3 )] = "m3" , + [i(x_src_t::mc0)] = "mc0", + [i(x_src_t::mc1)] = "mc1", + [i(x_src_t::mc2)] = "mc2", + [i(x_src_t::mc3)] = "mc3", }; -const std::string xy_src_string[] = { - [i(xy_src_t::m0 )] = "m0" , - [i(xy_src_t::m1 )] = "m1" , - [i(xy_src_t::m2 )] = "m2" , - [i(xy_src_t::m3 )] = "m3" , - [i(xy_src_t::mc0)] = "mc0", - [i(xy_src_t::mc1)] = "mc1", - [i(xy_src_t::mc2)] = "mc2", - [i(xy_src_t::mc3)] = "mc3", +const std::string y_src_string[] = { + [i(y_src_t::m0 )] = "m0" , + [i(y_src_t::m1 )] = "m1" , + [i(y_src_t::m2 )] = "m2" , + [i(y_src_t::m3 )] = "m3" , + [i(y_src_t::mc0)] = "mc0", + [i(y_src_t::mc1)] = "mc1", + [i(y_src_t::mc2)] = "mc2", + [i(y_src_t::mc3)] = "mc3", }; -const std::string d1_dest_string[] = { - [i(d1_dest_t::mc0)] = "mc0", - [i(d1_dest_t::mc1)] = "mc1", - [i(d1_dest_t::mc2)] = "mc2", - [i(d1_dest_t::mc3)] = "mc3", - [i(d1_dest_t::rx )] = "rx" , - [i(d1_dest_t::pl )] = "pl" , - [i(d1_dest_t::ra0)] = "ra0", - [i(d1_dest_t::wa0)] = "wa0", - [i(d1_dest_t::lop)] = "lop", - [i(d1_dest_t::top)] = "top", - [i(d1_dest_t::ct0)] = "ct0", - [i(d1_dest_t::ct1)] = "ct1", - [i(d1_dest_t::ct2)] = "ct2", - [i(d1_dest_t::ct3)] = "ct3", +const std::string d1_dst_string[] = { + [i(d1_dst_t::mc0)] = "mc0", + [i(d1_dst_t::mc1)] = "mc1", + [i(d1_dst_t::mc2)] = "mc2", + [i(d1_dst_t::mc3)] = "mc3", + [i(d1_dst_t::rx )] = "rx" , + [i(d1_dst_t::pl )] = "pl" , + [i(d1_dst_t::ra0)] = "ra0", + [i(d1_dst_t::wa0)] = "wa0", + [i(d1_dst_t::lop)] = "lop", + [i(d1_dst_t::top)] = "top", + [i(d1_dst_t::ct0)] = "ct0", + [i(d1_dst_t::ct1)] = "ct1", + [i(d1_dst_t::ct2)] = "ct2", + [i(d1_dst_t::ct3)] = "ct3", }; const std::string d1_src_string[] = { @@ -66,17 +63,17 @@ const std::string d1_src_string[] = { namespace load { -const std::string dest_string[] = { - [i(dest_t::mc0)] = "mc0", - [i(dest_t::mc1)] = "mc1", - [i(dest_t::mc2)] = "mc2", - [i(dest_t::mc3)] = "mc3", - [i(dest_t::rx )] = "rx" , - [i(dest_t::pl )] = "pl" , - [i(dest_t::ra0)] = "ra0", - [i(dest_t::wa0)] = "wa0", - [i(dest_t::lop)] = "lop", - [i(dest_t::pc )] = "pc" , +const std::string dst_string[] = { + [i(dst_t::mc0)] = "mc0", + [i(dst_t::mc1)] = "mc1", + [i(dst_t::mc2)] = "mc2", + [i(dst_t::mc3)] = "mc3", + [i(dst_t::rx )] = "rx" , + [i(dst_t::pl )] = "pl" , + [i(dst_t::ra0)] = "ra0", + [i(dst_t::wa0)] = "wa0", + [i(dst_t::lop)] = "lop", + [i(dst_t::pc )] = "pc" , }; const std::string cond_string[] = { @@ -102,14 +99,14 @@ const std::string hold_mode_string[] = { }; const std::string add_mode_string[] = { - [i(add_mode_t::_0 )] = "0" , - [i(add_mode_t::_1 )] = "1" , - [i(add_mode_t::_2 )] = "2" , - [i(add_mode_t::_4 )] = "4" , - [i(add_mode_t::_8 )] = "8" , - [i(add_mode_t::_16)] = "16", - [i(add_mode_t::_32)] = "32", - [i(add_mode_t::_64)] = "64", + [i(add_t::_0 )] = "0" , + [i(add_t::_1 )] = "1" , + [i(add_t::_2 )] = "2" , + [i(add_t::_4 )] = "4" , + [i(add_t::_8 )] = "8" , + [i(add_t::_16)] = "16", + [i(add_t::_32)] = "32", + [i(add_t::_64)] = "64", }; const std::string src_string[] = { @@ -128,14 +125,14 @@ const std::string dst_string[] = { }; const std::string length_ram_string[] = { - [i(length_ram_t::m0 )] = "m0" , - [i(length_ram_t::m1 )] = "m1" , - [i(length_ram_t::m2 )] = "m2" , - [i(length_ram_t::m3 )] = "m3" , - [i(length_ram_t::mc0)] = "mc0", - [i(length_ram_t::mc1)] = "mc1", - [i(length_ram_t::mc2)] = "mc2", - [i(length_ram_t::mc3)] = "mc3", + [i(ram_t::m0 )] = "m0" , + [i(ram_t::m1 )] = "m1" , + [i(ram_t::m2 )] = "m2" , + [i(ram_t::m3 )] = "m3" , + [i(ram_t::mc0)] = "mc0", + [i(ram_t::mc1)] = "mc1", + [i(ram_t::mc2)] = "mc2", + [i(ram_t::mc3)] = "mc3", }; } // dma diff --git a/stmt_string.hpp b/stmt_string.hpp index 730955b..f637204 100644 --- a/stmt_string.hpp +++ b/stmt_string.hpp @@ -7,15 +7,16 @@ namespace dsp { namespace op { extern const std::string alu_type_string[]; -extern const std::string xy_src_string[]; -extern const std::string d1_dest_string[]; +extern const std::string x_src_string[]; +extern const std::string y_src_string[]; +extern const std::string d1_dst_string[]; extern const std::string d1_src_string[]; } namespace load { -extern const std::string dest_string[]; +extern const std::string dst_string[]; extern const std::string cond_string[]; } // load diff --git a/test/Makefile b/test/Makefile index 418e37f..5179b30 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,12 +4,16 @@ SRC = sample1.asm sample2a.asm sample2b.asm sample3.asm #SRC += cmpnm.asm fbtrans.asm loop_pr.asm udiv.asm EXPECT = $(patsubst %.asm,expect/%.bin,$(SRC)) ACTUAL = $(patsubst %.asm,actual/%.bin,$(SRC)) +EXPECT_TXT = $(patsubst %.bin,%.txt,$(EXPECT)) +ACTUAL_TXT = $(patsubst %.bin,%.txt,$(ACTUAL)) ALL = $(EXPECT) $(ACTUAL) -ALL_TXT = $(patsubst %.bin,%.txt,$(ALL)) +ALL_TXT = $(EXPECT_TXT) $(ACTUAL_TXT) all: $(ALL) -all-expect: $(EXPECT) -all-actual: $(ACTUAL) +expect: $(EXPECT) +actual: $(ACTUAL) +expect-txt: $(EXPECT_TXT) +actual-txt: $(ACTUAL_TXT) all-txt: $(ALL_TXT) %.s: %.asm @@ -35,7 +39,7 @@ expect/%.bin: %.s @mkdir -p $(dir $@) srec_cat -Output $@ -Binary $< -actual/%.bin: %.asm +actual/%.bin: %.asm ../scu-dsp-asm @mkdir -p $(dir $@) ../scu-dsp-asm $< $@ diff --git a/token.hpp b/token.hpp index d6bf8c8..c37e920 100644 --- a/token.hpp +++ b/token.hpp @@ -64,7 +64,9 @@ struct token_t { const std::string_view lexeme; const literal_t literal; - token_t() = delete; + constexpr token_t() + : pos({0, 0}), type(type_t::number), lexeme(""), literal({}) + { } constexpr token_t(token_pos_t pos, type_t type, const std::string_view lexeme, num_type number) : pos(pos), type(type), lexeme(lexeme), literal(number) diff --git a/visitable.hpp b/visitable.hpp index d1001ae..453d055 100644 --- a/visitable.hpp +++ b/visitable.hpp @@ -11,7 +11,18 @@ struct unary_t; // instructions namespace op { -struct alu_t; +struct andl_t; +struct orl_t; +struct xorl_t; +struct add_t; +struct sub_t; +struct ad2_t; +struct sr_t; +struct rr_t; +struct sl_t; +struct rl_t; +struct rl8_t; + struct mov_ram_x_t; struct mov_ram_x_t; struct mov_mul_p_t; @@ -22,6 +33,7 @@ struct mov_alu_a_t; struct mov_ram_a_t; struct mov_imm_d1_t; struct mov_ram_d1_t; + struct control_word_t; } diff --git a/visitor.hpp b/visitor.hpp index ddc8a7b..e2ea63b 100644 --- a/visitor.hpp +++ b/visitor.hpp @@ -14,7 +14,18 @@ struct visitor_t virtual T visit(const literal_t * expr) const = 0; virtual T visit(const unary_t * expr) const = 0; - virtual T visit(const op::alu_t * alu) const = 0; + virtual T visit(const op::andl_t * andl) const = 0; + virtual T visit(const op::orl_t * orl) const = 0; + virtual T visit(const op::xorl_t * xorl) const = 0; + virtual T visit(const op::add_t * add) const = 0; + virtual T visit(const op::sub_t * sub) const = 0; + virtual T visit(const op::ad2_t * ad2) const = 0; + virtual T visit(const op::sr_t * sr) const = 0; + virtual T visit(const op::rr_t * rr) const = 0; + virtual T visit(const op::sl_t * sl) const = 0; + virtual T visit(const op::rl_t * rl) const = 0; + virtual T visit(const op::rl8_t * rl8) const = 0; + virtual T visit(const op::mov_ram_x_t * mov_ram_x) const = 0; virtual T visit(const op::mov_mul_p_t * mov_mul_p) const = 0; virtual T visit(const op::mov_ram_p_t * mov_ram_p) const = 0; @@ -24,6 +35,7 @@ struct visitor_t virtual T visit(const op::mov_ram_a_t * mov_ram_a) const = 0; virtual T visit(const op::mov_imm_d1_t * mov_imm_d1) const = 0; virtual T visit(const op::mov_ram_d1_t * mov_ram_d1) const = 0; + virtual T visit(const op::control_word_t * control_word) const = 0; virtual T visit(const load::mvi_t * mvi) const = 0;