OpenASIP 2.2
Loading...
Searching...
No Matches
RV32MicroCodeGenerator.cc
Go to the documentation of this file.
1/*
2 Copyright (C) 2021-2024 Tampere University.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
18*/
19/**
20 * @file RV32MicroCodeGenerator.cc
21 *
22 * Implementation of RV32MicroCodeGenerator class.
23 *
24 * @author Kari Hepola 2021-2024 (kari.hepola@tuni.fi)
25 * @note rating: red
26 */
27
28#include <cmath>
29#include <vector>
30#include <string>
31#include <memory>
32#include <fstream>
33#include <utility>
34#include <bitset>
35
37#include "Machine.hh"
38#include "Socket.hh"
39#include "Bus.hh"
40#include "RFPort.hh"
41#include "FUPort.hh"
42#include "BaseFUPort.hh"
43#include "Port.hh"
45#include "FunctionUnit.hh"
46#include "RegisterFile.hh"
47#include "InstructionField.hh"
48#include "BinaryEncoding.hh"
49#include "MoveSlot.hh"
50#include "DestinationField.hh"
51#include "Instruction.hh"
52#include "HWOperation.hh"
53#include "TerminalRegister.hh"
54#include "TerminalFUPort.hh"
55#include "SimValue.hh"
56#include "TerminalImmediate.hh"
57#include "Move.hh"
61#include "Environment.hh"
63#include "FileSystem.hh"
65#include "ControlUnit.hh"
67#include "RISCVFields.hh"
68#include "InstructionFormat.hh"
69#include "BitVector.hh"
70#include "MapTools.hh"
71#include "VectorTools.hh"
73#include "LicenseGenerator.hh"
74
75#define RV32_RTL_GEN_VERBOSE 0
76
77using namespace std;
78
79namespace ProGe {
80
82 const Machine& machine, const BinaryEncoding& bem,
83 const std::string& entityName)
84 :
85 MicroCodeGenerator(machine, bem, entityName),
86 RF_(NULL),
87 rs1Bus_(NULL),
88 rs2Bus_(NULL),
89 rdBus_(NULL),
90 rs1RFPort_(NULL),
91 rs2RFPort_(NULL),
92 rdRFPort_(NULL),
93 pig_(new ProgramImageGenerator()),
94 NOP_(""),
95 bypassInstructionRegister_(false),
96 hasForwarding_(false),
97 variableLengthOpLatency_(false),
98 eVariant_(false),
99 hasCustom0Operations_(false) {
101 for (int i = 0; i < busNav.count(); i++) {
102 busses_.push_back(busNav.item(i));
103 }
104
106
109
110 pig_->loadBEM(bem);
112
113 generateNOP();
114
115 findRF();
116 connectRF();
119 if (hasForwarding_) {
120 std::cout << "Generated bypass logic" << std::endl;
121 } else {
122 std::cout << "Not required connectivity for bypass logic"
123 << std::endl;
124 }
125 }
126}
127
129
130void
132 for (const auto& op : rdPorts_) {
133 if (sourceOperationMap_.count(op.second)) {
134 sourceOperationMap_.at(op.second).push_back(op.first);
135 } else {
136 sourceOperationMap_.insert({op.second, {op.first}});
137 }
138 }
139}
140
141void
143 for (int i = 0; i < bem_->instructionFormatCount(); i++) {
145 for (int j = 0; j < fTemp.operationCount(); j++) {
146 std::string name = fTemp.operationAtIndex(j);
147 int encoding = fTemp.encoding(name);
148 BitVector bits = BitVector();
149 if (fTemp.name() == RISCVFields::RISCV_R_TYPE_NAME) {
150 bits.pushBack(encoding, 17);
151 std::string encBits = bits.toString();
153 const std::string tceOpName = RISCVFields::RISCVOperationNameTable.at(name);
154 rOperations_.insert({tceOpName, encBits});
155 } else {
157 rOperations_.insert({name, encBits});
158 }
159 } else if (fTemp.name() == RISCVFields::RISCV_I_TYPE_NAME) {
160 std::string encBits;
161 // Shift operations use imm bits for opcode
162 if (name == "srai" || name == "slli" || name == "srli") {
163 bits.pushBack(encoding, 17);
164 encBits = bits.toString();
165 } else {
166 bits.pushBack(encoding, 10);
167 encBits = bits.toString();
168 }
170 const std::string tceOpName = RISCVFields::RISCVOperationNameTable.at(name);
171 iOperations_.insert({tceOpName, encBits});
172 } else {
173 iOperations_.insert({name, encBits});
174 }
175 } else if (fTemp.name() == RISCVFields::RISCV_S_TYPE_NAME) {
176 bits.pushBack(encoding, 10);
177 std::string encBits = bits.toString();
179 const std::string tceOpName = RISCVFields::RISCVOperationNameTable.at(name);
180 sOperations_.insert({tceOpName, encBits});
181 } else {
182 sOperations_.insert({name, encBits});
183 }
184 } else if (fTemp.name() == RISCVFields::RISCV_B_TYPE_NAME) {
185 bits.pushBack(encoding, 10);
186 std::string encBits = bits.toString();
188 const std::string tceOpName = RISCVFields::RISCVOperationNameTable.at(name);
189 bOperations_.insert(
190 {RISCVFields::RISCVOperationNameTable.at(name), encBits});
191 } else {
192 bOperations_.insert({name, encBits});
193 }
194 } else if (fTemp.name() == RISCVFields::RISCV_U_TYPE_NAME) {
195 bits.pushBack(encoding, 7);
196 std::string encBits = bits.toString();
198 const std::string tceOpName = RISCVFields::RISCVOperationNameTable.at(name);
199 ujOperations_.insert({tceOpName, encBits});
200 } else {
201 ujOperations_.insert({name, encBits});
202 }
203 } else if (fTemp.name() == RISCVFields::RISCV_J_TYPE_NAME) {
204 bits.pushBack(encoding, 7);
205 std::string encBits = bits.toString();
207 const std::string tceOpName = RISCVFields::RISCVOperationNameTable.at(name);
208 ujOperations_.insert({tceOpName, encBits});
209 } else {
210 ujOperations_.insert({name, encBits});
211 }
212 } else if (fTemp.name() == RISCVFields::RISCV_R1R_TYPE_NAME) {
213 bits.pushBack(encoding, 17);
214 std::string encBits = bits.toString();
216 const std::string tceOpName = RISCVFields::RISCVOperationNameTable.at(name);
217 r1rOperations_.insert({tceOpName, encBits});
218 } else {
219 r1rOperations_.insert({name, encBits});
220 }
221 } else if (fTemp.name() == RISCVFields::RISCV_R1_TYPE_NAME) {
222 bits.pushBack(encoding, 17);
223 std::string encBits = bits.toString();
225 const std::string tceOpName = RISCVFields::RISCVOperationNameTable.at(name);
226 r1Operations_.insert({tceOpName, encBits});
227 } else {
228 r1Operations_.insert({name, encBits});
229 }
230 }
231 }
232 }
233}
234
235void
237 for (const auto& op : sOperations_) {
238 const std::string opName = op.first;
239 if (!machine_->hasOperation(opName)) {
241 }
242 }
243 for (const auto& op : bOperations_) {
244 const std::string opName = op.first;
245 if (!machine_->hasOperation(opName)) {
247 }
248 }
249 for (const auto& op : ujOperations_) {
250 const std::string opName = op.first;
251 if (op.first != "move") {
252 if (!machine_->hasOperation(opName)) {
254 }
255 }
256 }
257 for (const auto& op : rOperations_) {
258 const std::string opName = op.first;
259 if (!machine_->hasOperation(opName)) {
261 }
262 }
263
264 for (const auto& op : r1rOperations_) {
265 const std::string opName = op.first;
266 if (!machine_->hasOperation(opName)) {
268 }
269 }
270
271 for (const auto& op : r1Operations_) {
272 const std::string opName = op.first;
273 if (!machine_->hasOperation(opName)) {
275 }
276 }
277}
278
280RV32MicroCodeGenerator::mapFunctionUnit(const std::string& operation) const {
282 for (int i = 0; i < fuNav.count(); i++) {
283 FunctionUnit* fu = fuNav.item(i);
284 if (fu->hasOperation(operation)) {
285 return fu;
286 }
287 }
288 if (machine_->controlUnit()->hasOperation(operation)) {
289 return static_cast<FunctionUnit*>(machine_->controlUnit());
290 }
292 return NULL;
293}
294
295void
297 const std::string& op) const {
298 std::string msg = "Cannot find operation '" + op + "\' in machine.";
299 throw InvalidData(__FILE__, __LINE__, __func__, msg);
300}
301
302void
304 const BaseFUPort* port, const std::string& type) const {
305 std::string fuName = port->parentUnit()->name();
306 std::string msg = type + " operand port \'" + port->name() +
307 "\' in FU \'" + fuName +
308 "\' not mapped as triggering port";
309 throw InvalidData(__FILE__, __LINE__, __func__, msg);
310}
311
312void
314 const BaseFUPort* port, const std::string& type) const {
315 std::string fuName = port->parentUnit()->name();
316 std::string msg = type + " operand port \'" + port->name() +
317 "\' in FU \'" + fuName + "\' not mapped as input";
318 throw InvalidData(__FILE__, __LINE__, __func__, msg);
319}
320
321void
323 const BaseFUPort* port, const std::string& type) const {
324 std::string fuName = port->parentUnit()->name();
325 std::string msg = type + " operand port \'" + port->name() +
326 "\' in FU \'" + fuName + "\' not mapped as output";
327 throw InvalidData(__FILE__, __LINE__, __func__, msg);
328}
329
330void
332 const std::string& op, int required, int found) const {
333 std::string msg = "Operation " + op +
334 " has invalid amount of operands. " +
335 std::to_string(required) + " required, " +
336 std::to_string(found) + " found.";
337 throw InvalidData(__FILE__, __LINE__, __func__, msg);
338}
339
340void
341RV32MicroCodeGenerator::addRPorts(const std::string& opName) {
342 FunctionUnit* fu = mapFunctionUnit(opName);
343 HWOperation* op = fu->operation(opName);
344 if (op->operandCount() != 3) {
345 throwOperandCountError(opName, 3, op->operandCount());
346 }
347 FUPort* rs1Port = op->port(1);
348 FUPort* rs2Port = op->port(2);
349 FUPort* rdPort = op->port(3);
350 if (!rs1Port->isTriggering()) {
351 throwTriggeringPortError(rs1Port, "rs1");
352 }
353 if (!rs2Port->isInput()) {
354 throwInputPortError(rs2Port, "rs2");
355 }
356 if (!rdPort->isOutput()) {
357 throwOutputPortError(rdPort, "rd");
358 }
359 rs1Ports_.insert({opName, rs1Port});
360 rs2Ports_.insert({opName, rs2Port});
361 // Do not add custom ops to simm ports
363 const std::string riscvOpName =MapTools::keyForValue
364 <string, map<string, string>, string>(RISCVFields::RISCVOperationNameTable, opName);
365 // Do not add M-extension ops
367 riscvOpName)) {
368 simmPorts_.insert({opName, rs2Port});
369 }
370 }
371 rdPorts_.insert({opName, rdPort});
372}
373
374void
375RV32MicroCodeGenerator::addR1RPorts(const std::string& opName) {
376 FunctionUnit* fu = mapFunctionUnit(opName);
377 HWOperation* op = fu->operation(opName);
378 if (op->operandCount() != 2) {
379 throwOperandCountError(opName, 2, op->operandCount());
380 }
381 FUPort* rs1Port = op->port(1);
382 FUPort* rdPort = op->port(2);
383 if (!rs1Port->isTriggering()) {
384 throwTriggeringPortError(rs1Port, "rs1");
385 }
386 if (!rdPort->isOutput()) {
387 throwOutputPortError(rdPort, "rd");
388 }
389 rs1Ports_.insert({opName, rs1Port});
390 rdPorts_.insert({opName, rdPort});
391}
392
393void
394RV32MicroCodeGenerator::addR1Ports(const std::string& opName) {
395 FunctionUnit* fu = mapFunctionUnit(opName);
396 HWOperation* op = fu->operation(opName);
397 if (op->operandCount() != 1) {
398 throwOperandCountError(opName, 1, op->operandCount());
399 }
400 FUPort* rs1Port = op->port(1);
401 if (!rs1Port->isTriggering()) {
402 throwTriggeringPortError(rs1Port, "rs1");
403 }
404 rs1Ports_.insert({opName, rs1Port});
405}
406
407void
408RV32MicroCodeGenerator::addIPorts(const std::string& opName) {
409 if (rOperations_.count(opName)) {
410 return;
411 }
412 FunctionUnit* fu = mapFunctionUnit(opName);
413 HWOperation* op = fu->operation(opName);
414 const int operandCount = (opName == "calla") ? 2 : 3;
415 if (op->operandCount() != operandCount) {
416 throwOperandCountError(opName, operandCount, op->operandCount());
417 }
418 FUPort* rs1Port = op->port(1);
419 FUPort* simmPort = op->port(2);
420 BaseFUPort* rdPort;
421 if (opName != "calla") {
422 rdPort = op->port(3);
423 if (!rdPort->isOutput()) {
424 throwOutputPortError(rdPort, "rd");
425 }
426 } else {
427 rs1Port = op->port(2);
428 simmPort = op->port(1);
430 }
431 rs1Ports_.insert({opName, rs1Port});
432 simmPorts_.insert({opName, simmPort});
433 rdPorts_.insert({opName, rdPort});
434}
435
436void
437RV32MicroCodeGenerator::addBPorts(const std::string& opName) {
438 FunctionUnit* fu = mapFunctionUnit(opName);
439 HWOperation* op = fu->operation(opName);
440 if (op->operandCount() != 3) {
441 throwOperandCountError(opName, 3, op->operandCount());
442 }
443 FUPort* simmPort = op->port(1);
444 FUPort* rs1Port = op->port(2);
445 FUPort* rs2Port = op->port(3);
446 if (!simmPort->isTriggering()) {
447 throwTriggeringPortError(simmPort, "imm");
448 } else if (!rs1Port->isInput()) {
449 throwInputPortError(rs1Port, "rs1");
450 } else if (!rs2Port->isInput()) {
451 throwInputPortError(rs1Port, "rs2");
452 }
453 rs1Ports_.insert({opName, rs1Port});
454 simmPorts_.insert({opName, simmPort});
455 rs2Ports_.insert({opName, rs2Port});
456}
457
458void
459RV32MicroCodeGenerator::addUJPorts(const std::string& opName) {
460 if (opName == "move") {
461 return;
462 }
463 ControlUnit* fu = dynamic_cast<ControlUnit*>(mapFunctionUnit(opName));
464 HWOperation* op = fu->operation(opName);
465 FUPort* simmPort = op->port(1);
466 BaseFUPort* rdPort;
467 if (opName == "apc") {
468 rdPort = op->port(2);
469 if (!rdPort->isOutput()) {
470 throwOutputPortError(rdPort, "rd");
471 }
472 } else {
473 rdPort = fu->returnAddressPort();
474 }
475 if (!simmPort->isTriggering()) {
476 throwTriggeringPortError(simmPort, "imm");
477 }
478 rdPorts_.insert({opName, rdPort});
479 simmPorts_.insert({opName, simmPort});
480}
481
482void
483RV32MicroCodeGenerator::addSPorts(const std::string& opName) {
484 FunctionUnit* fu = mapFunctionUnit(opName);
485 HWOperation* op = fu->operation(opName);
486 if (op->operandCount() != 3) {
487 throwOperandCountError(opName, 3, op->operandCount());
488 }
489 FUPort* rs1Port = op->port(1);
490 FUPort* simmPort = op->port(2);
491 FUPort* rs2Port = op->port(3);
492 if (!rs1Port->isTriggering()) {
493 throwTriggeringPortError(rs1Port, "rs1");
494 }
495 if (!rs2Port->isInput()) {
496 throwInputPortError(rs2Port, "rs2");
497 }
498 if (!simmPort->isInput()) {
499 throwInputPortError(simmPort, "imm");
500 }
501 rs1Ports_.insert({opName, rs1Port});
502 simmPorts_.insert({opName, simmPort});
503 rs2Ports_.insert({opName, rs2Port});
504}
505
506void
508 for (const auto& op : rOperations_) {
509 addRPorts(op.first);
510 }
511 for (const auto& op : iOperations_) {
512 addIPorts(op.first);
513 }
514 for (const auto& op : sOperations_) {
515 addSPorts(op.first);
516 }
517 for (const auto& op : bOperations_) {
518 addBPorts(op.first);
519 }
520 for (const auto& op : ujOperations_) {
521 addUJPorts(op.first);
522 }
523 for (const auto& op : r1rOperations_) {
524 addR1RPorts(op.first);
525 }
526 for (const auto& op : r1Operations_) {
527 addR1Ports(op.first);
528 }
529}
530
531void
533 CodeCompressorPlugin* compressor = &pig_->compressor();
534 Instruction* instruction = new Instruction();
535 InstructionBitVector* bits = compressor->bemInstructionBits(*instruction);
536 NOP_ = bits->toString();
537 delete instruction;
538}
539
540void
543 // TODO: Design can have multiple register files. Iterate over all of
544 // them and find one that fits based on connectivity.
545 for (int i = 0; i < rfNav.count(); i++) {
546 RegisterFile* rf = rfNav.item(0);
547 if (rf->inputPortCount() > 0 && rf->outputPortCount() > 1 &&
548 rf->zeroRegister()) {
549 if (rf->size() > 31 && rf->width() == 32) {
550 RF_ = rf;
551 } else if (rf->size() == 16 && rf->width() == 32) {
552 RF_ = rf;
553 eVariant_ = true;
554 }
555 }
556 }
557 if (RF_ == NULL) {
558 std::string msg = "Could not find a valid register file for RISC-V";
559 throw InvalidData(__FILE__, __LINE__, __func__, msg);
560 }
561}
562
563void
565 for (int i = 0; i < bem_->moveSlotCount(); i++) {
566 MoveSlot& slot = bem_->moveSlot(i);
567 if (slot.name() == rs1Bus_->name()) {
568 rs1BusWidth_ = slot.width();
571 rs1BusStart_ = slot.bitPosition();
572 } else if (slot.name() == rs2Bus_->name()) {
573 rs2BusWidth_ = slot.width();
576 rs2BusStart_ = slot.bitPosition();
577 } else if (slot.name() == rdBus_->name()) {
578 rdBusWidth_ = slot.width();
579 rdRFStart_ = 0;
580 rdBusStart_ = slot.bitPosition();
581 } else if (slot.name() == simmBus_->name()) {
582 simmBusWidth_ = slot.width();
583 simmRFStart_ = 0;
584 simmBusStart_ = slot.bitPosition();
585 }
586 }
587 assert(rs1BusWidth_ > 0);
588 assert(rs2BusWidth_ > 0);
589 assert(rdBusWidth_ > 0);
591}
592
593void
595 RFPort* rs1RFPort = NULL;
596 RFPort* rs2RFPort = NULL;
597 RFPort* rdRFPort = NULL;
598
599 std::vector<RFPort*> RFOutputPorts;
600 std::vector<RFPort*> RFInputPorts;
601 for (int i = 0; i < RF_->portCount(); i++) {
602 RFPort* tmpPort = RF_->port(i);
603 if (tmpPort->outputSocket() != NULL) {
604 RFOutputPorts.push_back(tmpPort);
605 } else if (tmpPort->inputSocket() != NULL) {
606 RFInputPorts.push_back(tmpPort);
607 }
608 }
609
610 assert(RFInputPorts.size() > 0);
611 assert(RFOutputPorts.size() > 1);
612
613 Connection rs1;
614 Connection rs2;
615 Connection rd;
616 Connection simm;
617
618 // Find candidates for rs1, rs2 and rd busses.
619 bool success = false;
620 bool forwarding = false;
621 for (int l = 0; l < 2 && !success; l++) {
622 // First try with forwarding enabled
623 forwarding = !forwarding;
624 for (unsigned int i = 0; i < RFOutputPorts.size() && !success; i++) {
625 std::vector<RFPort*> tmpRFOutputPorts = RFOutputPorts;
626 rs1RFPort = RFOutputPorts.at(i);
627 tmpRFOutputPorts.erase(tmpRFOutputPorts.begin() + i);
628 for (unsigned int j = 0; j < tmpRFOutputPorts.size() && !success;
629 j++) {
630 rs2RFPort = tmpRFOutputPorts.at(j);
631 for (unsigned int k = 0; k < RFInputPorts.size() && !success;
632 k++) {
633 std::vector<RFPort*> tmpRFInputPorts;
634 tmpRFInputPorts = RFInputPorts;
635 rdRFPort = RFInputPorts.at(k);
636
637 rs1.port = rs1RFPort;
638 rs2.port = rs2RFPort;
639 rd.port = rdRFPort;
640
641 rs1.bus = NULL;
642 rs2.bus = NULL;
643 rd.bus = NULL;
644 simm.bus = NULL;
645
646 success =
647 findConnectedBusses(rs1, rs2, rd, simm, forwarding);
648 if (success) {
649 break;
650 }
651 }
652 }
653 }
654 }
655
656 if (!success) {
657 std::string msg =
658 "Could not find enough connectivity in the "
659 "interconnect to construct RISC-V control and decode logic. Make "
660 "sure "
661 "the minimum connections are in place and that the operand-port "
662 "bindings are valid in FUs";
663 throw InvalidData(__FILE__, __LINE__, __func__, msg);
664 }
665 hasForwarding_ = forwarding;
666
667 rs1Bus_ = rs1.bus;
668 rs2Bus_ = rs2.bus;
669 rdBus_ = rd.bus;
670 simmBus_ = simm.bus;
671 rs1RFPort_ = rs1RFPort;
672 rs2RFPort_ = rs2RFPort;
673 rdRFPort_ = rdRFPort;
674}
675
676std::set<Port*>
678 const std::unordered_map<std::string, BaseFUPort*>& ports) const {
679 std::set<Port*> retval;
680 for (const auto& op : ports) {
681 retval.insert(static_cast<Port*>(op.second));
682 }
683 return retval;
684}
685
686bool
688 Connection& rs1, Connection& rs2, Connection& rd, Connection& simm,
689 const bool& forwarding) const {
690 std::set<Port*> rs1Ports = operationPorts(rs1Ports_);
691 rs1Ports.insert(rs1.port);
692
693 std::set<Port*> rs2Ports = operationPorts(rs2Ports_);
694 rs2Ports.insert(rs2.port);
695
696 std::set<Port*> simmPorts = operationPorts(simmPorts_);
697
698 std::set<Port*> rdPorts = operationPorts(rdPorts_);
699
700 if (forwarding) {
701 rs1Ports.insert(rdPorts.begin(), rdPorts.end());
702 rs2Ports.insert(rdPorts.begin(), rdPorts.end());
703 }
704
705 rdPorts.insert(rd.port);
706
707 // Brute forces all combinations until all ports can be mapped to a bus
708 for (unsigned int i = 0; i < busses_.size(); i++) {
709 std::vector<Bus*> tmpBusses = busses_;
710 rs1.bus = NULL;
711 rs2.bus = NULL;
712 rd.bus = NULL;
713 simm.bus = NULL;
714 Bus* tmpBus = busses_.at(i);
715 if (!MachineConnectivityCheck::isConnected(rs1Ports, *tmpBus)) {
716 continue;
717 }
718 rs1.bus = tmpBus;
719 tmpBusses.erase(tmpBusses.begin() + i);
720 rs2.bus = NULL;
721 for (unsigned int j = 0; j < tmpBusses.size(); j++) {
722 tmpBus = tmpBusses.at(j);
723 if (!MachineConnectivityCheck::isConnected(rs2Ports, *tmpBus)) {
724 continue;
725 }
726 rs2.bus = tmpBus;
727 tmpBusses.erase(tmpBusses.begin() + j);
728 for (unsigned int k = 0; k < tmpBusses.size(); k++) {
729 tmpBus = tmpBusses.at(k);
731 rdPorts, *tmpBus)) {
732 continue;
733 }
734 rd.bus = tmpBus;
735 tmpBusses.erase(tmpBusses.begin() + k);
736 for (unsigned int h = 0; h < tmpBusses.size(); h++) {
737 tmpBus = tmpBusses.at(h);
739 simmPorts, *tmpBus) &&
740 tmpBus->immediateWidth() > 0) {
741 simm.bus = tmpBus;
742 return true;
743 }
744 }
745 }
746 }
747 }
748 return false;
749}
750
751std::unordered_map<std::string, InstructionBitVector*>
753 std::unordered_map<std::string, InstructionBitVector*> retval;
754 CodeCompressorPlugin* compressor = &pig_->compressor();
755 for (const auto& op : rOperations_) {
756 Instruction* instruction = new Instruction();
757 HWOperation* operation =
758 mapFunctionUnit(op.first)->operation(op.first);
759
760 FUPort* rs1Port = static_cast<FUPort*>(rs1Ports_.at(op.first));
761 FUPort* rs2Port = static_cast<FUPort*>(rs2Ports_.at(op.first));
762 FUPort* rdPort = static_cast<FUPort*>(rdPorts_.at(op.first));
763
764 if (dynamic_cast<RFPort*>(src1)) {
765 instruction->addMove(std::make_shared<Move>(
766 new TerminalRegister(*src1, 0),
767 new TerminalFUPort(*rs1Port, *operation), *rs1Bus_));
768 } else {
769 instruction->addMove(std::make_shared<Move>(
770 new TerminalFUPort(*static_cast<BaseFUPort*>(src1)),
771 new TerminalFUPort(*rs1Port, *operation), *rs1Bus_));
772 }
773
774 if (dynamic_cast<RFPort*>(src2)) {
775 instruction->addMove(std::make_shared<Move>(
776 new TerminalRegister(*src2, 0), new TerminalFUPort(*rs2Port),
777 *rs2Bus_));
778 } else {
779 instruction->addMove(std::make_shared<Move>(
780 new TerminalFUPort(*static_cast<BaseFUPort*>(src2)),
781 new TerminalFUPort(*rs2Port), *rs2Bus_));
782 }
783
784 instruction->addMove(std::make_shared<Move>(
785 new TerminalFUPort(*rdPort), new TerminalRegister(*rdRFPort_, 0),
786 *rdBus_));
787
789 compressor->bemInstructionBits(*instruction);
790 delete instruction;
791 retval.insert({op.first, bits});
792 }
793 return retval;
794}
795
796std::unordered_map<std::string, InstructionBitVector*>
798 std::unordered_map<std::string, InstructionBitVector*> retval;
799 CodeCompressorPlugin* compressor = &pig_->compressor();
800 for (const auto& op : r1rOperations_) {
801 Instruction* instruction = new Instruction();
802 HWOperation* operation =
803 mapFunctionUnit(op.first)->operation(op.first);
804
805 FUPort* rs1Port = static_cast<FUPort*>(rs1Ports_.at(op.first));
806 FUPort* rdPort = static_cast<FUPort*>(rdPorts_.at(op.first));
807
808 if (dynamic_cast<RFPort*>(src1)) {
809 instruction->addMove(std::make_shared<Move>(
810 new TerminalRegister(*src1, 0),
811 new TerminalFUPort(*rs1Port, *operation), *rs1Bus_));
812 } else {
813 instruction->addMove(std::make_shared<Move>(
814 new TerminalFUPort(*static_cast<BaseFUPort*>(src1)),
815 new TerminalFUPort(*rs1Port, *operation), *rs1Bus_));
816 }
817
818 instruction->addMove(std::make_shared<Move>(
819 new TerminalFUPort(*rdPort), new TerminalRegister(*rdRFPort_, 0),
820 *rdBus_));
821
823 compressor->bemInstructionBits(*instruction);
824 delete instruction;
825 retval.insert({op.first, bits});
826 }
827 return retval;
828}
829
830std::unordered_map<std::string, InstructionBitVector*>
832 std::unordered_map<std::string, InstructionBitVector*> retval;
833 CodeCompressorPlugin* compressor = &pig_->compressor();
834 for (const auto& op : r1Operations_) {
835 Instruction* instruction = new Instruction();
836 HWOperation* operation =
837 mapFunctionUnit(op.first)->operation(op.first);
838
839 FUPort* rs1Port = static_cast<FUPort*>(rs1Ports_.at(op.first));
840
841 if (dynamic_cast<RFPort*>(src1)) {
842 instruction->addMove(std::make_shared<Move>(
843 new TerminalRegister(*src1, 0),
844 new TerminalFUPort(*rs1Port, *operation), *rs1Bus_));
845 } else {
846 instruction->addMove(std::make_shared<Move>(
847 new TerminalFUPort(*static_cast<BaseFUPort*>(src1)),
848 new TerminalFUPort(*rs1Port, *operation), *rs1Bus_));
849 }
850
852 compressor->bemInstructionBits(*instruction);
853 delete instruction;
854 retval.insert({op.first, bits});
855 }
856 return retval;
857}
858
859std::unordered_map<std::string, InstructionBitVector*>
861 Port* src1, Port* /*src2*/) const {
862 std::unordered_map<std::string, InstructionBitVector*> retval;
863 CodeCompressorPlugin* compressor = &pig_->compressor();
864 for (const auto& op : iOperations_) {
865 Instruction* instruction = new Instruction();
866
867 HWOperation* operation =
868 mapFunctionUnit(op.first)->operation(op.first);
869
870 FUPort* rdPort = static_cast<FUPort*>(rdPorts_.at(op.first));
871
872 // ALU operations are a special case as they are shared with R type
873 if (op.first != "calla") {
874 FUPort* simmPort = static_cast<FUPort*>(simmPorts_.at(op.first));
875 FUPort* rs1Port = static_cast<FUPort*>(rs1Ports_.at(op.first));
876
877 if (dynamic_cast<RFPort*>(src1)) {
878 instruction->addMove(std::make_shared<Move>(
879 new TerminalRegister(*src1, 0),
880 new TerminalFUPort(*rs1Port, *operation), *rs1Bus_));
881 } else {
882 instruction->addMove(std::make_shared<Move>(
883 new TerminalFUPort(*static_cast<BaseFUPort*>(src1)),
884 new TerminalFUPort(*rs1Port, *operation), *rs1Bus_));
885 }
886
887 instruction->addMove(std::make_shared<Move>(
889 new TerminalFUPort(*simmPort), *simmBus_));
890
891 } else {
892 FUPort* rs1Port = static_cast<FUPort*>(rs1Ports_.at(op.first));
893 FUPort* simmPort = static_cast<FUPort*>(simmPorts_.at(op.first));
894
895 if (dynamic_cast<RFPort*>(src1)) {
896 instruction->addMove(std::make_shared<Move>(
897 new TerminalRegister(*src1, 0),
898 new TerminalFUPort(*rs1Port), *rs1Bus_));
899 } else {
900 instruction->addMove(std::make_shared<Move>(
901 new TerminalFUPort(*static_cast<BaseFUPort*>(src1)),
902 new TerminalFUPort(*rs1Port), *rs1Bus_));
903 }
904
905 instruction->addMove(std::make_shared<Move>(
907 new TerminalFUPort(*simmPort, *operation), *simmBus_));
908 }
909
910 instruction->addMove(std::make_shared<Move>(
911 new TerminalFUPort(*rdPort), new TerminalRegister(*rdRFPort_, 0),
912 *rdBus_));
913
915 compressor->bemInstructionBits(*instruction);
916 delete instruction;
917 retval.insert({op.first, bits});
918 }
919 return retval;
920}
921
922std::unordered_map<std::string, InstructionBitVector*>
924 std::unordered_map<std::string, InstructionBitVector*> retval;
925 CodeCompressorPlugin* compressor = &pig_->compressor();
926 for (const auto& op : sOperations_) {
927 Instruction* instruction = new Instruction();
928 HWOperation* operation =
929 mapFunctionUnit(op.first)->operation(op.first);
930
931 FUPort* simmPort = static_cast<FUPort*>(simmPorts_.at(op.first));
932 FUPort* rs1Port = static_cast<FUPort*>(rs1Ports_.at(op.first));
933 FUPort* rs2Port = static_cast<FUPort*>(rs2Ports_.at(op.first));
934
935 if (dynamic_cast<RFPort*>(src1)) {
936 instruction->addMove(std::make_shared<Move>(
937 new TerminalRegister(*src1, 0),
938 new TerminalFUPort(*rs1Port, *operation), *rs1Bus_));
939 } else {
940 instruction->addMove(std::make_shared<Move>(
941 new TerminalFUPort(*static_cast<BaseFUPort*>(src1)),
942 new TerminalFUPort(*rs1Port, *operation), *rs1Bus_));
943 }
944
945 instruction->addMove(std::make_shared<Move>(
947 new TerminalFUPort(*simmPort), *simmBus_));
948
949 if (dynamic_cast<RFPort*>(src2)) {
950 instruction->addMove(std::make_shared<Move>(
951 new TerminalRegister(*src2, 0), new TerminalFUPort(*rs2Port),
952 *rs2Bus_));
953 } else {
954 instruction->addMove(std::make_shared<Move>(
955 new TerminalFUPort(*static_cast<BaseFUPort*>(src2)),
956 new TerminalFUPort(*rs2Port), *rs2Bus_));
957 }
958
960 compressor->bemInstructionBits(*instruction);
961 delete instruction;
962 retval.insert({op.first, bits});
963 }
964 return retval;
965}
966
967std::unordered_map<std::string, InstructionBitVector*>
969 std::unordered_map<std::string, InstructionBitVector*> retval;
970 CodeCompressorPlugin* compressor = &pig_->compressor();
971 for (const auto& op : bOperations_) {
972 Instruction* instruction = new Instruction();
973 HWOperation* operation =
974 mapFunctionUnit(op.first)->operation(op.first);
975
976 FUPort* rs1Port = static_cast<FUPort*>(rs1Ports_.at(op.first));
977 FUPort* simmPort = static_cast<FUPort*>(simmPorts_.at(op.first));
978 FUPort* rs2Port = static_cast<FUPort*>(rs2Ports_.at(op.first));
979
980 instruction->addMove(std::make_shared<Move>(
982 new TerminalFUPort(*simmPort, *operation), *simmBus_));
983
984 if (dynamic_cast<RFPort*>(src1)) {
985 instruction->addMove(std::make_shared<Move>(
986 new TerminalRegister(*src1, 0), new TerminalFUPort(*rs1Port),
987 *rs1Bus_));
988 } else {
989 instruction->addMove(std::make_shared<Move>(
990 new TerminalFUPort(*static_cast<BaseFUPort*>(src1)),
991 new TerminalFUPort(*rs1Port), *rs1Bus_));
992 }
993
994 if (dynamic_cast<RFPort*>(src2)) {
995 instruction->addMove(std::make_shared<Move>(
996 new TerminalRegister(*src2, 0), new TerminalFUPort(*rs2Port),
997 *rs2Bus_));
998 } else {
999 instruction->addMove(std::make_shared<Move>(
1000 new TerminalFUPort(*static_cast<BaseFUPort*>(src2)),
1001 new TerminalFUPort(*rs2Port), *rs2Bus_));
1002 }
1003
1004 InstructionBitVector* bits =
1005 compressor->bemInstructionBits(*instruction);
1006 delete instruction;
1007 retval.insert({op.first, bits});
1008 }
1009 return retval;
1010}
1011
1012std::unordered_map<std::string, InstructionBitVector*>
1014 std::unordered_map<std::string, InstructionBitVector*> retval;
1015 CodeCompressorPlugin* compressor = &pig_->compressor();
1017
1018 for (const auto& op : ujOperations_) {
1019 Instruction* instruction = new Instruction();
1020 if (op.first == "move") {
1021 HWOperation* operation = mapFunctionUnit("add")->operation("add");
1022 FUPort* rs1Port = static_cast<FUPort*>(rs1Ports_.at("add"));
1023 FUPort* simmPort = static_cast<FUPort*>(simmPorts_.at("add"));
1024 FUPort* rdPort = static_cast<FUPort*>(rdPorts_.at("add"));
1025 instruction->addMove(std::make_shared<Move>(
1027 new TerminalFUPort(*rs1Port, *operation), *rs1Bus_));
1028
1029 instruction->addMove(std::make_shared<Move>(
1031 new TerminalFUPort(*simmPort), *simmBus_));
1032
1033 instruction->addMove(std::make_shared<Move>(
1034 new TerminalFUPort(*rdPort),
1035 new TerminalRegister(*rdRFPort_, 0), *rdBus_));
1036
1037 bits = compressor->bemInstructionBits(*instruction);
1038 retval.insert({"move", bits});
1039 delete instruction;
1040 } else if (op.first == "callr" or op.first == "apc") {
1041 FUPort* rdPort = static_cast<FUPort*>(rdPorts_.at(op.first));
1042
1043 instruction->addMove(std::make_shared<Move>(
1044 new TerminalFUPort(*rdPort),
1045 new TerminalRegister(*rdRFPort_, 0), *rdBus_));
1046
1047 bits = compressor->bemInstructionBits(*instruction);
1048 delete instruction;
1049 retval.insert({op.first, bits});
1050
1051 } else {
1052 FUPort* simmPort = static_cast<FUPort*>(simmPorts_.at(op.first));
1053 FUPort* rdPort = static_cast<FUPort*>(rdPorts_.at(op.first));
1054
1055 HWOperation* operation =
1056 mapFunctionUnit(op.first)->operation(op.first);
1057
1058 instruction->addMove(std::make_shared<Move>(
1060 new TerminalFUPort(*simmPort, *operation), *simmBus_));
1061
1062 instruction->addMove(std::make_shared<Move>(
1063 new TerminalFUPort(*rdPort),
1064 new TerminalRegister(*rdRFPort_, 0), *rdBus_));
1065
1066 bits = compressor->bemInstructionBits(*instruction);
1067 delete instruction;
1068
1069 retval.insert({op.first, bits});
1070 }
1071 }
1072
1073 return retval;
1074}
1075
1076void
1078 std::unordered_map<std::string, InstructionBitVector*> instructions,
1079 const std::map<std::string, std::string> encodings,
1080 std::ofstream& stream) const {
1081 assert(instructions.size() == encodings.size());
1082 for (const auto& op : instructions) {
1083 stream << " elsif(fu_opcode(" << encodings.at(op.first).size()
1084 << " - 1 downto 0) = "
1085 << "\"" << encodings.at(op.first) << "\""
1086 << ") then" << std::endl
1087 << " moves <= \"" << op.second->toString() << "\";"
1088 << std::endl;
1089 delete op.second;
1090 }
1091}
1092
1093void
1095 std::unordered_map<std::string, std::string> operations;
1096 operations.insert(rOperations_.begin(), rOperations_.end());
1097 operations.insert(iOperations_.begin(), iOperations_.end());
1098 operations.insert(sOperations_.begin(), sOperations_.end());
1099 operations.insert(bOperations_.begin(), bOperations_.end());
1100 operations.insert(ujOperations_.begin(), ujOperations_.end());
1101 operations.insert(r1rOperations_.begin(), r1rOperations_.end());
1102 operations.insert(r1Operations_.begin(), r1Operations_.end());
1103 int len = std::ceil(std::log2(sourceOperationMap_.size()));
1104
1105 stream << " process(fu_opcode)" << std::endl
1106 << " begin" << std::endl
1107 << " target_fu <= to_unsigned(0, " << len << ");" << std::endl;
1108
1109 int id = 0;
1110 bool firstCond = true;
1111 std::string cond;
1112 for (const auto& p : sourceOperationMap_) {
1113 sourcePortID_.insert({p.first, id});
1114 for (const auto& op : p.second) {
1115 if (firstCond) {
1116 cond = " if ";
1117 firstCond = false;
1118 } else {
1119 cond = " elsif ";
1120 }
1121 // Add is a special case as it is used in LUI
1122 if (op == "add") {
1123 int iLen = iOperations_.at(op).size();
1124 int uLen = ujOperations_.at("move").size();
1125 stream << cond << "fu_opcode(" << iLen << "-1 downto 0)"
1126 << " = \"" << iOperations_.at(op) << "\""
1127 << " or "
1128 << "fu_opcode = \"" << rOperations_.at(op)
1129 << "\" or fu_opcode(" << uLen << "-1 downto 0) = \""
1130 << ujOperations_.at("move") << "\""
1131 << " then\n";
1132
1133 } else if (iOperations_.count(op) && rOperations_.count(op)) {
1134 int iLen = iOperations_.at(op).size();
1135 stream << cond << "fu_opcode(" << iLen << "-1 downto 0)"
1136 << " = \"" << iOperations_.at(op) << "\" or "
1137 << "fu_opcode = \"" << rOperations_.at(op)
1138 << "\" then\n";
1139 } else {
1140 int opLen = operations.at(op).size();
1141 stream << cond << "fu_opcode(" << opLen << "-1 downto 0)"
1142 << "= \"" << operations.at(op) << "\" then\n";
1143 }
1144 stream << " target_fu <= to_unsigned(" << id << ", " << len
1145 << ");\n";
1146 }
1147 id++;
1148 }
1149 stream << " end if;" << std::endl << " end process;" << std::endl;
1150
1151 stream << std::endl << std::endl;
1152 stream << " process(clk, rstx)" << std::endl
1153 << " begin" << std::endl
1154 << " if(rstx = '0') then" << std::endl
1155 << " target_fu_r <= (others => '0');" << std::endl
1156 << " elsif clk'event and clk = '1' then" << std::endl
1157 << " if glock_in = '0' and halt = '0' then" << std::endl
1158 << " target_fu_r <= target_fu;" << std::endl
1159 << " end if;" << std::endl
1160 << " end if;" << std::endl
1161 << " end process;" << std::endl
1162 << std::endl
1163 << std::endl;
1164}
1165
1166void
1168 std::map<std::string, std::string> ops,
1169 std::unordered_map<std::string, InstructionBitVector*> (
1170 ProGe::RV32MicroCodeGenerator::*instructionFunc)(Port* p1, Port* p2)
1171 const,
1172 std::ofstream& stream) const {
1173 if (ops.size() == 0) {
1174 return;
1175 }
1176 bool firstOpcodeCond = true;
1177 for (const auto& op : ops) {
1178 std::string opcodeCond = " elsif ";
1179 if (firstOpcodeCond) {
1180 opcodeCond = " if ";
1181 firstOpcodeCond = false;
1182 }
1183 stream << opcodeCond << "fu_opcode(" << op.second.size()
1184 << "-1 downto 0) = \"" << op.second << "\"";
1185 if (rOperations_.count(op.first) && iOperations_.count(op.first)) {
1186 stream << " or fu_opcode(" << iOperations_.at(op.first).size()
1187 << "-1 downto 0) = \"" << iOperations_.at(op.first)
1188 << "\"";
1189 }
1190 stream << "then\n";
1191 bool firstTargetCond = true;
1192 for (const auto& p : sourceOperationMap_) {
1193 std::string targetCond = " elsif ";
1194 if (firstTargetCond) {
1195 targetCond = " if ";
1196 firstTargetCond = false;
1197 }
1198 stream << targetCond + "target_fu_r = "
1199 << sourcePortID_.at(p.first) << " then \n";
1200 std::unordered_map<std::string, InstructionBitVector*>
1201 instructions = (this->*instructionFunc)(p.first, rs2RFPort_);
1202 std::string bits = instructions.at(op.first)->toString();
1203 reverse(bits.begin(), bits.end());
1204 bits = bits.substr(rs1BusStart_, rs1BusWidth_);
1205 reverse(bits.begin(), bits.end());
1206 stream << " moves(rs1_start_c + rs1_width_c -1 downto"
1207 << " rs1_start_c)"
1208 << " <= \"" << bits << "\";\n";
1209 for (const auto& val : instructions) {
1210 delete val.second;
1211 }
1212 }
1213 stream << " end if;" << std::endl;
1214 }
1215 stream << " end if;" << std::endl;
1216}
1217
1218void
1219RV32MicroCodeGenerator::addRs2ForwardingConditions(
1220 std::map<std::string, std::string> ops,
1221 std::unordered_map<std::string, InstructionBitVector*> (
1222 ProGe::RV32MicroCodeGenerator::*instructionFunc)(Port* p1, Port* p2)
1223 const,
1224 std::ofstream& stream) const {
1225 bool firstOpcodeCond = true;
1226 for (const auto& op : ops) {
1227 std::string opcodeCond = " elsif ";
1228 if (firstOpcodeCond) {
1229 opcodeCond = " if ";
1230 firstOpcodeCond = false;
1231 }
1232 stream << opcodeCond << "fu_opcode(" << op.second.size()
1233 << "-1 downto 0) = \"" << op.second << "\" then\n";
1234 bool firstTargetCond = true;
1235 for (const auto& p : sourceOperationMap_) {
1236 std::string targetCond = " elsif ";
1237 if (firstTargetCond) {
1238 targetCond = " if ";
1239 firstTargetCond = false;
1240 }
1241 stream << targetCond + "target_fu_r = "
1242 << sourcePortID_.at(p.first) << " then \n";
1243 std::unordered_map<std::string, InstructionBitVector*>
1244 instructions = (this->*instructionFunc)(rs1RFPort_, p.first);
1245 std::string bits = instructions.at(op.first)->toString();
1246 reverse(bits.begin(), bits.end());
1247 bits = bits.substr(rs2BusStart_, rs2BusWidth_);
1248 reverse(bits.begin(), bits.end());
1249 stream << " moves(rs2_start_c + rs2_width_c -1 downto"
1250 << " rs2_start_c)"
1251 << " <= \"" << bits << "\";\n";
1252 for (const auto& val : instructions) {
1253 delete val.second;
1254 }
1255 }
1256 stream << " end if;" << std::endl;
1257 }
1258 stream << " end if;" << std::endl;
1259}
1260
1261void
1262RV32MicroCodeGenerator::generateMap(const std::string& dstDirectory) {
1263 /*TODO: The if structure should be replaced with a case statement
1264 The problem is that the fu_opcode's width is different between
1265 formats. Don't care states in a case statement
1266 is a VHDL-2OO8 feature
1267 */
1268 const std::string DS = FileSystem::DIRECTORY_SEPARATOR;
1269 std::string mapFile = dstDirectory + DS + "rv32_microcode.vhdl";
1270
1271 std::ofstream stream;
1272 stream.open(mapFile);
1273 stream << LicenseGenerator::generateMITLicense("2023", "--");
1274
1275 stream << "library IEEE;" << std::endl
1276 << "use IEEE.std_logic_1164.all;" << std::endl
1277 << "use IEEE.numeric_std.all;" << std::endl
1278 << "use work." << entityName_ << "_globals.all;" << std::endl
1279 << std::endl
1280 << std::endl;
1281
1282 stream << "entity rv32_microcode is" << std::endl << "port(" << std::endl;
1283 if (hasForwarding_) {
1284 stream << " clk : in std_logic;" << std::endl
1285 << " rstx : in std_logic;" << std::endl
1286 << " glock_in : in std_logic;" << std::endl
1287 << " data_hazard_in : in std_logic;" << std::endl
1288 << " rs1_hazard_in : in std_logic;" << std::endl
1289 << " rs2_hazard_in : in std_logic;" << std::endl
1290 << " halt : in std_logic;" << std::endl;
1291 }
1292 stream << " fu_opcode_in : in std_logic_vector(16 downto 0);"
1293 << std::endl
1294 << " moves_out : out std_logic_vector(INSTRUCTIONWIDTH-1 "
1295 "downto 0));"
1296 << std::endl
1297 << std::endl
1298 << "end rv32_microcode;" << std::endl
1299 << std::endl
1300 << "architecture rtl of rv32_microcode is" << std::endl
1301 << " signal fu_opcode : std_logic_vector(16 downto 0);"
1302 << std::endl
1303 << " signal moves : std_logic_vector(INSTRUCTIONWIDTH-1 "
1304 "downto 0);"
1305 << std::endl
1306 << " constant rs1_start_c : integer := " << rs1BusStart_ << ";"
1307 << std::endl
1308 << " constant rs2_start_c : integer := " << rs2BusStart_ << ";"
1309 << std::endl
1310 << " constant rs1_width_c : integer := " << rs1BusWidth_ << ";"
1311 << std::endl
1312 << " constant rs2_width_c : integer := " << rs2BusWidth_ << ";"
1313 << std::endl;
1314 if (hasForwarding_) {
1315 int len = std::ceil(std::log2(sourceOperationMap_.size()));
1316 stream << " signal target_fu : unsigned(" << len << "-1 downto 0);"
1317 << std::endl;
1318 stream << " signal target_fu_r : unsigned (" << len
1319 << "-1 downto 0);" << std::endl
1320 << " signal data_hazard : std_logic;\n"
1321 << " signal rs1_hazard : std_logic;\n"
1322 << " signal rs2_hazard : std_logic;\n";
1323 }
1324
1325 stream << std::endl
1326 << " begin" << std::endl
1327 << std::endl
1328 << " fu_opcode <= fu_opcode_in;" << std::endl
1329 << " moves_out <= moves;" << std::endl
1330 << std::endl;
1331 if (hasForwarding_) {
1332 stream << " data_hazard <= data_hazard_in;" << std::endl
1333 << " rs1_hazard <= rs1_hazard_in;" << std::endl
1334 << " rs2_hazard <= rs2_hazard_in;" << std::endl;
1335 stream << std::endl;
1336 generateFUTargetProcess(stream);
1337 }
1338 stream << " process(fu_opcode";
1339 if (hasForwarding_) {
1340 stream << ", data_hazard, rs1_hazard, rs2_hazard, target_fu_r";
1341 }
1342 stream << ")" << std::endl;
1343 stream << " begin" << std::endl;
1344
1345 std::unordered_map<std::string, InstructionBitVector*> instructions =
1346 constructRInstructions(rs1RFPort_, rs2RFPort_);
1347 bool firstCond = true;
1348 for (const auto& op : instructions) {
1349 if (firstCond) {
1350 stream << " if(fu_opcode = \"" << rOperations_.at(op.first)
1351 << "\") then" << std::endl
1352 << " moves <= \"" << op.second->toString() << "\";"
1353 << std::endl;
1354 delete op.second;
1355 firstCond = false;
1356 continue;
1357 }
1358 stream << " elsif(fu_opcode(" << rOperations_.at(op.first).size()
1359 << " - 1 downto 0) = \"" << rOperations_.at(op.first) << "\""
1360 << ") then" << std::endl
1361 << " moves <= \"" << op.second->toString() << "\";"
1362 << std::endl;
1363 delete op.second;
1364 }
1365
1366 instructions = constructIInstructions(rs1RFPort_, rs1RFPort_);
1367 addBitsToMap(instructions, iOperations_, stream);
1368
1369 instructions = constructSInstructions(rs1RFPort_, rs2RFPort_);
1370 addBitsToMap(instructions, sOperations_, stream);
1371
1372 instructions = constructBInstructions(rs1RFPort_, rs2RFPort_);
1373 addBitsToMap(instructions, bOperations_, stream);
1374
1375 instructions = constructUJInstructions();
1376 addBitsToMap(instructions, ujOperations_, stream);
1377
1378 instructions = constructR1RInstructions(rs1RFPort_, rs2RFPort_);
1379 addBitsToMap(instructions, r1rOperations_, stream);
1380
1381 instructions = constructR1Instructions(rs1RFPort_, rs2RFPort_);
1382 addBitsToMap(instructions, r1Operations_, stream);
1383
1384 stream << " else" << std::endl;
1385 stream << " moves <= \"" + NOP_ + "\";" << std::endl;
1386
1387 stream << " end if;" << std::endl;
1388
1389 if (hasForwarding_) {
1390 stream << " if(data_hazard = '1') then\n"
1391 << " if(rs1_hazard = '1') then\n";
1392 addRs1ForwardingConditions(
1393 rOperations_,
1395 addRs1ForwardingConditions(
1396 bOperations_,
1398 addRs1ForwardingConditions(
1399 sOperations_,
1401 addRs1ForwardingConditions(
1402 iOperations_,
1404 addRs1ForwardingConditions(
1405 r1rOperations_,
1407 addRs1ForwardingConditions(
1408 r1Operations_,
1410 stream << " end if;\n"
1411 << " if(rs2_hazard = '1') then\n";
1412 addRs2ForwardingConditions(
1413 rOperations_,
1415 addRs2ForwardingConditions(
1416 bOperations_,
1418 addRs2ForwardingConditions(
1419 sOperations_,
1421 stream << " end if;\n"
1422 << " end if;\n";
1423 }
1424
1425 stream << " end process;" << std::endl;
1426
1427 stream << "end architecture rtl;" << std::endl;
1428
1429 stream.close();
1430}
1431
1432std::string
1433RV32MicroCodeGenerator::generateOperationLatencyLogic(
1434 HDLTemplateInstantiator& instantiator) {
1435 std::map<std::string, std::string> operations;
1436 operations.insert(rOperations_.begin(), rOperations_.end());
1437 operations.insert(r1rOperations_.begin(), r1rOperations_.end());
1438 int maxVal = 1;
1439 for (const auto& op : iOperations_) {
1440 if (!rOperations_.count(op.first)) {
1441 operations.insert(op);
1442 }
1443 }
1444 std::map<std::string, int> opLatency;
1445 for (const auto& op : operations) {
1446 FunctionUnit* fu = mapFunctionUnit(op.first);
1447 HWOperation* operation = fu->operation(op.first);
1448 if (operation->latency() > 1) {
1449 opLatency.insert({op.first, operation->latency() - 1});
1450 if (operation->latency() > maxVal) {
1451 maxVal = operation->latency();
1452 }
1453 }
1454 }
1455 int len = std::ceil(std::log2((maxVal)) + 1);
1456 instantiator.replacePlaceholder("op-lat-width", std::to_string(len));
1457 if (opLatency.size() == 0) {
1458 return "op_latency <= to_unsigned(0,op_lat_width_c);";
1459 }
1460 variableLengthOpLatency_ = true;
1461 std::string logic =
1462 "process(fu_opcode)\n"
1463 "begin\n";
1464 bool firstCond = true;
1465 for (const auto& op : opLatency) {
1466 std::string cond = " elsif ";
1467 if (firstCond) {
1468 cond = " if ";
1469 firstCond = false;
1470 }
1471 if (rOperations_.count(op.first) && iOperations_.count(op.first)) {
1472 cond += "fu_opcode = \"" + rOperations_.at(op.first) + "\" or " +
1473 "fu_opcode(" +
1474 std::to_string(iOperations_.at(op.first).size()) +
1475 "-1 downto 0) = \"" + iOperations_.at(op.first) +
1476 "\" then\n";
1477 } else {
1478 cond += "fu_opcode(" +
1479 std::to_string(operations.at(op.first).size()) +
1480 "-1 downto 0) = \"" + operations.at(op.first) +
1481 "\" then\n";
1482 }
1483 logic += cond + " op_latency <= to_unsigned(" +
1484 std::to_string(op.second) + ",op_lat_width_c);\n";
1485 }
1486 logic +=
1487 " else\n"
1488 " op_latency <= to_unsigned(0,op_lat_width_c);\n"
1489 " end if;\n"
1490 "end process;\n";
1491 return logic;
1492}
1493
1494void
1495RV32MicroCodeGenerator::generateWrapper(
1496 HDLTemplateInstantiator& instantiator, const std::string& fileDst) {
1497 instantiator.replacePlaceholder(
1498 "rs1-bus-width", std::to_string(rs1BusWidth_));
1499 instantiator.replacePlaceholder(
1500 "rs2-bus-width", std::to_string(rs2BusWidth_));
1501 instantiator.replacePlaceholder(
1502 "rd-bus-width", std::to_string(rdBusWidth_));
1503 instantiator.replacePlaceholder(
1504 "simm-bus-width", std::to_string(simmBusWidth_));
1505
1506 instantiator.replacePlaceholder(
1507 "rs1-bus-start", std::to_string(rs1BusStart_));
1508 instantiator.replacePlaceholder(
1509 "rs2-bus-start", std::to_string(rs2BusStart_));
1510 instantiator.replacePlaceholder(
1511 "rd-bus-start", std::to_string(rdBusStart_));
1512 instantiator.replacePlaceholder(
1513 "simm-bus-start", std::to_string(simmBusStart_));
1514
1515 instantiator.replacePlaceholder(
1516 "rs1-rf-start", std::to_string(rs1RFStart_));
1517 instantiator.replacePlaceholder(
1518 "rs2-rf-start", std::to_string(rs2RFStart_));
1519 instantiator.replacePlaceholder(
1520 "rd-rf-start", std::to_string(rdRFStart_));
1521 instantiator.replacePlaceholder(
1522 "simm-rf-start", std::to_string(simmRFStart_));
1523
1524 if (eVariant_) {
1525 instantiator.replacePlaceholder("rf-width", std::to_string(4));
1526 } else {
1527 instantiator.replacePlaceholder("rf-width", std::to_string(5));
1528 }
1529
1530 std::string nop = NOP_;
1531 reverse(nop.begin(), nop.end());
1532 nop = nop.substr(rdBusStart_, rdBusWidth_);
1533 reverse(nop.begin(), nop.end());
1534 const std::string rdNOP = nop;
1535
1536 instantiator.replacePlaceholder("rd-nop", rdNOP);
1537 instantiator.replacePlaceholder("nop-instruction", NOP_);
1538 instantiator.replacePlaceholder(
1539 "rv32-microcode-simm-assign", "simm_out <= simm_r;");
1540
1541 const std::string DS = FileSystem::DIRECTORY_SEPARATOR;
1542 const std::string templateDir = Environment::dataDirPath("ProGe");
1543
1544 instantiator.replacePlaceholder(
1545 "rv32-microcode-instruction-assign",
1546 "instruction <= instruction_in;");
1547
1548 if (hasForwarding_) {
1549 std::string forwardingPorts =
1550 " clk : in std_logic;\n"
1551 " rstx : in std_logic;\n"
1552 " glock_in : in std_logic;\n"
1553 " data_hazard_in : in std_logic;\n"
1554 " rs1_hazard_in : in std_logic;\n"
1555 " rs2_hazard_in : in std_logic;\n"
1556 " halt : in std_logic;\n";
1557
1558 std::string forwardingPortMapping =
1559 "clk => clk,\n"
1560 "rstx => rstx,\n"
1561 "glock_in => glock_in,\n"
1562 "data_hazard_in => data_hazard,\n"
1563 "rs1_hazard_in => rs1_hazard,\n"
1564 "rs2_hazard_in => rs2_hazard,\n"
1565 "halt => filling_instruction_pipeline,";
1566
1567 instantiator.replacePlaceholder("forwarding-ports", forwardingPorts);
1568 instantiator.replacePlaceholder(
1569 "forwarding-port-mapping", forwardingPortMapping);
1570 } else {
1571 instantiator.replacePlaceholder(
1572 "data-hazard-stall", "and data_hazard = '0'");
1573 instantiator.replacePlaceholder(
1574 "data-hazard-assign-conds",
1575 "elsif(data_hazard_r = '1') then\n"
1576 " data_hazard <= '0';");
1577 instantiator.replacePlaceholder(
1578 "data-hazard-detection-sensitivity-list-signals",
1579 ", data_hazard_r");
1580 }
1581 instantiator.replacePlaceholder(
1582 "rv32-microcode-op-latency-process",
1583 generateOperationLatencyLogic(instantiator));
1584 std::string otherStates;
1585
1586 if (variableLengthOpLatency_) {
1587 otherStates += ",HANDLE_OP_LATENCY";
1588 }
1589 if (!bypassInstructionRegister_) {
1590 otherStates += ",FILL_INSTRUCTION_PIPELINE_2";
1591 }
1592 instantiator.replacePlaceholder(
1593 "rv32-microcode-other-states", otherStates);
1594 std::string executeLogic;
1595 std::string fsm_sensitivity_list_signals;
1596 executeLogic =
1597 " if(glock_in = '1') then\n"
1598 " bubble <= '1';\n"
1599 " stall_ifetch <= '0';\n"
1600 " NS <= EXECUTE;\n"
1601 " elsif (rv_jump_wire = '1' or rv_auipc_wire = '1') then\n"
1602 " rd_bus_move <= rd_move;\n"
1603 " stall_ifetch <= '0';\n"
1604 " bubble <= '1';\n"
1605 " if rv_auipc_wire = '0' then\n"
1606 " NS <= FILL_INSTRUCTION_PIPELINE;\n"
1607 " end if;\n";
1608 if (!hasForwarding_) {
1609 fsm_sensitivity_list_signals = ", data_hazard";
1610 if (variableLengthOpLatency_) {
1611 executeLogic +=
1612 " elsif(op_latency_stall = '1' and data_hazard = '0') then\n"
1613 " bubble <= '0';\n"
1614 " NS <= HANDLE_OP_LATENCY;\n"
1615 " stall_ifetch <= '1';\n"
1616 " rd_bus_move <= rd_nop_c;\n";
1617 }
1618 executeLogic +=
1619 " elsif(data_hazard = '1') then\n"
1620 " bubble <= '1';\n"
1621 " rd_bus_move <= rd_nop_c;\n"
1622 " stall_ifetch <= '1';\n"
1623 " NS <= EXECUTE;\n"
1624 " elsif (is_control_flow_op = '1') then\n"
1625 " bubble <= '0';\n"
1626 " stall_ifetch <= '1';\n"
1627 " NS <= HANDLE_CONTROL_FLOW_OP;\n"
1628 " handle_control_flow_ns <= '1';\n"
1629 " else\n"
1630 " bubble <= '0';\n"
1631 " stall_ifetch <= '0';\n"
1632 " NS <= EXECUTE;\n"
1633 " end if;\n";
1634 } else {
1635 if (variableLengthOpLatency_) {
1636 executeLogic +=
1637 " elsif(op_latency_stall = '1') then\n"
1638 " bubble <= '0';\n"
1639 " NS <= HANDLE_OP_LATENCY;\n"
1640 " stall_ifetch <= '1';\n"
1641 " rd_bus_move <= rd_nop_c;\n";
1642 }
1643 executeLogic +=
1644 " elsif (is_control_flow_op = '1') then\n"
1645 " bubble <= '0';\n"
1646 " stall_ifetch <= '1';\n"
1647 " NS <= HANDLE_CONTROL_FLOW_OP;\n"
1648 " handle_control_flow_ns <= '1';\n"
1649 " else\n"
1650 " bubble <= '0';\n"
1651 " stall_ifetch <= '0';\n"
1652 " NS <= EXECUTE;\n"
1653 " end if;\n";
1654 }
1655 if (variableLengthOpLatency_) {
1656 fsm_sensitivity_list_signals += ", op_latency_stall";
1657 executeLogic +=
1658 "\n"
1659 "when HANDLE_OP_LATENCY =>\n"
1660 " bubble <= '1';\n"
1661 " stall_ifetch <= '1';\n"
1662 " rd_bus_move <= rd_nop_c;\n"
1663 " NS <= HANDLE_OP_LATENCY;\n"
1664 " if(op_latency_stall = '0') then\n"
1665 " NS <= EXECUTE;\n"
1666 " stall_ifetch <= '0';\n"
1667 " rd_bus_move <= rd_move;\n"
1668 " end if;";
1669 }
1670 std::string instructionPipelineStates;
1671 if (bypassInstructionRegister_) {
1672 instructionPipelineStates =
1673 "when FILL_INSTRUCTION_PIPELINE =>\n"
1674 " filling_instruction_pipeline <= '1';\n"
1675 " bubble <= '1';\n"
1676 " rd_bus_move <= rd_nop_c;\n"
1677 " stall_ifetch <= '0';\n"
1678 " NS <= EXECUTE;\n";
1679 } else {
1680 instructionPipelineStates =
1681 "when FILL_INSTRUCTION_PIPELINE =>\n"
1682 " filling_instruction_pipeline <= '1';\n"
1683 " bubble <= '1';\n"
1684 " rd_bus_move <= rd_nop_c;\n"
1685 " stall_ifetch <= '0';\n"
1686 " NS <= FILL_INSTRUCTION_PIPELINE_2;\n"
1687 "\n"
1688 "\n"
1689 "when FILL_INSTRUCTION_PIPELINE_2 =>\n"
1690 " filling_instruction_pipeline <= '1';\n"
1691 " bubble <= '1';\n"
1692 " rd_bus_move <= rd_nop_c;\n"
1693 " stall_ifetch <= '0';\n"
1694 " NS <= EXECUTE;\n"
1695 "\n";
1696 }
1697 instantiator.replacePlaceholder(
1698 "rv32-microcode-instruction-pipeline-logic",
1699 instructionPipelineStates);
1700
1701 instantiator.replacePlaceholder(
1702 "rv32-microcode-fsm-sensitivity-list-signals",
1703 fsm_sensitivity_list_signals);
1704 instantiator.replacePlaceholder(
1705 "rv32-microcode-execute-logic", executeLogic);
1706
1707 if (hasCustom0Operations_) {
1708 instantiator.replacePlaceholder("rv32-custom0-frame-cond",
1709 "or frame_r_c(1) = opcode");
1710 }
1711 instantiator.instantiateTemplateFile(
1712 templateDir + DS + "rv32_microcode_wrapper.vhdl.tmpl",
1713 fileDst + DS + "rv32_microcode_wrapper.vhdl");
1714}
1715
1716void
1717RV32MicroCodeGenerator::generateRTL(
1718 HDLTemplateInstantiator& instantiator, const std::string& fileDst) {
1719 generateMap(fileDst);
1720 generateWrapper(instantiator, fileDst);
1721}
1722
1723void
1724RV32MicroCodeGenerator::setBypassInstructionRegister(const bool& value) {
1725 bypassInstructionRegister_ = value;
1726}
1727
1728} // namespace ProGe
#define __func__
#define assert(condition)
TTAMachine::Machine * machine
the architecture definition of the estimated processor
find Finds info of the inner loops in the false
#define DS
#define RV32_RTL_GEN_VERBOSE
int instructionFormatCount() const
int moveSlotCount() const
MoveSlot & moveSlot(int index) const
InstructionFormat & instructionFormat(int index) const
void pushBack(long long unsigned int integer, int size)
Definition BitVector.cc:94
std::string toString() const
Definition BitVector.cc:130
InstructionBitVector * bemInstructionBits(const TTAProgram::Instruction &)
static std::string dataDirPath(const std::string &prog)
static const std::string DIRECTORY_SEPARATOR
void instantiateTemplateFile(const std::string &templateFile, const std::string &dstFile)
void replacePlaceholder(const std::string &key, const std::string &replacer, bool append=false)
std::string operationAtIndex(const int index) const
int encoding(const std::string &op) const
std::string name() const
static std::string generateMITLicense(const std::string &year, const std::string &comment)
static bool isConnected(const TTAMachine::Port &sourcePort, const TTAMachine::Port &destinationPort, const TTAMachine::Guard *guard=NULL)
static KeyType keyForValue(const MapType &aMap, const ValueType &aValue)
static bool containsKey(const MapType &aMap, const KeyType &aKey)
static bool containsValue(const MapType &aMap, const ValueType &aValue)
DestinationField & destinationField() const
Definition MoveSlot.cc:341
virtual int width() const
Definition MoveSlot.cc:406
std::string name() const
Definition MoveSlot.cc:136
bool hasDestinationField() const
Definition MoveSlot.cc:327
const BinaryEncoding * bem_
std::unordered_map< std::string, InstructionBitVector * > constructIInstructions(Port *src1, Port *src2) const
void addR1RPorts(const std::string &opName)
void addRs1ForwardingConditions(std::map< std::string, std::string > ops, std::unordered_map< std::string, InstructionBitVector * >(ProGe::RV32MicroCodeGenerator::*instructionFunc)(Port *p1, Port *p2) const, std::ofstream &stream) const
std::unordered_map< std::string, BaseFUPort * > rs1Ports_
FunctionUnit * mapFunctionUnit(const std::string &operation) const
bool findConnectedBusses(Connection &rs1, Connection &rs2, Connection &rd, Connection &simm, const bool &forwarding) const
std::unordered_map< std::string, BaseFUPort * > simmPorts_
RV32MicroCodeGenerator(const Machine &machine, const BinaryEncoding &bem, const std::string &entityName)
std::unordered_map< std::string, BaseFUPort * > rdPorts_
std::map< std::string, std::string > r1rOperations_
void throwOutputPortError(const BaseFUPort *port, const std::string &type) const
void addR1Ports(const std::string &opName)
std::map< std::string, std::string > r1Operations_
void addBitsToMap(std::unordered_map< std::string, InstructionBitVector * > instructions, const std::map< std::string, std::string > encodings, std::ofstream &stream) const
std::unordered_map< std::string, InstructionBitVector * > constructR1Instructions(Port *src1, Port *src2) const
void addRPorts(const std::string &opName)
void addSPorts(const std::string &opName)
void addUJPorts(const std::string &opName)
std::map< std::string, std::string > iOperations_
std::map< std::string, std::string > bOperations_
std::unordered_map< std::string, InstructionBitVector * > constructRInstructions(Port *src1, Port *src2) const
std::map< std::string, std::string > rOperations_
void throwOperationNotFoundError(const std::string &op) const
std::unordered_map< std::string, InstructionBitVector * > constructSInstructions(Port *src1, Port *src2) const
void generateFUTargetProcess(std::ofstream &stream)
std::map< std::string, std::string > sOperations_
std::unordered_map< std::string, BaseFUPort * > rs2Ports_
std::unordered_map< Port *, std::vector< std::string > > sourceOperationMap_
void throwTriggeringPortError(const BaseFUPort *port, const std::string &type) const
std::map< std::string, std::string > ujOperations_
std::unordered_map< std::string, InstructionBitVector * > constructR1RInstructions(Port *src1, Port *src2) const
void addIPorts(const std::string &opName)
std::unordered_map< Port *, int > sourcePortID_
void throwOperandCountError(const std::string &op, int required, int found) const
std::unordered_map< std::string, InstructionBitVector * > constructUJInstructions() const
std::set< Port * > operationPorts(const std::unordered_map< std::string, BaseFUPort * > &ports) const
std::unordered_map< std::string, InstructionBitVector * > constructBInstructions(Port *src1, Port *src2) const
void throwInputPortError(const BaseFUPort *port, const std::string &type) const
void addBPorts(const std::string &opName)
void loadMachine(const TTAMachine::Machine &machine)
CodeCompressorPlugin & compressor()
void loadBEM(const BinaryEncoding &bem)
virtual int width() const
Definition SlotField.cc:307
FunctionUnit * parentUnit() const
Definition BaseFUPort.cc:96
virtual int size() const
virtual int width() const
virtual RFPort * port(const std::string &name) const
int width() const
Definition Bus.cc:149
int immediateWidth() const
Definition Bus.cc:160
virtual TCEString name() const
SpecialRegisterPort * returnAddressPort() const
virtual bool isTriggering() const
Definition FUPort.cc:182
virtual HWOperation * operation(const std::string &name) const
virtual bool hasOperation(const std::string &name) const
virtual FUPort * port(int operand) const
ComponentType * item(int index) const
virtual RegisterFileNavigator registerFileNavigator() const
Definition Machine.cc:450
virtual FunctionUnitNavigator functionUnitNavigator() const
Definition Machine.cc:380
bool hasOperation(const TCEString &opName) const
Definition Machine.cc:1042
virtual BusNavigator busNavigator() const
Definition Machine.cc:356
virtual ControlUnit * controlUnit() const
Definition Machine.cc:345
virtual Socket * outputSocket() const
Definition Port.cc:281
virtual bool isInput() const
Definition Port.cc:298
virtual bool isOutput() const
Definition Port.cc:308
virtual Socket * inputSocket() const
Definition Port.cc:261
virtual std::string name() const
Definition Port.cc:141
virtual bool zeroRegister() const
virtual int portCount() const
Definition Unit.cc:135
virtual int inputPortCount(bool countBidir=false) const
Definition Unit.cc:160
virtual int outputPortCount(bool countBidir=false) const
Definition Unit.cc:145
void addMove(std::shared_ptr< Move > move)
static bool containsValue(const ContainerType &aVec, const ValueType &aValue)
Definition FUGen.hh:54
const std::string RISCV_S_TYPE_NAME
const std::string RISCV_R1R_TYPE_NAME
const std::string RISCV_B_TYPE_NAME
const std::string RISCV_J_TYPE_NAME
const std::string RISCV_R_TYPE_NAME
const std::string RISCV_R1_TYPE_NAME
const std::string RISCV_I_TYPE_NAME
const std::string RISCV_U_TYPE_NAME
const std::vector< std::string > RISCVMExtensionOperations
const std::map< std::string, std::string > RISCVOperationNameTable