Compare commits
6 Commits
2fe2f0a1a7
...
b6e9d5ae86
Author | SHA1 | Date | |
---|---|---|---|
b6e9d5ae86 | |||
dd205b5e3e | |||
c12374f5fd | |||
c2c59495b3 | |||
118942521e | |||
f51ec95713 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,4 +1,6 @@
|
|||||||
main
|
main
|
||||||
|
scu-dsp-asm
|
||||||
*.o
|
*.o
|
||||||
*.gch
|
*.gch
|
||||||
*.d
|
*.d
|
||||||
|
test/*.s
|
11
Makefile
11
Makefile
@ -1,8 +1,9 @@
|
|||||||
CXXFLAGS = -Og -g -Wall -Wextra -Werror -Wfatal-errors -Wpedantic -Wno-c99-designator -std=c++20
|
STATIC = -static -static-libgcc -static-libstdc++
|
||||||
|
CXXFLAGS = -Og -g -Wall -Wextra -Werror -Wfatal-errors -Wno-c99-designator -std=c++20
|
||||||
LDFLAGS =
|
LDFLAGS =
|
||||||
|
|
||||||
TARGET =
|
TARGET =
|
||||||
CXX = $(TARGET)clang++
|
CXX = $(TARGET)g++
|
||||||
|
|
||||||
SRC = main.cpp
|
SRC = main.cpp
|
||||||
SRC += lexer.cpp
|
SRC += lexer.cpp
|
||||||
@ -14,15 +15,15 @@ SRC += stmt_string.cpp
|
|||||||
OBJ = $(patsubst %.cpp,%.o,$(SRC))
|
OBJ = $(patsubst %.cpp,%.o,$(SRC))
|
||||||
DEP = $(patsubst %.cpp,%.d,$(SRC))
|
DEP = $(patsubst %.cpp,%.d,$(SRC))
|
||||||
|
|
||||||
all: main
|
all: scu-dsp-asm
|
||||||
|
|
||||||
-include $(DEP)
|
-include $(DEP)
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
$(CXX) $(CXXFLAGS) -MMD -MF $(basename $<).d -c $< -o $@
|
$(CXX) $(CXXFLAGS) -MMD -MF $(basename $<).d -c $< -o $@
|
||||||
|
|
||||||
main: $(OBJ)
|
scu-dsp-asm: $(OBJ)
|
||||||
$(CXX) $(LDFLAGS) $^ -o $@
|
$(CXX) $(STATIC) $(LDFLAGS) $^ -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *.d *.gch main
|
rm -f *.o *.d *.gch main
|
||||||
|
@ -131,7 +131,7 @@ uint32_t emitter_t::visit(const op::mov_ram_a_t * mov_ram_a) const
|
|||||||
|
|
||||||
uint32_t emitter_t::visit(const op::mov_imm_d1_t * mov_imm_d1) const
|
uint32_t emitter_t::visit(const op::mov_imm_d1_t * mov_imm_d1) const
|
||||||
{
|
{
|
||||||
num_t value = mov_imm_d1->imm.expr->accept(this);
|
num_t value = mov_imm_d1->imm.normalize(mov_imm_d1->imm.expr->accept(this));
|
||||||
if (mov_imm_d1->imm.in_range(value))
|
if (mov_imm_d1->imm.in_range(value))
|
||||||
return mov_imm_d1->code() | mov_imm_d1->bits() | value;
|
return mov_imm_d1->code() | mov_imm_d1->bits() | value;
|
||||||
else
|
else
|
||||||
@ -152,7 +152,7 @@ uint32_t emitter_t::visit(const op::control_word_t * control_word) const
|
|||||||
|
|
||||||
uint32_t emitter_t::visit(const load::mvi_t * mvi) const
|
uint32_t emitter_t::visit(const load::mvi_t * mvi) const
|
||||||
{
|
{
|
||||||
num_t value = mvi->imm.expr->accept(this);
|
num_t value = mvi->imm.normalize(mvi->imm.expr->accept(this));
|
||||||
if (mvi->imm.in_range(value))
|
if (mvi->imm.in_range(value))
|
||||||
return mvi->code() | mvi->bits() | value;
|
return mvi->code() | mvi->bits() | value;
|
||||||
else
|
else
|
||||||
@ -161,7 +161,7 @@ uint32_t emitter_t::visit(const load::mvi_t * mvi) const
|
|||||||
|
|
||||||
uint32_t emitter_t::visit(const load::mvi_cond_t * mvi_cond) const
|
uint32_t emitter_t::visit(const load::mvi_cond_t * mvi_cond) const
|
||||||
{
|
{
|
||||||
num_t value = mvi_cond->imm.expr->accept(this);
|
num_t value = mvi_cond->imm.normalize(mvi_cond->imm.expr->accept(this));
|
||||||
if (mvi_cond->imm.in_range(value))
|
if (mvi_cond->imm.in_range(value))
|
||||||
return mvi_cond->code() | mvi_cond->bits() | value;
|
return mvi_cond->code() | mvi_cond->bits() | value;
|
||||||
else
|
else
|
||||||
@ -170,7 +170,7 @@ uint32_t emitter_t::visit(const load::mvi_cond_t * mvi_cond) const
|
|||||||
|
|
||||||
uint32_t emitter_t::visit(const dma::src_d0_imm_t * src_d0_imm) const
|
uint32_t emitter_t::visit(const dma::src_d0_imm_t * src_d0_imm) const
|
||||||
{
|
{
|
||||||
num_t value = src_d0_imm->imm.expr->accept(this);
|
num_t value = src_d0_imm->imm.normalize(src_d0_imm->imm.expr->accept(this));
|
||||||
if (src_d0_imm->imm.in_range(value))
|
if (src_d0_imm->imm.in_range(value))
|
||||||
return src_d0_imm->code() | src_d0_imm->bits() | value;
|
return src_d0_imm->code() | src_d0_imm->bits() | value;
|
||||||
else
|
else
|
||||||
@ -179,7 +179,7 @@ uint32_t emitter_t::visit(const dma::src_d0_imm_t * src_d0_imm) const
|
|||||||
|
|
||||||
uint32_t emitter_t::visit(const dma::d0_dst_imm_t * d0_dst_imm) const
|
uint32_t emitter_t::visit(const dma::d0_dst_imm_t * d0_dst_imm) const
|
||||||
{
|
{
|
||||||
num_t value = d0_dst_imm->imm.expr->accept(this);
|
num_t value = d0_dst_imm->imm.normalize(d0_dst_imm->imm.expr->accept(this));
|
||||||
if (d0_dst_imm->imm.in_range(value))
|
if (d0_dst_imm->imm.in_range(value))
|
||||||
return d0_dst_imm->code() | d0_dst_imm->bits() | value;
|
return d0_dst_imm->code() | d0_dst_imm->bits() | value;
|
||||||
else
|
else
|
||||||
@ -198,7 +198,7 @@ uint32_t emitter_t::visit(const dma::d0_dst_ram_t * d0_dst_ram) const
|
|||||||
|
|
||||||
uint32_t emitter_t::visit(const jump::jmp_t * jmp) const
|
uint32_t emitter_t::visit(const jump::jmp_t * jmp) const
|
||||||
{
|
{
|
||||||
num_t value = jmp->imm.expr->accept(this);
|
num_t value = jmp->imm.normalize(jmp->imm.expr->accept(this));
|
||||||
if (jmp->imm.in_range(value))
|
if (jmp->imm.in_range(value))
|
||||||
return jmp->code() | jmp->bits() | value;
|
return jmp->code() | jmp->bits() | value;
|
||||||
else
|
else
|
||||||
@ -207,7 +207,7 @@ uint32_t emitter_t::visit(const jump::jmp_t * jmp) const
|
|||||||
|
|
||||||
uint32_t emitter_t::visit(const jump::jmp_cond_t * jmp_cond) const
|
uint32_t emitter_t::visit(const jump::jmp_cond_t * jmp_cond) const
|
||||||
{
|
{
|
||||||
num_t value = jmp_cond->imm.expr->accept(this);
|
num_t value = jmp_cond->imm.normalize(jmp_cond->imm.expr->accept(this));
|
||||||
if (jmp_cond->imm.in_range(value))
|
if (jmp_cond->imm.in_range(value))
|
||||||
return jmp_cond->code() | jmp_cond->bits() | value;
|
return jmp_cond->code() | jmp_cond->bits() | value;
|
||||||
else
|
else
|
||||||
|
@ -22,11 +22,10 @@ struct emitter_error_t : std::runtime_error
|
|||||||
|
|
||||||
struct emitter_t : visitor_t<uint32_t>
|
struct emitter_t : visitor_t<uint32_t>
|
||||||
{
|
{
|
||||||
emitter_t(variables_t& variables, const addresses_t& addresses)
|
emitter_t(variables_t& variables)
|
||||||
: variables(variables), addresses(addresses) {}
|
: variables(variables) {}
|
||||||
|
|
||||||
variables_t& variables;
|
variables_t& variables;
|
||||||
const addresses_t& addresses;
|
|
||||||
|
|
||||||
uint32_t visit(const binary_t * binary) const;
|
uint32_t visit(const binary_t * binary) const;
|
||||||
uint32_t visit(const grouping_t * grouping) const;
|
uint32_t visit(const grouping_t * grouping) const;
|
||||||
|
@ -174,10 +174,10 @@ void resolver_t::visit(const assign_t * assign) const
|
|||||||
|
|
||||||
void resolver_t::visit(const label_t * label) const
|
void resolver_t::visit(const label_t * label) const
|
||||||
{
|
{
|
||||||
if (addresses.contains(label->name.lexeme)) {
|
if (variables.contains(label->name.lexeme)) {
|
||||||
throw std::runtime_error("label redefinition is not allowed");
|
throw std::runtime_error("label redefinition is not allowed");
|
||||||
} else {
|
} else {
|
||||||
addresses.insert({label->name.lexeme, pc.value});
|
variables.insert({label->name.lexeme, pc.value});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,11 +25,11 @@ struct pc_t
|
|||||||
|
|
||||||
struct resolver_t : visitor_t<void>
|
struct resolver_t : visitor_t<void>
|
||||||
{
|
{
|
||||||
resolver_t(pc_t& pc, addresses_t& addresses)
|
resolver_t(pc_t& pc, variables_t& variables)
|
||||||
: pc(pc), addresses(addresses) {}
|
: pc(pc), variables(variables) {}
|
||||||
|
|
||||||
pc_t& pc;
|
pc_t& pc;
|
||||||
addresses_t& addresses;
|
variables_t& variables;
|
||||||
|
|
||||||
void visit(const binary_t * binary) const;
|
void visit(const binary_t * binary) const;
|
||||||
void visit(const grouping_t * grouping) const;
|
void visit(const grouping_t * grouping) const;
|
||||||
|
38
grammar.txt
38
grammar.txt
@ -1,3 +1,25 @@
|
|||||||
|
expression → term
|
||||||
|
term → factor ( ( "-" | "+" ) factor )*
|
||||||
|
factor → unary ( ( "/" | "*" | "%" ) unary )*
|
||||||
|
unary → ( "~" | "+" | "-" ) unary
|
||||||
|
| shift
|
||||||
|
shift → andl ( ( "<<" | ">>" ) andl )*
|
||||||
|
andl → orl ( "&" orl )*
|
||||||
|
orl → andl ( ( "|" | "^" ) andl )*
|
||||||
|
primary → number
|
||||||
|
| "(" expression ")"
|
||||||
|
|
||||||
|
number → "%" base2-number
|
||||||
|
| "$" base16-number
|
||||||
|
| "0b" base2-number
|
||||||
|
| "0x" base16-number
|
||||||
|
| base10-number
|
||||||
|
|
||||||
|
imm → ("#")? expression
|
||||||
|
uimm8 → imm
|
||||||
|
uimm19 → imm
|
||||||
|
uimm25 → imm
|
||||||
|
|
||||||
alu → and | or | xor | add | sub | ad2 | sr | rr | sl | rl | rl8
|
alu → and | or | xor | add | sub | ad2 | sr | rr | sl | rl | rl8
|
||||||
|
|
||||||
xy_src → "mc0" | "mc1" | "mc2" | "mc3"
|
xy_src → "mc0" | "mc1" | "mc2" | "mc3"
|
||||||
@ -25,12 +47,14 @@ d1_src → "mc0" | "mc1" | "mc2" | "mc3"
|
|||||||
| "m0" | "m1" | "m2" | "m3"
|
| "m0" | "m1" | "m2" | "m3"
|
||||||
| "alh" | "all"
|
| "alh" | "all"
|
||||||
|
|
||||||
mov_imm_d1 → "mov" simm8 "," d1_dest
|
mov_imm_d1 → "mov" uimm8 "," d1_dest
|
||||||
mov_ram_d1 → "mov" d1_src "," d1_dest
|
mov_ram_d1 → "mov" d1_src "," d1_dest
|
||||||
|
|
||||||
d1_bus → mov_imm_d1 → mov_ram_d1
|
d1_bus → mov_imm_d1 → mov_ram_d1
|
||||||
|
|
||||||
op → ( alu | x_bus | y_bus | d1_bus ) +
|
nop → "nop"
|
||||||
|
|
||||||
|
op → ( nop | alu | x_bus | y_bus | d1_bus ) +
|
||||||
|
|
||||||
load_dest → "mc0" | "mc1" | "mc2" | "mc3"
|
load_dest → "mc0" | "mc1" | "mc2" | "mc3"
|
||||||
| "rx" | "pl"
|
| "rx" | "pl"
|
||||||
@ -50,7 +74,7 @@ load → mvi | mvi_cond
|
|||||||
|
|
||||||
dma_ingress → "m0" | "m1" | "m2" | "m3"
|
dma_ingress → "m0" | "m1" | "m2" | "m3"
|
||||||
| "prg"
|
| "prg"
|
||||||
|
|
||||||
dma_egress → "m0" | "m1" | "m2" | "m3"
|
dma_egress → "m0" | "m1" | "m2" | "m3"
|
||||||
|
|
||||||
add_mode = "0" | "1" | "2" | "4" | "8" | "16" | "32" | "64"
|
add_mode = "0" | "1" | "2" | "4" | "8" | "16" | "32" | "64"
|
||||||
@ -60,8 +84,8 @@ dma_dmah → ("dma" | "dmah") add_mode?
|
|||||||
dma_length_ram → "m0" | "m1" | "m2" | "m3"
|
dma_length_ram → "m0" | "m1" | "m2" | "m3"
|
||||||
| "mc0" | "mc1" | "mc2" | "mc3"
|
| "mc0" | "mc1" | "mc2" | "mc3"
|
||||||
|
|
||||||
dma_ingress_imm → dma_dmah "d0" "," dma_ingress "," simm8
|
dma_ingress_imm → dma_dmah "d0" "," dma_ingress "," uimm8
|
||||||
dma_egress_imm → dma_dmah dma_egress "," "d0" "," simm8
|
dma_egress_imm → dma_dmah dma_egress "," "d0" "," uimm8
|
||||||
dma_ingress_ram → dma_dmah "d0" "," dma_ingress "," dma_length_ram
|
dma_ingress_ram → dma_dmah "d0" "," dma_ingress "," dma_length_ram
|
||||||
dma_egress_ram → dma_dmah dma_egress "," "d0" "," dma_length_ram
|
dma_egress_ram → dma_dmah dma_egress "," "d0" "," dma_length_ram
|
||||||
|
|
||||||
@ -82,8 +106,7 @@ loop → "btm" | "lps"
|
|||||||
|
|
||||||
end → "end" | "endi"
|
end → "end" | "endi"
|
||||||
|
|
||||||
instruction → "nop"
|
instruction → op
|
||||||
| op
|
|
||||||
| load
|
| load
|
||||||
| dma
|
| dma
|
||||||
| jump
|
| jump
|
||||||
@ -98,4 +121,3 @@ instruction_statement → label? instruction? "\n"
|
|||||||
|
|
||||||
statement → assignment_statement
|
statement → assignment_statement
|
||||||
| instruction_statement
|
| instruction_statement
|
||||||
|
|
||||||
|
41
lexer.cpp
41
lexer.cpp
@ -53,6 +53,19 @@ constexpr static N parse_number(const std::string_view s)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct bin_t {
|
||||||
|
constexpr static bool pred(const char c)
|
||||||
|
{
|
||||||
|
return c >= '0' && c <= '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename N>
|
||||||
|
constexpr static N parse(const std::string_view s)
|
||||||
|
{
|
||||||
|
return parse_number<N, 2>(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct dec_t {
|
struct dec_t {
|
||||||
constexpr static bool pred(const char c)
|
constexpr static bool pred(const char c)
|
||||||
{
|
{
|
||||||
@ -159,13 +172,13 @@ std::optional<token_t> lexer_t::lex_token()
|
|||||||
case '-': return {{pos, minus, lexeme()}};
|
case '-': return {{pos, minus, lexeme()}};
|
||||||
case '*': return {{pos, star, lexeme()}};
|
case '*': return {{pos, star, lexeme()}};
|
||||||
case '/': return {{pos, slash, lexeme()}};
|
case '/': return {{pos, slash, lexeme()}};
|
||||||
case '%': return {{pos, percent, lexeme()}};
|
|
||||||
case '~': return {{pos, tilde, lexeme()}};
|
case '~': return {{pos, tilde, lexeme()}};
|
||||||
case '&': return {{pos, ampersand, lexeme()}};
|
case '&': return {{pos, ampersand, lexeme()}};
|
||||||
case '|': return {{pos, bar, lexeme()}};
|
case '|': return {{pos, bar, lexeme()}};
|
||||||
case '^': return {{pos, carot, lexeme()}};
|
case '^': return {{pos, carot, lexeme()}};
|
||||||
case '=': return {{pos, equal, lexeme()}};
|
case '=': return {{pos, equal, lexeme()}};
|
||||||
case ':': return {{pos, colon, lexeme()}};
|
case ':': return {{pos, colon, lexeme()}};
|
||||||
|
case '#': return {{pos, hash, lexeme()}};
|
||||||
case '<':
|
case '<':
|
||||||
if (match('<')) return {{pos, left_shift, lexeme()}};
|
if (match('<')) return {{pos, left_shift, lexeme()}};
|
||||||
break;
|
break;
|
||||||
@ -175,8 +188,12 @@ std::optional<token_t> lexer_t::lex_token()
|
|||||||
case ';':
|
case ';':
|
||||||
while (!at_end_p() && peek() != '\n') advance();
|
while (!at_end_p() && peek() != '\n') advance();
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case '\\':
|
||||||
|
if (match('\n')) { continue; }
|
||||||
|
else if (match('\r')) { if (match('\n')) continue; }
|
||||||
|
break;
|
||||||
case '\r':
|
case '\r':
|
||||||
|
case ' ':
|
||||||
case '\t':
|
case '\t':
|
||||||
break;
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
@ -187,6 +204,13 @@ std::optional<token_t> lexer_t::lex_token()
|
|||||||
return {{tmp, eol, lexeme()}};
|
return {{tmp, eol, lexeme()}};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case '%':
|
||||||
|
if (bin_t::pred(peek())) {
|
||||||
|
start_ix += 1;
|
||||||
|
return {_number<bin_t>()};
|
||||||
|
} else {
|
||||||
|
return {{pos, percent, lexeme()}};
|
||||||
|
}
|
||||||
case '$':
|
case '$':
|
||||||
if (hex_t::pred(peek())) {
|
if (hex_t::pred(peek())) {
|
||||||
start_ix += 1;
|
start_ix += 1;
|
||||||
@ -198,7 +222,18 @@ std::optional<token_t> lexer_t::lex_token()
|
|||||||
if (hex_t::pred(peek())) {
|
if (hex_t::pred(peek())) {
|
||||||
start_ix += 2;
|
start_ix += 2;
|
||||||
return {_number<hex_t>()};
|
return {_number<hex_t>()};
|
||||||
}
|
} else {
|
||||||
|
error(pos.line, pos.col, "expected hexadecimal literal");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} else if (match('b')) {
|
||||||
|
if (bin_t::pred(peek())) {
|
||||||
|
start_ix += 2;
|
||||||
|
return {_number<bin_t>()};
|
||||||
|
} else {
|
||||||
|
error(pos.line, pos.col, "expected binary literal");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
default:
|
default:
|
||||||
|
7
main.cpp
7
main.cpp
@ -40,15 +40,14 @@ static void run(std::ostream& os, std::string source)
|
|||||||
parser_t pass2(tokens);
|
parser_t pass2(tokens);
|
||||||
ast::printer_t printer(std::cout);
|
ast::printer_t printer(std::cout);
|
||||||
ast::pc_t pc;
|
ast::pc_t pc;
|
||||||
ast::addresses_t addresses;
|
ast::variables_t variables;
|
||||||
ast::resolver_t resolver(pc, addresses);
|
ast::resolver_t resolver(pc, variables);
|
||||||
while (auto stmt_o = pass1.statement()) {
|
while (auto stmt_o = pass1.statement()) {
|
||||||
(*stmt_o)->accept(&printer);
|
(*stmt_o)->accept(&printer);
|
||||||
std::cout << std::endl << std::flush;
|
std::cout << std::endl << std::flush;
|
||||||
(*stmt_o)->accept(&resolver);
|
(*stmt_o)->accept(&resolver);
|
||||||
}
|
}
|
||||||
ast::variables_t variables;
|
ast::emitter_t emitter(variables);
|
||||||
ast::emitter_t emitter(variables, addresses);
|
|
||||||
while (auto stmt_o = pass2.statement()) {
|
while (auto stmt_o = pass2.statement()) {
|
||||||
uint32_t output = (*stmt_o)->accept(&emitter);
|
uint32_t output = (*stmt_o)->accept(&emitter);
|
||||||
if (output != 0xffff'ffff) {
|
if (output != 0xffff'ffff) {
|
||||||
|
33
parser.cpp
33
parser.cpp
@ -1,16 +1,3 @@
|
|||||||
/*
|
|
||||||
expression → term ;
|
|
||||||
term → factor ( ( "-" | "+" ) factor )* ;
|
|
||||||
factor → unary ( ( "/" | "*" | "%" ) unary )* ;
|
|
||||||
unary → ( "~" | "+" | "-" ) unary
|
|
||||||
| shift ;
|
|
||||||
shift → andl ( ( "<<" | ">>" ) andl )*
|
|
||||||
andl → orl ( "&" orl )*
|
|
||||||
orl → andl ( ( "|" | "^" ) andl )*
|
|
||||||
primary → NUMBER
|
|
||||||
| "(" expression ")" ;
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -44,6 +31,11 @@ const token_t& parser_t::peek()
|
|||||||
return tokens[current_ix];
|
return tokens[current_ix];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const token_t& parser_t::peek(int n)
|
||||||
|
{
|
||||||
|
return tokens[current_ix + n];
|
||||||
|
}
|
||||||
|
|
||||||
const token_t& parser_t::advance()
|
const token_t& parser_t::advance()
|
||||||
{
|
{
|
||||||
if (!at_end_p()) current_ix++;
|
if (!at_end_p()) current_ix++;
|
||||||
@ -280,6 +272,7 @@ std::optional<op::op_t *> parser_t::xyd1_bus()
|
|||||||
else
|
else
|
||||||
throw error(peek(), "expected x-bus, y-bus, or d-bus destination operand");
|
throw error(peek(), "expected x-bus, y-bus, or d-bus destination operand");
|
||||||
} else {
|
} else {
|
||||||
|
match(hash); // optionally consume a hash
|
||||||
uimm_t<8> imm = uimm_t<8>(peek(), expression());
|
uimm_t<8> imm = uimm_t<8>(peek(), expression());
|
||||||
consume(comma, "expected `,`");
|
consume(comma, "expected `,`");
|
||||||
if (auto dest_o = d1_dest())
|
if (auto dest_o = d1_dest())
|
||||||
@ -297,6 +290,7 @@ std::optional<op::op_t *> parser_t::xyd1_bus()
|
|||||||
|
|
||||||
std::optional<stmt_t *> parser_t::op()
|
std::optional<stmt_t *> parser_t::op()
|
||||||
{
|
{
|
||||||
|
bool saw_nop = false;
|
||||||
std::vector<const op::op_t *> ops;
|
std::vector<const op::op_t *> ops;
|
||||||
std::vector<const token_t *> tokens;
|
std::vector<const token_t *> tokens;
|
||||||
|
|
||||||
@ -315,11 +309,12 @@ std::optional<stmt_t *> parser_t::op()
|
|||||||
while (true) {
|
while (true) {
|
||||||
// fixme: check for emplacement here
|
// fixme: check for emplacement here
|
||||||
const token_t& token = peek();
|
const token_t& token = peek();
|
||||||
if (auto op_o = alu() ) emplace_op(token, *op_o);
|
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 if (auto op_o = xyd1_bus()) emplace_op(token, *op_o);
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
if (ops.size() != 0)
|
if (ops.size() != 0 || saw_nop)
|
||||||
return {new op::control_word_t(ops)};
|
return {new op::control_word_t(ops)};
|
||||||
else
|
else
|
||||||
return {};
|
return {};
|
||||||
@ -367,6 +362,7 @@ std::optional<stmt_t *> parser_t::load()
|
|||||||
{
|
{
|
||||||
if (match(_mvi)) {
|
if (match(_mvi)) {
|
||||||
const token_t& expr_token = peek();
|
const token_t& expr_token = peek();
|
||||||
|
match(hash); // optionally consume a hash
|
||||||
expr_t * expr = expression();
|
expr_t * expr = expression();
|
||||||
consume(comma, "expected `,`");
|
consume(comma, "expected `,`");
|
||||||
load::dest_t dest = parser_t::load_dest();
|
load::dest_t dest = parser_t::load_dest();
|
||||||
@ -512,6 +508,7 @@ std::optional<stmt_t *> parser_t::dma()
|
|||||||
if (auto length_ram_o = dma_length_ram()) {
|
if (auto length_ram_o = dma_length_ram()) {
|
||||||
return {new dma::d0_dst_ram_t(hold, add, dst, *length_ram_o)};
|
return {new dma::d0_dst_ram_t(hold, add, dst, *length_ram_o)};
|
||||||
} else {
|
} else {
|
||||||
|
match(hash); // optionally consume a hash
|
||||||
uimm_t<8> imm = uimm_t<8>(peek(), expression());
|
uimm_t<8> imm = uimm_t<8>(peek(), expression());
|
||||||
return {new dma::d0_dst_imm_t(hold, add, dst, imm)};
|
return {new dma::d0_dst_imm_t(hold, add, dst, imm)};
|
||||||
}
|
}
|
||||||
@ -523,6 +520,7 @@ std::optional<stmt_t *> parser_t::dma()
|
|||||||
if (auto length_ram_o = dma_length_ram()) {
|
if (auto length_ram_o = dma_length_ram()) {
|
||||||
return {new dma::src_d0_ram_t(hold, add, src, *length_ram_o)};
|
return {new dma::src_d0_ram_t(hold, add, src, *length_ram_o)};
|
||||||
} else {
|
} else {
|
||||||
|
match(hash); // optionally consume a hash
|
||||||
uimm_t<8> imm = uimm_t<8>(peek(), expression());
|
uimm_t<8> imm = uimm_t<8>(peek(), expression());
|
||||||
return {new dma::src_d0_imm_t(hold, add, src, imm)};
|
return {new dma::src_d0_imm_t(hold, add, src, imm)};
|
||||||
}
|
}
|
||||||
@ -553,9 +551,11 @@ std::optional<stmt_t *> parser_t::jump()
|
|||||||
if (match(_jmp)) {
|
if (match(_jmp)) {
|
||||||
if (auto cond_o = jump_cond()) {
|
if (auto cond_o = jump_cond()) {
|
||||||
consume(comma, "expected `,` after jump condition");
|
consume(comma, "expected `,` after jump condition");
|
||||||
|
match(hash); // optionally consume a hash
|
||||||
uimm_t<8> imm = uimm_t<8>(peek(), expression());
|
uimm_t<8> imm = uimm_t<8>(peek(), expression());
|
||||||
return {new jump::jmp_cond_t(*cond_o, imm)};
|
return {new jump::jmp_cond_t(*cond_o, imm)};
|
||||||
} else {
|
} else {
|
||||||
|
match(hash); // optionally consume a hash
|
||||||
uimm_t<8> imm = uimm_t<8>(peek(), expression());
|
uimm_t<8> imm = uimm_t<8>(peek(), expression());
|
||||||
return {new jump::jmp_t(imm)};
|
return {new jump::jmp_t(imm)};
|
||||||
}
|
}
|
||||||
@ -579,8 +579,7 @@ std::optional<stmt_t *> parser_t::end()
|
|||||||
|
|
||||||
std::optional<stmt_t *> parser_t::instruction()
|
std::optional<stmt_t *> parser_t::instruction()
|
||||||
{
|
{
|
||||||
if (match(_nop)) return {new nop::nop_t()};
|
if (auto op_o = op()) return op_o;
|
||||||
else if (auto op_o = op()) return op_o;
|
|
||||||
else if (auto load_o = load()) return load_o;
|
else if (auto load_o = load()) return load_o;
|
||||||
else if (auto dma_o = dma()) return dma_o;
|
else if (auto dma_o = dma()) return dma_o;
|
||||||
else if (auto jump_o = jump()) return jump_o;
|
else if (auto jump_o = jump()) return jump_o;
|
||||||
|
@ -31,6 +31,7 @@ struct parser_t
|
|||||||
|
|
||||||
const token_t& previous();
|
const token_t& previous();
|
||||||
const token_t& peek();
|
const token_t& peek();
|
||||||
|
const token_t& peek(int n);
|
||||||
const token_t& advance();
|
const token_t& advance();
|
||||||
bool check(enum token_t::type_t token_type);
|
bool check(enum token_t::type_t token_type);
|
||||||
bool match(enum token_t::type_t token_type);
|
bool match(enum token_t::type_t token_type);
|
||||||
|
10
stmt.hpp
10
stmt.hpp
@ -40,6 +40,15 @@ struct imm_t {
|
|||||||
static constexpr num_t max = (1L << (bits - static_cast<num_t>(sign))) - 1;
|
static constexpr num_t max = (1L << (bits - static_cast<num_t>(sign))) - 1;
|
||||||
static constexpr num_t min = sign ? -(max + 1) : 0;
|
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
|
bool in_range(num_t value) const
|
||||||
{
|
{
|
||||||
return value <= max && value >= min;
|
return value <= max && value >= min;
|
||||||
@ -257,7 +266,6 @@ struct control_word_t : stmt_accept_t<control_word_t>
|
|||||||
control_word_t(std::vector<const op::op_t *> ops)
|
control_word_t(std::vector<const op::op_t *> ops)
|
||||||
: ops(ops)
|
: ops(ops)
|
||||||
{
|
{
|
||||||
if (ops.size() == 0) throw std::runtime_error("zero-length ops");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<const op_t *> ops;
|
const std::vector<const op_t *> ops;
|
||||||
|
@ -22,17 +22,21 @@ const std::string alu_type_string[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const std::string xy_src_string[] = {
|
const std::string xy_src_string[] = {
|
||||||
[i(xy_src_t::mc0)] = "mc0",
|
|
||||||
[i(xy_src_t::mc1)] = "mc1",
|
|
||||||
[i(xy_src_t::mc2)] = "mc2",
|
|
||||||
[i(xy_src_t::mc3)] = "mc3",
|
|
||||||
[i(xy_src_t::m0 )] = "m0" ,
|
[i(xy_src_t::m0 )] = "m0" ,
|
||||||
[i(xy_src_t::m1 )] = "m1" ,
|
[i(xy_src_t::m1 )] = "m1" ,
|
||||||
[i(xy_src_t::m2 )] = "m2" ,
|
[i(xy_src_t::m2 )] = "m2" ,
|
||||||
[i(xy_src_t::m3 )] = "m3" ,
|
[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 d1_dest_string[] = {
|
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::rx )] = "rx" ,
|
||||||
[i(d1_dest_t::pl )] = "pl" ,
|
[i(d1_dest_t::pl )] = "pl" ,
|
||||||
[i(d1_dest_t::ra0)] = "ra0",
|
[i(d1_dest_t::ra0)] = "ra0",
|
||||||
@ -46,14 +50,16 @@ const std::string d1_dest_string[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const std::string d1_src_string[] = {
|
const std::string d1_src_string[] = {
|
||||||
[i(d1_src_t::mc0)] = "mc0",
|
|
||||||
[i(d1_src_t::mc1)] = "mc1",
|
|
||||||
[i(d1_src_t::mc2)] = "mc2",
|
|
||||||
[i(d1_src_t::mc3)] = "mc3",
|
|
||||||
[i(d1_src_t::m0 )] = "m0" ,
|
[i(d1_src_t::m0 )] = "m0" ,
|
||||||
[i(d1_src_t::m1 )] = "m1" ,
|
[i(d1_src_t::m1 )] = "m1" ,
|
||||||
[i(d1_src_t::m2 )] = "m2" ,
|
[i(d1_src_t::m2 )] = "m2" ,
|
||||||
[i(d1_src_t::m3 )] = "m3" ,
|
[i(d1_src_t::m3 )] = "m3" ,
|
||||||
|
[i(d1_src_t::mc0)] = "mc0",
|
||||||
|
[i(d1_src_t::mc1)] = "mc1",
|
||||||
|
[i(d1_src_t::mc2)] = "mc2",
|
||||||
|
[i(d1_src_t::mc3)] = "mc3",
|
||||||
|
[i(d1_src_t::all)] = "all",
|
||||||
|
[i(d1_src_t::alh)] = "alh",
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
52
test/Makefile
Normal file
52
test/Makefile
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
DSPASM = dspasm.exe
|
||||||
|
|
||||||
|
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))
|
||||||
|
ALL = $(EXPECT) $(ACTUAL)
|
||||||
|
ALL_TXT = $(patsubst %.bin,%.txt,$(ALL))
|
||||||
|
|
||||||
|
all: $(ALL)
|
||||||
|
all-txt: $(ALL_TXT)
|
||||||
|
|
||||||
|
%.s: %.asm
|
||||||
|
@test -f $(DSPASM) || (echo $(DSPASM) does not exist--set the DSPASM make variable; exit 1)
|
||||||
|
@rm -f $@
|
||||||
|
echo '[autoexec]' > $@.conf
|
||||||
|
echo 'mount C $(dir $(DSPASM))' >> $@.conf
|
||||||
|
echo 'mount D $(dir $<)' >> $@.conf
|
||||||
|
echo 'D:' >> $@.conf
|
||||||
|
echo 'C:\$(notdir $(DSPASM)) $(notdir $<) $(notdir $@)' >> $@.conf
|
||||||
|
echo 'exit' >> $@.conf
|
||||||
|
dosbox -conf $@.conf
|
||||||
|
@rm $@.conf
|
||||||
|
mv $(shell echo '$@' | tr '[:lower:]' '[:upper:]') $@
|
||||||
|
|
||||||
|
%.txt: %.bin
|
||||||
|
python bin-dump.py $< > $@
|
||||||
|
|
||||||
|
%.txt: %.bin
|
||||||
|
python bin-dump.py $< > $@
|
||||||
|
|
||||||
|
expect/%.bin: %.s
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
srec_cat -Output $@ -Binary $<
|
||||||
|
|
||||||
|
actual/%.bin: %.asm
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
../main $< $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f expect/*.{bin,txt} actual/*.{bin,txt} *.s
|
||||||
|
|
||||||
|
.SUFFIXES:
|
||||||
|
.INTERMEDIATE:
|
||||||
|
.SECONDARY:
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
%: RCS/%,v
|
||||||
|
%: RCS/%
|
||||||
|
%: %,v
|
||||||
|
%: s.%
|
||||||
|
%: SCCS/s.%
|
12
test/bin-dump.py
Normal file
12
test/bin-dump.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import sys
|
||||||
|
import struct
|
||||||
|
|
||||||
|
with open(sys.argv[1], 'rb') as f:
|
||||||
|
b = f.read()
|
||||||
|
|
||||||
|
assert len(b) % 4 == 0, len(b)
|
||||||
|
|
||||||
|
for i in range(len(b) // 4):
|
||||||
|
word = b[i*4:i*4+4]
|
||||||
|
n, = struct.unpack('>I', word)
|
||||||
|
print(f'{n:>032b}')
|
@ -25,6 +25,7 @@ struct token_t {
|
|||||||
|
|
||||||
comma,
|
comma,
|
||||||
dot,
|
dot,
|
||||||
|
hash,
|
||||||
|
|
||||||
// operators
|
// operators
|
||||||
plus,
|
plus,
|
||||||
@ -81,6 +82,7 @@ struct token_t {
|
|||||||
|
|
||||||
case comma : return os << "COMMA";
|
case comma : return os << "COMMA";
|
||||||
case dot : return os << "DOT";
|
case dot : return os << "DOT";
|
||||||
|
case hash : return os << "HASH";
|
||||||
|
|
||||||
// operators
|
// operators
|
||||||
case plus : return os << "PLUS";
|
case plus : return os << "PLUS";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user