xiiregexbuilder
FPGA-Accelerated Regular Expression Matching Engineprocessor/regex_cpu.v (4243B)
1`timescale 1ns / 1ps
2
3module regex_cpu #(
4 parameter NUM_REGEX = 16
5) (
6 input wire clk,
7 input wire rst,
8 input wire start,
9 input wire end_of_str,
10 input wire [7:0] char_in,
11 input wire char_valid,
12
13 input wire prog_en,
14 input wire [ 7:0] prog_addr,
15 input wire [31:0] prog_data,
16
17 output wire ready,
18 output reg [NUM_REGEX-1:0] match_bus
19);
20
21 // --- Instruction Memory (BRAM Inferred) ---
22 reg [31:0] imem[0:255];
23 initial $readmemh("processor/build/imem.hex", imem);
24
25 always @(posedge clk) begin
26 if (prog_en) imem[prog_addr] <= prog_data;
27 end
28
29 // --- State Machine ---
30 localparam STATE_IDLE = 3'd0;
31 localparam STATE_START_INIT = 3'd1;
32 localparam STATE_CHAR_MATCH = 3'd2;
33 localparam STATE_EPSILON_RECURSE = 3'd3;
34 localparam STATE_END_OF_STR = 3'd4;
35
36 reg [ 2:0] state = STATE_IDLE;
37 reg [255:0] active_candidates;
38 reg [ 5:0] recurse_count;
39 reg [ 7:0] pc_cnt;
40 reg [255:0] next_set_buffer;
41 reg [ 7:0] char_reg;
42 reg recurse_changed;
43
44 assign ready = (state == STATE_IDLE);
45
46 // Single-port instruction fetch
47 wire [31:0] current_instr = imem[pc_cnt];
48 wire [ 7:0] p_char = current_instr[31:24];
49 wire [ 7:0] p_next1 = current_instr[23:16];
50 wire [ 7:0] p_next2 = current_instr[15:8];
51 wire [ 3:0] p_mid = current_instr[7:4];
52 wire p_term = current_instr[3];
53 wire p_any = current_instr[0];
54
55 always @(posedge clk) begin
56 if (rst) begin
57 state <= STATE_IDLE;
58 active_candidates <= 0;
59 match_bus <= 0;
60 recurse_count <= 0;
61 char_reg <= 0;
62 pc_cnt <= 0;
63 next_set_buffer <= 0;
64 end else begin
65 case (state)
66 STATE_IDLE: begin
67 if (start) begin
68 state <= STATE_START_INIT;
69 match_bus <= 0;
70 end else if (char_valid) begin
71 char_reg <= char_in;
72 pc_cnt <= 0;
73 next_set_buffer <= 0;
74 state <= STATE_CHAR_MATCH;
75 end else if (end_of_str) begin
76 pc_cnt <= 0;
77 state <= STATE_END_OF_STR;
78 end
79 end
80
81 STATE_START_INIT: begin
82 active_candidates <= 256'd1; // Start at Address 0 (the split chain)
83 recurse_count <= 0;
84 pc_cnt <= 0;
85 recurse_changed <= 0;
86 state <= STATE_EPSILON_RECURSE;
87 end
88
89 STATE_CHAR_MATCH: begin
90 if (active_candidates[pc_cnt]) begin
91 if (p_any || (p_char != 0 && p_char == char_reg)) begin
92 if (p_next1 != 0) next_set_buffer[p_next1] <= 1'b1;
93 if (p_next2 != 0) next_set_buffer[p_next2] <= 1'b1;
94 end
95 end
96
97 if (pc_cnt == 8'd255) begin
98 active_candidates <= next_set_buffer;
99 recurse_count <= 0;
100 pc_cnt <= 0;
101 recurse_changed <= 1; // Force at least one pass of epsilon recurse
102 state <= STATE_EPSILON_RECURSE;
103 end else begin
104 pc_cnt <= pc_cnt + 1;
105 end
106 end
107
108 STATE_EPSILON_RECURSE: begin
109 // One pass over all nodes to expand epsilon transitions
110 if (active_candidates[pc_cnt] && p_char == 0 && !p_any && !p_term) begin
111 active_candidates[pc_cnt] <= 1'b0; // Node consumed
112 if (p_next1 != 0) active_candidates[p_next1] <= 1'b1;
113 if (p_next2 != 0) active_candidates[p_next2] <= 1'b1;
114 recurse_changed <= 1;
115 end
116
117 if (pc_cnt == 8'd255) begin
118 if (recurse_count == 6'd63 || !recurse_changed) begin
119 state <= STATE_IDLE;
120 end else begin
121 recurse_count <= recurse_count + 1;
122 pc_cnt <= 0;
123 recurse_changed <= 0;
124 end
125 end else begin
126 pc_cnt <= pc_cnt + 1;
127 end
128 end
129
130 STATE_END_OF_STR: begin
131 if (active_candidates[pc_cnt] && p_term) begin
132 match_bus[p_mid] <= 1'b1;
133 end
134
135 if (pc_cnt == 8'd255) begin
136 state <= STATE_IDLE;
137 end else begin
138 pc_cnt <= pc_cnt + 1;
139 end
140 end
141
142 default: state <= STATE_IDLE;
143 endcase
144 end
145 end
146
147endmodule