commit b98cdd2ed1a02ffcd879c0abad800b27a10d02bd
parent 9639da9d4aebf625f01e8b3987447850881bf3c4
Author: yash modi <yash3108m@gmail.com>
Date: Thu, 26 Mar 2026 23:50:46 +0530
Week 2: Begin Verilog Emitter Implementation (Part 1: Initial definitions)
Diffstat:
| A | src/emitter.cpp | | | 132 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 132 insertions(+), 0 deletions(-)
diff --git a/src/emitter.cpp b/src/emitter.cpp
@@ -0,0 +1,132 @@
+#include "emitter.h"
+#include <fstream>
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <algorithm>
+#include <set>
+#include <map>
+#include <system_error>
+#include <filesystem>
+
+// =============================================================================
+// Emitter::emit — orchestration
+// =============================================================================
+void Emitter::emit(const std::vector<std::unique_ptr<NFA>> &nfas,
+ const std::string &outputDirStr,
+ const std::vector<std::string> &testStrings,
+ const std::vector<std::string> &expectedMatches)
+{
+ if (nfas.empty())
+ {
+ std::cout << "No valid NFAs were provided; skipping Verilog emission." << std::endl;
+ return;
+ }
+
+ std::filesystem::path outputDir(outputDirStr);
+ try
+ {
+ std::filesystem::create_directories(outputDir);
+ }
+ catch (const std::filesystem::filesystem_error &e)
+ {
+ throw std::system_error(e.code(), "Failed to create output directory: " + outputDir.string());
+ }
+
+ for (const auto &nfa : nfas)
+ {
+ emitNFAModule(*nfa, outputDir);
+ }
+
+ emitTopModule(nfas, outputDir);
+ emitUARTRX(outputDir); // uart_rx.v
+ emitUARTTX(outputDir); // uart_tx.v
+ emitFIFO(outputDir); // uart_rx_fifo.v
+ emitTopFPGA(nfas, outputDir); // top_fpga.v
+ emitConstraints(nfas, outputDir);
+ emitTestbench(nfas, outputDir, testStrings, expectedMatches);
+}
+
+// =============================================================================
+// emitNFAModule — one file per regex
+// =============================================================================
+void Emitter::emitNFAModule(const NFA &nfa, const std::filesystem::path &outputDir)
+{
+ auto filePath = outputDir / ("nfa_" + std::to_string(nfa.regexIndex) + ".v");
+ std::ofstream out;
+ out.exceptions(std::ofstream::failbit | std::ofstream::badbit);
+
+ try
+ {
+ out.open(filePath);
+ }
+ catch (const std::ios_base::failure &e)
+ {
+ throw std::system_error(errno, std::generic_category(), "Could not open " + filePath.string() + " for writing");
+ }
+
+ int numStates = static_cast<int>(nfa.states.size());
+ if (numStates == 0)
+ return;
+
+ std::map<int, int> globalToLocal;
+ int localIdx = 0;
+
+ // Ensure start state is always local state 0
+ globalToLocal[nfa.startStateId] = localIdx++;
+
+ // Sort other state IDs for deterministic output
+ std::set<int> otherIds;
+ for (const auto &pair : nfa.states)
+ {
+ if (pair.first != nfa.startStateId)
+ otherIds.insert(pair.first);
+ }
+ for (int id : otherIds)
+ {
+ globalToLocal[id] = localIdx++;
+ }
+
+ out << "`timescale 1ns / 1ps\n\n";
+ out << "// NFA for regex index " << nfa.regexIndex << "\n";
+ out << "module nfa_" << nfa.regexIndex << " (\n"
+ << " input wire clk,\n"
+ << " input wire en,\n"
+ << " input wire rst,\n"
+ << " input wire start,\n"
+ << " input wire end_of_str,\n"
+ << " input wire [7:0] char_in,\n"
+ << " output reg match\n"
+ << ");\n\n";
+
+ out << " // One-hot state register\n"
+ << " reg [" << numStates - 1 << ":0] state_reg;\n"
+ << " wire [" << numStates - 1 << ":0] next_state;\n\n";
+
+ std::map<int, std::vector<std::pair<int, unsigned char>>> invertedTransitions;
+ for (const auto &[srcGlobalId, srcState] : nfa.states)
+ {
+ for (const auto &[c, dstIds] : srcState.transitions)
+ {
+ for (int dstGlobalId : dstIds)
+ {
+ invertedTransitions[dstGlobalId].push_back({srcGlobalId, c});
+ }
+ }
+ }
+
+ for (const auto &[globalId, localId] : globalToLocal)
+ {
+ out << " assign next_state[" << localId << "] = ";
+
+ std::vector<std::string> terms;
+
+ if (auto it = invertedTransitions.find(globalId); it != invertedTransitions.end())
+ {
+ std::map<int, std::vector<unsigned char>> charsBySrc;
+ for (const auto &[srcGlobalId, c] : it->second)
+ {
+ charsBySrc[globalToLocal.at(srcGlobalId)].push_back(c);
+ }
+
+ // Magnitude comparators for contiguous wildcard ranges