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// High-Speed communtcation to USB device controller's Slave FIFO
14//
15// For Slave FIFO's signaling and timing diagram, see CY7C68013-56PVC-Datasheet
16//
17// Version 1 comment:
18//
19// It is implemented on a state machine with outputs dependent on both input
20// and internal state. That's slow and is unable to operate at 48 MHz IFCLK.
21//
22// Version 2 improvements:
23//
24// 1. Removed asynchronous circuitry. That allows to operate at 48 MHz,
25//		removes synchronization to CPU issues.
26// 2. I/O registers placed most close to pins - into ILOGIC/OLOGIC components.
27//		That removes the nesessity to manually allocate areas in UCF file.
28//		IFCLK appears to arrive too late, added some phase backshift.
29// 3. One cycle delay when switching control outputs into Z-state on CS deassertion
30//		so controls for Slave FIFO (active low) always in a defined state.
31//
32//*****************************************************************************
33
34module hs_io_v2 #(
35	parameter USB_ENDPOINT_IN = 2, // from the point of view from the host
36	parameter USB_ENDPOINT_OUT = 6
37	)(
38	input IFCLK,
39	// Low CS puts all outputs into Z-state,
40	// exactly as examples/intraffic is doing
41	input CS,
42	input out_z_wait1,
43
44	// enable read/write
45	// Deasserted EN doesn't perform read/write,
46	// keeps signals for Slave FIFO in proper state.
47	input EN,
48
49	// Attention: attempt to send data to FPGA not aligned to
50	// 2-byte word would result in a junk in upper byte
51	inout [15:0] FIFO_DATA,
52	output FIFOADR0,
53	output FIFOADR1,
54	// Following signals are active low.
55	output SLOE, // Slave output enable
56	output SLRD,
57	output SLWR,
58	output PKTEND,
59	// FLAGA/B/C are fixed (independent from FIFOADR)
60	input FLAGA, // PROG_FULL
61	input FLAGB, // FULL
62	input FLAGC, // EMPTY
63
64	// write into some internal FIFO
65	output [15:0] dout,
66	output wr_en,
67	input almost_full,
68
69	// read from some internal FIFO
70	input [15:0] din,
71	output rd_en,
72	input empty,
73
74	// status information
75	output [7:0] io_timeout, // in ~1us intervals @30MHz IFCLK
76	output reg io_fsm_error = 0, // CS or EN deasserted while active I/O
77	output reg sfifo_not_empty = 0,
78	output reg io_err_write = 0
79	);
80
81	reg rw_direction = 0; // 1: FPGA writes
82
83	always @(posedge IFCLK)
84		if (CS & EN)
85			sfifo_not_empty <= FLAGC_R;
86
87	// Timeout
88	localparam TIMEOUT_MSB = 12;
89	reg [TIMEOUT_MSB:0] timeout = {TIMEOUT_MSB+1{1'b1}};
90	assign io_timeout = timeout[TIMEOUT_MSB : TIMEOUT_MSB-7];
91
92
93	// FIFOADR (Address for USB endpoint buffer)
94	// - at 48 MHz, sometimes takes 2 cycles to propagate
95	localparam USB_EP_OUT_B = (USB_ENDPOINT_OUT-2) >> 1;
96	localparam USB_EP_IN_B = (USB_ENDPOINT_IN-2) >> 1;
97	assign {FIFOADR1, FIFOADR0} =
98		out_z_wait1 ? 2'bz :
99		rw_direction ? USB_EP_IN_B[1:0] :
100		USB_EP_OUT_B[1:0];
101
102
103	// *************************
104	//
105	// High-Speed Input
106	//
107	// *************************
108
109	// FPGA's Input register (data-out from hs_io)
110	(* IOB="true" *) reg [15:0] input_r;
111	assign dout = input_r;
112	always @(posedge IFCLK)
113		input_r <= FIFO_DATA;
114
115	(* IOB="true" *) reg FLAGC_R = 0;
116	always @(posedge IFCLK)
117		FLAGC_R <= FLAGC;
118
119	(* IOB="true" *) reg SLOE_R = 1;
120	assign SLOE = out_z_wait1 ? 1'bz : SLOE_R;
121
122	(* IOB="true" *) reg SLRD_R = 1;
123	assign SLRD = out_z_wait1 ? 1'bz : SLRD_R;
124
125	// input_r_ok indicates there was read last cycle (SLRD was active)
126	reg input_r_ok = 0;
127	always @(posedge IFCLK)
128		input_r_ok <= ~SLRD_R;
129	assign wr_en = input_r_ok & FLAGC_R;
130
131
132	// *************************
133	//
134	// High-Speed Output
135	//
136	// *************************
137
138	// FLAGA(active low) is configured to be active when 0 bytes in buffer
139	(* IOB="true" *) reg FLAGA_R = 1;
140	always @(posedge IFCLK)
141		FLAGA_R <= FLAGA;
142
143	(* IOB="true" *) reg FLAGB_R = 0;
144	always @(posedge IFCLK)
145		FLAGB_R <= FLAGB;
146
147	(* IOB="true" *) reg SLWR_R = 1;
148	assign SLWR = out_z_wait1 ? 1'bz : SLWR_R;
149
150	// FPGA's output register.
151	// valid data must be present on output 9.2 ns before write
152	(* IOB="true" *) reg [15:0] output_r = 0;
153	// Tristate-enable FF inside OLOGIC component
154	(* IOB="true" *) reg out_z = 1;
155	assign FIFO_DATA = out_z ? 16'bz : output_r;
156	always @(posedge IFCLK)
157		out_z <= ~(CS & EN & rw_direction);
158
159	// Flag indicates valid data in output register.
160	// Could be better if output FIFO had almost_empty flag.
161	reg output_r_valid = 0;
162	assign rd_en = (~SLWR_R | io_state == IO_STATE_WR_SETUP1 & ~output_r_valid);
163
164	(* IOB="true" *) reg PKTEND_R = 1;
165	assign PKTEND = out_z_wait1 ? 1'bz : PKTEND_R;
166
167
168	// It works as follows:
169	// 1. reads as long as possible;
170	// 2. writes up to USB_PKT_SIZE.
171	localparam USB_PKT_SIZE = 256; // in 16-bit words
172	reg [8:0] word_counter = 0;
173
174	// Finally deal with PKTEND issue.
175	// - when output FIFO is in mode_limit, there's no problem:
176	// FIFO already has all the data, so it outputs every cycle
177	// until EMPTY.
178	// - when mode_limit is off, the data might arrive from FPGA's output FIFO
179	// in small pieces such as 2-8 bytes or so, with intervals like 2-4 cycles.
180	// That might result in partial reads by the host and overall performance degradation.
181	//
182	localparam PKTEND_WR_TIMEOUT = 5;
183	reg [2:0] wr_timeout = 0;
184
185
186	//localparam IO_STATE_RESET = 1;
187	localparam IO_STATE_READ_SETUP0 = 2;
188	localparam IO_STATE_READ_SETUP1 = 3;
189	localparam IO_STATE_READ_SETUP2 = 4;
190	localparam IO_STATE_READ = 6;
191	localparam IO_STATE_WR_SETUP0 = 7;
192	localparam IO_STATE_WR_SETUP1 = 8;
193	localparam IO_STATE_WR_SETUP2 = 9;
194	localparam IO_STATE_WR = 11;
195	localparam IO_STATE_DISABLED = 13;
196	localparam IO_STATE_WR_WAIT = 14;
197	localparam IO_STATE_PKT_COMMIT = 15;
198
199	(* FSM_EXTRACT="YES" *)
200	reg [4:0] io_state = IO_STATE_DISABLED;
201
202	always @(posedge IFCLK)
203	begin
204		if ( ! (&timeout[TIMEOUT_MSB : TIMEOUT_MSB-7])
205					& io_state != IO_STATE_READ & io_state != IO_STATE_WR)
206			timeout <= timeout + 1'b1;
207
208		// Disabled: EN is off, outputs in proper state
209		if (io_state == IO_STATE_DISABLED) begin
210			if (CS & EN)
211				io_state <= IO_STATE_READ_SETUP0;
212		end
213
214		else if (~CS | ~EN) begin
215			// Expecting EZ-USB to disable hs_io before selecting other fpga
216			if (!io_timeout | (~CS & EN))
217				io_fsm_error <= 1;
218
219			SLOE_R <= 1;
220			SLRD_R <= 1;
221			SLWR_R <= 1;
222			output_r_valid <= 0;
223			PKTEND_R <= 1;
224			rw_direction <= 0;
225			io_state <= IO_STATE_DISABLED;
226		end
227
228		else // CS & EN
229		(* FULL_CASE, PARALLEL_CASE *) case (io_state)
230
231		IO_STATE_READ_SETUP0: begin
232			if (almost_full | ~FLAGC_R)
233				io_state <= IO_STATE_WR_SETUP0;
234			else begin
235				io_state <= IO_STATE_READ_SETUP1;
236			end
237		end
238
239		IO_STATE_READ_SETUP1: begin
240			io_state <= IO_STATE_READ_SETUP2;
241		end
242
243		IO_STATE_READ_SETUP2: begin
244			// must assert 18.7 ns before read
245			SLOE_R <= 0;
246			SLRD_R <= 0;
247			io_state <= IO_STATE_READ;
248		end
249
250		IO_STATE_READ: begin
251			if (!almost_full & FLAGC_R) begin
252				timeout <= 0;
253			end
254			else begin
255				SLOE_R <= 1;
256				SLRD_R <= 1;
257				io_state <= IO_STATE_WR_SETUP0;
258			end
259		end
260
261		IO_STATE_WR_SETUP0: begin
262			if ((empty & ~output_r_valid) | FLAGA_R)
263				io_state <= IO_STATE_READ_SETUP0;
264			// go on transmit
265			else begin
266				rw_direction <= 1;
267				word_counter <= 0;
268				io_state <= IO_STATE_WR_SETUP1;
269			end
270		end
271
272		IO_STATE_WR_SETUP1: begin
273			if (~output_r_valid) begin
274				output_r <= din;
275				output_r_valid <= 1;
276			end
277			io_state <= IO_STATE_WR_SETUP2;
278		end
279
280		IO_STATE_WR_SETUP2: begin
281			// must assert 18.1 ns before write
282			SLWR_R <= 0;
283			io_state <= IO_STATE_WR;
284		end
285
286		IO_STATE_WR: begin
287			output_r <= din;
288			timeout <= 0;
289			wr_timeout <= 0;
290			word_counter <= word_counter + 1'b1;
291			if (empty)
292				output_r_valid <= 0;
293
294			if (word_counter == USB_PKT_SIZE - 1) begin
295				SLWR_R <= 1;
296				rw_direction <= 0;
297				io_state <= IO_STATE_READ_SETUP0;
298			end
299			else if (empty) begin
300				SLWR_R <= 1;
301				io_state <= IO_STATE_WR_WAIT;
302			end
303
304			if (~FLAGB_R)
305				io_err_write <= 1;
306		end
307
308		IO_STATE_WR_WAIT: begin
309			wr_timeout <= wr_timeout + 1'b1;
310
311			if (wr_timeout == PKTEND_WR_TIMEOUT) begin
312				PKTEND_R <= 0;
313				io_state <= IO_STATE_PKT_COMMIT;
314			end
315			else if (!empty)
316				io_state <= IO_STATE_WR_SETUP1;
317		end
318
319		IO_STATE_PKT_COMMIT: begin
320			PKTEND_R <= 1;
321			rw_direction <= 0;
322			io_state <= IO_STATE_READ_SETUP0;
323		end
324
325		endcase
326		// CS & EN
327
328	end // IFCLK
329
330
331endmodule
332
333