1`timescale 1ns / 1ps
2/*
3 * This software is Copyright (c) 2018 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// Unit output packet format:
13// - header (1 word)
14// - IDs (64 bits)
15// - MD5 hash (128 bits)
16//
17// Total: 16+8 = 24 bytes
18//
19module arbiter_rx #(
20	parameter N_UNITS = -1,
21	parameter UNIT_OUTPUT_WIDTH = -1,
22	parameter PKT_NUM_WORDS = `RESULT_LEN/2 + 4
23	)(
24	input CLK,
25	input mode_cmp,
26	// Units
27	input [UNIT_OUTPUT_WIDTH * N_UNITS -1 :0] unit_dout,
28	output reg [N_UNITS-1:0] unit_rd_en = 0,
29	input [N_UNITS-1:0] unit_empty,
30	// Iteraction with arbiter_tx
31	input [31:0] num_processed_tx,
32	input [15:0] pkt_id_tx,
33	input pkt_tx_done,
34	output reg pkt_rx_done = 0,
35	output reg recv_item = 0, // asserts for 1 for every RX item
36	// Comparator
37	output reg [31:0] cmp_data,
38	output reg cmp_start = 0,
39	input cmp_found, cmp_finished,
40	input [`HASH_NUM_MSB:0] cmp_hash_num,
41	// Output
42	output reg [`OUTPKT_TYPE_MSB:0] outpkt_type,
43	output [15:0] dout,
44	input [`MSB(PKT_NUM_WORDS-1):0] rd_addr,
45	output reg [15:0] pkt_id,
46	output reg [31:0] num_processed = 0,
47	output reg [`HASH_NUM_MSB:0] hash_num,
48	input rd_en,
49	output reg empty = 1,
50
51	output reg [1:0] err = 0,
52	output reg [15:0] debug = 0
53	);
54
55	reg [`MSB(N_UNITS-1):0] unit_num = 0;
56	reg [UNIT_OUTPUT_WIDTH-1 :0] din = 0;
57	reg unit_empty_r = 1;
58	always @(posedge CLK) begin
59		din <= unit_dout [unit_num * UNIT_OUTPUT_WIDTH +:UNIT_OUTPUT_WIDTH];
60		unit_empty_r <= unit_empty [unit_num];
61	end
62
63	(* RAM_STYLE="DISTRIBUTED" *)
64	reg [15:0] output_r [0:PKT_NUM_WORDS-1];
65	assign dout = output_r [rd_addr];
66
67	reg rd_tmp_wr_en = 0;
68	reg [`MSB(PKT_NUM_WORDS-1):0] rd_tmp_wr_addr = 0;
69	always @(posedge CLK)
70		if (rd_tmp_wr_en)
71			output_r [rd_tmp_wr_addr] <= rd_tmp;
72
73
74	reg [2:0] rd_count = 0;
75	reg [15:0] rd_tmp = 0;
76	reg [`MSB(PKT_NUM_WORDS-1):0] result_word_count = 0;
77
78	reg [31:0] delay_shr = 0;
79
80	localparam STATE_IDLE = 0,
81				STATE_WAIT = 1,
82				STATE_WAIT2 = 2,
83				STATE_READ = 3,
84				STATE_RX_HEADER = 4,
85				STATE_RX_DATA = 5,
86				STATE_RX_END = 6,
87				STATE_CMP = 7,
88				STATE_OUTPKT_RESULT = 8,
89				STATE_PKT_ACCOUNT = 9,
90				STATE_PKT_ACCOUNT2 = 10,
91				STATE_PKT_ACCOUNT3 = 11,
92				STATE_OUTPKT_PROCESSING_DONE = 12;
93
94	(* FSM_EXTRACT="true" *)
95	reg [3:0] state = STATE_IDLE;
96
97	always @(posedge CLK) begin
98		if (rd_tmp_wr_en)
99			rd_tmp_wr_en <= 0;
100
101		if (cmp_start)
102			cmp_start <= 0;
103
104		if (pkt_rx_done)
105			pkt_rx_done <= 0;
106
107		if (recv_item)
108			recv_item <= 0;
109
110		if (state == STATE_IDLE | delay_shr[31])
111			delay_shr <= { delay_shr[30:0], state == STATE_IDLE };
112
113		case (state)
114		STATE_IDLE: if (delay_shr[31])
115			state <= STATE_WAIT;
116
117		STATE_WAIT:
118			if (~unit_empty_r)// [unit_num])
119				state <= STATE_READ;
120			else begin
121				unit_num <= unit_num == N_UNITS-1
122					? {`MSB(N_UNITS-1)+1{1'b0}} : unit_num + 1'b1;
123				state <= STATE_WAIT2;
124			end
125
126		STATE_WAIT2:
127			state <= STATE_WAIT;
128
129		STATE_READ: begin
130			recv_item <= 1;
131			unit_rd_en [unit_num] <= 1;
132			state <= STATE_RX_HEADER;
133		end
134
135		STATE_RX_HEADER: begin
136			unit_rd_en <= 0;
137			result_word_count <= 0;
138			if (din != 0) begin
139				if (din != {UNIT_OUTPUT_WIDTH{1'b1}}) begin
140					err[0] <= 1;
141					debug [unit_num] <= 1;
142				end
143				else
144					state <= STATE_RX_DATA;
145			end
146		end
147
148		// Collect PKT_NUM_WORDS words X 16 bit in output_r
149		STATE_RX_DATA: begin
150			rd_tmp [rd_count * UNIT_OUTPUT_WIDTH +:UNIT_OUTPUT_WIDTH]
151				<= din;
152			rd_count <= rd_count + 1'b1;
153			if (rd_count == (16 / UNIT_OUTPUT_WIDTH) -1) begin
154				rd_tmp_wr_en <= 1;
155				rd_tmp_wr_addr <= result_word_count;
156				result_word_count <= result_word_count + 1'b1;
157				if (result_word_count == PKT_NUM_WORDS-1)
158					state <= STATE_RX_END;
159			end
160
161			// 2nd 16-bit word: pkt_id
162			if (result_word_count == 2 & rd_count == 0)
163				pkt_id <= rd_tmp;
164
165			// externalize comparator data, start comparison
166			// before all the data received from a computing unit
167			if (result_word_count == 5 & rd_count == 0)
168				cmp_data[15:0] <= rd_tmp;
169			if (result_word_count == 6 & rd_count == 0) begin
170				cmp_data[31:16] <= rd_tmp;
171				cmp_start <= 1;
172			end
173		end
174
175		STATE_RX_END: begin
176			outpkt_type <= `OUTPKT_TYPE_RESULT;
177			if (din != 0) begin
178				err[1] <= 1;
179				debug [unit_num] <= 1;
180			end
181			else if (mode_cmp)
182				state <= STATE_CMP;
183			else begin
184				empty <= 0;
185				state <= STATE_OUTPKT_RESULT;
186			end
187		end
188
189		STATE_CMP: begin
190			if (cmp_found) begin
191				outpkt_type <= `OUTPKT_TYPE_CMP_RESULT;
192				hash_num <= cmp_hash_num;
193				empty <= 0;
194				state <= STATE_OUTPKT_RESULT;
195			end
196			else if (cmp_finished)
197				state <= STATE_PKT_ACCOUNT;
198		end
199
200		// output PKT_RESULT or PKT_CMP_RESULT
201		STATE_OUTPKT_RESULT: if (rd_en) begin
202			empty <= 1;
203			if (mode_cmp)
204				state <= STATE_PKT_ACCOUNT;
205			else
206				state <= STATE_WAIT;
207		end
208
209		STATE_PKT_ACCOUNT: begin
210			num_processed <= num_processed + 1'b1;
211			if (pkt_tx_done)
212				state <= STATE_PKT_ACCOUNT2;
213			else
214				state <= STATE_WAIT;
215		end
216
217		STATE_PKT_ACCOUNT2:
218			if (num_processed_tx == num_processed)
219				state <= STATE_PKT_ACCOUNT3;
220			else
221				state <= STATE_WAIT;
222
223		STATE_PKT_ACCOUNT3: begin
224			outpkt_type <= `OUTPKT_TYPE_PACKET_DONE;
225			pkt_id <= pkt_id_tx;
226			empty <= 0;
227			pkt_rx_done <= 1;
228			state <= STATE_OUTPKT_PROCESSING_DONE;
229		end
230
231		// output PKT_PROCESSING_DONE
232		STATE_OUTPKT_PROCESSING_DONE: if (rd_en) begin
233			empty <= 1;
234			num_processed <= 0;
235			state <= STATE_WAIT;
236		end
237		endcase
238	end
239
240
241endmodule
242