74 #define RV32_RTL_GEN_VERBOSE 0
80 RV32MicroCodeGenerator::RV32MicroCodeGenerator(
93 bypassInstructionRegister_(
false),
94 hasForwarding_(
false),
95 variableLengthOpLatency_(
false),
98 for (
int i = 0; i < busNav.
count(); i++) {
117 std::cout <<
"Generated bypass logic" << std::endl;
119 std::cout <<
"Not required connectivity for bypass logic"
142 std::map<std::string, int> ops = fTemp.
operations();
143 for (
const auto& op : ops) {
144 std::string name = op.first;
145 int encoding = op.second;
147 if (fTemp.
name() ==
"riscv_r_type") {
149 std::string encBits = bits.
toString();
156 }
else if (fTemp.
name() ==
"riscv_i_type") {
159 if (name ==
"srai" || name ==
"slli" || name ==
"srli") {
172 }
else if (fTemp.
name() ==
"riscv_s_type") {
174 std::string encBits = bits.
toString();
181 }
else if (fTemp.
name() ==
"riscv_b_type") {
183 std::string encBits = bits.
toString();
191 }
else if (fTemp.
name() ==
"riscv_u_type") {
193 std::string encBits = bits.
toString();
200 }
else if (fTemp.
name() ==
"riscv_j_type") {
202 std::string encBits = bits.
toString();
217 const std::string opName = op.first;
223 const std::string opName = op.first;
229 const std::string opName = op.first;
230 if (op.first !=
"move") {
237 const std::string opName = op.first;
247 for (
int i = 0; i < fuNav.
count(); i++) {
262 const std::string& op)
const {
263 std::string msg =
"Cannot find operation '" + op +
"\' in machine.";
269 const BaseFUPort* port,
const std::string& type)
const {
271 std::string msg = type +
" operand port \'" + port->
name() +
272 "\' in FU \'" + fuName +
273 "\' not mapped as triggering port";
279 const BaseFUPort* port,
const std::string& type)
const {
281 std::string msg = type +
" operand port \'" + port->
name() +
282 "\' in FU \'" + fuName +
"\' not mapped as input";
288 const BaseFUPort* port,
const std::string& type)
const {
290 std::string msg = type +
" operand port \'" + port->
name() +
291 "\' in FU \'" + fuName +
"\' not mapped as output";
297 const std::string& op,
int required,
int found)
const {
298 std::string msg =
"Operation " + op +
299 " has invalid amount of operands. " +
300 std::to_string(required) +
" required, " +
301 std::to_string(found) +
" found.";
346 const int operandCount = (opName ==
"calla") ? 2 : 3;
353 if (opName !=
"calla") {
354 rdPort = op->
port(3);
359 rs1Port = op->
port(2);
360 simmPort = op->
port(1);
380 }
else if (!rs1Port->
isInput()) {
382 }
else if (!rs2Port->
isInput()) {
392 if (opName ==
"move") {
399 if (opName ==
"apc") {
400 rdPort = op->
port(2);
471 for (
int i = 0; i < rfNav.
count(); i++) {
475 if (rf->
size() > 31 && rf->
width() == 32) {
477 }
else if (rf->
size() == 16 && rf->
width() == 32) {
484 std::string msg =
"Could not find a valid register file for RISC-V";
525 std::vector<RFPort*> RFOutputPorts;
526 std::vector<RFPort*> RFInputPorts;
530 RFOutputPorts.push_back(tmpPort);
532 RFInputPorts.push_back(tmpPort);
536 assert(RFInputPorts.size() > 0);
537 assert(RFOutputPorts.size() > 1);
545 bool success =
false;
546 bool forwarding =
false;
547 for (
int l = 0; l < 2 && !success; l++) {
549 forwarding = !forwarding;
550 for (
unsigned int i = 0; i < RFOutputPorts.size() && !success; i++) {
551 std::vector<RFPort*> tmpRFOutputPorts = RFOutputPorts;
552 rs1RFPort = RFOutputPorts.at(i);
553 tmpRFOutputPorts.erase(tmpRFOutputPorts.begin() + i);
554 for (
unsigned int j = 0; j < tmpRFOutputPorts.size() && !success;
556 rs2RFPort = tmpRFOutputPorts.at(j);
557 for (
unsigned int k = 0; k < RFInputPorts.size() && !success;
559 std::vector<RFPort*> tmpRFInputPorts;
560 tmpRFInputPorts = RFInputPorts;
561 rdRFPort = RFInputPorts.at(k);
563 rs1.
port = rs1RFPort;
564 rs2.
port = rs2RFPort;
584 "Could not find enough connectivity in the "
585 "interconnect to construct RISC-V control and decode logic. Make "
587 "the minimum connections are in place and that the operand-port "
588 "bindings are valid in FUs";
604 const std::unordered_map<std::string, BaseFUPort*>& ports)
const {
605 std::set<Port*> retval;
606 for (
const auto& op : ports) {
607 retval.insert(
static_cast<Port*
>(op.second));
615 const bool& forwarding)
const {
617 rs1Ports.insert(rs1.
port);
620 rs2Ports.insert(rs2.
port);
627 rs1Ports.insert(rdPorts.begin(), rdPorts.end());
628 rs2Ports.insert(rdPorts.begin(), rdPorts.end());
631 rdPorts.insert(rd.
port);
634 for (
unsigned int i = 0; i <
busses_.size(); i++) {
635 std::vector<Bus*> tmpBusses =
busses_;
645 tmpBusses.erase(tmpBusses.begin() + i);
647 for (
unsigned int j = 0; j < tmpBusses.size(); j++) {
648 tmpBus = tmpBusses.at(j);
653 tmpBusses.erase(tmpBusses.begin() + j);
654 for (
unsigned int k = 0; k < tmpBusses.size(); k++) {
655 tmpBus = tmpBusses.at(k);
661 tmpBusses.erase(tmpBusses.begin() + k);
662 for (
unsigned int h = 0; h < tmpBusses.size(); h++) {
663 tmpBus = tmpBusses.at(h);
665 simmPorts, *tmpBus) &&
677 std::unordered_map<std::string, InstructionBitVector*>
679 std::unordered_map<std::string, InstructionBitVector*> retval;
690 if (
dynamic_cast<RFPort*
>(src1)) {
691 instruction->
addMove(std::make_shared<Move>(
695 instruction->
addMove(std::make_shared<Move>(
700 if (
dynamic_cast<RFPort*
>(src2)) {
701 instruction->
addMove(std::make_shared<Move>(
705 instruction->
addMove(std::make_shared<Move>(
710 instruction->
addMove(std::make_shared<Move>(
717 retval.insert({op.first, bits});
722 std::unordered_map<std::string, InstructionBitVector*>
725 std::unordered_map<std::string, InstructionBitVector*> retval;
736 if (op.first !=
"calla") {
740 if (
dynamic_cast<RFPort*
>(src1)) {
741 instruction->
addMove(std::make_shared<Move>(
745 instruction->
addMove(std::make_shared<Move>(
750 instruction->
addMove(std::make_shared<Move>(
758 if (
dynamic_cast<RFPort*
>(src1)) {
759 instruction->
addMove(std::make_shared<Move>(
763 instruction->
addMove(std::make_shared<Move>(
768 instruction->
addMove(std::make_shared<Move>(
773 instruction->
addMove(std::make_shared<Move>(
780 retval.insert({op.first, bits});
785 std::unordered_map<std::string, InstructionBitVector*>
787 std::unordered_map<std::string, InstructionBitVector*> retval;
798 if (
dynamic_cast<RFPort*
>(src1)) {
799 instruction->
addMove(std::make_shared<Move>(
803 instruction->
addMove(std::make_shared<Move>(
808 instruction->
addMove(std::make_shared<Move>(
812 if (
dynamic_cast<RFPort*
>(src2)) {
813 instruction->
addMove(std::make_shared<Move>(
817 instruction->
addMove(std::make_shared<Move>(
825 retval.insert({op.first, bits});
830 std::unordered_map<std::string, InstructionBitVector*>
832 std::unordered_map<std::string, InstructionBitVector*> retval;
843 instruction->
addMove(std::make_shared<Move>(
847 if (
dynamic_cast<RFPort*
>(src1)) {
848 instruction->
addMove(std::make_shared<Move>(
852 instruction->
addMove(std::make_shared<Move>(
857 if (
dynamic_cast<RFPort*
>(src2)) {
858 instruction->
addMove(std::make_shared<Move>(
862 instruction->
addMove(std::make_shared<Move>(
870 retval.insert({op.first, bits});
875 std::unordered_map<std::string, InstructionBitVector*>
877 std::unordered_map<std::string, InstructionBitVector*> retval;
883 if (op.first ==
"move") {
888 instruction->
addMove(std::make_shared<Move>(
892 instruction->
addMove(std::make_shared<Move>(
896 instruction->
addMove(std::make_shared<Move>(
901 retval.insert({
"move", bits});
903 }
else if (op.first ==
"callr" or op.first ==
"apc") {
906 instruction->
addMove(std::make_shared<Move>(
912 retval.insert({op.first, bits});
921 instruction->
addMove(std::make_shared<Move>(
925 instruction->
addMove(std::make_shared<Move>(
932 retval.insert({op.first, bits});
941 std::unordered_map<std::string, InstructionBitVector*> instructions,
942 const std::map<std::string, std::string> encodings,
943 std::ofstream& stream)
const {
944 assert(instructions.size() == encodings.size());
945 for (
const auto& op : instructions) {
946 stream <<
" elsif(fu_opcode(" << encodings.at(op.first).size()
947 <<
" - 1 downto 0) = "
948 <<
"\"" << encodings.at(op.first) <<
"\""
949 <<
") then" << std::endl
950 <<
" moves <= \"" << op.second->toString() <<
"\";"
958 std::unordered_map<std::string, std::string> operations;
966 stream <<
" process(fu_opcode)" << std::endl
967 <<
" begin" << std::endl
968 <<
" target_fu <= to_unsigned(0, " << len <<
");" << std::endl;
971 bool firstCond =
true;
975 for (
const auto& op : p.second) {
986 stream << cond <<
"fu_opcode(" << iLen <<
"-1 downto 0)"
990 <<
"\" or fu_opcode(" << uLen <<
"-1 downto 0) = \""
996 stream << cond <<
"fu_opcode(" << iLen <<
"-1 downto 0)"
1001 int opLen = operations.at(op).size();
1002 stream << cond <<
"fu_opcode(" << opLen <<
"-1 downto 0)"
1003 <<
"= \"" << operations.at(op) <<
"\" then\n";
1005 stream <<
" target_fu <= to_unsigned(" <<
id <<
", " << len
1010 stream <<
" end if;" << std::endl <<
" end process;" << std::endl;
1012 stream << std::endl << std::endl;
1013 stream <<
" process(clk, rstx)" << std::endl
1014 <<
" begin" << std::endl
1015 <<
" if(rstx = '0') then" << std::endl
1016 <<
" target_fu_r <= (others => '0');" << std::endl
1017 <<
" elsif clk'event and clk = '1' then" << std::endl
1018 <<
" if glock_in = '0' and halt = '0' then" << std::endl
1019 <<
" target_fu_r <= target_fu;" << std::endl
1020 <<
" end if;" << std::endl
1021 <<
" end if;" << std::endl
1022 <<
" end process;" << std::endl
1029 std::map<std::string, std::string> ops,
1030 std::unordered_map<std::string, InstructionBitVector*> (
1033 std::ofstream& stream)
const {
1034 bool firstOpcodeCond =
true;
1035 for (
const auto& op : ops) {
1036 std::string opcodeCond =
" elsif ";
1037 if (firstOpcodeCond) {
1038 opcodeCond =
" if ";
1039 firstOpcodeCond =
false;
1041 stream << opcodeCond <<
"fu_opcode(" << op.second.size()
1042 <<
"-1 downto 0) = \"" << op.second <<
"\"";
1044 stream <<
" or fu_opcode(" <<
iOperations_.at(op.first).size()
1049 bool firstTargetCond =
true;
1051 std::string targetCond =
" elsif ";
1052 if (firstTargetCond) {
1053 targetCond =
" if ";
1054 firstTargetCond =
false;
1056 stream << targetCond +
"target_fu_r = "
1058 std::unordered_map<std::string, InstructionBitVector*>
1059 instructions = (this->*instructionFunc)(p.first,
rs2RFPort_);
1060 std::string bits = instructions.at(op.first)->toString();
1061 reverse(bits.begin(), bits.end());
1063 reverse(bits.begin(), bits.end());
1064 stream <<
" moves(rs1_start_c + rs1_width_c -1 downto"
1066 <<
" <= \"" << bits <<
"\";\n";
1067 for (
const auto& val : instructions) {
1071 stream <<
" end if;" << std::endl;
1073 stream <<
" end if;" << std::endl;
1078 std::map<std::string, std::string> ops,
1079 std::unordered_map<std::string, InstructionBitVector*> (
1082 std::ofstream& stream)
const {
1083 bool firstOpcodeCond =
true;
1084 for (
const auto& op : ops) {
1085 std::string opcodeCond =
" elsif ";
1086 if (firstOpcodeCond) {
1087 opcodeCond =
" if ";
1088 firstOpcodeCond =
false;
1090 stream << opcodeCond <<
"fu_opcode(" << op.second.size()
1091 <<
"-1 downto 0) = \"" << op.second <<
"\" then\n";
1092 bool firstTargetCond =
true;
1094 std::string targetCond =
" elsif ";
1095 if (firstTargetCond) {
1096 targetCond =
" if ";
1097 firstTargetCond =
false;
1099 stream << targetCond +
"target_fu_r = "
1101 std::unordered_map<std::string, InstructionBitVector*>
1102 instructions = (this->*instructionFunc)(
rs1RFPort_, p.first);
1103 std::string bits = instructions.at(op.first)->toString();
1104 reverse(bits.begin(), bits.end());
1106 reverse(bits.begin(), bits.end());
1107 stream <<
" moves(rs2_start_c + rs2_width_c -1 downto"
1109 <<
" <= \"" << bits <<
"\";\n";
1110 for (
const auto& val : instructions) {
1114 stream <<
" end if;" << std::endl;
1116 stream <<
" end if;" << std::endl;
1127 std::string mapFile = dstDirectory +
DS +
"rv32_microcode.vhdl";
1129 std::ofstream stream;
1130 stream.open(mapFile);
1132 stream <<
"library IEEE;" << std::endl
1133 <<
"use IEEE.std_logic_1164.all;" << std::endl
1134 <<
"use IEEE.numeric_std.all;" << std::endl
1135 <<
"use work.tta0_globals.all;" << std::endl
1139 stream <<
"entity rv32_microcode is" << std::endl <<
"port(" << std::endl;
1141 stream <<
" clk : in std_logic;" << std::endl
1142 <<
" rstx : in std_logic;" << std::endl
1143 <<
" glock_in : in std_logic;" << std::endl
1144 <<
" data_hazard_in : in std_logic;" << std::endl
1145 <<
" rs1_hazard_in : in std_logic;" << std::endl
1146 <<
" rs2_hazard_in : in std_logic;" << std::endl
1147 <<
" halt : in std_logic;" << std::endl;
1149 stream <<
" fu_opcode_in : in std_logic_vector(16 downto 0);"
1151 <<
" moves_out : out std_logic_vector(INSTRUCTIONWIDTH-1 "
1155 <<
"end rv32_microcode;" << std::endl
1157 <<
"architecture rtl of rv32_microcode is" << std::endl
1158 <<
" signal fu_opcode : std_logic_vector(16 downto 0);"
1160 <<
" signal moves : std_logic_vector(INSTRUCTIONWIDTH-1 "
1163 <<
" constant rs1_start_c : integer := " <<
rs1BusStart_ <<
";"
1165 <<
" constant rs2_start_c : integer := " <<
rs2BusStart_ <<
";"
1167 <<
" constant rs1_width_c : integer := " <<
rs1BusWidth_ <<
";"
1169 <<
" constant rs2_width_c : integer := " <<
rs2BusWidth_ <<
";"
1173 stream <<
" signal target_fu : unsigned(" << len <<
"-1 downto 0);"
1175 stream <<
" signal target_fu_r : unsigned (" << len
1176 <<
"-1 downto 0);" << std::endl
1177 <<
" signal data_hazard : std_logic;\n"
1178 <<
" signal rs1_hazard : std_logic;\n"
1179 <<
" signal rs2_hazard : std_logic;\n";
1183 <<
" begin" << std::endl
1185 <<
" fu_opcode <= fu_opcode_in;" << std::endl
1186 <<
" moves_out <= moves;" << std::endl
1189 stream <<
" data_hazard <= data_hazard_in;" << std::endl
1190 <<
" rs1_hazard <= rs1_hazard_in;" << std::endl
1191 <<
" rs2_hazard <= rs2_hazard_in;" << std::endl;
1192 stream << std::endl;
1195 stream <<
" process(fu_opcode";
1197 stream <<
", data_hazard, rs1_hazard, rs2_hazard, target_fu_r";
1199 stream <<
")" << std::endl;
1200 stream <<
" begin" << std::endl;
1202 std::unordered_map<std::string, InstructionBitVector*> instructions =
1204 bool firstCond =
true;
1205 for (
const auto& op : instructions) {
1207 stream <<
" if(fu_opcode = \"" <<
rOperations_.at(op.first)
1208 <<
"\") then" << std::endl
1209 <<
" moves <= \"" << op.second->toString() <<
"\";"
1215 stream <<
" elsif(fu_opcode(" <<
rOperations_.at(op.first).size()
1216 <<
" - 1 downto 0) = \"" <<
rOperations_.at(op.first) <<
"\""
1217 <<
") then" << std::endl
1218 <<
" moves <= \"" << op.second->toString() <<
"\";"
1235 stream <<
" else" << std::endl;
1236 stream <<
" moves <= \"" +
NOP_ +
"\";" << std::endl;
1238 stream <<
" end if;" << std::endl;
1241 stream <<
" if(data_hazard = '1') then\n"
1242 <<
" if(rs1_hazard = '1') then\n";
1255 stream <<
" end if;\n"
1256 <<
" if(rs2_hazard = '1') then\n";
1266 stream <<
" end if;\n"
1270 stream <<
" end process;" << std::endl;
1272 stream <<
"end architecture rtl;" << std::endl;
1280 std::map<std::string, std::string> operations;
1285 operations.insert(op);
1288 std::map<std::string, int> opLatency;
1289 for (
const auto& op : operations) {
1292 if (operation->
latency() > 1) {
1293 opLatency.insert({op.first, operation->
latency() - 1});
1294 if (operation->
latency() > maxVal) {
1295 maxVal = operation->
latency();
1299 int len = std::ceil(std::log2((maxVal)) + 1);
1301 if (opLatency.size() == 0) {
1302 return "op_latency <= to_unsigned(0,op_lat_width_c);";
1306 "process(fu_opcode)\n"
1308 bool firstCond =
true;
1309 for (
const auto& op : opLatency) {
1310 std::string cond =
" elsif ";
1316 cond +=
"fu_opcode = \"" +
rOperations_.at(op.first) +
"\" or " +
1322 cond +=
"fu_opcode(" +
1323 std::to_string(operations.at(op.first).size()) +
1324 "-1 downto 0) = \"" + operations.at(op.first) +
1327 logic += cond +
" op_latency <= to_unsigned(" +
1328 std::to_string(op.second) +
",op_lat_width_c);\n";
1332 " op_latency <= to_unsigned(0,op_lat_width_c);\n"
1374 std::string nop =
NOP_;
1375 reverse(nop.begin(), nop.end());
1377 reverse(nop.begin(), nop.end());
1378 const std::string rdNOP = nop;
1383 "rv32-microcode-simm-assign",
"simm_out <= simm_r;");
1389 "rv32-microcode-instruction-assign",
1390 "instruction <= instruction_in;");
1393 std::string forwardingPorts =
1394 " clk : in std_logic;\n"
1395 " rstx : in std_logic;\n"
1396 " glock_in : in std_logic;\n"
1397 " data_hazard_in : in std_logic;\n"
1398 " rs1_hazard_in : in std_logic;\n"
1399 " rs2_hazard_in : in std_logic;\n"
1400 " halt : in std_logic;\n";
1402 std::string forwardingPortMapping =
1405 "glock_in => glock_in,\n"
1406 "data_hazard_in => data_hazard,\n"
1407 "rs1_hazard_in => rs1_hazard,\n"
1408 "rs2_hazard_in => rs2_hazard,\n"
1409 "halt => filling_instruction_pipeline,";
1413 "forwarding-port-mapping", forwardingPortMapping);
1416 "data-hazard-stall",
"and data_hazard = '0'");
1418 "data-hazard-assign-conds",
1419 "elsif(data_hazard_r = '1') then\n"
1420 " data_hazard <= '0';");
1422 "data-hazard-detection-sensitivity-list-signals",
1426 "rv32-microcode-op-latency-process",
1428 std::string otherStates;
1431 otherStates +=
",HANDLE_OP_LATENCY";
1434 otherStates +=
",FILL_INSTRUCTION_PIPELINE_2";
1437 "rv32-microcode-other-states", otherStates);
1438 std::string executeLogic;
1439 std::string fsm_sensitivity_list_signals;
1441 " if(glock_in = '1') then\n"
1443 " stall_ifetch <= '0';\n"
1445 " elsif (rv_jump_wire = '1' or rv_auipc_wire = '1') then\n"
1446 " rd_bus_move <= rd_move;\n"
1447 " stall_ifetch <= '0';\n"
1449 " if rv_auipc_wire = '0' then\n"
1450 " NS <= FILL_INSTRUCTION_PIPELINE;\n"
1453 fsm_sensitivity_list_signals =
", data_hazard";
1456 " elsif(op_latency_stall = '1' and data_hazard = '0') then\n"
1458 " NS <= HANDLE_OP_LATENCY;\n"
1459 " stall_ifetch <= '1';\n"
1460 " rd_bus_move <= rd_nop_c;\n";
1463 " elsif(data_hazard = '1') then\n"
1465 " rd_bus_move <= rd_nop_c;\n"
1466 " stall_ifetch <= '1';\n"
1468 " elsif (is_control_flow_op = '1') then\n"
1470 " stall_ifetch <= '1';\n"
1471 " NS <= HANDLE_CONTROL_FLOW_OP;\n"
1472 " handle_control_flow_ns <= '1';\n"
1475 " stall_ifetch <= '0';\n"
1481 " elsif(op_latency_stall = '1') then\n"
1483 " NS <= HANDLE_OP_LATENCY;\n"
1484 " stall_ifetch <= '1';\n"
1485 " rd_bus_move <= rd_nop_c;\n";
1488 " elsif (is_control_flow_op = '1') then\n"
1490 " stall_ifetch <= '1';\n"
1491 " NS <= HANDLE_CONTROL_FLOW_OP;\n"
1492 " handle_control_flow_ns <= '1';\n"
1495 " stall_ifetch <= '0';\n"
1500 fsm_sensitivity_list_signals +=
", op_latency_stall";
1503 "when HANDLE_OP_LATENCY =>\n"
1505 " stall_ifetch <= '1';\n"
1506 " rd_bus_move <= rd_nop_c;\n"
1507 " NS <= HANDLE_OP_LATENCY;\n"
1508 " if(op_latency_stall = '0') then\n"
1510 " stall_ifetch <= '0';\n"
1511 " rd_bus_move <= rd_move;\n"
1514 std::string instructionPipelineStates;
1516 instructionPipelineStates =
1517 "when FILL_INSTRUCTION_PIPELINE =>\n"
1518 " filling_instruction_pipeline <= '1';\n"
1520 " rd_bus_move <= rd_nop_c;\n"
1521 " stall_ifetch <= '0';\n"
1522 " NS <= EXECUTE;\n";
1524 instructionPipelineStates =
1525 "when FILL_INSTRUCTION_PIPELINE =>\n"
1526 " filling_instruction_pipeline <= '1';\n"
1528 " rd_bus_move <= rd_nop_c;\n"
1529 " stall_ifetch <= '0';\n"
1530 " NS <= FILL_INSTRUCTION_PIPELINE_2;\n"
1533 "when FILL_INSTRUCTION_PIPELINE_2 =>\n"
1534 " filling_instruction_pipeline <= '1';\n"
1536 " rd_bus_move <= rd_nop_c;\n"
1537 " stall_ifetch <= '0';\n"
1542 "rv32-microcode-instruction-pipeline-logic",
1543 instructionPipelineStates);
1546 "rv32-microcode-fsm-sensitivity-list-signals",
1547 fsm_sensitivity_list_signals);
1549 "rv32-microcode-execute-logic", executeLogic);
1551 templateDir +
DS +
"rv32_microcode_wrapper.vhdl.tmpl",
1552 fileDst +
DS +
"rv32_microcode_wrapper.vhdl");