aboutsummaryrefslogtreecommitdiffstats
path: root/sources/api/lexyacc
diff options
context:
space:
mode:
authorAtaberk <olgunataberk@gmail.com>2022-09-25 17:22:03 +0200
committerAtaberk <olgunataberk@gmail.com>2022-09-25 17:22:03 +0200
commitdc0b3db1b4f1895a07e5fe280ee3790e87f97b9f (patch)
treeb47203aa281bdd959def4451c84d310cd9cf2e12 /sources/api/lexyacc
downloaddram-bender-dc0b3db1b4f1895a07e5fe280ee3790e87f97b9f.tar.gz
Initial commit
Diffstat (limited to 'sources/api/lexyacc')
-rw-r--r--sources/api/lexyacc/Makefile29
-rw-r--r--sources/api/lexyacc/example.smc102
-rw-r--r--sources/api/lexyacc/smc.l77
-rw-r--r--sources/api/lexyacc/smc.y427
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]));
+}
+