prototype version with 2 cycles instructions

This commit is contained in:
Romain Dolbeau 2021-02-14 03:18:11 -05:00
parent 413a570ee9
commit c56ad23e49
9 changed files with 191 additions and 27 deletions

View file

@ -60,7 +60,7 @@ PDataProcess.scala: gen_plugin data_Zpn.txt
./gen_plugin -n PDataProcess -i data_Zpn.txt -I Zpn >| $@
PSlowDataProcess.scala: gen_plugin data_Zpn.txt
./gen_plugin -n PSlowDataProcess -i data_Zpn.txt -I Zpnslow >| $@
./gen_plugin -n PSlowDataProcess -i data_Zpn_2cycles.txt -I Zpn >| $@
P64DataProcess.scala: gen_plugin data_Zp64.txt
./gen_plugin -w -n P64DataProcess -i data_Zp64.txt -I '*' >| $@

46
data_Zpn_2cycles.txt Normal file
View file

@ -0,0 +1,46 @@
I SMAQA SMAQA 1100100----------000----01110111 pdpiumul8 Zpn
I UMAQA UMAQA 1100110----------000----01110111 pdpismul8 Zpn
S SMAQA "fun_smaqa1(input(SRC1), input(SRC2), input(SRC3))"
S UMAQA "fun_umaqa1(input(SRC1), input(SRC2), input(SRC3))"
T SMAQA 96 "fun_smaqa2"
T UMAQA 96 "fun_umaqa2"
P """
def fun_smaqa1(rs1: Bits, rs2: Bits, rs3: Bits) : Bits = {
// 18 bits needed so that intermediate sums don't overflow
val h0 = (rs1( 7 downto 0).asSInt * rs2( 7 downto 0).asSInt)
val h1 = (rs1(15 downto 8).asSInt * rs2(15 downto 8).asSInt)
val h2 = (rs1(23 downto 16).asSInt * rs2(23 downto 16).asSInt)
val h3 = (rs1(31 downto 24).asSInt * rs2(31 downto 24).asSInt)
rs3 ## h3 ## h2 ## h1 ## h0 // return value 96 bits
}
def fun_smaqa2(input:Bits ) : Bits = {
val r = input(95 downto 64).asSInt + (
input(63 downto 48).asSInt.resize(18) +
input(47 downto 32).asSInt.resize(18) +
input(31 downto 16).asSInt.resize(18) +
input(15 downto 0).asSInt.resize(18))
r.asBits.resize(32) // return value
}
def fun_umaqa1(rs1: Bits, rs2: Bits, rs3: Bits) : Bits = {
// 18 bits needed so that intermediate sums don't overflow
val h0 = (rs1( 7 downto 0).asUInt * rs2( 7 downto 0).asUInt)
val h1 = (rs1(15 downto 8).asUInt * rs2(15 downto 8).asUInt)
val h2 = (rs1(23 downto 16).asUInt * rs2(23 downto 16).asUInt)
val h3 = (rs1(31 downto 24).asUInt * rs2(31 downto 24).asUInt)
rs3 ## h3 ## h2 ## h1 ## h0 // return value 96 bits
}
def fun_umaqa2(input:Bits ) : Bits = {
val r = input(95 downto 64).asUInt + (
input(63 downto 48).asUInt.resize(18) +
input(47 downto 32).asUInt.resize(18) +
input(31 downto 16).asUInt.resize(18) +
input(15 downto 0).asUInt.resize(18))
r.asBits.resize(32) // return value
}
"""

View file

@ -28,6 +28,8 @@ extern int yydebug;
std::set<const instruction*> instructions;
std::map<std::string, std::string> semantics;
std::map<std::string, int> em_widths;
std::map<std::string, std::string> mem_semantics;
std::vector<std::string> prologues;
std::vector<std::string> extras;
@ -77,7 +79,15 @@ void add_inst5(const char* name, const char* opname, const char* key, const char
instructions.insert(i);
}
void add_sem(const char* name, const char* sem) {
semantics[std::string(name)] = std::string(sem);
const std::string key(name);
semantics[key] = std::string(sem);
}
void add_memsem(const char* name, const int em_width, const char* memsem) {
const std::string key(name);
if ((em_width > 0) && (memsem != NULL)) {
em_widths[key] = em_width;
mem_semantics[key] = std::string(memsem);
}
}
void add_prol(const char *prol) {
prologues.push_back(std::string(prol));
@ -155,7 +165,18 @@ int main(int argc, char **argv) {
//printf("adding %s\n", inst->name.c_str());
}
unparse(std::cout, pluginName, filtered_instructions, semantics, prologues, extras, wide == 1);
if ((em_widths.size() != 0) || (mem_semantics.size() !=0)) {
if (em_widths.size() != mem_semantics.size()) {
std::cerr << "Multicycle error: emwidths.size() != mem_semantics.size()" << std::endl;
exit(-1);
}
if (semantics.size() != mem_semantics.size()) {
std::cerr << "Multicycle error: semantics.size() != mem_semantics.size() (all instructions should have the same nuber of cycles in the same plugin)" << std::endl;
exit(-1);
}
}
unparse(std::cout, pluginName, filtered_instructions, semantics, em_widths, mem_semantics, prologues, extras, wide == 1);
return 0;
}

View file

@ -17,6 +17,7 @@ extern "C" {
void add_inst4(const char* name, const char* opname, const char* key, const char* group, const char* e1, const char* e2, const char *e3, const char *e4);
void add_inst5(const char* name, const char* opname, const char* key, const char* group, const char* e1, const char* e2, const char *e3, const char *e4, const char *e5);
void add_sem(const char* name, const char* sem);
void add_memsem(const char* name, const int em_width, const char* memsem);
void add_prol(const char *prol);
void add_extra(const char *extra);
#ifdef __cplusplus

View file

@ -5,35 +5,44 @@
* See the LICENSE file at the top level of this software distribution for details.
*/
#include <stdio.h>
#include <stdlib.h>
#include "inst_par.h"
%}
CHAR [[:alnum:] ,'&./()-]
FCHARNAME [[:alpha:]]
CHARNAME [[:alnum:]_+-]
SPACE [ \t]
%%
^"I" { return INST; }
^"I" { return INST; }
^"S" { return SEM; }
^"S" { return SEM; }
^"P" { return PROL; }
^"T" { return MEMSEM; }
^"E" { return EXTRA; }
^"P" { return PROL; }
"//".* { }
^"E" { return EXTRA; }
{CHARNAME}{CHARNAME}{CHARNAME}* { yylval.string = strdup(yytext); return NAME; }
"//".* { }
"\"\"\""[^ù]*"\"\"\"" { yylval.string = strndup(yytext+3, strlen(yytext)-6); return STRING; }
{FCHARNAME}{CHARNAME}{CHARNAME}* { yylval.string = strdup(yytext); return NAME; }
"'''"[^ù]*"'''" { yylval.string = strndup(yytext+3, strlen(yytext)-6); return STRING; }
{CHARNAME}{32} { yylval.string = strdup(yytext); return NAME; }
"\"".*"\"" { yylval.string = strndup(yytext+1, strlen(yytext)-2); return STRING; }
\n { return yytext[0]; }
"\"\"\""[^ù]*"\"\"\"" { yylval.string = strndup(yytext+3, strlen(yytext)-6); return STRING; }
{SPACE}+ { }
"'''"[^ù]*"'''" { yylval.string = strndup(yytext+3, strlen(yytext)-6); return STRING; }
"\"".*"\"" { yylval.string = strndup(yytext+1, strlen(yytext)-2); return STRING; }
[0-9][0-9]* { yylval.num = atoi(yytext); return NUM; }
\n { return yytext[0]; }
{SPACE}+ { }
%%

View file

@ -47,10 +47,12 @@ extern int yydebug;
{
NAME = 258,
STRING = 259,
INST = 260,
SEM = 261,
PROL = 262,
EXTRA = 263
NUM = 260,
INST = 261,
SEM = 262,
MEMSEM = 263,
PROL = 264,
EXTRA = 265
};
#endif
@ -61,9 +63,10 @@ union YYSTYPE
{
#line 14 "inst_par.y" /* yacc.c:1909 */
int num;
char* string;
#line 67 "inst_par.h" /* yacc.c:1909 */
#line 70 "inst_par.h" /* yacc.c:1909 */
};
typedef union YYSTYPE YYSTYPE;

View file

@ -12,14 +12,17 @@
%union
{
int num;
char* string;
}
%token <string> NAME
%token <string> STRING
%token <num> NUM
%token INST
%token SEM
%token MEMSEM
%token PROL
%token EXTRA
@ -36,6 +39,7 @@ INST NAME NAME NAME NAME { /* printf("0 - %s\n", $2); */
| INST NAME NAME NAME NAME NAME NAME NAME NAME { /* printf("4 - %s\n", $2); */ add_inst4($2, $3, $4, $5, $6, $7, $8, $9); }
| INST NAME NAME NAME NAME NAME NAME NAME NAME NAME { /* printf("5 - %s\n", $2); */ add_inst5($2, $3, $4, $5, $6, $7, $8, $9, $10); }
| SEM NAME STRING { add_sem($2, $3); }
| MEMSEM NAME NUM STRING { add_memsem($2, $3, $4); }
| PROL STRING { add_prol($2); }
| EXTRA STRING { add_extra($2); }
| '\n'

View file

@ -8,6 +8,7 @@
#include <set>
#include <map>
#include <vector>
#include <string>
#include "inst.hpp"
#include "group.hpp"
@ -39,6 +40,8 @@ void unparse(std::ostream& output,
const std::string prefix,
const std::set<const instruction*> instructions,
std::map<std::string,std::string> semantics,
std::map<std::string,int> em_widths,
std::map<std::string,std::string> mem_semantics,
std::vector<std::string> prologues,
std::vector<std::string> extras,
bool wide) {
@ -48,6 +51,8 @@ void unparse(std::ostream& output,
const std::string ctrlEnumString = prefix + "CtrlEnum";
const std::string outputString = prefix + "_FINAL_OUTPUT";
const std::string isString = "IS_" + prefix;
const bool two_cycles = em_widths.size() > 0;
const std::string bypassableExecuteString = two_cycles ? "False" : "Bool(earlyInjection)";
output << "// WARNING: this is auto-generated code!" << std::endl;
output << "// See https://github.com/rdolbeau/VexRiscvBPluginGenerator/" << std::endl;
@ -104,10 +109,17 @@ void unparse(std::ostream& output,
output << "} // object Plugin" << std::endl;
// Plugin class
output << "class " << prefix << "Plugin(earlyInjection : Boolean = true) extends Plugin[VexRiscv] {" << std::endl;
output << "class " << prefix << "Plugin"; if (!two_cycles) output << "(earlyInjection : Boolean = true)"; output << " extends Plugin[VexRiscv] {" << std::endl;
output << '\t' << "import " << prefix << "Plugin._" << std::endl;
output << '\t' << "object " << isString << " extends Stageable(Bool)" << std::endl;
output << '\t' << "object " << outputString << " extends Stageable(Bits(" << (wide ? 64 : 32) << " bits))" << std::endl;
if (two_cycles) {
for (auto const& pair : em_widths) {
std::string regName = prefix + "_INTERMEDIATE_" + pair.first + "" + std::to_string(pair.second);
output << '\t' << "object " << regName << " extends Stageable(Bits(" << pair.second << " bits))" << std::endl;
}
}
output << '\t' << "override def setup(pipeline: VexRiscv): Unit = {" << std::endl;
output << '\t' << '\t' << "import pipeline.config._" << std::endl;
@ -118,7 +130,7 @@ void unparse(std::ostream& output,
output << '\t' << '\t' << "\tSRC2_CTRL -> Src2CtrlEnum.IMI," << std::endl;
output << '\t' << '\t' << "\tREGFILE_WRITE_VALID -> True," << std::endl;
if (wide) output << '\t' << '\t' << "\tREGFILE_WRITE_VALID_ODD -> True," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_EXECUTE_STAGE -> Bool(earlyInjection)," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_EXECUTE_STAGE -> " << bypassableExecuteString << "," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_MEMORY_STAGE -> True," << std::endl;
output << '\t' << '\t' << "\tRS1_USE -> True," << std::endl;
output << '\t' << '\t' << "\t" << isString << " -> True" << std::endl;
@ -129,7 +141,7 @@ void unparse(std::ostream& output,
output << '\t' << '\t' << "\tSRC2_CTRL -> Src2CtrlEnum.RS," << std::endl;
output << '\t' << '\t' << "\tREGFILE_WRITE_VALID -> True," << std::endl;
if (wide) output << '\t' << '\t' << "\tREGFILE_WRITE_VALID_ODD -> True," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_EXECUTE_STAGE -> Bool(earlyInjection)," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_EXECUTE_STAGE -> " << bypassableExecuteString << "," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_MEMORY_STAGE -> True," << std::endl;
output << '\t' << '\t' << "\tRS1_USE -> True," << std::endl;
output << '\t' << '\t' << "\tRS2_USE -> True," << std::endl;
@ -140,7 +152,7 @@ void unparse(std::ostream& output,
output << '\t' << '\t' << "\tSRC1_CTRL -> Src1CtrlEnum.RS," << std::endl;
output << '\t' << '\t' << "\tREGFILE_WRITE_VALID -> True," << std::endl;
if (wide) output << '\t' << '\t' << "\tREGFILE_WRITE_VALID_ODD -> True," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_EXECUTE_STAGE -> Bool(earlyInjection)," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_EXECUTE_STAGE -> " << bypassableExecuteString << "," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_MEMORY_STAGE -> True," << std::endl;
output << '\t' << '\t' << "\tRS1_USE -> True," << std::endl;
output << '\t' << '\t' << "\t" << isString << " -> True" << std::endl;
@ -152,7 +164,7 @@ void unparse(std::ostream& output,
output << '\t' << '\t' << "\tSRC3_CTRL -> Src3CtrlEnum.RS," << std::endl;
output << '\t' << '\t' << "\tREGFILE_WRITE_VALID -> True," << std::endl;
if (wide) output << '\t' << '\t' << "\tREGFILE_WRITE_VALID_ODD -> True," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_EXECUTE_STAGE -> Bool(earlyInjection)," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_EXECUTE_STAGE -> " << bypassableExecuteString << "," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_MEMORY_STAGE -> True," << std::endl;
output << '\t' << '\t' << "\tRS1_USE -> True," << std::endl;
output << '\t' << '\t' << "\tRS2_USE -> True," << std::endl;
@ -166,7 +178,7 @@ void unparse(std::ostream& output,
output << '\t' << '\t' << "\tSRC3_CTRL -> Src3CtrlEnum.RS," << std::endl;
output << '\t' << '\t' << "\tREGFILE_WRITE_VALID -> True," << std::endl;
if (wide) output << '\t' << '\t' << "\tREGFILE_WRITE_VALID_ODD -> True," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_EXECUTE_STAGE -> Bool(earlyInjection)," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_EXECUTE_STAGE -> " << bypassableExecuteString << "," << std::endl;
output << '\t' << '\t' << "\tBYPASSABLE_MEMORY_STAGE -> True," << std::endl;
output << '\t' << '\t' << "\tRS1_USE -> True," << std::endl;
output << '\t' << '\t' << "\tRS3_USE -> True," << std::endl;
@ -228,7 +240,8 @@ void unparse(std::ostream& output,
output << extra << std::endl;
output << "// End Extra" << std::endl;
}
if (!two_cycles) {
output << '\t' << '\t' << "execute plug new Area{" << std::endl;
output << '\t' << '\t' << '\t' << "import execute._" << std::endl;
@ -276,8 +289,73 @@ void unparse(std::ostream& output,
output << '\t' << '\t' << '\t' << '\t' << "output(REGFILE_WRITE_DATA) := input(" << outputString << ")" << std::endl;
}
output << '\t' << '\t' << '\t' << "} // when input is" << std::endl;
output << '\t' << '\t' << "} // injectionStage plug newArea" << std::endl;
} else { // two-cycles
output << '\t' << '\t' << "execute plug new Area{" << std::endl;
output << '\t' << '\t' << '\t' << "import execute._" << std::endl;
for (auto const& pair : em_widths) {
std::string regName = prefix + "_INTERMEDIATE_" + pair.first + "" + std::to_string(pair.second);
output << '\t' << '\t' << '\t' << "insert(" << regName << ") := " << semantics[pair.first] << ".asBits" << std::endl;
}
output << '\t' << '\t' << "} // execute plug newArea" << std::endl;
output << '\t' << '\t' << "memory plug new Area{" << std::endl;
output << '\t' << '\t' << '\t' << "import memory._" << std::endl;
// 2nd level MUXes
for (const group* g : *groups) {
if (g->opnames.size() > 1) {
output << '\t' << '\t' << '\t' << "val val_" << g->name << " = input("<< ctrlString << g->name << ").mux(" << std::endl;
for (auto it = g->opnames.begin() ; it != g->opnames.end() ; it++) {
std::string opname = *it;
std::string semantic = semantics[opname];
std::string regName = prefix + "_INTERMEDIATE_" + opname + "" + std::to_string(em_widths[opname]);
output << '\t' << '\t' << '\t' << '\t' << ctrlString << g->name << "Enum.CTRL_" << opname << " -> " << mem_semantics[opname] << "(input(" << regName << ")).asBits";
if (std::next(it, 1) == g->opnames.end())
output << std::endl;
else
output << "," << std::endl;
}
output << '\t' << '\t' << '\t' << ") // mux " << g->name << std::endl;
}
}
// conditional last level mux
output << '\t' << '\t' << '\t' << "when (arbitration.isValid && input(" << isString << ")) {" << std::endl;
output << '\t' << '\t' << '\t' << '\t' << "output(REGFILE_WRITE_DATA) := input(" << ctrlString << ").mux(" << std::endl;
for (auto it = groups->begin() ; it != groups->end() ; it++) {
group* g = *it;
if (g->opnames.size() > 1) {
output << '\t' << '\t' << '\t' << '\t' <<'\t' << ctrlEnumString << "." << g->ctrlName() << " -> val_" << g->name << ".asBits";
} else {
std::string opname = *g->opnames.begin();
std::string regName = prefix + "_INTERMEDIATE_" + opname + "" + std::to_string(em_widths[opname]);
output << '\t' << '\t' << '\t' << '\t' << '\t' << ctrlEnumString << ".CTRL_" << opname << " -> " << mem_semantics[opname] << "(input(" << regName << ")).asBits(31 downto 0)";
}
if (std::next(it, 1) == groups->end())
output << std::endl;
else
output << "," << std::endl;
}
output << '\t' << '\t' << '\t' << '\t' << ") // primary mux" << std::endl;
if (wide) {
output << '\t' << '\t' << '\t' << '\t' << "output(REGFILE_WRITE_DATA_ODD) := input(" << ctrlString << ").mux(" << std::endl;
for (auto it = groups->begin() ; it != groups->end() ; it++) {
group* g = *it;
if (g->opnames.size() > 1) {
output << '\t' << '\t' << '\t' << '\t' <<'\t' << ctrlEnumString << "." << g->ctrlName() << " -> val_" << g->name << ".asBits";
} else {
std::string opname = *g->opnames.begin();
std::string regName = prefix + "_INTERMEDIATE_" + opname + "" + std::to_string(em_widths[opname]);
output << '\t' << '\t' << '\t' << '\t' << '\t' << ctrlEnumString << ".CTRL_" << opname << " -> " << mem_semantics[opname] << "(input(" << regName << ")).asBits(63 downto 32)";
}
if (std::next(it, 1) == groups->end())
output << std::endl;
else
output << "," << std::endl;
}
}
output << '\t' << '\t' << '\t' << '\t' << ") // primary mux" << std::endl;
output << '\t' << '\t' << '\t' << "} // when input is" << std::endl;
output << '\t' << '\t' << "} // memory plug newArea" << std::endl;
}
output << '\t' << "} // override def build" << std::endl;
output << "} // class Plugin" << std::endl;
}

View file

@ -13,6 +13,8 @@ void unparse(std::ostream& output,
const std::string prefix,
const std::set<const instruction*> instructions,
std::map<std::string,std::string> semantics,
std::map<std::string,int> em_widths,
std::map<std::string,std::string> mem_semantics,
std::vector<std::string> prologues,
std::vector<std::string> extras,
bool wide);