1096 lines
33 KiB
Verilog
1096 lines
33 KiB
Verilog
/////////////////////////////////////////////////////////////////////
|
|
//// ////
|
|
//// Protocol Engine ////
|
|
//// Performs automatic protocol functions ////
|
|
//// ////
|
|
//// Author: Rudolf Usselmann ////
|
|
//// rudi@asics.ws ////
|
|
//// ////
|
|
//// ////
|
|
//// Downloaded from: http://www.opencores.org/cores/usb/ ////
|
|
//// ////
|
|
/////////////////////////////////////////////////////////////////////
|
|
//// ////
|
|
//// Copyright (C) 2000-2003 Rudolf Usselmann ////
|
|
//// www.asics.ws ////
|
|
//// rudi@asics.ws ////
|
|
//// ////
|
|
//// This source file may be used and distributed without ////
|
|
//// restriction provided that this copyright statement is not ////
|
|
//// removed from the file and that any derivative work contains ////
|
|
//// the original copyright notice and the associated disclaimer.////
|
|
//// ////
|
|
//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
|
|
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
|
|
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
|
|
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
|
|
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ////
|
|
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ////
|
|
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ////
|
|
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ////
|
|
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ////
|
|
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ////
|
|
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ////
|
|
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ////
|
|
//// POSSIBILITY OF SUCH DAMAGE. ////
|
|
//// ////
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
// CVS Log
|
|
//
|
|
// $Id: usbf_pe.v,v 1.8 2003/10/17 02:36:57 rudi Exp $
|
|
//
|
|
// $Date: 2003/10/17 02:36:57 $
|
|
// $Revision: 1.8 $
|
|
// $Author: rudi $
|
|
// $Locker: $
|
|
// $State: Exp $
|
|
//
|
|
// Change History:
|
|
// $Log: usbf_pe.v,v $
|
|
// Revision 1.8 2003/10/17 02:36:57 rudi
|
|
// - Disabling bit stuffing and NRZI encoding during speed negotiation
|
|
// - Now the core can send zero size packets
|
|
// - Fixed register addresses for some of the higher endpoints
|
|
// (conversion between decimal/hex was wrong)
|
|
// - The core now does properly evaluate the function address to
|
|
// determine if the packet was intended for it.
|
|
// - Various other minor bugs and typos
|
|
//
|
|
// Revision 1.7 2001/11/04 12:22:45 rudi
|
|
//
|
|
// - Fixed previous fix (brocke something else ...)
|
|
// - Majore Synthesis cleanup
|
|
//
|
|
// Revision 1.6 2001/11/03 03:26:22 rudi
|
|
//
|
|
// - Fixed several interrupt and error condition reporting bugs
|
|
//
|
|
// Revision 1.5 2001/09/24 01:15:28 rudi
|
|
//
|
|
// Changed reset to be active high async.
|
|
//
|
|
// Revision 1.4 2001/09/23 08:39:33 rudi
|
|
//
|
|
// Renamed DEBUG and VERBOSE_DEBUG to USBF_DEBUG and USBF_VERBOSE_DEBUG ...
|
|
//
|
|
// Revision 1.3 2001/09/13 13:14:02 rudi
|
|
//
|
|
// Fixed a problem that would sometimes prevent the core to come out of
|
|
// reset and immediately be operational ...
|
|
//
|
|
// Revision 1.2 2001/08/10 08:48:33 rudi
|
|
//
|
|
// - Changed IO names to be more clear.
|
|
// - Uniquifyed define names to be core specific.
|
|
//
|
|
// Revision 1.1 2001/08/03 05:30:09 rudi
|
|
//
|
|
//
|
|
// 1) Reorganized directory structure
|
|
//
|
|
// Revision 1.2 2001/03/31 13:00:51 rudi
|
|
//
|
|
// - Added Core configuration
|
|
// - Added handling of OUT packets less than MAX_PL_SZ in DMA mode
|
|
// - Modified WISHBONE interface and sync logic
|
|
// - Moved SSRAM outside the core (added interface)
|
|
// - Many small bug fixes ...
|
|
//
|
|
// Revision 1.0 2001/03/07 09:17:12 rudi
|
|
//
|
|
//
|
|
// Changed all revisions to revision 1.0. This is because OpenCores CVS
|
|
// interface could not handle the original '0.1' revision ....
|
|
//
|
|
// Revision 0.2 2001/03/07 09:08:13 rudi
|
|
//
|
|
// Added USB control signaling (Line Status) block. Fixed some minor
|
|
// typos, added resume bit and signal.
|
|
//
|
|
// Revision 0.1.0.1 2001/02/28 08:11:07 rudi
|
|
// Initial Release
|
|
//
|
|
//
|
|
|
|
`include "usbf_defines.v"
|
|
|
|
module usbf_pe( clk, rst,
|
|
|
|
// UTMI Interfaces
|
|
tx_valid, rx_active,
|
|
|
|
// PID Information
|
|
pid_OUT, pid_IN, pid_SOF, pid_SETUP,
|
|
pid_DATA0, pid_DATA1, pid_DATA2, pid_MDATA,
|
|
pid_ACK, pid_NACK, pid_STALL, pid_NYET,
|
|
pid_PRE, pid_ERR, pid_SPLIT, pid_PING,
|
|
|
|
// Speed Mode
|
|
mode_hs,
|
|
|
|
// Token Information
|
|
token_valid, crc5_err,
|
|
|
|
// Receive Data Output
|
|
rx_data_valid, rx_data_done, crc16_err,
|
|
|
|
// Packet Assembler Interface
|
|
send_token, token_pid_sel,
|
|
data_pid_sel, send_zero_length,
|
|
|
|
// IDMA Interface
|
|
rx_dma_en, tx_dma_en,
|
|
abort, idma_done,
|
|
adr, size, buf_size,
|
|
sizu_c, dma_en,
|
|
|
|
// Register File Interface
|
|
fsel, idin,
|
|
dma_in_buf_sz1, dma_out_buf_avail,
|
|
ep_sel, match, nse_err,
|
|
buf0_rl, buf0_set, buf1_set,
|
|
uc_bsel_set, uc_dpd_set,
|
|
|
|
int_buf1_set, int_buf0_set, int_upid_set,
|
|
int_crc16_set, int_to_set, int_seqerr_set,
|
|
out_to_small,
|
|
|
|
csr, buf0, buf1
|
|
|
|
);
|
|
|
|
parameter SSRAM_HADR = 14;
|
|
|
|
input clk, rst;
|
|
input tx_valid, rx_active;
|
|
|
|
// Packet Disassembler Interface
|
|
// Decoded PIDs (used when token_valid is asserted)
|
|
input pid_OUT, pid_IN, pid_SOF, pid_SETUP;
|
|
input pid_DATA0, pid_DATA1, pid_DATA2, pid_MDATA;
|
|
input pid_ACK, pid_NACK, pid_STALL, pid_NYET;
|
|
input pid_PRE, pid_ERR, pid_SPLIT, pid_PING;
|
|
|
|
input mode_hs;
|
|
input token_valid; // Token is valid
|
|
input crc5_err; // Token crc5 error
|
|
|
|
input rx_data_valid; // Data on rx_data_st is valid
|
|
input rx_data_done; // Indicates end of a transfer
|
|
input crc16_err; // Data packet CRC 16 error
|
|
|
|
// Packet Assembler Interface
|
|
output send_token;
|
|
output [1:0] token_pid_sel;
|
|
output [1:0] data_pid_sel;
|
|
output send_zero_length;
|
|
|
|
// IDMA Interface
|
|
output rx_dma_en; // Allows the data to be stored
|
|
output tx_dma_en; // Allows for data to be retrieved
|
|
output abort; // Abort Transfer (time_out, crc_err or rx_error)
|
|
input idma_done; // DMA is done indicator
|
|
output [SSRAM_HADR + 2:0] adr; // Byte Address
|
|
output [13:0] size; // Size in bytes
|
|
output [13:0] buf_size; // Actual buffer size
|
|
input [10:0] sizu_c; // Up and Down counting size registers, used to update
|
|
output dma_en; // USB external DMA mode enabled
|
|
|
|
// Register File interface
|
|
input fsel; // This function is selected
|
|
output [31:0] idin; // Data Output
|
|
input [3:0] ep_sel; // Endpoint Number Input
|
|
input match; // Endpoint Matched
|
|
output nse_err; // no such endpoint error
|
|
input dma_in_buf_sz1, dma_out_buf_avail;
|
|
|
|
output buf0_rl; // Reload Buf 0 with original values
|
|
output buf0_set; // Write to buf 0
|
|
output buf1_set; // Write to buf 1
|
|
output uc_bsel_set; // Write to the uc_bsel field
|
|
output uc_dpd_set; // Write to the uc_dpd field
|
|
output int_buf1_set; // Set buf1 full/empty interrupt
|
|
output int_buf0_set; // Set buf0 full/empty interrupt
|
|
output int_upid_set; // Set unsupported PID interrupt
|
|
output int_crc16_set; // Set CRC16 error interrupt
|
|
output int_to_set; // Set time out interrupt
|
|
output int_seqerr_set; // Set PID sequence error interrupt
|
|
output out_to_small; // OUT packet was to small for DMA operation
|
|
|
|
input [31:0] csr; // Internal CSR Output
|
|
input [31:0] buf0; // Internal Buf 0 Output
|
|
input [31:0] buf1; // Internal Buf 1 Output
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Local Wires and Registers
|
|
//
|
|
|
|
// tx token decoding
|
|
parameter ACK = 0,
|
|
NACK = 1,
|
|
STALL = 2,
|
|
NYET = 3;
|
|
|
|
// State decoding
|
|
parameter [9:0] // synopsys enum state
|
|
IDLE = 10'b000000_0001,
|
|
TOKEN = 10'b000000_0010,
|
|
IN = 10'b000000_0100,
|
|
IN2 = 10'b000000_1000,
|
|
OUT = 10'b000001_0000,
|
|
OUT2A = 10'b000010_0000,
|
|
OUT2B = 10'b000100_0000,
|
|
UPDATEW = 10'b001000_0000,
|
|
UPDATE = 10'b010000_0000,
|
|
UPDATE2 = 10'b100000_0000;
|
|
|
|
reg [1:0] token_pid_sel;
|
|
reg [1:0] token_pid_sel_d;
|
|
reg send_token;
|
|
reg send_token_d;
|
|
reg rx_dma_en, tx_dma_en;
|
|
reg int_seqerr_set_d;
|
|
reg int_seqerr_set;
|
|
reg int_upid_set;
|
|
|
|
reg match_r;
|
|
|
|
// Endpoint Decoding
|
|
wire IN_ep, OUT_ep, CTRL_ep; // Endpoint Types
|
|
wire txfr_iso, txfr_bulk; // Transfer Types
|
|
wire ep_disabled, ep_stall; // Endpoint forced conditions
|
|
|
|
wire lrg_ok, sml_ok; // Packet size acceptance
|
|
wire [1:0] tr_fr; // Number of transfers per micro-frame
|
|
wire [10:0] max_pl_sz; // Max payload size
|
|
|
|
wire [1:0] uc_dpd, uc_bsel;
|
|
|
|
// Buffer checks
|
|
wire buf_sel;
|
|
reg buf0_na, buf1_na;
|
|
wire [SSRAM_HADR + 2:0] buf0_adr, buf1_adr;
|
|
wire [13:0] buf0_sz, buf1_sz;
|
|
reg [9:0] /* synopsys enum state */ state, next_state;
|
|
// synopsys state_vector state
|
|
|
|
// PID next and current decoders
|
|
reg [1:0] next_dpid;
|
|
reg [1:0] this_dpid;
|
|
reg pid_seq_err;
|
|
wire [1:0] tr_fr_d;
|
|
|
|
wire [13:0] size_next;
|
|
wire buf_smaller;
|
|
|
|
reg [SSRAM_HADR + 2:0] adr;
|
|
reg [13:0] new_size;
|
|
reg [13:0] new_sizeb;
|
|
reg buffer_full;
|
|
reg buffer_empty;
|
|
wire [SSRAM_HADR + 2:0] new_adr;
|
|
reg buffer_done;
|
|
|
|
reg no_bufs0, no_bufs1;
|
|
wire no_bufs;
|
|
|
|
// After sending Data in response to an IN token from host, the
|
|
// host must reply with an ack. The host has XXXnS to reply.
|
|
// "rx_ack_to" indicates when this time has expired.
|
|
// rx_ack_to_clr, clears the timer
|
|
reg rx_ack_to_clr;
|
|
reg rx_ack_to_clr_d;
|
|
reg rx_ack_to;
|
|
reg [7:0] rx_ack_to_cnt;
|
|
|
|
// After sending a OUT token the host must send a data packet.
|
|
// The host has XX nS to send the packet. "tx_data_to" indicates
|
|
// when this time has expired.
|
|
// tx_data_to_clr, clears the timer
|
|
wire tx_data_to_clr;
|
|
reg tx_data_to;
|
|
reg [7:0] tx_data_to_cnt;
|
|
|
|
wire [7:0] rx_ack_to_val, tx_data_to_val;
|
|
|
|
reg int_set_en;
|
|
|
|
wire [1:0] next_bsel;
|
|
reg buf_set_d;
|
|
reg uc_stat_set_d;
|
|
reg [31:0] idin;
|
|
reg buf0_set, buf1_set;
|
|
reg uc_bsel_set;
|
|
reg uc_dpd_set;
|
|
reg buf0_rl_d;
|
|
reg buf0_rl;
|
|
wire no_buf0_dma;
|
|
reg buf0_st_max;
|
|
reg buf1_st_max;
|
|
|
|
reg [SSRAM_HADR + 2:0] adr_r;
|
|
reg [13:0] size_next_r;
|
|
|
|
reg in_token;
|
|
reg out_token;
|
|
reg setup_token;
|
|
|
|
wire in_op, out_op; // Indicate a IN or OUT operation
|
|
reg to_small; // Indicates a "to small packer" error
|
|
reg to_large; // Indicates a "to large packer" error
|
|
|
|
reg buffer_overflow;
|
|
reg [1:0] allow_pid;
|
|
|
|
reg nse_err;
|
|
reg out_to_small, out_to_small_r;
|
|
reg abort;
|
|
|
|
reg buf0_not_aloc, buf1_not_aloc;
|
|
|
|
reg send_zero_length;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Misc Logic
|
|
//
|
|
|
|
// Endpoint/CSR Decoding
|
|
assign IN_ep = csr[27:26]==2'b01;
|
|
assign OUT_ep = csr[27:26]==2'b10;
|
|
assign CTRL_ep = csr[27:26]==2'b00;
|
|
|
|
assign txfr_iso = csr[25:24]==2'b01;
|
|
assign txfr_bulk = csr[25:24]==2'b10;
|
|
|
|
assign ep_disabled = csr[23:22]==2'b01;
|
|
assign ep_stall = csr[23:22]==2'b10;
|
|
|
|
assign lrg_ok = csr[17];
|
|
assign sml_ok = csr[16];
|
|
assign dma_en = csr[15] & !CTRL_ep;
|
|
|
|
assign tr_fr = csr[12:11];
|
|
assign max_pl_sz = csr[10:0];
|
|
|
|
assign uc_dpd = csr[29:28];
|
|
assign uc_bsel = csr[31:30];
|
|
|
|
// Buffer decoding and allocation checks
|
|
assign buf0_adr = buf0[SSRAM_HADR + 2:0];
|
|
assign buf1_adr = buf1[SSRAM_HADR + 2:0];
|
|
assign buf0_sz = buf0[30:17];
|
|
assign buf1_sz = buf1[30:17];
|
|
|
|
// Buffers Not Available
|
|
always @(posedge clk)
|
|
buf0_na <= buf0[31] | ( &buf0_adr );
|
|
|
|
always @(posedge clk)
|
|
buf1_na <= buf1[31] | ( &buf1_adr );
|
|
|
|
// Buffer Not Allocated
|
|
always @(posedge clk)
|
|
buf0_not_aloc <= &buf0_adr;
|
|
|
|
always @(posedge clk)
|
|
buf1_not_aloc <= &buf1_adr;
|
|
|
|
always @(posedge clk)
|
|
match_r <= match;
|
|
|
|
// No Such Endpoint Indicator
|
|
always @(posedge clk)
|
|
nse_err <= token_valid & (pid_OUT | pid_IN | pid_SETUP) & !match;
|
|
|
|
always @(posedge clk)
|
|
send_token <= send_token_d;
|
|
|
|
always @(posedge clk)
|
|
token_pid_sel <= token_pid_sel_d;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Data Pid Sequencer
|
|
//
|
|
|
|
assign tr_fr_d = mode_hs ? tr_fr : 2'h0;
|
|
|
|
always @(posedge clk) // tr/mf:ep/type:tr/type:last dpd
|
|
casex({tr_fr_d,csr[27:26],csr[25:24],uc_dpd}) // synopsys full_case parallel_case
|
|
8'b0?_01_01_??: next_dpid <= 2'b00; // ISO txfr. IN, 1 tr/mf
|
|
|
|
8'b10_01_01_?0: next_dpid <= 2'b01; // ISO txfr. IN, 2 tr/mf
|
|
8'b10_01_01_?1: next_dpid <= 2'b00; // ISO txfr. IN, 2 tr/mf
|
|
|
|
8'b11_01_01_00: next_dpid <= 2'b01; // ISO txfr. IN, 3 tr/mf
|
|
8'b11_01_01_01: next_dpid <= 2'b10; // ISO txfr. IN, 3 tr/mf
|
|
8'b11_01_01_10: next_dpid <= 2'b00; // ISO txfr. IN, 3 tr/mf
|
|
|
|
8'b0?_10_01_??: next_dpid <= 2'b00; // ISO txfr. OUT, 1 tr/mf
|
|
|
|
8'b10_10_01_??: // ISO txfr. OUT, 2 tr/mf
|
|
begin // Resynchronize in case of PID error
|
|
case({pid_MDATA, pid_DATA1}) // synopsys full_case parallel_case
|
|
2'b10: next_dpid <= 2'b01;
|
|
2'b01: next_dpid <= 2'b00;
|
|
endcase
|
|
end
|
|
|
|
8'b11_10_01_00: // ISO txfr. OUT, 3 tr/mf
|
|
begin // Resynchronize in case of PID error
|
|
case({pid_MDATA, pid_DATA2}) // synopsys full_case parallel_case
|
|
2'b10: next_dpid <= 2'b01;
|
|
2'b01: next_dpid <= 2'b00;
|
|
endcase
|
|
end
|
|
8'b11_10_01_01: // ISO txfr. OUT, 3 tr/mf
|
|
begin // Resynchronize in case of PID error
|
|
case({pid_MDATA, pid_DATA2}) // synopsys full_case parallel_case
|
|
2'b10: next_dpid <= 2'b10;
|
|
2'b01: next_dpid <= 2'b00;
|
|
endcase
|
|
end
|
|
8'b11_10_01_10: // ISO txfr. OUT, 3 tr/mf
|
|
begin // Resynchronize in case of PID error
|
|
case({pid_MDATA, pid_DATA2}) // synopsys full_case parallel_case
|
|
2'b10: next_dpid <= 2'b01;
|
|
2'b01: next_dpid <= 2'b00;
|
|
endcase
|
|
end
|
|
|
|
8'b??_01_00_?0, // IN/OUT endpoint only
|
|
8'b??_10_00_?0: next_dpid <= 2'b01; // INT transfers
|
|
|
|
8'b??_01_00_?1, // IN/OUT endpoint only
|
|
8'b??_10_00_?1: next_dpid <= 2'b00; // INT transfers
|
|
|
|
8'b??_01_10_?0, // IN/OUT endpoint only
|
|
8'b??_10_10_?0: next_dpid <= 2'b01; // BULK transfers
|
|
|
|
8'b??_01_10_?1, // IN/OUT endpoint only
|
|
8'b??_10_10_?1: next_dpid <= 2'b00; // BULK transfers
|
|
|
|
8'b??_00_??_??: // CTRL Endpoint
|
|
casex({setup_token, in_op, out_op, uc_dpd}) // synopsys full_case parallel_case
|
|
5'b1_??_??: next_dpid <= 2'b11; // SETUP operation
|
|
5'b0_10_0?: next_dpid <= 2'b11; // IN operation
|
|
5'b0_10_1?: next_dpid <= 2'b01; // IN operation
|
|
5'b0_01_?0: next_dpid <= 2'b11; // OUT operation
|
|
5'b0_01_?1: next_dpid <= 2'b10; // OUT operation
|
|
endcase
|
|
|
|
endcase
|
|
|
|
// Current PID decoder
|
|
|
|
// Allow any PID for ISO. transfers when mode full speed or tr_fr is zero
|
|
always @(pid_DATA0 or pid_DATA1 or pid_DATA2 or pid_MDATA)
|
|
case({pid_DATA0, pid_DATA1, pid_DATA2, pid_MDATA} ) // synopsys full_case parallel_case
|
|
4'b1000: allow_pid = 2'b00;
|
|
4'b0100: allow_pid = 2'b01;
|
|
4'b0010: allow_pid = 2'b10;
|
|
4'b0001: allow_pid = 2'b11;
|
|
endcase
|
|
|
|
always @(posedge clk) // tf/mf:ep/type:tr/type:last dpd
|
|
casex({tr_fr_d,csr[27:26],csr[25:24],uc_dpd}) // synopsys full_case parallel_case
|
|
8'b0?_01_01_??: this_dpid <= 2'b00; // ISO txfr. IN, 1 tr/mf
|
|
|
|
8'b10_01_01_?0: this_dpid <= 2'b01; // ISO txfr. IN, 2 tr/mf
|
|
8'b10_01_01_?1: this_dpid <= 2'b00; // ISO txfr. IN, 2 tr/mf
|
|
|
|
8'b11_01_01_00: this_dpid <= 2'b10; // ISO txfr. IN, 3 tr/mf
|
|
8'b11_01_01_01: this_dpid <= 2'b01; // ISO txfr. IN, 3 tr/mf
|
|
8'b11_01_01_10: this_dpid <= 2'b00; // ISO txfr. IN, 3 tr/mf
|
|
|
|
8'b00_10_01_??: this_dpid <= allow_pid; // ISO txfr. OUT, 0 tr/mf
|
|
8'b01_10_01_??: this_dpid <= 2'b00; // ISO txfr. OUT, 1 tr/mf
|
|
|
|
8'b10_10_01_?0: this_dpid <= 2'b11; // ISO txfr. OUT, 2 tr/mf
|
|
8'b10_10_01_?1: this_dpid <= 2'b01; // ISO txfr. OUT, 2 tr/mf
|
|
|
|
8'b11_10_01_00: this_dpid <= 2'b11; // ISO txfr. OUT, 3 tr/mf
|
|
8'b11_10_01_01: this_dpid <= 2'b11; // ISO txfr. OUT, 3 tr/mf
|
|
8'b11_10_01_10: this_dpid <= 2'b10; // ISO txfr. OUT, 3 tr/mf
|
|
|
|
8'b??_01_00_?0, // IN/OUT endpoint only
|
|
8'b??_10_00_?0: this_dpid <= 2'b00; // INT transfers
|
|
8'b??_01_00_?1, // IN/OUT endpoint only
|
|
8'b??_10_00_?1: this_dpid <= 2'b01; // INT transfers
|
|
|
|
8'b??_01_10_?0, // IN/OUT endpoint only
|
|
8'b??_10_10_?0: this_dpid <= 2'b00; // BULK transfers
|
|
8'b??_01_10_?1, // IN/OUT endpoint only
|
|
8'b??_10_10_?1: this_dpid <= 2'b01; // BULK transfers
|
|
|
|
8'b??_00_??_??: // CTRL Endpoint
|
|
casex({setup_token,in_op, out_op, uc_dpd}) // synopsys full_case parallel_case
|
|
5'b1_??_??: this_dpid <= 2'b00; // SETUP operation
|
|
5'b0_10_0?: this_dpid <= 2'b00; // IN operation
|
|
5'b0_10_1?: this_dpid <= 2'b01; // IN operation
|
|
5'b0_01_?0: this_dpid <= 2'b00; // OUT operation
|
|
5'b0_01_?1: this_dpid <= 2'b01; // OUT operation
|
|
endcase
|
|
endcase
|
|
|
|
// Assign PID for outgoing packets
|
|
assign data_pid_sel = this_dpid;
|
|
|
|
// Verify PID for incoming data packets
|
|
always @(posedge clk)
|
|
pid_seq_err <= !( (this_dpid==2'b00 & pid_DATA0) |
|
|
(this_dpid==2'b01 & pid_DATA1) |
|
|
(this_dpid==2'b10 & pid_DATA2) |
|
|
(this_dpid==2'b11 & pid_MDATA) );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// IDMA Setup & src/dst buffer select
|
|
//
|
|
|
|
// For Control endpoints things are different:
|
|
// buffer0 is used for OUT (incoming) data packets
|
|
// buffer1 is used for IN (outgoing) data packets
|
|
|
|
// Keep track of last token for control endpoints
|
|
`ifdef USBF_ASYNC_RESET
|
|
always @(posedge clk or negedge rst)
|
|
`else
|
|
always @(posedge clk)
|
|
`endif
|
|
if(!rst) in_token <= 1'b0;
|
|
else
|
|
if(pid_IN) in_token <= 1'b1;
|
|
else
|
|
if(pid_OUT || pid_SETUP) in_token <= 1'b0;
|
|
|
|
`ifdef USBF_ASYNC_RESET
|
|
always @(posedge clk or negedge rst)
|
|
`else
|
|
always @(posedge clk)
|
|
`endif
|
|
if(!rst) out_token <= 1'b0;
|
|
else
|
|
if(pid_OUT || pid_SETUP) out_token <= 1'b1;
|
|
else
|
|
if(pid_IN) out_token <= 1'b0;
|
|
|
|
`ifdef USBF_ASYNC_RESET
|
|
always @(posedge clk or negedge rst)
|
|
`else
|
|
always @(posedge clk)
|
|
`endif
|
|
if(!rst) setup_token <= 1'b0;
|
|
else
|
|
if(pid_SETUP) setup_token <= 1'b1;
|
|
else
|
|
if(pid_OUT || pid_IN) setup_token <= 1'b0;
|
|
|
|
// Indicates if we are performing an IN operation
|
|
assign in_op = IN_ep | (CTRL_ep & in_token);
|
|
|
|
// Indicates if we are performing an OUT operation
|
|
assign out_op = OUT_ep | (CTRL_ep & out_token);
|
|
|
|
// Select buffer: buf_sel==0 buffer0; buf_sel==1 buffer1
|
|
assign buf_sel = dma_en ? 1'b0 : CTRL_ep ? in_token : ((uc_bsel[0] | buf0_na) & !buf1_na);
|
|
|
|
// Select Address for IDMA
|
|
always @(posedge clk)
|
|
adr <= buf_sel ? buf1_adr : buf0_adr;
|
|
|
|
// Size from Buffer
|
|
assign buf_size = buf_sel ? buf1_sz : buf0_sz;
|
|
|
|
// Determine which is smaller: buffer or max_pl_sz
|
|
assign buf_smaller = buf_size < {3'h0, max_pl_sz};
|
|
|
|
// Determine actual size for this transfer (for IDMA) IN endpoint only
|
|
// (OUT endpoint uses sizeu_c from IDMA)
|
|
assign size_next = buf_smaller ? buf_size : max_pl_sz;
|
|
assign size = size_next; // "size" is an output for IDMA
|
|
|
|
// Buffer Full (only for OUT endpoints)
|
|
// Indicates that there is not enough space in the buffer for one
|
|
// more max_pl_sz packet
|
|
always @(posedge clk)
|
|
buffer_full <= new_size < {3'h0, max_pl_sz};
|
|
|
|
// Buffer Empty (only for IN endpoints)
|
|
// Indicates that there are zero bytes left in the buffer
|
|
always @(posedge clk)
|
|
buffer_empty <= (new_size == 14'h0);
|
|
|
|
// Joint buffer full/empty flag This is the "USED" flag
|
|
always @(posedge clk)
|
|
buffer_done <= in_op ? buffer_empty : buffer_full;
|
|
|
|
// No More buffer space at all (For high speed out - issue NYET)
|
|
assign no_buf0_dma = dma_en &
|
|
((IN_ep & !dma_in_buf_sz1) | (OUT_ep & !dma_out_buf_avail));
|
|
|
|
always @(posedge clk)
|
|
buf0_st_max <= (buf0_sz < {3'h0, max_pl_sz});
|
|
|
|
always @(posedge clk)
|
|
buf1_st_max <= (buf1_sz < {3'h0, max_pl_sz});
|
|
|
|
always @(posedge clk)
|
|
no_bufs0 <= buf0_na | no_buf0_dma |
|
|
(buf_sel ? buf0_st_max : (buffer_full & !dma_en));
|
|
|
|
always @(posedge clk)
|
|
no_bufs1 <= buf1_na | (buf_sel ? buffer_full : buf1_st_max);
|
|
|
|
assign no_bufs = no_bufs0 & no_bufs1;
|
|
|
|
// New Size (to be written to register file)
|
|
always @(posedge clk)
|
|
new_sizeb <= (out_op && dma_en) ? max_pl_sz : (in_op ? size_next : sizu_c);
|
|
|
|
always @(posedge clk)
|
|
new_size <= buf_size - new_sizeb;
|
|
|
|
|
|
// New Buffer Address (to be written to register file)
|
|
always @(posedge clk)
|
|
adr_r <= adr;
|
|
|
|
always @(posedge clk)
|
|
size_next_r <= size_next;
|
|
|
|
assign new_adr = adr_r[SSRAM_HADR + 2:0] +
|
|
((out_op && dma_en) ? {{SSRAM_HADR + 2-10{1'b0}}, max_pl_sz[10:0]} :
|
|
(in_op ? {{SSRAM_HADR + 2-13{1'b0}}, size_next_r[13:0] } :
|
|
{ {SSRAM_HADR + 2-10{1'b0}}, sizu_c[10:0]}));
|
|
|
|
// Buffer Overflow
|
|
always @(posedge clk)
|
|
buffer_overflow <= ( {3'h0, sizu_c} > buf_size) & rx_data_valid;
|
|
|
|
|
|
// OUT packet smaller than MAX_PL_SZ in DMA operation
|
|
always @(posedge clk)
|
|
out_to_small_r <= uc_stat_set_d & out_op & dma_en & (sizu_c != max_pl_sz);
|
|
|
|
always @(posedge clk)
|
|
out_to_small <= out_to_small_r;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Determine if packet is to small or to large
|
|
// This is used to NACK and ignore packet for OUT endpoints
|
|
//
|
|
|
|
always @(posedge clk)
|
|
to_small <= !sml_ok & (sizu_c < max_pl_sz);
|
|
|
|
always @(posedge clk)
|
|
to_large <= !lrg_ok & (sizu_c > max_pl_sz);
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Register File Update Logic
|
|
//
|
|
|
|
assign next_bsel = dma_en ? 2'h0 : buffer_done ? uc_bsel + 2'h1 : uc_bsel; // FIX_ME
|
|
|
|
always @(posedge clk)
|
|
idin[31:17] <= out_to_small_r ? {4'h0,sizu_c} : {buffer_done,new_size};
|
|
|
|
always @(posedge clk)
|
|
idin[SSRAM_HADR + 2:4] <= out_to_small_r ? buf0_adr[SSRAM_HADR + 2:4] :
|
|
new_adr[SSRAM_HADR + 2:4];
|
|
|
|
always @(posedge clk)
|
|
if(buf_set_d) idin[3:0] <= new_adr[3:0];
|
|
else
|
|
if(out_to_small_r) idin[3:0] <= buf0_adr[3:0];
|
|
else idin[3:0] <= {next_dpid, next_bsel};
|
|
|
|
always @(posedge clk)
|
|
buf0_set <= !buf_sel & buf_set_d;
|
|
|
|
always @(posedge clk)
|
|
buf1_set <= buf_sel & buf_set_d;
|
|
|
|
always @(posedge clk)
|
|
uc_bsel_set <= uc_stat_set_d;
|
|
|
|
always @(posedge clk)
|
|
uc_dpd_set <= uc_stat_set_d;
|
|
|
|
always @(posedge clk)
|
|
buf0_rl <= buf0_rl_d;
|
|
|
|
// Abort signal
|
|
always @(posedge clk)
|
|
abort <= buffer_overflow | (match & (state != IDLE) ) | (match_r & to_large);
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// TIME OUT TIMERS
|
|
//
|
|
|
|
// After sending Data in response to an IN token from host, the
|
|
// host must reply with an ack. The host has 622nS in Full Speed
|
|
// mode and 400nS in High Speed mode to reply.
|
|
// "rx_ack_to" indicates when this time has expired.
|
|
// rx_ack_to_clr, clears the timer
|
|
|
|
always @(posedge clk)
|
|
rx_ack_to_clr <= tx_valid | rx_ack_to_clr_d;
|
|
|
|
always @(posedge clk)
|
|
if(rx_ack_to_clr) rx_ack_to_cnt <= 8'h0;
|
|
else rx_ack_to_cnt <= rx_ack_to_cnt + 8'h1;
|
|
|
|
always @(posedge clk)
|
|
rx_ack_to <= (rx_ack_to_cnt == rx_ack_to_val);
|
|
|
|
assign rx_ack_to_val = mode_hs ? `USBF_RX_ACK_TO_VAL_HS : `USBF_RX_ACK_TO_VAL_FS;
|
|
|
|
// After sending a OUT token the host must send a data packet.
|
|
// The host has 622nS in Full Speed mode and 400nS in High Speed
|
|
// mode to send the data packet.
|
|
// "tx_data_to" indicates when this time has expired.
|
|
// "tx_data_to_clr" clears the timer
|
|
|
|
assign tx_data_to_clr = rx_active;
|
|
|
|
always @(posedge clk)
|
|
if(tx_data_to_clr) tx_data_to_cnt <= 8'h0;
|
|
else tx_data_to_cnt <= tx_data_to_cnt + 8'h1;
|
|
|
|
always @(posedge clk)
|
|
tx_data_to <= (tx_data_to_cnt == tx_data_to_val);
|
|
|
|
assign tx_data_to_val = mode_hs ? `USBF_TX_DATA_TO_VAL_HS : `USBF_TX_DATA_TO_VAL_FS;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Interrupts
|
|
//
|
|
reg pid_OUT_r, pid_IN_r, pid_PING_r, pid_SETUP_r;
|
|
|
|
assign int_buf1_set = !buf_sel & buffer_done & int_set_en & !buf1_not_aloc;
|
|
assign int_buf0_set = buf_sel & buffer_done & int_set_en & !buf0_not_aloc;
|
|
|
|
always @(posedge clk)
|
|
pid_OUT_r <= pid_OUT;
|
|
|
|
always @(posedge clk)
|
|
pid_IN_r <= pid_IN;
|
|
|
|
always @(posedge clk)
|
|
pid_PING_r <= pid_PING;
|
|
|
|
always @(posedge clk)
|
|
pid_SETUP_r <= pid_SETUP;
|
|
|
|
always @(posedge clk)
|
|
int_upid_set <= match_r & !pid_SOF & (
|
|
( OUT_ep & !(pid_OUT_r | pid_PING_r)) |
|
|
( IN_ep & !pid_IN_r) |
|
|
(CTRL_ep & !(pid_IN_r | pid_OUT_r | pid_PING_r | pid_SETUP_r))
|
|
);
|
|
|
|
assign int_to_set = ((state == IN2) & rx_ack_to) | ((state == OUT) & tx_data_to);
|
|
|
|
assign int_crc16_set = rx_data_done & crc16_err;
|
|
|
|
always @(posedge clk)
|
|
int_seqerr_set <= int_seqerr_set_d;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Main Protocol State Machine
|
|
//
|
|
|
|
`ifdef USBF_ASYNC_RESET
|
|
always @(posedge clk or negedge rst)
|
|
`else
|
|
always @(posedge clk)
|
|
`endif
|
|
if(!rst) state <= IDLE;
|
|
else
|
|
if(match) state <= IDLE;
|
|
else state <= next_state;
|
|
|
|
always @(state or ep_stall or buf0_na or buf1_na or
|
|
pid_seq_err or idma_done or token_valid or pid_ACK or rx_data_done or
|
|
tx_data_to or crc16_err or ep_disabled or no_bufs or mode_hs
|
|
or dma_en or rx_ack_to or pid_PING or txfr_iso or to_small or to_large or
|
|
CTRL_ep or pid_IN or pid_OUT or IN_ep or OUT_ep or pid_SETUP or pid_SOF
|
|
or match_r or abort or buffer_done or no_buf0_dma or max_pl_sz)
|
|
begin
|
|
next_state = state;
|
|
token_pid_sel_d = ACK;
|
|
send_token_d = 1'b0;
|
|
rx_dma_en = 1'b0;
|
|
tx_dma_en = 1'b0;
|
|
buf_set_d = 1'b0;
|
|
uc_stat_set_d = 1'b0;
|
|
buf0_rl_d = 1'b0;
|
|
int_set_en = 1'b0;
|
|
rx_ack_to_clr_d = 1'b1;
|
|
int_seqerr_set_d = 1'b0;
|
|
send_zero_length = 1'b0;
|
|
|
|
case(state) // synopsys full_case parallel_case
|
|
IDLE:
|
|
begin
|
|
// synopsys translate_off
|
|
`ifdef USBF_VERBOSE_DEBUG
|
|
$display("PE: Entered state IDLE (%t)", $time);
|
|
`endif
|
|
`ifdef USBF_DEBUG
|
|
if(rst && match_r && !ep_disabled && !pid_SOF)
|
|
begin
|
|
if(match_r === 1'bx) $display("ERROR: IDLE: match_r is unknown. (%t)", $time);
|
|
if(ep_disabled === 1'bx)$display("ERROR: IDLE: ep_disabled is unknown. (%t)", $time);
|
|
if(pid_SOF === 1'bx) $display("ERROR: IDLE: pid_SOF is unknown. (%t)", $time);
|
|
if(ep_stall === 1'bx) $display("ERROR: IDLE: ep_stall is unknown. (%t)", $time);
|
|
if(buf0_na === 1'bx) $display("ERROR: IDLE: buf0_na is unknown. (%t)", $time);
|
|
if(buf1_na === 1'bx) $display("ERROR: IDLE: buf1_na is unknown. (%t)", $time);
|
|
if(no_buf0_dma === 1'bx)$display("ERROR: IDLE: no_buf0_dma is unknown. (%t)", $time);
|
|
if(CTRL_ep === 1'bx) $display("ERROR: IDLE: CTRL_ep is unknown. (%t)", $time);
|
|
if(pid_IN === 1'bx) $display("ERROR: IDLE: pid_IN is unknown. (%t)", $time);
|
|
if(pid_OUT === 1'bx) $display("ERROR: IDLE: pid_OUT is unknown. (%t)", $time);
|
|
if(pid_SETUP === 1'bx) $display("ERROR: IDLE: pid_SETUP is unknown. (%t)", $time);
|
|
if(pid_PING === 1'bx) $display("ERROR: IDLE: pid_PING is unknown. (%t)", $time);
|
|
if(mode_hs === 1'bx) $display("ERROR: IDLE: mode_hs is unknown. (%t)", $time);
|
|
if(IN_ep === 1'bx) $display("ERROR: IDLE: IN_ep is unknown. (%t)", $time);
|
|
if(OUT_ep === 1'bx) $display("ERROR: IDLE: OUT_ep is unknown. (%t)", $time);
|
|
end
|
|
`endif
|
|
// synopsys translate_on
|
|
|
|
if(match_r && !ep_disabled && !pid_SOF)
|
|
begin
|
|
if(ep_stall) // Halt Forced send STALL
|
|
begin
|
|
token_pid_sel_d = STALL;
|
|
send_token_d = 1'b1;
|
|
next_state = TOKEN;
|
|
end
|
|
else
|
|
if( (buf0_na && buf1_na) || no_buf0_dma ||
|
|
(CTRL_ep && pid_IN && buf1_na) ||
|
|
(CTRL_ep && pid_OUT && buf0_na)
|
|
)
|
|
begin // No buffers send NAK
|
|
token_pid_sel_d = NACK;
|
|
send_token_d = 1'b1;
|
|
next_state = TOKEN;
|
|
end
|
|
else
|
|
if(pid_PING && mode_hs)
|
|
begin
|
|
token_pid_sel_d = ACK;
|
|
send_token_d = 1'b1;
|
|
next_state = TOKEN;
|
|
end
|
|
else
|
|
if(IN_ep || (CTRL_ep && pid_IN))
|
|
begin
|
|
if(max_pl_sz == 11'h0) send_zero_length = 1'b1;
|
|
tx_dma_en = 1'b1;
|
|
next_state = IN;
|
|
end
|
|
else
|
|
if(OUT_ep || (CTRL_ep && (pid_OUT || pid_SETUP)))
|
|
begin
|
|
rx_dma_en = 1'b1;
|
|
next_state = OUT;
|
|
end
|
|
end
|
|
end
|
|
|
|
TOKEN:
|
|
begin
|
|
// synopsys translate_off
|
|
`ifdef USBF_VERBOSE_DEBUG
|
|
$display("PE: Entered state TOKEN (%t)", $time);
|
|
`endif
|
|
// synopsys translate_on
|
|
next_state = IDLE;
|
|
end
|
|
|
|
IN:
|
|
begin
|
|
// synopsys translate_off
|
|
`ifdef USBF_VERBOSE_DEBUG
|
|
$display("PE: Entered state IN (%t)", $time);
|
|
`endif
|
|
`ifdef USBF_DEBUG
|
|
if(idma_done === 1'bx) $display("ERROR: IN: idma_done is unknown. (%t)", $time);
|
|
if(txfr_iso === 1'bx) $display("ERROR: IN: txfr_iso is unknown. (%t)", $time);
|
|
`endif
|
|
// synopsys translate_on
|
|
rx_ack_to_clr_d = 1'b0;
|
|
if(idma_done)
|
|
begin
|
|
if(txfr_iso) next_state = UPDATE;
|
|
else next_state = IN2;
|
|
end
|
|
|
|
end
|
|
IN2:
|
|
begin
|
|
// synopsys translate_off
|
|
`ifdef USBF_VERBOSE_DEBUG
|
|
$display("PE: Entered state IN2 (%t)", $time);
|
|
`endif
|
|
`ifdef USBF_DEBUG
|
|
if(rx_ack_to === 1'bx) $display("ERROR: IN2: rx_ack_to is unknown. (%t)", $time);
|
|
if(token_valid === 1'bx)$display("ERROR: IN2: token_valid is unknown. (%t)", $time);
|
|
if(pid_ACK === 1'bx) $display("ERROR: IN2: pid_ACK is unknown. (%t)", $time);
|
|
`endif
|
|
// synopsys translate_on
|
|
rx_ack_to_clr_d = 1'b0;
|
|
// Wait for ACK from HOST or Timeout
|
|
if(rx_ack_to) next_state = IDLE;
|
|
else
|
|
if(token_valid && pid_ACK)
|
|
begin
|
|
next_state = UPDATE;
|
|
end
|
|
end
|
|
|
|
OUT:
|
|
begin
|
|
// synopsys translate_off
|
|
`ifdef USBF_VERBOSE_DEBUG
|
|
$display("PE: Entered state OUT (%t)", $time);
|
|
`endif
|
|
`ifdef USBF_DEBUG
|
|
if(tx_data_to === 1'bx) $display("ERROR: OUT: tx_data_to is unknown. (%t)", $time);
|
|
if(crc16_err === 1'bx) $display("ERROR: OUT: crc16_err is unknown. (%t)", $time);
|
|
if(abort === 1'bx) $display("ERROR: OUT: abort is unknown. (%t)", $time);
|
|
if(rx_data_done === 1'bx)$display("ERROR: OUT: rx_data_done is unknown. (%t)", $time);
|
|
if(txfr_iso === 1'bx) $display("ERROR: OUT: txfr_iso is unknown. (%t)", $time);
|
|
if(pid_seq_err === 1'bx)$display("ERROR: OUT: rx_data_done is unknown. (%t)", $time);
|
|
`endif
|
|
// synopsys translate_on
|
|
if(tx_data_to || crc16_err || abort )
|
|
next_state = IDLE;
|
|
else
|
|
if(rx_data_done)
|
|
begin // Send Ack
|
|
if(txfr_iso)
|
|
begin
|
|
if(pid_seq_err) int_seqerr_set_d = 1'b1;
|
|
next_state = UPDATEW;
|
|
end
|
|
else next_state = OUT2A;
|
|
end
|
|
end
|
|
|
|
OUT2A:
|
|
begin // This is a delay State to NACK to small or to
|
|
// large packets. this state could be skipped
|
|
// synopsys translate_off
|
|
`ifdef USBF_VERBOSE_DEBUG
|
|
$display("PE: Entered state OUT2A (%t)", $time);
|
|
`endif
|
|
`ifdef USBF_DEBUG
|
|
if(abort === 1'bx) $display("ERROR: OUT2A: abort is unknown. (%t)", $time);
|
|
`endif
|
|
// synopsys translate_on
|
|
if(abort) next_state = IDLE;
|
|
else next_state = OUT2B;
|
|
end
|
|
OUT2B:
|
|
begin // Send ACK/NACK/NYET
|
|
// synopsys translate_off
|
|
`ifdef USBF_VERBOSE_DEBUG
|
|
$display("PE: Entered state OUT2B (%t)", $time);
|
|
`endif
|
|
`ifdef USBF_DEBUG
|
|
if(abort === 1'bx) $display("ERROR: OUT2B: abort is unknown. (%t)", $time);
|
|
if(to_small === 1'bx) $display("ERROR: OUT2B: to_small is unknown. (%t)", $time);
|
|
if(to_large === 1'bx) $display("ERROR: OUT2B: to_large is unknown. (%t)", $time);
|
|
if(pid_seq_err === 1'bx)$display("ERROR: OUT2B: rx_data_done is unknown. (%t)", $time);
|
|
if(mode_hs === 1'bx) $display("ERROR: OUT2B: mode_hs is unknown. (%t)", $time);
|
|
if(no_bufs === 1'bx) $display("ERROR: OUT2B: no_bufs is unknown. (%t)", $time);
|
|
`endif
|
|
// synopsys translate_on
|
|
if(abort) next_state = IDLE;
|
|
else
|
|
if(to_small || to_large)
|
|
begin
|
|
token_pid_sel_d = NACK;
|
|
next_state = IDLE;
|
|
end
|
|
else
|
|
if(pid_seq_err)
|
|
begin
|
|
token_pid_sel_d = ACK;
|
|
send_token_d = 1'b1;
|
|
next_state = IDLE;
|
|
end
|
|
else
|
|
begin
|
|
if(mode_hs && no_bufs) token_pid_sel_d = NYET;
|
|
else token_pid_sel_d = ACK;
|
|
send_token_d = 1'b1;
|
|
next_state = UPDATE;
|
|
end
|
|
end
|
|
|
|
UPDATEW:
|
|
begin
|
|
// synopsys translate_off
|
|
`ifdef USBF_VERBOSE_DEBUG
|
|
$display("PE: Entered state UPDATEW (%t)", $time);
|
|
`endif
|
|
// synopsys translate_on
|
|
next_state = UPDATE;
|
|
end
|
|
UPDATE:
|
|
begin
|
|
// synopsys translate_off
|
|
`ifdef USBF_VERBOSE_DEBUG
|
|
$display("PE: Entered state UPDATE (%t)", $time);
|
|
`endif
|
|
`ifdef USBF_DEBUG
|
|
if(buffer_done === 1'bx) $display("ERROR: UPDATE: buffer_done is unknown. (%t)", $time);
|
|
if(dma_en === 1'bx) $display("ERROR: UPDATE: dma_en is unknown. (%t)", $time);
|
|
`endif
|
|
// synopsys translate_on
|
|
// Interrupts
|
|
int_set_en = 1'b1;
|
|
// Buffer (used, size, adr) set or reload
|
|
if(buffer_done && dma_en)
|
|
begin
|
|
buf0_rl_d = 1'b1;
|
|
end
|
|
else
|
|
begin
|
|
buf_set_d = 1'b1;
|
|
end
|
|
next_state = UPDATE2;
|
|
end
|
|
UPDATE2: // Update Register File & state
|
|
begin
|
|
// synopsys translate_off
|
|
`ifdef USBF_VERBOSE_DEBUG
|
|
$display("PE: Entered state UPDATE2 (%t)", $time);
|
|
`endif
|
|
// synopsys translate_on
|
|
// pid sequence & buffer usage
|
|
uc_stat_set_d = 1'b1;
|
|
next_state = IDLE;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
endmodule
|
|
|