diff options
| author | Ataberk <olgunataberk@gmail.com> | 2022-09-25 17:22:03 +0200 |
|---|---|---|
| committer | Ataberk <olgunataberk@gmail.com> | 2022-09-25 17:22:03 +0200 |
| commit | dc0b3db1b4f1895a07e5fe280ee3790e87f97b9f (patch) | |
| tree | b47203aa281bdd959def4451c84d310cd9cf2e12 /sources/api/lexyacc | |
| download | dram-bender-dc0b3db1b4f1895a07e5fe280ee3790e87f97b9f.tar.gz | |
Initial commit
Diffstat (limited to 'sources/api/lexyacc')
| -rw-r--r-- | sources/api/lexyacc/Makefile | 29 | ||||
| -rw-r--r-- | sources/api/lexyacc/example.smc | 102 | ||||
| -rw-r--r-- | sources/api/lexyacc/smc.l | 77 | ||||
| -rw-r--r-- | sources/api/lexyacc/smc.y | 427 |
4 files changed, 635 insertions, 0 deletions
diff --git a/sources/api/lexyacc/Makefile b/sources/api/lexyacc/Makefile new file mode 100644 index 0000000..67a05fa --- /dev/null +++ b/sources/api/lexyacc/Makefile @@ -0,0 +1,29 @@ +program_NAME := smc_parser +program_CXX_SRCS := lex.yy.c y.tab.c $(wildcard ../*.c*) +program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o} +program_OBJS := $(program_CXX_OBJS) +program_INCLUDE_DIRS := ../ ../../../boost-lib +program_LIBRARY_DIRS := +program_LIBRARIES := +CPPFLAGS += -g -std=c++11 -pthread + +CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir)) +LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir)) +LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library)) + +CC=g++ + +.PHONY: all clean distclean + +all: $(program_NAME) + +$(program_NAME): $(program_OBJS) lex.yy.c + $(CC) $(CPPFLAGS) $(program_OBJS) -o $(program_NAME) $(LDFLAGS) + +lex.yy.c: y.tab.c smc.l + flex smc.l + +y.tab.c: smc.y + yacc -d smc.y + +distclean: clean diff --git a/sources/api/lexyacc/example.smc b/sources/api/lexyacc/example.smc new file mode 100644 index 0000000..f9cc4f6 --- /dev/null +++ b/sources/api/lexyacc/example.smc @@ -0,0 +1,102 @@ +// Initialize register ids +// Similar to #define +casr = 0 +basr = 1 +rasr = 2 +bar = 2 +rar = 3 +car = 4 +pattern_reg = 5 +no_row_reg = 6 +no_bank_reg = 7 + +// Begin writing the program +LI no_row_reg 32768 // Write 2^15 to no_row_Reg +LI no_bank_reg 16 // write 16 to no_bank_reg + +// Set stride registers (not required if you +// are not going to increment address registers +// with ddr commands) +LI casr 8 // set column address stride to 8 +LI basr 1 // set bas to 1 +LI rasr 1 // set ras to 1 + +LI bar 0 // Initialize bank address register + +// Init pattern register, we are going to fill +// dram with 0xffs. +LI pattern_reg 0xffffffff + +// Load the data register with the pattern +// second argument here is the word offset +// we are writing to in the data register +// e.g. LDWD 0 pattern reg fills the first four bytes + +LDWD 0 pattern_reg +LDWD 1 pattern_reg +LDWD 2 pattern_reg +LDWD 3 pattern_reg +LDWD 4 pattern_reg +LDWD 5 pattern_reg +LDWD 6 pattern_reg +LDWD 7 pattern_reg +LDWD 8 pattern_reg +LDWD 9 pattern_reg +LDWD 10 pattern_reg +LDWD 11 pattern_reg +LDWD 12 pattern_reg +LDWD 13 pattern_reg +LDWD 14 pattern_reg +LDWD 15 pattern_reg + +BANK_BEGIN: // Add label to loop over banks +LI rar 0 // Reload rar per bank loop + +ROW_BEGIN: // Add label to loop over rows +LI car 0 // Reload car per row loop + +PRE bar // PREcharge bar, don't increment, no precharge-all +WAIT 7 // Insert seven cycles of NOPs + +ACT bar rar // ACTivate bar, rar +WAIT 7 + +// This is a basic primitive that can be used +// to replicate instructions-commands +// this block replicates the WR command 128 times +// and adds it to the program +times 128 { + WR bar car++ + WAIT 3 +} + +// Reload car, we are now going to read from DRAM +LI car 0 + +// Wait tWR, might not be precise. +WAIT 8 +PRE bar +WAIT 7 + +ACT bar rar +WAIT 7 + +times 128 { + RD bar car++ + WAIT 3 +} + +WAIT 8 +PRE bar + +// Increment rar per row loop +ADDI rar rar 1 +// if rar < no_row_reg, execute the "row loop" once more +BL ROW_BEGIN rar no_row_reg + +ADDI bar bar 1 +BL BANK_BEGIN bar no_bank_reg + +// Tell softmc that the program has ended +// This is important! +END
\ No newline at end of file diff --git a/sources/api/lexyacc/smc.l b/sources/api/lexyacc/smc.l new file mode 100644 index 0000000..4d9e478 --- /dev/null +++ b/sources/api/lexyacc/smc.l @@ -0,0 +1,77 @@ +%{ + #include <stdlib.h> + #include "instruction.h" + #include "y.tab.h" +%} + +%% + +"//"[^\n]* ; /* Skip comments */ +[%\t ]+ ; /* Skip whitespace */ + +0x[0-9a-f]+ { + yylval.lit = yytext+2; + return HEX_NUMBER; + } + +[0-9]+ { + yylval.num = atoi(yytext); + return DEC_NUMBER; + } + +r[0-9][0-9]? { + yylval.num = atoi(++yytext); /* Skip the first character? */ + return REG_ID; + } + +"wait"|"WAIT" return WAIT; + +"add"|"ADD" return ADD; +"addi"|"ADDI" return ADDI; +"sub"|"SUB" return SUB; +"subi"|"SUBI" return SUBI; +"mov"|"MOV" return MOV; +"src"|"SRC" return SRC; +"li"|"LI" return LI; +"ldwd"|"LDWD" return LDWD; + +"bl"|"BL" return BRL; +"beq"|"beq" return BREQ; +"jmp"|"JMP" return JMP; + +"wr"|"WR" return WR; +"rd"|"RD" return RD; +"act"|"ACT" return ACT; +"pre"|"PRE" return PRE; +"ref"|"REF" return REF; +"zq"|"ZQ" return ZQ; +"end"|"END" return END; + + +"++" return INCREMENT; +"AP"|"ap" return AUTO_PRECHARGE; +"BC"|"bc" return BURST_CHOP; +"PA"|"pa" return PRECHARGE_ALL; + +"times" return GENFOR; +"ENDPROGRAM" return ENDPROGRAM; + + [a-z_]+ { + char* var_name = (char*) malloc((yyleng+1)*sizeof(char)); + strcpy(var_name, yytext); + yylval.lit = var_name; + return VARIABLE; + } + + [A-Z_]+ { + char* lbl_name = (char*) malloc((yyleng+1)*sizeof(char)); + strcpy(lbl_name, yytext); + yylval.lit = lbl_name; + return LABEL; + } + + . return *yytext; + +%% + +int yywrap(void) { return 1; } diff --git a/sources/api/lexyacc/smc.y b/sources/api/lexyacc/smc.y new file mode 100644 index 0000000..f9ff06d --- /dev/null +++ b/sources/api/lexyacc/smc.y @@ -0,0 +1,427 @@ +%{ + #include "prog.h" + #include "instruction.h" + #include <iostream> + #include <stdlib.h> + #include <stdint.h> + #include <string> + #include <string.h> + #include <queue> + #include <map> + #include <stack> + + extern char* yytext; + extern int yyleng; + extern int yylex(void); + extern "C" void yyerror(char const*); + + int block_levels = 0; + + Program* prog; + std::stack <Program*> prog_addr_stack; + void process_ddr_command_queue(); + std::stack <uint32_t> num_generate_stack; + std::queue <Mininst> ddr_command_queue; + std::map<std::string, uint32_t> variable_map; +%} + +%start program + +%union { void* prg; + Mininst mini_i_type; + Inst i_type; + uint32_t num; + char* lit; + } + +%token <lit> HEX_NUMBER +%token <num> DEC_NUMBER +%token <num> REG_ID +%token <lit> LABEL +%token <lit> VARIABLE + +/* Instruction OP-Codes */ +%token WAIT + +%token ADD +%token ADDI +%token SUB +%token SUBI +%token MOV +%token SRC +%token LI +%token LDWD + +%token BRL +%token BREQ +%token JMP + +%token WR +%token RD +%token ACT +%token PRE +%token REF +%token ZQ +%token END + +/* Misc. operators */ +%token INCREMENT +%token AUTO_PRECHARGE +%token BURST_CHOP +%token PRECHARGE_ALL + +/* Other Expressions */ +%token GENFOR +%token ENDPROGRAM + +%type <num> gen_begin +%type <num> immediate +%type <i_type> instruction +%type <mini_i_type> ddr_command +%type <num> address_register +%type <num> reg_id +%type <num> rw_args +%type <num> pre_args + +%% + +program: + expression_list + | program ENDPROGRAM + { + } + ; + +expression_list: + expression {} + | expression_list expression {} + +expression: + instruction + { + // See if DDR command queue is empty + if (ddr_command_queue.size() > 0) + { + printf("WARNING: I just appended some NOPs to your code\n"); + int nops_to_append = 4 - ddr_command_queue.size(); + Mininst ddr_cmd_batch[4]; + for (int i = 0 ; i < ddr_command_queue.size() ; i++) + { + ddr_cmd_batch[i] = ddr_command_queue.front(); + ddr_command_queue.pop(); + } + for (int i = ddr_command_queue.size() ; i < 4 ; i++) + ddr_cmd_batch[i] = SMC_NOP(); + prog->add_inst(__pack_mininsts(ddr_cmd_batch[0],ddr_cmd_batch[1], + ddr_cmd_batch[2],ddr_cmd_batch[3])); + } + prog->add_inst($1); + } + | branch + { + + } + | pseudo_instruction + { + + } + | LABEL ':' + { + prog->add_label(std::string($1)); + } + | ddr_command + { + ddr_command_queue.push($1); + process_ddr_command_queue(); + } + | definition + { + + } + | gen_begin + { + num_generate_stack.push($1); + } + | '}' // end of a generate block + { + if(block_levels == 0) // pop an error: no generate blocks present, cannot end a block definition + printf("Expected \'}\' somewhere.\n"); // TODO change this with a correct error displaying function + else + { + Program* previous_in_stack = prog_addr_stack.top(); + prog_addr_stack.pop(); + int num_gen = num_generate_stack.top(); + num_generate_stack.pop(); + for (int i = 0 ; i < num_gen ; i++) + previous_in_stack->add_below(*prog); + free(prog); + prog = previous_in_stack; + } + } + ; + +instruction: + ADD reg_id reg_id reg_id + { + $$ = SMC_ADD($3, $4, $2); + } + | ADDI reg_id reg_id immediate + { + $$ = SMC_ADDI($3, $4, $2); + } + | SUB reg_id reg_id reg_id + { + $$ = SMC_SUB($3, $4, $2); + } + | SUBI reg_id reg_id immediate + { + $$ = SMC_SUBI($3, $4, $2); + } + | MOV reg_id reg_id + { + $$ = SMC_MV($3, $2); + } + | SRC reg_id reg_id + { + $$ = SMC_SRC($3, $2); + } + | LI reg_id immediate + { + $$ = SMC_LI($3, $2); + } + | LDWD immediate reg_id + { + $$ = SMC_LDWD($3, $2); + } + | END + { + $$ = SMC_END(); + } + ; + +branch: + BRL LABEL reg_id reg_id + { + prog->add_branch(prog->BR_TYPE::BL, $3, $4, $2); + } + | BREQ LABEL reg_id reg_id + { + prog->add_branch(prog->BR_TYPE::BEQ, $3, $4, $2); + } + | JMP LABEL + { + prog->add_branch(prog->BR_TYPE::JUMP, 0, 0, $2); + } + ; + +pseudo_instruction: + WAIT immediate + { + // currently functions only by adding NOPs + // TODO depending on the # of cycles specified + // we can instead generate a "loop" which enables + // us to wait for more with less instructions. + for(int i = 0 ; i < $2 ; i++) + ddr_command_queue.push(SMC_NOP()); + process_ddr_command_queue(); + } + ; + +immediate: + HEX_NUMBER + { + $$ = (uint32_t) strtol($1, NULL, 16); + } + | DEC_NUMBER + { + $$ = $1; + } + ; +ddr_command: + WR address_register address_register rw_args + { + int reg1_id = $2; + int reg2_id = $3; + int do_increment1 = reg1_id >= 100 ? 1 : 0; + int do_increment2 = reg2_id >= 100 ? 1 : 0; + if(do_increment1) + reg1_id -= 100; + if(do_increment2) + reg2_id -= 100; + int do_ap = $4 == 3 ? 1 : $4 == 1 ? 1 : 0; + int do_bc = $4 == 3 ? 1 : $4 == 2 ? 1 : 0; + $$ = SMC_WRITE(reg1_id, do_increment1, reg2_id, do_increment2, do_bc, do_ap); + } + | RD address_register address_register rw_args + { + int reg1_id = $2; + int reg2_id = $3; + int do_increment1 = reg1_id >= 100 ? 1 : 0; + int do_increment2 = reg2_id >= 100 ? 1 : 0; + if(do_increment1) + reg1_id -= 100; + if(do_increment2) + reg2_id -= 100; + int do_ap = $4 == 3 ? 1 : $4 == 1 ? 1 : 0; + int do_bc = $4 == 3 ? 1 : $4 == 2 ? 1 : 0; + $$ = SMC_READ(reg1_id, do_increment1, reg2_id, do_increment2, do_bc, do_ap); + } + | ACT address_register address_register + { + int reg1_id = $2; + int reg2_id = $3; + int do_increment1 = reg1_id >= 100 ? 1 : 0; + int do_increment2 = reg2_id >= 100 ? 1 : 0; + if(do_increment1) + reg1_id -= 100; + if(do_increment2) + reg2_id -= 100; + $$ = SMC_ACT(reg1_id, do_increment1, reg2_id, do_increment2); + } + | PRE address_register pre_args + { + int reg_id = $2; + int do_increment = reg_id>=100 ? 1 : 0; + if(do_increment) + reg_id -= 100; + $$ = SMC_PRE(reg_id, do_increment, $3); + } + | REF + { + $$ = SMC_REF(); + } + | ZQ + { + $$ = SMC_ZQ(); + } + ; + +address_register: + reg_id + { + $$ = $1; + } + | reg_id INCREMENT + { + $$ = 100 + $1; + } + ; + +definition: + VARIABLE '=' immediate + { + std::string key = std::string($1); + variable_map[key] = $3; + } + ; + +reg_id: + REG_ID + { + $$ = $1; + } + | VARIABLE + { + std::string key = std::string($1); + if (variable_map.find(key) == variable_map.end()) + { + // TODO proper error handling + std::cout << "Variable " << key << " is not defined." << std::endl; + $$ = 0; + } else + $$ = variable_map[key]; + } + ; + +rw_args: + %empty + { + $$ = 0; + } + | AUTO_PRECHARGE + { + $$ = 1; + } + | BURST_CHOP + { + $$ = 2; + } + | AUTO_PRECHARGE BURST_CHOP + { + $$ = 3; + } + | BURST_CHOP AUTO_PRECHARGE + { + $$ = 3; + } + ; + +pre_args: + %empty + { + $$ = 0; + } + | PRECHARGE_ALL + { + $$ = 1; + } + ; + +gen_begin: + GENFOR immediate '{' + { + // See if DDR command queue is empty + if (ddr_command_queue.size() > 0) + { + printf("WARNING: I just appended some NOPs to your code\n"); + int nops_to_append = 4 - ddr_command_queue.size(); + Mininst ddr_cmd_batch[4]; + for (int i = 0 ; i < ddr_command_queue.size() ; i++) + { + ddr_cmd_batch[i] = ddr_command_queue.front(); + ddr_command_queue.pop(); + } + for (int i = ddr_command_queue.size() ; i < 4 ; i++) + ddr_cmd_batch[i] = SMC_NOP(); + prog->add_inst(__pack_mininsts(ddr_cmd_batch[0],ddr_cmd_batch[1], + ddr_cmd_batch[2],ddr_cmd_batch[3])); + } + prog_addr_stack.push(prog); + prog = new Program(); + block_levels++; + $$ = $2; // Number of times this block is generated + } + ; + +%% + +void process_ddr_command_queue() +{ + while (ddr_command_queue.size() >= 4) + { + Mininst ddr_cmd_batch[4]; + for (int i = 0 ; i < 4 ; i++) + { + ddr_cmd_batch[i] = ddr_command_queue.front(); + ddr_command_queue.pop(); + } + prog->add_inst(__pack_mininsts(ddr_cmd_batch[0],ddr_cmd_batch[1], + ddr_cmd_batch[2],ddr_cmd_batch[3])); + } +} + +void yyerror (char const *s) { + fprintf (stderr, "%s\n", s); +} + +int main(int argc, char* argv[]) +{ + if(argc != 2){ + printf("I need you to supply me with the filename!\n"); + exit(1); + } + prog = new Program(); + yyparse(); + prog->save_bin(std::string(argv[1])); +} + |
