1`timescale 1ns / 1ps 2/* 3 * This software is Copyright (c) 2016 Denis Burykin 4 * [denis_burykin yahoo com], [denis-burykin2014 yandex ru] 5 * and it is hereby released to the general public under the following terms: 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted. 8 * 9 */ 10 11// ******************************************************************** 12// 13// template_list is going to replace word_list. 14// 15// * Designed for usage with word_gen_v2 16// 17// * Accepts both PKT_TYPE_WORD_LIST and PKT_TYPE_TEMPLATE_LIST 18// 19// * If word length is WORD_MAX_LEN, then it isn't followed by '\0'; 20// shorter words are '\0' terminated. 21// 22// * In PKT_TYPE_TEMPLATE_LIST, each word is followed by 23// RANGE_INFO records: RANGES_MAX records 1 byte each. 24// If some RANGE_INFO record is zero, then it was the last range_info 25// for the template key. 26// 27// * Last word is followed by a dummy word with word_list_end asserted 28// 29// ******************************************************************** 30 31module template_list #( 32 parameter CHAR_BITS = -1, // valid values: 7 8 33 parameter WORD_MAX_LEN = -1, 34 parameter RANGES_MAX = -1, 35 parameter RANGE_INFO_MSB = 1 + `MSB(WORD_MAX_LEN-1) 36 )( 37 input wr_clk, 38 input [7:0] din, 39 input wr_en, 40 output full, 41 input inpkt_end, 42 input is_template_list, 43 44 input rd_clk, 45 output [WORD_MAX_LEN * CHAR_BITS - 1 :0] dout, 46 output [RANGES_MAX * (RANGE_INFO_MSB+1) - 1 :0] range_info, 47 (* USE_DSP48="true" *) 48 output [15:0] word_id, 49 output word_list_end, 50 input rd_en, 51 output empty, 52 53 output reg err_template = 0, err_word_list_count = 0 54 ); 55 56 reg full_r = 0; 57 assign full = full_r; 58 59 reg [WORD_MAX_LEN * CHAR_BITS - 1 :0] dout_r = 0; 60 reg [RANGES_MAX * (RANGE_INFO_MSB+1) - 1 :0] range_info_r = 0; 61 reg [15:0] word_id_r = 0; 62 reg word_list_end_r = 0; 63 64 reg [`MSB(WORD_MAX_LEN-1):0] char_count = 0; 65 reg [`MSB(RANGES_MAX-1):0] range_info_count = 0; 66 67 68 localparam [1:0] STATE_WR_WORD = 0, 69 STATE_WR_RANGE_INFO = 1, 70 STATE_RD = 2, 71 STATE_RD_LIST_END = 3; 72 73 (* FSM_EXTRACT="true" *) 74 reg [1:0] state = STATE_WR_WORD; 75 76 always @(posedge wr_clk) begin 77 case (state) 78 STATE_WR_WORD: if (wr_en) begin 79 if (din == 0) begin 80 // word ends; word of zero length - OK, permitted 81 if (~is_template_list) 82 full_r <= 1; 83 state <= is_template_list ? STATE_WR_RANGE_INFO : STATE_RD; 84 end 85 else begin 86 // next char is going 87 dout_r[(char_count + 1'b1)*CHAR_BITS-1 -:CHAR_BITS] <= din[CHAR_BITS-1:0]; 88 89 if (char_count == WORD_MAX_LEN - 1) begin 90 // word is at max.length - word ends 91 if (~is_template_list) 92 full_r <= 1; 93 state <= is_template_list ? STATE_WR_RANGE_INFO : STATE_RD; 94 end 95 else 96 char_count <= char_count + 1'b1; 97 end 98 99 if (inpkt_end) begin 100 word_list_end_r <= 1; 101 if (is_template_list || (din && char_count != WORD_MAX_LEN - 1) ) 102 // inexpected pkt_end 103 err_template <= 1; 104 end 105 end 106 107 STATE_WR_RANGE_INFO: if (wr_en) begin 108 if (din == 0) begin 109 // range_info ends 110 full_r <= 1; 111 state <= STATE_RD; 112 end 113 else begin 114 // next item of range_info going 115 range_info_r[(range_info_count + 1'b1)*(RANGE_INFO_MSB+1)-1 -:RANGE_INFO_MSB+1] 116 <= { din[7], din[RANGE_INFO_MSB-1:0] }; 117 //if (WORD_MAX_LEN < 64) 118 if (din[6:RANGE_INFO_MSB] != 0) 119 // unexpected content in range_info 120 err_template <= 1; 121 122 if (range_info_count == RANGES_MAX - 1) begin 123 full_r <= 1; 124 state <= STATE_RD; 125 end 126 else 127 range_info_count <= range_info_count + 1'b1; 128 end 129 130 if (inpkt_end) begin 131 word_list_end_r <= 1; 132 if ( din && range_info_count != RANGES_MAX - 1) 133 // inexpected pkt_end 134 err_template <= 1; 135 end 136 end 137 138 STATE_RD: if (rd_en_internal) begin 139 dout_r <= 0; 140 range_info_r <= 0; 141 char_count <= 0; 142 range_info_count <= 0; 143 144 word_list_end_r <= 0; 145 if (word_list_end_r) begin 146 word_id_r <= 0; 147 state <= STATE_RD_LIST_END; 148 end 149 else begin 150 full_r <= 0; 151 word_id_r <= word_id_r + 1'b1; 152 state <= STATE_WR_WORD; 153 end 154 155 if (&word_id_r) 156 // word_id_r overflows 157 err_word_list_count <= 1; 158 end 159 160 // Write dummy word after the end of the list, with word_list_end set 161 STATE_RD_LIST_END: if (rd_en_internal) begin 162 full_r <= 0; 163 state <= STATE_WR_WORD; 164 end 165 166 endcase 167 end 168 169 assign rd_en_internal = ~output_reg_full 170 & (state == STATE_RD || state == STATE_RD_LIST_END); 171 172 cdc_reg #( 173 .WIDTH(WORD_MAX_LEN*CHAR_BITS + RANGES_MAX*(RANGE_INFO_MSB+1) + 16 + 1) 174 ) output_reg ( 175 .wr_clk(wr_clk), 176 .din({ dout_r, range_info_r, word_id_r, state == STATE_RD_LIST_END }), 177 .wr_en(rd_en_internal), .full(output_reg_full), 178 179 .rd_clk(rd_clk), 180 .dout({ dout, range_info, word_id, word_list_end }), 181 .rd_en(rd_en), .empty(empty) 182 ); 183 184endmodule 185