xiiregexbuilder

FPGA-Accelerated Regular Expression Matching Engine
commit 68de20aebb7b522651dd591789127470eaeaeefc
parent 9fb3f273ed339b048202b5ea54b7a03a8f900964
Author: Vishrut Gurrala <maydayv7@gmail.com>
Date:   Fri, 24 Apr 2026 00:34:17 +0530

Week 6: UART modules, example testbench, and repository configuration (Part 2: Core logic)

Diffstat:
MREADME.md | 10+++++-----
Moutput-eg/tb_top.v | 586+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Moutput-eg/top.v | 55++++++++++++++++++++++++++++++++++++++++++++++++-------
3 files changed, 538 insertions(+), 113 deletions(-)

diff --git a/README.md b/README.md @@ -12,7 +12,7 @@ The host PC communicates with the FPGA over a standard USB-UART serial link at 1 - **FIX Protocol Parsing**: High-speed filtering of electronic trading messages (orders/fills) to route data before it reaches the software stack. - **Market Data Feed Filtering**: Scanning millions of events per second to discard irrelevant instrument data at line-rate, saving CPU cycles. -- **Trade Surveillance**: Detecting malicious network patterns (e.g., spoofing, wash trading) continuously across live, high-speed data flows. +- **Trade Surveillance**: Detecting malicious network patterns (Eg., spoofing, wash trading) continuously across live, high-speed data flows. ## 3. FPGA Relevance @@ -63,17 +63,17 @@ Send `?` at any time to query the current counters without feeding any character ### Hardware Counters -- `byte_count [31:0]` — total bytes fed into the NFA engine since the last reset. -- `match_count_k [15:0]` — cumulative match events for regex _k_ (independent counter per regex). +- `byte_count [31:0]` - total bytes fed into the NFA engine since the last reset. +- `match_count_k [15:0]` - cumulative match events for regex _k_ (independent counter per regex). ## 5. System Scope ### Minimum System (Commitment) -- C++ Verilog Emitter compiling basic literal and concatenation patterns (e.g., abc). +- C++ Verilog Emitter compiling basic literal and concatenation patterns (Eg., abc). - At least one generated Verilog FSM successfully simulated and executing correctly on the FPGA. -### Goal System — **ACHIEVED** +### Goal System - **ACHIEVED** - Full compiler support for complex operators (`*`, `+`, `?`, `|`, `.`) via Glushkov's epsilon-free construction. - Integration of up to 16 parallel FSM modules passing the C++ golden reference testbenches. diff --git a/output-eg/tb_top.v b/output-eg/tb_top.v @@ -3,9 +3,10 @@ module tb_top; reg clk, en, rst, start, end_of_str; reg [7:0] char_in; - wire [5:0] match_bus; + wire [15:0] match_bus; + wire [15:0] active_bus; - top uut (.clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match_bus(match_bus)); + top uut (.clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match_bus(match_bus), .active_bus(active_bus)); always #5 clk = ~clk; @@ -20,253 +21,636 @@ module tb_top; clk = 0; en = 1; rst = 1; start = 0; end_of_str = 0; char_in = 0; #20 rst = 0; #10; - // Test case 0: "a" + // Test case 0: "cat" start = 1; #10 start = 0; + char_in = 8'h63; #10; char_in = 8'h61; #10; + char_in = 8'h74; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b000101) begin - $display("PASS: Test case 0 ('a') matches expected mask 000101"); + if (match_bus === 16'b0000000000000011) begin + $display("PASS: Test case 0 ('cat') matches expected mask 0000000000000011"); end else begin - $display("FAIL: Test case 0 ('a') expected 000101, got %b", match_bus); + $display("FAIL: Test case 0 ('cat') expected 0000000000000011, got %b", match_bus); end end_of_str = 0; #10; - // Test case 1: "b" + // Test case 1: "dog" start = 1; #10 start = 0; - char_in = 8'h62; #10; + char_in = 8'h64; #10; + char_in = 8'h6f; #10; + char_in = 8'h67; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b000101) begin - $display("PASS: Test case 1 ('b') matches expected mask 000101"); + if (match_bus === 16'b0000000000000100) begin + $display("PASS: Test case 1 ('dog') matches expected mask 0000000000000100"); end else begin - $display("FAIL: Test case 1 ('b') expected 000101, got %b", match_bus); + $display("FAIL: Test case 1 ('dog') expected 0000000000000100, got %b", match_bus); end end_of_str = 0; #10; - // Test case 2: "c" + // Test case 2: "tomcat" start = 1; #10 start = 0; + char_in = 8'h74; #10; + char_in = 8'h6f; #10; + char_in = 8'h6d; #10; char_in = 8'h63; #10; + char_in = 8'h61; #10; + char_in = 8'h74; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b000000) begin - $display("PASS: Test case 2 ('c') matches expected mask 000000"); + if (match_bus === 16'b0000000000000000) begin + $display("PASS: Test case 2 ('tomcat') matches expected mask 0000000000000000"); end else begin - $display("FAIL: Test case 2 ('c') expected 000000, got %b", match_bus); + $display("FAIL: Test case 2 ('tomcat') expected 0000000000000000, got %b", match_bus); end end_of_str = 0; #10; - // Test case 3: "aa" + // Test case 3: "cot" start = 1; #10 start = 0; - char_in = 8'h61; #10; - char_in = 8'h61; #10; + char_in = 8'h63; #10; + char_in = 8'h6f; #10; + char_in = 8'h74; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b000100) begin - $display("PASS: Test case 3 ('aa') matches expected mask 000100"); + if (match_bus === 16'b0000000000000010) begin + $display("PASS: Test case 3 ('cot') matches expected mask 0000000000000010"); end else begin - $display("FAIL: Test case 3 ('aa') expected 000100, got %b", match_bus); + $display("FAIL: Test case 3 ('cot') expected 0000000000000010, got %b", match_bus); end end_of_str = 0; #10; - // Test case 4: "ab" + // Test case 4: "cut" start = 1; #10 start = 0; - char_in = 8'h61; #10; - char_in = 8'h62; #10; + char_in = 8'h63; #10; + char_in = 8'h75; #10; + char_in = 8'h74; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b000100) begin - $display("PASS: Test case 4 ('ab') matches expected mask 000100"); + if (match_bus === 16'b0000000000000010) begin + $display("PASS: Test case 4 ('cut') matches expected mask 0000000000000010"); end else begin - $display("FAIL: Test case 4 ('ab') expected 000100, got %b", match_bus); + $display("FAIL: Test case 4 ('cut') expected 0000000000000010, got %b", match_bus); end end_of_str = 0; #10; - // Test case 5: "ac" + // Test case 5: "ct" start = 1; #10 start = 0; - char_in = 8'h61; #10; char_in = 8'h63; #10; + char_in = 8'h74; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b000110) begin - $display("PASS: Test case 5 ('ac') matches expected mask 000110"); + if (match_bus === 16'b0000000000000000) begin + $display("PASS: Test case 5 ('ct') matches expected mask 0000000000000000"); end else begin - $display("FAIL: Test case 5 ('ac') expected 000110, got %b", match_bus); + $display("FAIL: Test case 5 ('ct') expected 0000000000000000, got %b", match_bus); end end_of_str = 0; #10; - // Test case 6: "abc" + // Test case 6: "doog" + start = 1; #10 start = 0; + char_in = 8'h64; #10; + char_in = 8'h6f; #10; + char_in = 8'h6f; #10; + char_in = 8'h67; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000000000100) begin + $display("PASS: Test case 6 ('doog') matches expected mask 0000000000000100"); + end else begin + $display("FAIL: Test case 6 ('doog') expected 0000000000000100, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 7: "dg" + start = 1; #10 start = 0; + char_in = 8'h64; #10; + char_in = 8'h67; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000000000100) begin + $display("PASS: Test case 7 ('dg') matches expected mask 0000000000000100"); + end else begin + $display("FAIL: Test case 7 ('dg') expected 0000000000000100, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 8: "beep" start = 1; #10 start = 0; - char_in = 8'h61; #10; char_in = 8'h62; #10; - char_in = 8'h63; #10; + char_in = 8'h65; #10; + char_in = 8'h65; #10; + char_in = 8'h70; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b010110) begin - $display("PASS: Test case 6 ('abc') matches expected mask 010110"); + if (match_bus === 16'b0000000000001000) begin + $display("PASS: Test case 8 ('beep') matches expected mask 0000000000001000"); end else begin - $display("FAIL: Test case 6 ('abc') expected 010110, got %b", match_bus); + $display("FAIL: Test case 8 ('beep') expected 0000000000001000, got %b", match_bus); end end_of_str = 0; #10; - // Test case 7: "abbc" + // Test case 9: "bep" start = 1; #10 start = 0; - char_in = 8'h61; #10; char_in = 8'h62; #10; + char_in = 8'h65; #10; + char_in = 8'h70; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000000001000) begin + $display("PASS: Test case 9 ('bep') matches expected mask 0000000000001000"); + end else begin + $display("FAIL: Test case 9 ('bep') expected 0000000000001000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 10: "bp" + start = 1; #10 start = 0; char_in = 8'h62; #10; - char_in = 8'h63; #10; + char_in = 8'h70; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b000110) begin - $display("PASS: Test case 7 ('abbc') matches expected mask 000110"); + if (match_bus === 16'b0000000000000000) begin + $display("PASS: Test case 10 ('bp') matches expected mask 0000000000000000"); end else begin - $display("FAIL: Test case 7 ('abbc') expected 000110, got %b", match_bus); + $display("FAIL: Test case 10 ('bp') expected 0000000000000000, got %b", match_bus); end end_of_str = 0; #10; - // Test case 8: "abbbc" + // Test case 11: "fly" + start = 1; #10 start = 0; + char_in = 8'h66; #10; + char_in = 8'h6c; #10; + char_in = 8'h79; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000000010000) begin + $display("PASS: Test case 11 ('fly') matches expected mask 0000000000010000"); + end else begin + $display("FAIL: Test case 11 ('fly') expected 0000000000010000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 12: "fy" + start = 1; #10 start = 0; + char_in = 8'h66; #10; + char_in = 8'h79; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000000010000) begin + $display("PASS: Test case 12 ('fy') matches expected mask 0000000000010000"); + end else begin + $display("FAIL: Test case 12 ('fy') expected 0000000000010000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 13: "apple" start = 1; #10 start = 0; char_in = 8'h61; #10; - char_in = 8'h62; #10; - char_in = 8'h62; #10; - char_in = 8'h62; #10; - char_in = 8'h63; #10; + char_in = 8'h70; #10; + char_in = 8'h70; #10; + char_in = 8'h6c; #10; + char_in = 8'h65; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000000100000) begin + $display("PASS: Test case 13 ('apple') matches expected mask 0000000000100000"); + end else begin + $display("FAIL: Test case 13 ('apple') expected 0000000000100000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 14: "orange" + start = 1; #10 start = 0; + char_in = 8'h6f; #10; + char_in = 8'h72; #10; + char_in = 8'h61; #10; + char_in = 8'h6e; #10; + char_in = 8'h67; #10; + char_in = 8'h65; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b000110) begin - $display("PASS: Test case 8 ('abbbc') matches expected mask 000110"); + if (match_bus === 16'b0000000000100000) begin + $display("PASS: Test case 14 ('orange') matches expected mask 0000000000100000"); end else begin - $display("FAIL: Test case 8 ('abbbc') expected 000110, got %b", match_bus); + $display("FAIL: Test case 14 ('orange') expected 0000000000100000, got %b", match_bus); end end_of_str = 0; #10; - // Test case 9: "aaaa" + // Test case 15: "banana" start = 1; #10 start = 0; + char_in = 8'h62; #10; char_in = 8'h61; #10; + char_in = 8'h6e; #10; char_in = 8'h61; #10; + char_in = 8'h6e; #10; char_in = 8'h61; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000000000000) begin + $display("PASS: Test case 15 ('banana') matches expected mask 0000000000000000"); + end else begin + $display("FAIL: Test case 15 ('banana') expected 0000000000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 16: "redcar" + start = 1; #10 start = 0; + char_in = 8'h72; #10; + char_in = 8'h65; #10; + char_in = 8'h64; #10; + char_in = 8'h63; #10; char_in = 8'h61; #10; + char_in = 8'h72; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b000100) begin - $display("PASS: Test case 9 ('aaaa') matches expected mask 000100"); + if (match_bus === 16'b0000000001000000) begin + $display("PASS: Test case 16 ('redcar') matches expected mask 0000000001000000"); end else begin - $display("FAIL: Test case 9 ('aaaa') expected 000100, got %b", match_bus); + $display("FAIL: Test case 16 ('redcar') expected 0000000001000000, got %b", match_bus); end end_of_str = 0; #10; - // Test case 10: "bbbb" + // Test case 17: "bluecar" start = 1; #10 start = 0; char_in = 8'h62; #10; - char_in = 8'h62; #10; - char_in = 8'h62; #10; - char_in = 8'h62; #10; + char_in = 8'h6c; #10; + char_in = 8'h75; #10; + char_in = 8'h65; #10; + char_in = 8'h63; #10; + char_in = 8'h61; #10; + char_in = 8'h72; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b000100) begin - $display("PASS: Test case 10 ('bbbb') matches expected mask 000100"); + if (match_bus === 16'b0000000001000000) begin + $display("PASS: Test case 17 ('bluecar') matches expected mask 0000000001000000"); end else begin - $display("FAIL: Test case 10 ('bbbb') expected 000100, got %b", match_bus); + $display("FAIL: Test case 17 ('bluecar') expected 0000000001000000, got %b", match_bus); end end_of_str = 0; #10; - // Test case 11: "x" + // Test case 18: "greencar" start = 1; #10 start = 0; - char_in = 8'h78; #10; + char_in = 8'h67; #10; + char_in = 8'h72; #10; + char_in = 8'h65; #10; + char_in = 8'h65; #10; + char_in = 8'h6e; #10; + char_in = 8'h63; #10; + char_in = 8'h61; #10; + char_in = 8'h72; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b000000) begin - $display("PASS: Test case 11 ('x') matches expected mask 000000"); + if (match_bus === 16'b0000000000000000) begin + $display("PASS: Test case 18 ('greencar') matches expected mask 0000000000000000"); end else begin - $display("FAIL: Test case 11 ('x') expected 000000, got %b", match_bus); + $display("FAIL: Test case 18 ('greencar') expected 0000000000000000, got %b", match_bus); end end_of_str = 0; #10; - // Test case 12: "axb" + // Test case 19: "lolo" + start = 1; #10 start = 0; + char_in = 8'h6c; #10; + char_in = 8'h6f; #10; + char_in = 8'h6c; #10; + char_in = 8'h6f; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000010000000) begin + $display("PASS: Test case 19 ('lolo') matches expected mask 0000000010000000"); + end else begin + $display("FAIL: Test case 19 ('lolo') expected 0000000010000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 20: "lololo" + start = 1; #10 start = 0; + char_in = 8'h6c; #10; + char_in = 8'h6f; #10; + char_in = 8'h6c; #10; + char_in = 8'h6f; #10; + char_in = 8'h6c; #10; + char_in = 8'h6f; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000010000000) begin + $display("PASS: Test case 20 ('lololo') matches expected mask 0000000010000000"); + end else begin + $display("FAIL: Test case 20 ('lololo') expected 0000000010000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 21: "lo" + start = 1; #10 start = 0; + char_in = 8'h6c; #10; + char_in = 8'h6f; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000010000000) begin + $display("PASS: Test case 21 ('lo') matches expected mask 0000000010000000"); + end else begin + $display("FAIL: Test case 21 ('lo') expected 0000000010000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 22: "good" + start = 1; #10 start = 0; + char_in = 8'h67; #10; + char_in = 8'h6f; #10; + char_in = 8'h6f; #10; + char_in = 8'h64; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000100000000) begin + $display("PASS: Test case 22 ('good') matches expected mask 0000000100000000"); + end else begin + $display("FAIL: Test case 22 ('good') expected 0000000100000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 23: "goodod" + start = 1; #10 start = 0; + char_in = 8'h67; #10; + char_in = 8'h6f; #10; + char_in = 8'h6f; #10; + char_in = 8'h64; #10; + char_in = 8'h6f; #10; + char_in = 8'h64; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000100000000) begin + $display("PASS: Test case 23 ('goodod') matches expected mask 0000000100000000"); + end else begin + $display("FAIL: Test case 23 ('goodod') expected 0000000100000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 24: "go" + start = 1; #10 start = 0; + char_in = 8'h67; #10; + char_in = 8'h6f; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000000000000) begin + $display("PASS: Test case 24 ('go') matches expected mask 0000000000000000"); + end else begin + $display("FAIL: Test case 24 ('go') expected 0000000000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 25: "hello" + start = 1; #10 start = 0; + char_in = 8'h68; #10; + char_in = 8'h65; #10; + char_in = 8'h6c; #10; + char_in = 8'h6c; #10; + char_in = 8'h6f; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000001000000000) begin + $display("PASS: Test case 25 ('hello') matches expected mask 0000001000000000"); + end else begin + $display("FAIL: Test case 25 ('hello') expected 0000001000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 26: "llo" + start = 1; #10 start = 0; + char_in = 8'h6c; #10; + char_in = 8'h6c; #10; + char_in = 8'h6f; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000001000000000) begin + $display("PASS: Test case 26 ('llo') matches expected mask 0000001000000000"); + end else begin + $display("FAIL: Test case 26 ('llo') expected 0000001000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 27: "he" + start = 1; #10 start = 0; + char_in = 8'h68; #10; + char_in = 8'h65; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000000000000) begin + $display("PASS: Test case 27 ('he') matches expected mask 0000000000000000"); + end else begin + $display("FAIL: Test case 27 ('he') expected 0000000000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 28: "ad" start = 1; #10 start = 0; char_in = 8'h61; #10; - char_in = 8'h78; #10; - char_in = 8'h62; #10; + char_in = 8'h64; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b001000) begin - $display("PASS: Test case 12 ('axb') matches expected mask 001000"); + if (match_bus === 16'b0100010000000000) begin + $display("PASS: Test case 28 ('ad') matches expected mask 0100010000000000"); end else begin - $display("FAIL: Test case 12 ('axb') expected 001000, got %b", match_bus); + $display("FAIL: Test case 28 ('ad') expected 0100010000000000, got %b", match_bus); end end_of_str = 0; #10; - // Test case 13: "ayb" + // Test case 29: "abd" start = 1; #10 start = 0; char_in = 8'h61; #10; - char_in = 8'h79; #10; char_in = 8'h62; #10; + char_in = 8'h64; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b001000) begin - $display("PASS: Test case 13 ('ayb') matches expected mask 001000"); + if (match_bus === 16'b0000010000000000) begin + $display("PASS: Test case 29 ('abd') matches expected mask 0000010000000000"); end else begin - $display("FAIL: Test case 13 ('ayb') expected 001000, got %b", match_bus); + $display("FAIL: Test case 29 ('abd') expected 0000010000000000, got %b", match_bus); end end_of_str = 0; #10; - // Test case 14: "(a|b)" + // Test case 30: "acd" start = 1; #10 start = 0; - char_in = 8'h28; #10; char_in = 8'h61; #10; - char_in = 8'h7c; #10; - char_in = 8'h62; #10; - char_in = 8'h29; #10; + char_in = 8'h63; #10; + char_in = 8'h64; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b000000) begin - $display("PASS: Test case 14 ('(a|b)') matches expected mask 000000"); + if (match_bus === 16'b0000010000000000) begin + $display("PASS: Test case 30 ('acd') matches expected mask 0000010000000000"); end else begin - $display("FAIL: Test case 14 ('(a|b)') expected 000000, got %b", match_bus); + $display("FAIL: Test case 30 ('acd') expected 0000010000000000, got %b", match_bus); end end_of_str = 0; #10; - // Test case 15: "abc" + // Test case 31: "abcd" start = 1; #10 start = 0; char_in = 8'h61; #10; char_in = 8'h62; #10; char_in = 8'h63; #10; + char_in = 8'h64; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000010000000000) begin + $display("PASS: Test case 31 ('abcd') matches expected mask 0000010000000000"); + end else begin + $display("FAIL: Test case 31 ('abcd') expected 0000010000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 32: "the end" + start = 1; #10 start = 0; + char_in = 8'h74; #10; + char_in = 8'h68; #10; + char_in = 8'h65; #10; + char_in = 8'h20; #10; + char_in = 8'h65; #10; + char_in = 8'h6e; #10; + char_in = 8'h64; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0001100000000000) begin + $display("PASS: Test case 32 ('the end') matches expected mask 0001100000000000"); + end else begin + $display("FAIL: Test case 32 ('the end') expected 0001100000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 33: "end" + start = 1; #10 start = 0; + char_in = 8'h65; #10; + char_in = 8'h6e; #10; + char_in = 8'h64; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b010110) begin - $display("PASS: Test case 15 ('abc') matches expected mask 010110"); + if (match_bus === 16'b0000100000000000) begin + $display("PASS: Test case 33 ('end') matches expected mask 0000100000000000"); end else begin - $display("FAIL: Test case 15 ('abc') expected 010110, got %b", match_bus); + $display("FAIL: Test case 33 ('end') expected 0000100000000000, got %b", match_bus); end end_of_str = 0; #10; - // Test case 16: "abcd" + // Test case 34: "xay" start = 1; #10 start = 0; + char_in = 8'h78; #10; + char_in = 8'h61; #10; + char_in = 8'h79; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0010000000000000) begin + $display("PASS: Test case 34 ('xay') matches expected mask 0010000000000000"); + end else begin + $display("FAIL: Test case 34 ('xay') expected 0010000000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 35: "xayxby" + start = 1; #10 start = 0; + char_in = 8'h78; #10; char_in = 8'h61; #10; + char_in = 8'h79; #10; + char_in = 8'h78; #10; char_in = 8'h62; #10; + char_in = 8'h79; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0010000000000000) begin + $display("PASS: Test case 35 ('xayxby') matches expected mask 0010000000000000"); + end else begin + $display("FAIL: Test case 35 ('xayxby') expected 0010000000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 36: "xy" + start = 1; #10 start = 0; + char_in = 8'h78; #10; + char_in = 8'h79; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000000000000) begin + $display("PASS: Test case 36 ('xy') matches expected mask 0000000000000000"); + end else begin + $display("FAIL: Test case 36 ('xy') expected 0000000000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 37: "ac" + start = 1; #10 start = 0; + char_in = 8'h61; #10; char_in = 8'h63; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0100000000000000) begin + $display("PASS: Test case 37 ('ac') matches expected mask 0100000000000000"); + end else begin + $display("FAIL: Test case 37 ('ac') expected 0100000000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 38: "bd" + start = 1; #10 start = 0; + char_in = 8'h62; #10; char_in = 8'h64; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b100000) begin - $display("PASS: Test case 16 ('abcd') matches expected mask 100000"); + if (match_bus === 16'b0100000000000000) begin + $display("PASS: Test case 38 ('bd') matches expected mask 0100000000000000"); end else begin - $display("FAIL: Test case 16 ('abcd') expected 100000, got %b", match_bus); + $display("FAIL: Test case 38 ('bd') expected 0100000000000000, got %b", match_bus); end end_of_str = 0; #10; - // Test case 17: "abce" + // Test case 39: "bc" start = 1; #10 start = 0; - char_in = 8'h61; #10; char_in = 8'h62; #10; char_in = 8'h63; #10; - char_in = 8'h65; #10; end_of_str = 1; #10; // Match output is valid on the cycle immediately following end_of_str assertion - if (match_bus === 6'b100000) begin - $display("PASS: Test case 17 ('abce') matches expected mask 100000"); + if (match_bus === 16'b0100000000000000) begin + $display("PASS: Test case 39 ('bc') matches expected mask 0100000000000000"); + end else begin + $display("FAIL: Test case 39 ('bc') expected 0100000000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 40: "1234" + start = 1; #10 start = 0; + char_in = 8'h31; #10; + char_in = 8'h32; #10; + char_in = 8'h33; #10; + char_in = 8'h34; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b1000000000000000) begin + $display("PASS: Test case 40 ('1234') matches expected mask 1000000000000000"); + end else begin + $display("FAIL: Test case 40 ('1234') expected 1000000000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 41: "14" + start = 1; #10 start = 0; + char_in = 8'h31; #10; + char_in = 8'h34; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b1000000000000000) begin + $display("PASS: Test case 41 ('14') matches expected mask 1000000000000000"); + end else begin + $display("FAIL: Test case 41 ('14') expected 1000000000000000, got %b", match_bus); + end + end_of_str = 0; #10; + + // Test case 42: "124" + start = 1; #10 start = 0; + char_in = 8'h31; #10; + char_in = 8'h32; #10; + char_in = 8'h34; #10; + end_of_str = 1; #10; + // Match output is valid on the cycle immediately following end_of_str assertion + if (match_bus === 16'b0000000000000000) begin + $display("PASS: Test case 42 ('124') matches expected mask 0000000000000000"); end else begin - $display("FAIL: Test case 17 ('abce') expected 100000, got %b", match_bus); + $display("FAIL: Test case 42 ('124') expected 0000000000000000, got %b", match_bus); end end_of_str = 0; #10; diff --git a/output-eg/top.v b/output-eg/top.v @@ -7,31 +7,72 @@ module top ( input wire start, input wire end_of_str, input wire [7:0] char_in, - output wire [5:0] match_bus + output wire [15:0] match_bus, + output wire [15:0] active_bus ); nfa_0 inst_0 ( - .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[0]) + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[0]), .active(active_bus[0]) ); nfa_1 inst_1 ( - .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[1]) + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[1]), .active(active_bus[1]) ); nfa_2 inst_2 ( - .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[2]) + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[2]), .active(active_bus[2]) ); nfa_3 inst_3 ( - .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[3]) + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[3]), .active(active_bus[3]) ); nfa_4 inst_4 ( - .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[4]) + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[4]), .active(active_bus[4]) ); nfa_5 inst_5 ( - .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[5]) + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[5]), .active(active_bus[5]) + ); + + nfa_6 inst_6 ( + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[6]), .active(active_bus[6]) + ); + + nfa_7 inst_7 ( + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[7]), .active(active_bus[7]) + ); + + nfa_8 inst_8 ( + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[8]), .active(active_bus[8]) + ); + + nfa_9 inst_9 ( + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[9]), .active(active_bus[9]) + ); + + nfa_10 inst_10 ( + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[10]), .active(active_bus[10]) + ); + + nfa_11 inst_11 ( + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[11]), .active(active_bus[11]) + ); + + nfa_12 inst_12 ( + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[12]), .active(active_bus[12]) + ); + + nfa_13 inst_13 ( + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[13]), .active(active_bus[13]) + ); + + nfa_14 inst_14 ( + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[14]), .active(active_bus[14]) + ); + + nfa_15 inst_15 ( + .clk(clk), .en(en), .rst(rst), .start(start), .end_of_str(end_of_str), .char_in(char_in), .match(match_bus[15]), .active(active_bus[15]) ); endmodule