xiiregexbuilder

FPGA-Accelerated Regular Expression Matching Engine
commit 907199802749d357c7f9a12bdb596fee78e5f6a7
parent a9386b4caec8fcf9c2b7545e2be8b251cdf1af26
Author: yash modi <yash3108m@gmail.com>
Date:   Sun, 29 Mar 2026 16:27:41 +0530

Week 2: Complete Verilog Emitter Optimization (Part 1: Initial definitions)

Diffstat:
Msrc/emitter.cpp | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 169 insertions(+), 0 deletions(-)

diff --git a/src/emitter.cpp b/src/emitter.cpp @@ -398,3 +398,172 @@ module uart_rx #( end STOP_BIT: begin if (clk_count < CLKS_PER_BIT-1) begin + clk_count <= clk_count + 1; + end else begin + if (rx == 1'b1) rx_ready <= 1'b1; + state <= IDLE; + end + end + endcase + end +endmodule +)"; +} + +// ============================================================================= +// emitUARTTX - uart_tx.v +// ============================================================================= +void Emitter::emitUARTTX(const std::filesystem::path &outputDir) +{ + auto filePath = outputDir / "uart_tx.v"; + std::ofstream out(filePath); + out.exceptions(std::ofstream::failbit | std::ofstream::badbit); + + out << "`timescale 1ns / 1ps\n\n"; + out << R"( +module uart_tx #( + parameter CLKS_PER_BIT = 868 // 100 MHz / 115200 baud +)( + input wire clk, + input wire rst, + input wire [7:0] tx_data, + input wire tx_start, + output reg tx_busy, + output reg tx +); + localparam S_IDLE = 3'd0; + localparam S_START_BIT = 3'd1; + localparam S_DATA_BITS = 3'd2; + localparam S_STOP_BIT = 3'd3; + + reg [2:0] state = S_IDLE; + reg [9:0] clk_cnt = 10'd0; + reg [2:0] bit_idx = 3'd0; + reg [7:0] tx_shift = 8'd0; + + always @(posedge clk) begin + if (rst) begin + state <= S_IDLE; + tx <= 1'b1; + tx_busy <= 1'b0; + clk_cnt <= 10'd0; + bit_idx <= 3'd0; + tx_shift <= 8'd0; + end else begin + case (state) + S_IDLE: begin + tx <= 1'b1; + tx_busy <= 1'b0; + clk_cnt <= 10'd0; + bit_idx <= 3'd0; + if (tx_start) begin + tx_shift <= tx_data; + tx_busy <= 1'b1; + state <= S_START_BIT; + end + end + S_START_BIT: begin + tx <= 1'b0; + if (clk_cnt < CLKS_PER_BIT - 1) + clk_cnt <= clk_cnt + 1; + else begin + clk_cnt <= 10'd0; + state <= S_DATA_BITS; + end + end + S_DATA_BITS: begin + tx <= tx_shift[0]; + if (clk_cnt < CLKS_PER_BIT - 1) + clk_cnt <= clk_cnt + 1; + else begin + clk_cnt <= 10'd0; + tx_shift <= tx_shift >> 1; + if (bit_idx < 7) + bit_idx <= bit_idx + 1; + else begin + bit_idx <= 3'd0; + state <= S_STOP_BIT; + end + end + end + S_STOP_BIT: begin + tx <= 1'b1; + if (clk_cnt < CLKS_PER_BIT - 1) + clk_cnt <= clk_cnt + 1; + else begin + clk_cnt <= 10'd0; + state <= S_IDLE; + end + end + default: state <= S_IDLE; + endcase + end + end +endmodule +)"; +} + +// ============================================================================= +// emitFIFO - uart_rx_fifo.v +// ============================================================================= +void Emitter::emitFIFO(const std::filesystem::path &outputDir) +{ + auto filePath = outputDir / "uart_rx_fifo.v"; + std::ofstream out(filePath); + out.exceptions(std::ofstream::failbit | std::ofstream::badbit); + + out << "`timescale 1ns / 1ps\n\n"; + out << R"( +module uart_rx_fifo #( + parameter DEPTH_LOG2 = 4 // depth = 2^DEPTH_LOG2 = 16 +)( + input wire clk, + input wire rst, + input wire [7:0] wr_data, + input wire wr_en, + output wire full, + output wire [7:0] rd_data, + input wire rd_en, + output wire empty +); + localparam DEPTH = 1 << DEPTH_LOG2; + + reg [7:0] mem [0:DEPTH-1]; + reg [DEPTH_LOG2-1:0] wr_ptr = {DEPTH_LOG2{1'b0}}; + reg [DEPTH_LOG2-1:0] rd_ptr = {DEPTH_LOG2{1'b0}}; + reg [DEPTH_LOG2 :0] count = {(DEPTH_LOG2+1){1'b0}}; + + assign full = (count == DEPTH[DEPTH_LOG2:0]); + assign empty = (count == {(DEPTH_LOG2+1){1'b0}}); + assign rd_data = mem[rd_ptr]; + + always @(posedge clk) begin + if (rst) begin + wr_ptr <= {DEPTH_LOG2{1'b0}}; + rd_ptr <= {DEPTH_LOG2{1'b0}}; + count <= {(DEPTH_LOG2+1){1'b0}}; + end else begin + if (wr_en && !full && rd_en && !empty) begin + mem[wr_ptr] <= wr_data; + wr_ptr <= wr_ptr + 1; + rd_ptr <= rd_ptr + 1; + end else if (wr_en && !full) begin + mem[wr_ptr] <= wr_data; + wr_ptr <= wr_ptr + 1; + count <= count + 1; + end else if (rd_en && !empty) begin + rd_ptr <= rd_ptr + 1; + count <= count - 1; + end + end + end +endmodule +)"; +} + +// ============================================================================= +// emitTopFPGA - top_fpga.v +// ============================================================================= +void Emitter::emitTopFPGA(const std::vector<std::unique_ptr<NFA>> &nfas, const std::filesystem::path &outputDir) +{ + auto filePath = outputDir / "top_fpga.v";