OpenCores
URL https://opencores.org/ocsvn/usb_device_core/usb_device_core/trunk

Subversion Repositories usb_device_core

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /usb_device_core
    from Rev 2 to Rev 3
    Reverse comparison

Rev 2 → Rev 3

/trunk/rtl/phy/usb_rx_phy.v
0,0 → 1,447
/////////////////////////////////////////////////////////////////////
//// ////
//// USB 1.1 PHY ////
//// RX & DPLL ////
//// ////
//// ////
//// Author: Rudolf Usselmann ////
//// rudi@asics.ws ////
//// ////
//// ////
//// Downloaded from: http://www.opencores.org/cores/usb_phy/ ////
//// ////
/////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2000-2002 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: usb_rx_phy.v,v 1.5 2004-10-19 09:29:07 rudi Exp $
//
// $Date: 2004-10-19 09:29:07 $
// $Revision: 1.5 $
// $Author: rudi $
// $Locker: $
// $State: Exp $
//
// Change History:
// $Log: not supported by cvs2svn $
// Revision 1.4 2003/12/02 04:56:00 rudi
// Fixed a bug reported by Karl C. Posch from Graz University of Technology. Thanks Karl !
//
// Revision 1.3 2003/10/19 18:07:45 rudi
// - Fixed Sync Error to be only checked/generated during the sync phase
//
// Revision 1.2 2003/10/19 17:40:13 rudi
// - Made core more robust against line noise
// - Added Error Checking and Reporting
// (See README.txt for more info)
//
// Revision 1.1.1.1 2002/09/16 14:27:01 rudi
// Created Directory Structure
//
//
//
//
//
//
//
//
 
module usb_rx_phy( clk, rst, fs_ce,
// Transciever Interface
rxd, rxdp, rxdn,
 
// UTMI Interface
RxValid_o, RxActive_o, RxError_o, DataIn_o,
RxEn_i, LineState);
 
input clk;
input rst;
output fs_ce;
input rxd, rxdp, rxdn;
output [7:0] DataIn_o;
output RxValid_o;
output RxActive_o;
output RxError_o;
input RxEn_i;
output [1:0] LineState;
 
///////////////////////////////////////////////////////////////////
//
// Local Wires and Registers
//
 
reg rxd_s0, rxd_s1, rxd_s;
reg rxdp_s0, rxdp_s1, rxdp_s, rxdp_s_r;
reg rxdn_s0, rxdn_s1, rxdn_s, rxdn_s_r;
reg synced_d;
wire k, j, se0;
reg rxd_r;
reg rx_en;
reg rx_active;
reg [2:0] bit_cnt;
reg rx_valid1, rx_valid;
reg shift_en;
reg sd_r;
reg sd_nrzi;
reg [7:0] hold_reg;
wire drop_bit; // Indicates a stuffed bit
reg [2:0] one_cnt;
 
reg [1:0] dpll_state, dpll_next_state;
reg fs_ce_d;
reg fs_ce;
wire change;
wire lock_en;
reg [2:0] fs_state, fs_next_state;
reg rx_valid_r;
reg sync_err_d, sync_err;
reg bit_stuff_err;
reg se0_r, byte_err;
reg se0_s;
 
///////////////////////////////////////////////////////////////////
//
// Misc Logic
//
 
assign RxActive_o = rx_active;
assign RxValid_o = rx_valid;
assign RxError_o = sync_err | bit_stuff_err | byte_err;
assign DataIn_o = hold_reg;
assign LineState = {rxdn_s1, rxdp_s1};
 
always @(posedge clk) rx_en <= RxEn_i;
always @(posedge clk) sync_err <= !rx_active & sync_err_d;
 
///////////////////////////////////////////////////////////////////
//
// Synchronize Inputs
//
 
// First synchronize to the local system clock to
// avoid metastability outside the sync block (*_s0).
// Then make sure we see the signal for at least two
// clock cycles stable to avoid glitches and noise
 
always @(posedge clk) rxd_s0 <= rxd;
always @(posedge clk) rxd_s1 <= rxd_s0;
always @(posedge clk) // Avoid detecting Line Glitches and noise
if(rxd_s0 && rxd_s1) rxd_s <= 1'b1;
else
if(!rxd_s0 && !rxd_s1) rxd_s <= 1'b0;
 
always @(posedge clk) rxdp_s0 <= rxdp;
always @(posedge clk) rxdp_s1 <= rxdp_s0;
always @(posedge clk) rxdp_s_r <= rxdp_s0 & rxdp_s1;
always @(posedge clk) rxdp_s <= (rxdp_s0 & rxdp_s1) | rxdp_s_r; // Avoid detecting Line Glitches and noise
 
always @(posedge clk) rxdn_s0 <= rxdn;
always @(posedge clk) rxdn_s1 <= rxdn_s0;
always @(posedge clk) rxdn_s_r <= rxdn_s0 & rxdn_s1;
always @(posedge clk) rxdn_s <= (rxdn_s0 & rxdn_s1) | rxdn_s_r; // Avoid detecting Line Glitches and noise
 
assign k = !rxdp_s & rxdn_s;
assign j = rxdp_s & !rxdn_s;
assign se0 = !rxdp_s & !rxdn_s;
 
always @(posedge clk) if(fs_ce) se0_s <= se0;
 
///////////////////////////////////////////////////////////////////
//
// DPLL
//
 
// This design uses a clock enable to do 12Mhz timing and not a
// real 12Mhz clock. Everything always runs at 48Mhz. We want to
// make sure however, that the clock enable is always exactly in
// the middle between two virtual 12Mhz rising edges.
// We monitor rxdp and rxdn for any changes and do the appropiate
// adjustments.
// In addition to the locking done in the dpll FSM, we adjust the
// final latch enable to compensate for various sync registers ...
 
// Allow lockinf only when we are receiving
assign lock_en = rx_en;
 
always @(posedge clk) rxd_r <= rxd_s;
 
// Edge detector
assign change = rxd_r != rxd_s;
 
// DPLL FSM
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) dpll_state <= 2'h1;
else dpll_state <= dpll_next_state;
 
always @(dpll_state or lock_en or change)
begin
fs_ce_d = 1'b0;
case(dpll_state) // synopsys full_case parallel_case
2'h0:
if(lock_en && change) dpll_next_state = 2'h0;
else dpll_next_state = 2'h1;
2'h1:begin
fs_ce_d = 1'b1;
if(lock_en && change) dpll_next_state = 2'h3;
else dpll_next_state = 2'h2;
end
2'h2:
if(lock_en && change) dpll_next_state = 2'h0;
else dpll_next_state = 2'h3;
2'h3:
if(lock_en && change) dpll_next_state = 2'h0;
else dpll_next_state = 2'h0;
endcase
end
 
// Compensate for sync registers at the input - allign full speed
// clock enable to be in the middle between two bit changes ...
reg fs_ce_r1, fs_ce_r2;
 
always @(posedge clk) fs_ce_r1 <= fs_ce_d;
always @(posedge clk) fs_ce_r2 <= fs_ce_r1;
always @(posedge clk) fs_ce <= fs_ce_r2;
 
 
///////////////////////////////////////////////////////////////////
//
// Find Sync Pattern FSM
//
 
parameter FS_IDLE = 3'h0,
K1 = 3'h1,
J1 = 3'h2,
K2 = 3'h3,
J2 = 3'h4,
K3 = 3'h5,
J3 = 3'h6,
K4 = 3'h7;
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) fs_state <= FS_IDLE;
else fs_state <= fs_next_state;
 
always @(fs_state or fs_ce or k or j or rx_en or rx_active or se0 or se0_s)
begin
synced_d = 1'b0;
sync_err_d = 1'b0;
fs_next_state = fs_state;
if(fs_ce && !rx_active && !se0 && !se0_s)
case(fs_state) // synopsys full_case parallel_case
FS_IDLE:
begin
if(k && rx_en) fs_next_state = K1;
end
K1:
begin
if(j && rx_en) fs_next_state = J1;
else
begin
sync_err_d = 1'b1;
fs_next_state = FS_IDLE;
end
end
J1:
begin
if(k && rx_en) fs_next_state = K2;
else
begin
sync_err_d = 1'b1;
fs_next_state = FS_IDLE;
end
end
K2:
begin
if(j && rx_en) fs_next_state = J2;
else
begin
sync_err_d = 1'b1;
fs_next_state = FS_IDLE;
end
end
J2:
begin
if(k && rx_en) fs_next_state = K3;
else
begin
sync_err_d = 1'b1;
fs_next_state = FS_IDLE;
end
end
K3:
begin
if(j && rx_en) fs_next_state = J3;
else
if(k && rx_en)
begin
fs_next_state = FS_IDLE; // Allow missing first K-J
synced_d = 1'b1;
end
else
begin
sync_err_d = 1'b1;
fs_next_state = FS_IDLE;
end
end
J3:
begin
if(k && rx_en) fs_next_state = K4;
else
begin
sync_err_d = 1'b1;
fs_next_state = FS_IDLE;
end
end
K4:
begin
if(k) synced_d = 1'b1;
fs_next_state = FS_IDLE;
end
endcase
end
 
///////////////////////////////////////////////////////////////////
//
// Generate RxActive
//
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) rx_active <= 1'b0;
else
if(synced_d && rx_en) rx_active <= 1'b1;
else
if(se0 && rx_valid_r) rx_active <= 1'b0;
 
always @(posedge clk)
if(rx_valid) rx_valid_r <= 1'b1;
else
if(fs_ce) rx_valid_r <= 1'b0;
 
///////////////////////////////////////////////////////////////////
//
// NRZI Decoder
//
 
always @(posedge clk)
if(fs_ce) sd_r <= rxd_s;
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) sd_nrzi <= 1'b0;
else
if(!rx_active) sd_nrzi <= 1'b1;
else
if(rx_active && fs_ce) sd_nrzi <= !(rxd_s ^ sd_r);
 
///////////////////////////////////////////////////////////////////
//
// Bit Stuff Detect
//
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) one_cnt <= 3'h0;
else
if(!shift_en) one_cnt <= 3'h0;
else
if(fs_ce)
begin
if(!sd_nrzi || drop_bit) one_cnt <= 3'h0;
else one_cnt <= one_cnt + 3'h1;
end
 
assign drop_bit = (one_cnt==3'h6);
 
always @(posedge clk) bit_stuff_err <= drop_bit & sd_nrzi & fs_ce & !se0 & rx_active; // Bit Stuff Error
 
///////////////////////////////////////////////////////////////////
//
// Serial => Parallel converter
//
 
always @(posedge clk)
if(fs_ce) shift_en <= synced_d | rx_active;
 
always @(posedge clk)
if(fs_ce && shift_en && !drop_bit)
hold_reg <= {sd_nrzi, hold_reg[7:1]};
 
///////////////////////////////////////////////////////////////////
//
// Generate RxValid
//
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) bit_cnt <= 3'b0;
else
if(!shift_en) bit_cnt <= 3'h0;
else
if(fs_ce && !drop_bit) bit_cnt <= bit_cnt + 3'h1;
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) rx_valid1 <= 1'b0;
else
if(fs_ce && !drop_bit && (bit_cnt==3'h7)) rx_valid1 <= 1'b1;
else
if(rx_valid1 && fs_ce && !drop_bit) rx_valid1 <= 1'b0;
 
always @(posedge clk) rx_valid <= !drop_bit & rx_valid1 & fs_ce;
 
always @(posedge clk) se0_r <= se0;
 
always @(posedge clk) byte_err <= se0 & !se0_r & (|bit_cnt[2:1]) & rx_active;
 
endmodule
 
/trunk/rtl/phy/usb_tx_phy.v
0,0 → 1,456
/////////////////////////////////////////////////////////////////////
//// ////
//// USB 1.1 PHY ////
//// TX ////
//// ////
//// ////
//// Author: Rudolf Usselmann ////
//// rudi@asics.ws ////
//// ////
//// ////
//// Downloaded from: http://www.opencores.org/cores/usb_phy/ ////
//// ////
/////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2000-2002 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: usb_tx_phy.v,v 1.4 2004-10-19 09:29:07 rudi Exp $
//
// $Date: 2004-10-19 09:29:07 $
// $Revision: 1.4 $
// $Author: rudi $
// $Locker: $
// $State: Exp $
//
// Change History:
// $Log: not supported by cvs2svn $
// Revision 1.3 2003/10/21 05:58:41 rudi
// usb_rst is no longer or'ed with the incomming reset internally.
// Now usb_rst is simply an output, the application can decide how
// to utilize it.
//
// Revision 1.2 2003/10/19 17:40:13 rudi
// - Made core more robust against line noise
// - Added Error Checking and Reporting
// (See README.txt for more info)
//
// Revision 1.1.1.1 2002/09/16 14:27:02 rudi
// Created Directory Structure
//
//
//
//
//
//
//
 
module usb_tx_phy(
clk, rst, fs_ce, phy_mode,
// Transciever Interface
txdp, txdn, txoe,
 
// UTMI Interface
DataOut_i, TxValid_i, TxReady_o
);
 
input clk;
input rst;
input fs_ce;
input phy_mode;
output txdp, txdn, txoe;
input [7:0] DataOut_i;
input TxValid_i;
output TxReady_o;
 
///////////////////////////////////////////////////////////////////
//
// Local Wires and Registers
//
 
parameter IDLE = 3'd0;
parameter SOP = 3'h1;
parameter DATA = 3'h2;
parameter EOP = 3'h3;
 
reg TxReady_o;
reg [2:0] state, next_state;
reg tx_ready_d;
reg ld_sop_d;
reg ld_data_d;
reg ld_eop_d;
reg tx_ip;
reg tx_ip_sync;
reg [2:0] bit_cnt;
reg [7:0] hold_reg;
reg [7:0] hold_reg_d;
 
reg [2:0] eop_cnt;
wire eop_done;
 
reg sd_raw_o;
wire hold;
reg data_done;
reg sft_done;
reg sft_done_r;
wire sft_done_e;
reg ld_data;
reg [2:0] one_cnt;
wire stuff;
reg sd_bs_o;
reg sd_nrzi_o;
reg txdp, txdn;
reg txoe_r1, txoe_r2;
reg txoe;
 
///////////////////////////////////////////////////////////////////
//
// Misc Logic
//
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) TxReady_o <= 1'b0;
else TxReady_o <= tx_ready_d & TxValid_i;
 
always @(posedge clk) ld_data <= ld_data_d;
 
///////////////////////////////////////////////////////////////////
//
// Transmit in progress indicator
//
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) tx_ip <= 1'b0;
else
if(ld_sop_d) tx_ip <= 1'b1;
else
if(eop_done) tx_ip <= 1'b0;
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) tx_ip_sync <= 1'b0;
else
if(fs_ce) tx_ip_sync <= tx_ip;
 
// data_done helps us to catch cases where TxValid drops due to
// packet end and then gets re-asserted as a new packet starts.
// We might not see this because we are still transmitting.
// data_done should solve those cases ...
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) data_done <= 1'b0;
else
if(TxValid_i && ! tx_ip) data_done <= 1'b1;
else
if(!TxValid_i) data_done <= 1'b0;
 
///////////////////////////////////////////////////////////////////
//
// Shift Register
//
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst)
begin
bit_cnt <= 3'h0;
end
else
if(!tx_ip_sync) bit_cnt <= 3'h0;
else
if(fs_ce && !hold)
begin
bit_cnt <= bit_cnt + 3'h1;
end
 
assign hold = stuff;
 
always @(posedge clk)
if(!tx_ip_sync)
begin
sd_raw_o <= 1'b0;
end
else
begin
case(bit_cnt) // synopsys full_case parallel_case
3'h0: sd_raw_o <= hold_reg_d[0];
3'h1: sd_raw_o <= hold_reg_d[1];
3'h2: sd_raw_o <= hold_reg_d[2];
3'h3: sd_raw_o <= hold_reg_d[3];
3'h4: sd_raw_o <= hold_reg_d[4];
3'h5: sd_raw_o <= hold_reg_d[5];
3'h6: sd_raw_o <= hold_reg_d[6];
3'h7: sd_raw_o <= hold_reg_d[7];
endcase
`ifdef CONF_DISPLAY_USB_TX
if (fs_ce)
case(bit_cnt) // synopsys full_case parallel_case
3'h0: $display("\nTx0=%01d", hold_reg_d[0]);
3'h1: $display("Tx1=%01d", hold_reg_d[1]);
3'h2: $display("Tx2=%01d", hold_reg_d[2]);
3'h3: $display("Tx3=%01d", hold_reg_d[3]);
3'h4: $display("Tx4=%01d", hold_reg_d[4]);
3'h5: $display("Tx5=%01d", hold_reg_d[5]);
3'h6: $display("Tx6=%01d", hold_reg_d[6]);
3'h7: $display("Tx7=%01d", hold_reg_d[7]);
endcase
`endif
end
 
always @(posedge clk)
sft_done <= !hold & (bit_cnt == 3'h7);
 
always @(posedge clk)
sft_done_r <= sft_done;
 
assign sft_done_e = sft_done & !sft_done_r;
 
// Out Data Hold Register
always @(posedge clk)
if(ld_sop_d) hold_reg <= 8'h80;
else
if(ld_data) hold_reg <= DataOut_i;
 
always @(posedge clk) hold_reg_d <= hold_reg;
 
///////////////////////////////////////////////////////////////////
//
// Bit Stuffer
//
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) one_cnt <= 3'h0;
else
if(!tx_ip_sync) one_cnt <= 3'h0;
else
if(fs_ce)
begin
if(!sd_raw_o || stuff) one_cnt <= 3'h0;
else one_cnt <= one_cnt + 3'h1;
end
 
assign stuff = (one_cnt==3'h6);
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) sd_bs_o <= 1'h0;
else
if(fs_ce) sd_bs_o <= !tx_ip_sync ? 1'b0 : (stuff ? 1'b0 : sd_raw_o);
 
///////////////////////////////////////////////////////////////////
//
// NRZI Encoder
//
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) sd_nrzi_o <= 1'b1;
else
if(!tx_ip_sync || !txoe_r1) sd_nrzi_o <= 1'b1;
else
if(fs_ce) sd_nrzi_o <= sd_bs_o ? sd_nrzi_o : ~sd_nrzi_o;
 
///////////////////////////////////////////////////////////////////
//
// EOP append logic
//
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst)
begin
eop_cnt <= 3'b000;
end
else
begin
if (ld_eop_d)
eop_cnt <= 3'b001;
else if(fs_ce && eop_cnt != 3'b000)
begin
if (stuff && eop_cnt == 3'b010)
eop_cnt <= eop_cnt;
else
eop_cnt <= eop_cnt + 1;
end
end
 
 
assign eop_done = (eop_cnt == 3'h4 || eop_cnt == 3'h5) ? 1'b1 : 1'b0;
 
///////////////////////////////////////////////////////////////////
//
// Output Enable Logic
//
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) txoe_r1 <= 1'b0;
else
if(fs_ce) txoe_r1 <= tx_ip_sync;
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) txoe_r2 <= 1'b0;
else
if(fs_ce) txoe_r2 <= txoe_r1;
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) txoe <= 1'b1;
else
if(fs_ce) txoe <= !(txoe_r1 | txoe_r2);
 
///////////////////////////////////////////////////////////////////
//
// Output Registers
//
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) txdp <= 1'b1;
else
if(fs_ce) txdp <= phy_mode ?
(!eop_done & sd_nrzi_o) : sd_nrzi_o;
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) txdn <= 1'b0;
else
begin
if(fs_ce)
txdn <= phy_mode ?
(!eop_done & ~sd_nrzi_o) : eop_done;
end
 
///////////////////////////////////////////////////////////////////
//
// Tx state machine
//
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) state <= IDLE;
else state <= next_state;
 
always @(state or TxValid_i or data_done or sft_done_e or fs_ce or eop_cnt)
begin
next_state = state;
tx_ready_d = 1'b0;
 
ld_sop_d = 1'b0;
ld_data_d = 1'b0;
ld_eop_d = 1'b0;
 
case(state) // synopsys full_case parallel_case
IDLE:
if(TxValid_i)
begin
ld_sop_d = 1'b1;
next_state = SOP;
end
SOP:
if(sft_done_e)
begin
tx_ready_d = 1'b1;
ld_data_d = 1'b1;
next_state = DATA;
end
DATA:
begin
if(!data_done && sft_done_e)
begin
ld_eop_d = 1'b1;
next_state = EOP;
end
if(data_done && sft_done_e)
begin
tx_ready_d = 1'b1;
ld_data_d = 1'b1;
end
end
EOP:
if(fs_ce && eop_cnt == 3'h7)
next_state = IDLE;
default :
next_state = IDLE;
endcase
end
 
endmodule
 
/trunk/rtl/phy/README.txt
0,0 → 1,96
 
This core was written by Rudolf Usselmann and downloaded from:
 
http://opencores.org/project,usb_phy
 
This core has a bug fix applied related to bitstuffing prior to EOP.
 
====================================================================
 
Copyright (C) 2000-2002 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.
 
 
USB 1.1 PHY
==========
 
Status
------
This core is done. It was tested with a USB 1.1 core I have written on
a XESS XCV800 board with a a Philips PDIUSBP11A transceiver.
I have NOT yet tested it with my USB 2.0 Function IP core.
 
Test Bench
----------
There is no test bench, period ! As I said above I have tested this core
in real hardware and it works just fine.
 
Documentation
-------------
Sorry, there is none. I just don't have the time to write it. I have tried
to follow the UTMI interface specification from USB 2.0.
'phy_mode' selects between single ended and differential tx_phy output. See
Philips ISP 1105 transceiver data sheet for an explanation of it's MODE
select pin (see Note below).
Currently this PHY only operates in Full-Speed mode. Required clock frequency
is 48MHz, from which the 12MHz USB transmit and receive clocks are derived.
 
RxError reports the following errors:
- sync errors
Could not synchronize to incoming bit stream
- Bit Stuff Error
Stuff bit had the wrong value (expected '0' got '1')
- Byte Error
Got a EOP (se0) before finished assembling a full byteAll of those errors
are or'ed together and reported via RxError.
 
Note:
1) "phy_tx_mode" selects the PHY Transmit Mode:
When phy_tx_mode is '0' the outputs are encoded as:
txdn, txdp
0 0 Differential Logic '0'
0 1 Differential Logic '1'
1 0 Single Ended '0'
1 1 Single Ended '0'
 
When phy_tx_mode is '1' the outputs are encoded as:
txdn, txdp
0 0 Single Ended '0'
0 1 Differential Logic '1'
1 0 Differential Logic '0'
1 1 Illegal State
 
See PHILIPS Transceiver Data Sheet for: ISP1105, ISP1106 and ISP1107
for more details.
 
2) "usb_rst" Indicates a USB Bus Reset (this output is also or'ed with
the reset input).
 
Misc
----
The USB 1.1 Phy Project Page is:
http://www.opencores.org/cores/usb_phy
 
To find out more about me (Rudolf Usselmann), please visit:
http://www.asics.ws
 
/trunk/rtl/phy/usb_phy.v
0,0 → 1,228
/////////////////////////////////////////////////////////////////////
//// ////
//// USB 1.1 PHY ////
//// ////
//// ////
//// Author: Rudolf Usselmann ////
//// rudi@asics.ws ////
//// ////
//// ////
//// Downloaded from: http://www.opencores.org/cores/usb_phy/ ////
//// ////
/////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2000-2002 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. ////
//// ////
/////////////////////////////////////////////////////////////////////
 
//-----------------------------------------------------------------
// Module:
//-----------------------------------------------------------------
module usb_phy
(
// Clock (48MHz) & reset
clk,
rst,
// PHY Transmit Mode:
// When phy_tx_mode_i is '0' the outputs are encoded as:
// TX- TX+
// 0 0 Differential Logic '0'
// 0 1 Differential Logic '1'
// 1 0 Single Ended '0'
// 1 1 Single Ended '0'
// When phy_tx_mode_i is '1' the outputs are encoded as:
// TX- TX+
// 0 0 Single Ended '0'
// 0 1 Differential Logic '1'
// 1 0 Differential Logic '0'
// 1 1 Illegal State
phy_tx_mode_i,
// USB bus reset event
usb_rst_o,
usb_rst_i,
// Transciever Interface
// Tx +/-
tx_dp_o,
tx_dn_o,
// Tx output enable (active low)
tx_oen_o,
// Receive data
rx_rcv_i,
// Rx +/-
rx_dp_i,
rx_dn_i,
 
// UTMI Interface
// Transmit data [7:0]
utmi_data_i,
// Transmit data enable
utmi_txvalid_i,
// Transmit ready (L=hold,H=load data)
utmi_txready_o,
// Receive data [7:0]
utmi_data_o,
// Valid data on utmi_data_o
utmi_rxvalid_o,
// Receive active (SYNC recieved)
utmi_rxactive_o,
// Rx error occurred
utmi_rxerror_o,
// Receive line state [1=RX-, 0=RX+]
utmi_linestate_o
);
 
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
 
//-----------------------------------------------------------------
// I/O
//-----------------------------------------------------------------
input clk;
input rst;
input phy_tx_mode_i;
output usb_rst_o;
input usb_rst_i;
output tx_dp_o, tx_dn_o, tx_oen_o;
input rx_rcv_i, rx_dp_i, rx_dn_i;
input [7:0] utmi_data_i;
input utmi_txvalid_i;
output utmi_txready_o;
output [7:0] utmi_data_o;
output utmi_rxvalid_o;
output utmi_rxactive_o;
output utmi_rxerror_o;
output [1:0] utmi_linestate_o;
 
///////////////////////////////////////////////////////////////////
//
// Local Wires and Registers
//
 
reg [4:0] rst_cnt;
reg usb_rst_o;
wire fs_ce;
wire rst;
 
wire tx_dp_int;
wire tx_dn_int;
wire tx_oen_int;
 
///////////////////////////////////////////////////////////////////
//
// Misc Logic
//
 
///////////////////////////////////////////////////////////////////
//
// TX Phy
//
 
usb_tx_phy i_tx_phy(
.clk( clk ),
.rst( rst ),
.fs_ce( fs_ce ),
.phy_mode( phy_tx_mode_i ),
 
// Transciever Interface
.txdp( tx_dp_int ),
.txdn( tx_dn_int ),
.txoe( tx_oen_int ),
 
// UTMI Interface
.DataOut_i( utmi_data_i ),
.TxValid_i( utmi_txvalid_i ),
.TxReady_o( utmi_txready_o )
);
 
///////////////////////////////////////////////////////////////////
//
// RX Phy and DPLL
//
 
usb_rx_phy i_rx_phy(
.clk( clk ),
.rst( rst ),
.fs_ce( fs_ce ),
 
// Transciever Interface
.rxd( rx_rcv_i ),
.rxdp( rx_dp_i ),
.rxdn( rx_dn_i ),
 
// UTMI Interface
.DataIn_o( utmi_data_o ),
.RxValid_o( utmi_rxvalid_o ),
.RxActive_o( utmi_rxactive_o ),
.RxError_o( utmi_rxerror_o ),
.RxEn_i( tx_oen_o ),
.LineState( utmi_linestate_o )
);
 
///////////////////////////////////////////////////////////////////
//
// Generate an USB Reset is we see SE0 for at least 2.5uS
//
 
`ifdef USB_ASYNC_REST
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
if(!rst) rst_cnt <= 5'h0;
else
if(utmi_linestate_o != 2'h0) rst_cnt <= 5'h0;
else
if(!usb_rst_o && fs_ce) rst_cnt <= rst_cnt + 5'h1;
 
`ifdef CONF_TARGET_SIM
// Disable RST_O
always @(posedge clk)
usb_rst_o <= 1'b0;
`else
always @(posedge clk)
usb_rst_o <= (rst_cnt == 5'h1f);
`endif
// Host generate USB reset event (SE0)
assign tx_dp_o = usb_rst_i ? 1'b0 : tx_dp_int;
assign tx_dn_o = usb_rst_i ? 1'b1 : tx_dn_int;
assign tx_oen_o = usb_rst_i ? 1'b0 : tx_oen_int;
endmodule
 
/trunk/rtl/usbf_crc16.v
0,0 → 1,78
//-----------------------------------------------------------------
// USB Device Core
// V0.1
// Ultra-Embedded.com
// Copyright 2014
//
// Email: admin@ultra-embedded.com
//
// License: LGPL
//-----------------------------------------------------------------
//
// Copyright (C) 2013 - 2014 Ultra-Embedded.com
//
// 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 source file is free software; you can redistribute it
// and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any
// later version.
//
// This source is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this source; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330,
// Boston, MA 02111-1307 USA
//-----------------------------------------------------------------
 
//-----------------------------------------------------------------
// Module: 16-bit CRC used by USB data packets
//-----------------------------------------------------------------
module usbf_crc16
(
input [15:0] crc_in,
input [7:0] din,
output [15:0] crc_out
);
 
//-----------------------------------------------------------------
// Logic
//-----------------------------------------------------------------
assign crc_out[15] = din[0] ^ din[1] ^ din[2] ^ din[3] ^ din[4] ^ din[5] ^ din[6] ^ din[7] ^
crc_in[7] ^ crc_in[6] ^ crc_in[5] ^ crc_in[4] ^ crc_in[3] ^ crc_in[2] ^ crc_in[1] ^ crc_in[0];
assign crc_out[14] = din[0] ^ din[1] ^ din[2] ^ din[3] ^ din[4] ^ din[5] ^ din[6] ^
crc_in[6] ^ crc_in[5] ^ crc_in[4] ^ crc_in[3] ^ crc_in[2] ^ crc_in[1] ^ crc_in[0];
assign crc_out[13] = din[6] ^ din[7] ^
crc_in[7] ^ crc_in[6];
assign crc_out[12] = din[5] ^ din[6] ^
crc_in[6] ^ crc_in[5];
assign crc_out[11] = din[4] ^ din[5] ^
crc_in[5] ^ crc_in[4];
assign crc_out[10] = din[3] ^ din[4] ^
crc_in[4] ^ crc_in[3];
assign crc_out[9] = din[2] ^ din[3] ^
crc_in[3] ^ crc_in[2];
assign crc_out[8] = din[1] ^ din[2] ^
crc_in[2] ^ crc_in[1];
assign crc_out[7] = din[0] ^ din[1] ^
crc_in[15] ^ crc_in[1] ^ crc_in[0];
assign crc_out[6] = din[0] ^
crc_in[14] ^ crc_in[0];
assign crc_out[5] = crc_in[13];
assign crc_out[4] = crc_in[12];
assign crc_out[3] = crc_in[11];
assign crc_out[2] = crc_in[10];
assign crc_out[1] = crc_in[9];
assign crc_out[0] = din[0] ^ din[1] ^ din[2] ^ din[3] ^ din[4] ^ din[5] ^ din[6] ^ din[7] ^
crc_in[8] ^ crc_in[7] ^ crc_in[6] ^ crc_in[5] ^ crc_in[4] ^ crc_in[3] ^ crc_in[2] ^ crc_in[1] ^ crc_in[0];
 
endmodule
/trunk/rtl/usbf_device.v
0,0 → 1,211
//-----------------------------------------------------------------
// USB Device Core
// V0.1
// Ultra-Embedded.com
// Copyright 2014
//
// Email: admin@ultra-embedded.com
//
// License: LGPL
//-----------------------------------------------------------------
//
// Copyright (C) 2013 - 2014 Ultra-Embedded.com
//
// 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 source file is free software; you can redistribute it
// and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any
// later version.
//
// This source is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this source; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330,
// Boston, MA 02111-1307 USA
//-----------------------------------------------------------------
 
//-----------------------------------------------------------------
// Module: USB device core (top)
//-----------------------------------------------------------------
module usbf_device
(
// Clocking (48MHz) & Reset
input clk_i /*verilator public*/,
input rst_i /*verilator public*/,
 
// Interrupt output
output intr_o /*verilator public*/,
// Peripheral Interface (from CPU)
input [7:0] addr_i /*verilator public*/,
input [31:0] data_i /*verilator public*/,
output [31:0] data_o /*verilator public*/,
input we_i /*verilator public*/,
input stb_i /*verilator public*/,
 
// USB Transceiver Interface
output usb_vmo_o /*verilator public*/,
output usb_vpo_o /*verilator public*/,
output usb_oe_o /*verilator public*/,
input usb_rx_i /*verilator public*/,
input usb_vp_i /*verilator public*/,
input usb_vm_i /*verilator public*/,
output usb_speed_o /*verilator public*/,
output usb_susp_o /*verilator public*/,
output usb_mode_o /*verilator public*/,
output usb_en_o /*verilator public*/
);
 
//-----------------------------------------------------------------
// Registers / Wires
//-----------------------------------------------------------------
wire [7:0] utmi_data_w;
wire [7:0] utmi_data_r;
wire utmi_txvalid;
wire utmi_txready;
wire utmi_rxvalid;
wire utmi_rxactive;
wire utmi_rxerror;
wire [1:0] utmi_linestate;
 
wire usb_oen;
wire usb_tx_p;
wire usb_tx_n;
wire usb_rx_p;
wire usb_rx_n;
wire usb_rx;
wire usb_rst;
 
wire nrst;
 
//-----------------------------------------------------------------
// Instantiation
//-----------------------------------------------------------------
usbf_sie
usb
(
// Clocking (48MHz) & Reset
.clk_i(clk_i),
.rst_i(rst_i),
 
// Interrupt output
.intr_o(intr_o),
// Peripheral Interface (from CPU)
.addr_i(addr_i),
.data_i(data_i),
.data_o(data_o),
.we_i(we_i),
.stb_i(stb_i),
 
// UTMI interface
.utmi_rst_i(usb_rst),
.utmi_data_w(utmi_data_w),
.utmi_data_r(utmi_data_r),
.utmi_txvalid_o(utmi_txvalid),
.utmi_txready_i(utmi_txready),
.utmi_rxvalid_i(utmi_rxvalid),
.utmi_rxactive_i(utmi_rxactive),
.utmi_rxerror_i(utmi_rxerror),
.utmi_linestate_i(utmi_linestate),
 
// Pull-up enable
.usb_en_o(usb_en_o)
);
 
// USB-PHY module (UTMI->PHY interface)
usb_phy
u_phy
(
// Clock (48MHz) & reset
.clk(clk_i),
.rst(nrst),
 
// PHY Transmit Mode:
// When phy_tx_mode_i is '0' the outputs are encoded as:
// TX- TX+
// 0 0 Differential Logic '0'
// 0 1 Differential Logic '1'
// 1 0 Single Ended '0'
// 1 1 Single Ended '0'
// When phy_tx_mode_i is '1' the outputs are encoded as:
// TX- TX+
// 0 0 Single Ended '0'
// 0 1 Differential Logic '1'
// 1 0 Differential Logic '0'
// 1 1 Illegal State
.phy_tx_mode_i(1'b0),
 
// USB bus reset event
.usb_rst_o(usb_rst),
.usb_rst_i(1'b0),
 
// Transciever Interface
// Tx +/-
.tx_dp_o(usb_tx_p),
.tx_dn_o(usb_tx_n),
 
// Tx output enable (active low)
.tx_oen_o(usb_oen),
 
// Receive data
.rx_rcv_i(usb_rx),
 
// Rx +/-
.rx_dp_i(usb_rx_p),
.rx_dn_i(usb_rx_n),
 
// UTMI Interface
 
// Transmit data [7:0]
.utmi_data_i(utmi_data_w),
 
// Transmit data enable
.utmi_txvalid_i(utmi_txvalid),
 
// Transmit ready (L=hold,H=load data)
.utmi_txready_o(utmi_txready),
 
// Receive data [7:0]
.utmi_data_o(utmi_data_r),
 
// Valid data on utmi_data_o
.utmi_rxvalid_o(utmi_rxvalid),
 
// Receive active (SYNC recieved)
.utmi_rxactive_o(utmi_rxactive),
 
// Rx error occurred
.utmi_rxerror_o(utmi_rxerror),
 
// Receive line state [1=RX-, 0=RX+]
.utmi_linestate_o(utmi_linestate)
);
 
//-----------------------------------------------------------------
// Assignments
//-----------------------------------------------------------------
assign usb_rx = usb_rx_i;
assign usb_rx_p = usb_vp_i;
assign usb_rx_n = usb_vm_i;
assign usb_vpo_o = usb_tx_p;
assign usb_vmo_o = usb_tx_n;
assign usb_oe_o = usb_oen;
 
assign usb_mode_o = 1'b0;
assign usb_speed_o = 1'b1;
assign usb_susp_o = 1'b0;
 
assign nrst = !rst_i;
 
endmodule
/trunk/rtl/usbf_sie.v
0,0 → 1,1753
//-----------------------------------------------------------------
// USB Device Core
// V0.1
// Ultra-Embedded.com
// Copyright 2014
//
// Email: admin@ultra-embedded.com
//
// License: LGPL
//-----------------------------------------------------------------
//
// Copyright (C) 2013 - 2014 Ultra-Embedded.com
//
// 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 source file is free software; you can redistribute it
// and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any
// later version.
//
// This source is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this source; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330,
// Boston, MA 02111-1307 USA
//-----------------------------------------------------------------
 
//-----------------------------------------------------------------
// !!!! This file is auto generated !!!!
//-----------------------------------------------------------------
 
//-----------------------------------------------------------------
// Module: Simplified USB device serial interface engine
//-----------------------------------------------------------------
module usbf_sie
(
// Clocking (48MHz) & Reset
input wire clk_i /*verilator public*/,
input wire rst_i /*verilator public*/,
 
// Interrupt output
output reg intr_o /*verilator public*/,
 
// Peripheral Interface
input wire [7:0] addr_i /*verilator public*/,
input wire [31:0] data_i /*verilator public*/,
output reg [31:0] data_o /*verilator public*/,
input wire we_i /*verilator public*/,
input wire stb_i /*verilator public*/,
 
// UTMI interface
input wire utmi_rst_i /*verilator public*/,
output wire [7:0] utmi_data_w /*verilator public*/,
input wire [7:0] utmi_data_r /*verilator public*/,
output reg utmi_txvalid_o /*verilator public*/,
input wire utmi_txready_i /*verilator public*/,
input wire utmi_rxvalid_i /*verilator public*/,
input wire utmi_rxactive_i /*verilator public*/,
input wire utmi_rxerror_i /*verilator public*/,
input wire [1:0] utmi_linestate_i /*verilator public*/,
 
// Pull-up enable
output reg usb_en_o /*verilator public*/
);
 
//-----------------------------------------------------------------
// Registers / Wires
//-----------------------------------------------------------------
 
// Current state
parameter STATE_RX_IDLE = 4'b0000;
parameter STATE_RX_TOKEN2 = 4'b0001;
parameter STATE_RX_TOKEN3 = 4'b0010;
parameter STATE_RX_TOKEN_COMPLETE = 4'b0011;
parameter STATE_RX_SOF2 = 4'b0100;
parameter STATE_RX_SOF3 = 4'b0101;
parameter STATE_RX_DATA = 4'b0110;
parameter STATE_RX_DATA_IGNORE = 4'b0111;
parameter STATE_RX_DATA_COMPLETE = 4'b1000;
parameter STATE_TX_DATA = 4'b1001;
parameter STATE_TX_CRC = 4'b1010;
parameter STATE_TX_CRC1 = 4'b1011;
parameter STATE_TX_CRC2 = 4'b1100;
parameter STATE_TX_ACK = 4'b1101;
parameter STATE_TX_NAK = 4'b1110;
parameter STATE_TX_STALL = 4'b1111;
reg [3:0] usb_state;
 
reg [7:0] utmi_txdata;
 
// CRC16
reg [15:0] crc_sum;
wire [15:0] crc_out;
wire [7:0] crc_data_in;
 
// Others
reg [6:0] usb_this_device;
reg [6:0] usb_next_address;
reg usb_address_pending;
reg usb_event_bus_reset;
 
// Interrupt enables
reg usb_int_en_tx;
reg usb_int_en_rx;
reg usb_int_en_sof;
 
// Incoming request type
reg usb_rx_pid_out;
reg usb_rx_pid_in;
reg usb_rx_pid_setup;
 
// Request details
reg [10:0] usb_frame_number;
reg [6:0] usb_address;
reg [2-1:0] usb_endpoint;
 
// Request action
reg usb_rx_accept_data;
reg usb_rx_send_nak;
reg usb_rx_send_stall;
 
// Transmit details
reg [7:0] usb_tx_idx;
 
// Endpoint state
reg usb_ep_tx_pend[3:0];
reg usb_ep_tx_data1[3:0];
reg [7:0] usb_ep_tx_count[3:0];
reg usb_ep_stall[3:0];
reg usb_ep_iso[3:0];
 
reg [7:0] usb_rx_count;
 
reg usb_ep0_rx_setup;
 
reg usb_ep_full[3:0];
reg [7:0] usb_ep_rx_count[3:0];
reg usb_ep_crc_err[3:0];
 
// Endpoint receive FIFO (Host -> Device)
reg usb_fifo_rd_push[3:0];
reg usb_fifo_rd_flush[3:0];
reg usb_fifo_rd_pop[3:0];
reg [7:0] usb_fifo_rd_in;
wire [7:0] usb_fifo_rd_out[3:0];
 
// Endpoint transmit FIFO (Device -> Host)
reg usb_fifo_wr_push[3:0];
reg usb_fifo_wr_pop[3:0];
reg usb_fifo_wr_flush[3:0];
reg [7:0] usb_fifo_wr_data[3:0];
wire [7:0] usb_fifo_wr_out[3:0];
reg [7:0] usb_write_data;
 
wire new_data_ready = utmi_rxvalid_i & utmi_rxactive_i;
 
//-----------------------------------------------------------------
// Peripheral Memory Map
//-----------------------------------------------------------------
`define USB_FUNC_CTRL 8'd0
`define USB_FUNC_STAT 8'd0
`define USB_FUNC_EP0 8'd4
`define USB_FUNC_EP0_DATA 8'd32
`define USB_FUNC_EP1 8'd8
`define USB_FUNC_EP1_DATA 8'd36
`define USB_FUNC_EP2 8'd12
`define USB_FUNC_EP2_DATA 8'd40
`define USB_FUNC_EP3 8'd16
`define USB_FUNC_EP3_DATA 8'd44
 
//-----------------------------------------------------------------
// Register Definitions
//-----------------------------------------------------------------
// USB_FUNC_CTRL
`define USB_FUNC_CTRL_ADDR 6:0
`define USB_FUNC_CTRL_ADDR_SET 8
`define USB_FUNC_CTRL_INT_EN_TX 9
`define USB_FUNC_CTRL_INT_EN_RX 10
`define USB_FUNC_CTRL_INT_EN_SOF 11
`define USB_FUNC_CTRL_PULLUP_EN 12
 
// USB_FUNC_STAT
`define USB_FUNC_STAT_FRAME 10:0
`define USB_FUNC_STAT_LS_RXP 16
`define USB_FUNC_STAT_LS_RXN 17
`define USB_FUNC_STAT_RST 18
 
// USB_FUNC_EPx
`define USB_EP_COUNT 7:0
`define USB_EP_TX_READY 16
`define USB_EP_RX_AVAIL 17
`define USB_EP_RX_ACK 18
`define USB_EP_RX_SETUP 18
`define USB_EP_RX_CRC_ERR 19
`define USB_EP_STALL 20
`define USB_EP_TX_FLUSH 21
`define USB_EP_ISO 22
 
//-----------------------------------------------------------------
// Definitions
//-----------------------------------------------------------------
 
// Tokens
`define PID_OUT 8'hE1
`define PID_IN 8'h69
`define PID_SOF 8'hA5
`define PID_SETUP 8'h2D
 
// Data
`define PID_DATA0 8'hC3
`define PID_DATA1 8'h4B
 
// Handshake
`define PID_ACK 8'hD2
`define PID_NAK 8'h5A
`define PID_STALL 8'h1E
 
//-----------------------------------------------------------------
// Instantiation
//-----------------------------------------------------------------
 
// CRC16
usbf_crc16
u_crc16
(
.crc_in(crc_sum),
.din(crc_data_in),
.crc_out(crc_out)
);
 
//-----------------------------------------------------------------
// Endpoint 0: Host -> Device
//-----------------------------------------------------------------
usbf_fifo
#(
.DEPTH(8),
.ADDR_W(3)
)
u_fifo_rx_ep0
(
.clk_i(clk_i),
.rst_i(rst_i),
 
.data_i(usb_fifo_rd_in),
.push_i(usb_fifo_rd_push[0]),
 
.flush_i(usb_fifo_rd_flush[0]),
 
.full_o(),
.empty_o(),
 
.data_o(usb_fifo_rd_out[0]),
.pop_i(usb_fifo_rd_pop[0])
);
 
//-----------------------------------------------------------------
// Endpoint 0: Device -> Host
//-----------------------------------------------------------------
usbf_fifo
#(
.DEPTH(8),
.ADDR_W(3)
)
u_fifo_tx_ep0
(
.clk_i(clk_i),
.rst_i(rst_i),
 
.data_i(usb_fifo_wr_data[0]),
.push_i(usb_fifo_wr_push[0]),
 
.flush_i(usb_fifo_wr_flush[0]),
 
.full_o(),
.empty_o(),
 
.data_o(usb_fifo_wr_out[0]),
.pop_i(usb_fifo_wr_pop[0])
);
//-----------------------------------------------------------------
// Endpoint 1: Host -> Device
//-----------------------------------------------------------------
usbf_fifo
#(
.DEPTH(64),
.ADDR_W(6)
)
u_fifo_rx_ep1
(
.clk_i(clk_i),
.rst_i(rst_i),
 
.data_i(usb_fifo_rd_in),
.push_i(usb_fifo_rd_push[1]),
 
.flush_i(usb_fifo_rd_flush[1]),
 
.full_o(),
.empty_o(),
 
.data_o(usb_fifo_rd_out[1]),
.pop_i(usb_fifo_rd_pop[1])
);
 
//-----------------------------------------------------------------
// Endpoint 1: Device -> Host
//-----------------------------------------------------------------
usbf_fifo
#(
.DEPTH(64),
.ADDR_W(6)
)
u_fifo_tx_ep1
(
.clk_i(clk_i),
.rst_i(rst_i),
 
.data_i(usb_fifo_wr_data[1]),
.push_i(usb_fifo_wr_push[1]),
 
.flush_i(usb_fifo_wr_flush[1]),
 
.full_o(),
.empty_o(),
 
.data_o(usb_fifo_wr_out[1]),
.pop_i(usb_fifo_wr_pop[1])
);
//-----------------------------------------------------------------
// Endpoint 2: Host -> Device
//-----------------------------------------------------------------
usbf_fifo
#(
.DEPTH(64),
.ADDR_W(6)
)
u_fifo_rx_ep2
(
.clk_i(clk_i),
.rst_i(rst_i),
 
.data_i(usb_fifo_rd_in),
.push_i(usb_fifo_rd_push[2]),
 
.flush_i(usb_fifo_rd_flush[2]),
 
.full_o(),
.empty_o(),
 
.data_o(usb_fifo_rd_out[2]),
.pop_i(usb_fifo_rd_pop[2])
);
 
//-----------------------------------------------------------------
// Endpoint 2: Device -> Host
//-----------------------------------------------------------------
usbf_fifo
#(
.DEPTH(64),
.ADDR_W(6)
)
u_fifo_tx_ep2
(
.clk_i(clk_i),
.rst_i(rst_i),
 
.data_i(usb_fifo_wr_data[2]),
.push_i(usb_fifo_wr_push[2]),
 
.flush_i(usb_fifo_wr_flush[2]),
 
.full_o(),
.empty_o(),
 
.data_o(usb_fifo_wr_out[2]),
.pop_i(usb_fifo_wr_pop[2])
);
//-----------------------------------------------------------------
// Endpoint 3: Host -> Device
//-----------------------------------------------------------------
usbf_fifo
#(
.DEPTH(64),
.ADDR_W(6)
)
u_fifo_rx_ep3
(
.clk_i(clk_i),
.rst_i(rst_i),
 
.data_i(usb_fifo_rd_in),
.push_i(usb_fifo_rd_push[3]),
 
.flush_i(usb_fifo_rd_flush[3]),
 
.full_o(),
.empty_o(),
 
.data_o(usb_fifo_rd_out[3]),
.pop_i(usb_fifo_rd_pop[3])
);
 
//-----------------------------------------------------------------
// Endpoint 3: Device -> Host
//-----------------------------------------------------------------
usbf_fifo
#(
.DEPTH(64),
.ADDR_W(6)
)
u_fifo_tx_ep3
(
.clk_i(clk_i),
.rst_i(rst_i),
 
.data_i(usb_fifo_wr_data[3]),
.push_i(usb_fifo_wr_push[3]),
 
.flush_i(usb_fifo_wr_flush[3]),
 
.full_o(),
.empty_o(),
 
.data_o(usb_fifo_wr_out[3]),
.pop_i(usb_fifo_wr_pop[3])
);
 
//-----------------------------------------------------------------
// Next state
//-----------------------------------------------------------------
reg [3:0] next_state_r;
 
always @ *
begin
next_state_r = usb_state;
 
//-----------------------------------------
// State Machine
//-----------------------------------------
case (usb_state)
 
//-----------------------------------------
// IDLE
//-----------------------------------------
STATE_RX_IDLE :
begin
if (new_data_ready)
begin
// Decode PID
case (utmi_data_r)
 
`PID_OUT, `PID_IN, `PID_SETUP:
next_state_r = STATE_RX_TOKEN2;
 
`PID_SOF:
next_state_r = STATE_RX_SOF2;
 
`PID_DATA0, `PID_DATA1:
begin
if (usb_rx_accept_data && !usb_rx_send_stall)
next_state_r = STATE_RX_DATA;
else
next_state_r = STATE_RX_DATA_IGNORE;
end
 
`PID_ACK, `PID_NAK, `PID_STALL:
next_state_r = STATE_RX_IDLE;
 
default :
;
endcase
end
end
 
//-----------------------------------------
// SOF (BYTE 2)
//-----------------------------------------
STATE_RX_SOF2 :
begin
if (new_data_ready)
next_state_r = STATE_RX_SOF3;
end
 
//-----------------------------------------
// SOF (BYTE 3)
//-----------------------------------------
STATE_RX_SOF3 :
begin
if (new_data_ready)
next_state_r = STATE_RX_IDLE;
end
 
//-----------------------------------------
// TOKEN (IN/OUT/SETUP) (Address/Endpoint)
//-----------------------------------------
STATE_RX_TOKEN2 :
begin
if (new_data_ready)
next_state_r = STATE_RX_TOKEN3;
end
 
//-----------------------------------------
// TOKEN (IN/OUT/SETUP) (Endpoint/CRC)
//-----------------------------------------
STATE_RX_TOKEN3 :
begin
if (new_data_ready)
next_state_r = STATE_RX_TOKEN_COMPLETE;
end
 
//-----------------------------------------
// RX_TOKEN_COMPLETE
//-----------------------------------------
STATE_RX_TOKEN_COMPLETE :
begin
next_state_r = STATE_RX_IDLE;
 
// Addressed to this device?
if (usb_address == usb_this_device)
begin
//-------------------------------
// IN transfer (device -> host)
//-------------------------------
if (usb_rx_pid_in)
begin
// Stalled endpoint?
if (usb_ep_stall[usb_endpoint])
next_state_r = STATE_TX_STALL;
// Some data to TX?
else if (usb_ep_tx_pend[usb_endpoint])
next_state_r = STATE_TX_DATA;
// No data to TX
else
next_state_r = STATE_TX_NAK;
end
end
end
 
//-----------------------------------------
// RX_DATA
//-----------------------------------------
STATE_RX_DATA :
begin
// Receive complete
if (utmi_rxactive_i == 1'b0)
next_state_r = STATE_RX_DATA_COMPLETE;
end
 
//-----------------------------------------
// RX_DATA_IGNORE
//-----------------------------------------
STATE_RX_DATA_IGNORE :
begin
// Receive complete
if (utmi_rxactive_i == 1'b0)
begin
// ISO endpoint?
if (usb_ep_iso[usb_endpoint])
next_state_r = STATE_RX_IDLE;
// Send STALL?
else if (usb_rx_send_stall)
next_state_r = STATE_TX_STALL;
// Send NAK
else if (usb_rx_send_nak)
next_state_r = STATE_TX_NAK;
else
next_state_r = STATE_RX_IDLE;
end
end
 
//-----------------------------------------
// RX_DATA_COMPLETE
//-----------------------------------------
STATE_RX_DATA_COMPLETE :
begin
// Check for CRC error on receive data
if (crc_sum != 16'hB001)
next_state_r = STATE_RX_IDLE;
// Good CRC
else
begin
// ISO endpoint?
if (usb_ep_iso[usb_endpoint])
next_state_r = STATE_RX_IDLE;
// Non-ISO, send ACK
else
next_state_r = STATE_TX_ACK;
end
end
 
//-----------------------------------------
// TX_ACK/NAK/STALL
//-----------------------------------------
STATE_TX_ACK, STATE_TX_NAK, STATE_TX_STALL :
begin
// Data sent?
if (utmi_txready_i)
next_state_r = STATE_RX_IDLE;
end
 
//-----------------------------------------
// TX_DATA
//-----------------------------------------
STATE_TX_DATA :
begin
// Data sent?
if (utmi_txready_i)
begin
// Generate CRC16 at end of packet
if (usb_tx_idx == usb_ep_tx_count[usb_endpoint])
next_state_r = STATE_TX_CRC;
end
end
 
//-----------------------------------------
// TX_CRC (generate)
//-----------------------------------------
STATE_TX_CRC :
next_state_r = STATE_TX_CRC1;
 
//-----------------------------------------
// TX_CRC1 (first byte)
//-----------------------------------------
STATE_TX_CRC1 :
begin
// Data sent?
if (utmi_txready_i)
next_state_r = STATE_TX_CRC2;
end
 
//-----------------------------------------
// TX_CRC (second byte)
//-----------------------------------------
STATE_TX_CRC2 :
begin
// Data sent?
if (utmi_txready_i)
next_state_r = STATE_RX_IDLE;
end
 
default :
;
 
endcase
 
//-----------------------------------------
// USB Bus Reset (HOST->DEVICE)
//-----------------------------------------
if (utmi_rst_i)
next_state_r = STATE_RX_IDLE;
end
 
// Update state
always @ (posedge rst_i or posedge clk_i)
begin
if (rst_i == 1'b1)
usb_state <= STATE_RX_IDLE;
else
usb_state <= next_state_r;
end
 
//-----------------------------------------------------------------
// Tx
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
begin
utmi_txvalid_o <= 1'b0;
utmi_txdata <= 8'h00;
 
usb_tx_idx <= 8'b0;
 
usb_ep_tx_pend[0] <= 1'b0;
usb_ep_tx_data1[0] <= 1'b0;
usb_ep_tx_count[0] <= 8'b0;
usb_fifo_wr_pop[0] <= 1'b0;
usb_fifo_wr_push[0] <= 1'b0;
usb_fifo_wr_data[0] <= 8'h00;
usb_fifo_wr_flush[0]<= 1'b0;
usb_ep_tx_pend[1] <= 1'b0;
usb_ep_tx_data1[1] <= 1'b0;
usb_ep_tx_count[1] <= 8'b0;
usb_fifo_wr_pop[1] <= 1'b0;
usb_fifo_wr_push[1] <= 1'b0;
usb_fifo_wr_data[1] <= 8'h00;
usb_fifo_wr_flush[1]<= 1'b0;
usb_ep_tx_pend[2] <= 1'b0;
usb_ep_tx_data1[2] <= 1'b0;
usb_ep_tx_count[2] <= 8'b0;
usb_fifo_wr_pop[2] <= 1'b0;
usb_fifo_wr_push[2] <= 1'b0;
usb_fifo_wr_data[2] <= 8'h00;
usb_fifo_wr_flush[2]<= 1'b0;
usb_ep_tx_pend[3] <= 1'b0;
usb_ep_tx_data1[3] <= 1'b0;
usb_ep_tx_count[3] <= 8'b0;
usb_fifo_wr_pop[3] <= 1'b0;
usb_fifo_wr_push[3] <= 1'b0;
usb_fifo_wr_data[3] <= 8'h00;
usb_fifo_wr_flush[3]<= 1'b0;
end
else
begin
usb_fifo_wr_pop[0] <= 1'b0;
usb_fifo_wr_push[0] <= 1'b0;
usb_fifo_wr_flush[0] <= 1'b0;
usb_fifo_wr_pop[1] <= 1'b0;
usb_fifo_wr_push[1] <= 1'b0;
usb_fifo_wr_flush[1] <= 1'b0;
usb_fifo_wr_pop[2] <= 1'b0;
usb_fifo_wr_push[2] <= 1'b0;
usb_fifo_wr_flush[2] <= 1'b0;
usb_fifo_wr_pop[3] <= 1'b0;
usb_fifo_wr_push[3] <= 1'b0;
usb_fifo_wr_flush[3] <= 1'b0;
 
//-----------------------------------------
// State Machine
//-----------------------------------------
case (usb_state)
 
//-----------------------------------------
// IDLE
//-----------------------------------------
STATE_RX_IDLE :
begin
if (new_data_ready)
begin
usb_tx_idx <= 8'b0;
 
// Decode PID
case (utmi_data_r)
`PID_SETUP:
begin
// Send DATA1 when responding to SETUP
usb_ep_tx_data1[0] <= 1'b1;
end
 
default :
;
endcase
end
end
 
//-----------------------------------------
// TX_ACK
//-----------------------------------------
STATE_TX_ACK :
begin
// Tx active
utmi_txvalid_o <= 1'b1;
 
// Data to send
utmi_txdata <= `PID_ACK;
 
// Data sent?
if (utmi_txready_i)
begin
 
utmi_txvalid_o <= 1'b0;
end
end
 
//-----------------------------------------
// TX_NAK
//-----------------------------------------
STATE_TX_NAK :
begin
// Tx active
utmi_txvalid_o <= 1'b1;
 
// Data to send
utmi_txdata <= `PID_NAK;
 
// Data sent?
if (utmi_txready_i)
begin
 
utmi_txvalid_o <= 1'b0;
end
end
 
//-----------------------------------------
// TX_STALL
//-----------------------------------------
STATE_TX_STALL :
begin
// Tx active
utmi_txvalid_o <= 1'b1;
 
// Data to send
utmi_txdata <= `PID_STALL;
 
// Data sent?
if (utmi_txready_i)
begin
 
utmi_txvalid_o <= 1'b0;
end
end
 
//-----------------------------------------
// TX_DATA
//-----------------------------------------
STATE_TX_DATA :
begin
// Tx active
utmi_txvalid_o <= 1'b1;
 
// Send PID (first byte - DATA0 or DATA1)
if (usb_tx_idx == 8'b0)
begin
if (usb_ep_tx_data1[usb_endpoint])
utmi_txdata <= `PID_DATA1;
else
utmi_txdata <= `PID_DATA0;
end
// Data to send
else
utmi_txdata <= usb_write_data;
 
// Data sent?
if (utmi_txready_i)
begin
// First byte is PID (not CRC'd)
if (usb_tx_idx == 8'b0)
begin
usb_tx_idx <= usb_tx_idx + 8'd1;
 
// Switch to next DATAx
usb_ep_tx_data1[usb_endpoint] <= ~usb_ep_tx_data1[usb_endpoint];
end
else
begin
 
// Pop FIFO
usb_fifo_wr_pop[usb_endpoint] <= 1'b1;
 
// Increment index
usb_tx_idx <= usb_tx_idx + 8'd1;
end
end
end
 
//-----------------------------------------
// TX_CRC1 (first byte)
//-----------------------------------------
STATE_TX_CRC1 :
begin
// Tx active
utmi_txvalid_o <= 1'b1;
end
 
//-----------------------------------------
// TX_CRC (second byte)
//-----------------------------------------
STATE_TX_CRC2 :
begin
// Tx active
utmi_txvalid_o <= 1'b1;
 
// Data sent?
if (utmi_txready_i)
begin
// Transfer now complete
utmi_txvalid_o <= 1'b0;
 
// Mark data as sent
usb_ep_tx_pend[usb_endpoint] <= 1'b0;
 
end
end
 
//-----------------------------------------
// RX_TOKEN_COMPLETE
//-----------------------------------------
STATE_RX_TOKEN_COMPLETE :
begin
// Addressed to this device?
if (usb_address == usb_this_device)
begin
//-------------------------------
// SETUP transfer (EP0)
//-------------------------------
if (usb_rx_pid_setup)
begin
// New SETUP token resets Tx pending status on EP0
usb_ep_tx_pend[0] <= 1'b0;
usb_fifo_wr_flush[0] <= 1'b1;
end
end
end
 
default :
;
 
endcase
 
//-----------------------------------------------------------------
// Peripheral Registers (Write)
//-----------------------------------------------------------------
if (we_i & stb_i)
case (addr_i)
 
`USB_FUNC_EP0 :
begin
usb_ep_tx_pend[0] <= data_i[`USB_EP_TX_READY];
usb_ep_tx_count[0] <= data_i[`USB_EP_COUNT];
end
 
`USB_FUNC_EP1 :
begin
usb_ep_tx_pend[1] <= data_i[`USB_EP_TX_READY];
usb_ep_tx_count[1] <= data_i[`USB_EP_COUNT];
 
// Flush transmit FIFO?
if (data_i[`USB_EP_TX_FLUSH])
usb_fifo_wr_flush[1] <= 1'b1;
end
`USB_FUNC_EP2 :
begin
usb_ep_tx_pend[2] <= data_i[`USB_EP_TX_READY];
usb_ep_tx_count[2] <= data_i[`USB_EP_COUNT];
 
// Flush transmit FIFO?
if (data_i[`USB_EP_TX_FLUSH])
usb_fifo_wr_flush[2] <= 1'b1;
end
`USB_FUNC_EP3 :
begin
usb_ep_tx_pend[3] <= data_i[`USB_EP_TX_READY];
usb_ep_tx_count[3] <= data_i[`USB_EP_COUNT];
 
// Flush transmit FIFO?
if (data_i[`USB_EP_TX_FLUSH])
usb_fifo_wr_flush[3] <= 1'b1;
end
 
`USB_FUNC_EP0_DATA:
begin
usb_fifo_wr_data[0] <= data_i[7:0];
usb_fifo_wr_push[0] <= 1'b1;
end
`USB_FUNC_EP1_DATA:
begin
usb_fifo_wr_data[1] <= data_i[7:0];
usb_fifo_wr_push[1] <= 1'b1;
end
`USB_FUNC_EP2_DATA:
begin
usb_fifo_wr_data[2] <= data_i[7:0];
usb_fifo_wr_push[2] <= 1'b1;
end
`USB_FUNC_EP3_DATA:
begin
usb_fifo_wr_data[3] <= data_i[7:0];
usb_fifo_wr_push[3] <= 1'b1;
end
 
default :
;
endcase
 
//-----------------------------------------
// USB Bus Reset (HOST->DEVICE)
//-----------------------------------------
if (utmi_rst_i)
begin
// Reset endpoint state
usb_ep_tx_pend[0] <= 1'b0;
usb_ep_tx_data1[0]<= 1'b0;
usb_ep_tx_pend[1] <= 1'b0;
usb_ep_tx_data1[1]<= 1'b0;
usb_ep_tx_pend[2] <= 1'b0;
usb_ep_tx_data1[2]<= 1'b0;
usb_ep_tx_pend[3] <= 1'b0;
usb_ep_tx_data1[3]<= 1'b0;
 
// Reset to IDLE
utmi_txvalid_o <= 1'b0;
end
end
end
 
//-----------------------------------------------------------------
// Rx
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
begin
// Other
usb_rx_pid_out <= 1'b0;
usb_rx_pid_in <= 1'b0;
usb_rx_pid_setup <= 1'b0;
 
usb_endpoint <= 2'b0;
 
usb_rx_accept_data <= 1'b0;
usb_rx_send_nak <= 1'b0;
usb_rx_send_stall <= 1'b0;
 
usb_rx_count <= 8'b0;
usb_ep0_rx_setup <= 1'b0;
 
usb_ep_stall[0] <= 1'b0;
usb_ep_iso[0] <= 1'b0;
usb_fifo_rd_push[0] <= 1'b0;
usb_fifo_rd_flush[0]<= 1'b0;
 
usb_ep_full[0] <= 1'b0;
usb_ep_rx_count[0] <= 8'b0;
usb_ep_crc_err[0] <= 1'b0;
usb_ep_stall[1] <= 1'b0;
usb_ep_iso[1] <= 1'b0;
usb_fifo_rd_push[1] <= 1'b0;
usb_fifo_rd_flush[1]<= 1'b0;
 
usb_ep_full[1] <= 1'b0;
usb_ep_rx_count[1] <= 8'b0;
usb_ep_crc_err[1] <= 1'b0;
usb_ep_stall[2] <= 1'b0;
usb_ep_iso[2] <= 1'b0;
usb_fifo_rd_push[2] <= 1'b0;
usb_fifo_rd_flush[2]<= 1'b0;
 
usb_ep_full[2] <= 1'b0;
usb_ep_rx_count[2] <= 8'b0;
usb_ep_crc_err[2] <= 1'b0;
usb_ep_stall[3] <= 1'b0;
usb_ep_iso[3] <= 1'b0;
usb_fifo_rd_push[3] <= 1'b0;
usb_fifo_rd_flush[3]<= 1'b0;
 
usb_ep_full[3] <= 1'b0;
usb_ep_rx_count[3] <= 8'b0;
usb_ep_crc_err[3] <= 1'b0;
usb_fifo_rd_in <= 8'b0;
end
else
begin
usb_fifo_rd_push[0] <= 1'b0;
usb_fifo_rd_flush[0] <= 1'b0;
usb_fifo_rd_push[1] <= 1'b0;
usb_fifo_rd_flush[1] <= 1'b0;
usb_fifo_rd_push[2] <= 1'b0;
usb_fifo_rd_flush[2] <= 1'b0;
usb_fifo_rd_push[3] <= 1'b0;
usb_fifo_rd_flush[3] <= 1'b0;
 
//-----------------------------------------
// State Machine
//-----------------------------------------
case (usb_state)
 
//-----------------------------------------
// IDLE
//-----------------------------------------
STATE_RX_IDLE :
begin
if (new_data_ready)
begin
// Decode PID
case (utmi_data_r)
 
`PID_OUT:
begin
usb_rx_pid_out <= 1'b1;
usb_rx_pid_in <= 1'b0;
usb_rx_pid_setup <= 1'b0;
end
 
`PID_IN:
begin
usb_rx_pid_out <= 1'b0;
usb_rx_pid_in <= 1'b1;
usb_rx_pid_setup <= 1'b0;
end
 
`PID_SETUP:
begin
usb_rx_pid_out <= 1'b0;
usb_rx_pid_in <= 1'b0;
usb_rx_pid_setup <= 1'b1;
 
// Reset EP0 stall status on SETUP
usb_rx_send_stall <= 1'b0;
usb_ep_stall[0] <= 1'b0;
end
 
`PID_DATA0:
begin
if (usb_rx_accept_data && !usb_rx_send_stall)
begin
usb_rx_accept_data <= 1'b0;
usb_rx_count <= 0;
end
end
 
`PID_DATA1:
begin
if (usb_rx_accept_data && !usb_rx_send_stall)
begin
usb_rx_accept_data <= 1'b0;
usb_rx_count <= 0;
end
end
 
`PID_ACK:
begin
end
 
`PID_NAK:
begin
end
 
`PID_STALL:
begin
end
 
default :
begin
// Reset state
usb_rx_pid_out <= 1'b0;
usb_rx_pid_in <= 1'b0;
usb_rx_pid_setup <= 1'b0;
end
 
endcase
end
end
 
//-----------------------------------------
// TOKEN (IN/OUT/SETUP) (Address/Endpoint)
//-----------------------------------------
STATE_RX_TOKEN2 :
begin
if (new_data_ready)
usb_endpoint[0] <= utmi_data_r[7];
end
 
//-----------------------------------------
// TOKEN (IN/OUT/SETUP) (Endpoint/CRC)
//-----------------------------------------
STATE_RX_TOKEN3 :
begin
if (new_data_ready)
usb_endpoint[2-1:1] <= utmi_data_r[2-2:0];
end
 
//-----------------------------------------
// RX_TOKEN_COMPLETE
//-----------------------------------------
STATE_RX_TOKEN_COMPLETE :
begin
 
// Ignore following data unless addressed
usb_rx_accept_data <= 1'b0;
usb_rx_send_nak <= 1'b0;
usb_rx_send_stall <= 1'b0;
 
// Addressed to this device?
if (usb_address == usb_this_device)
begin
//-------------------------------
// OUT transfer (host -> device)
//-------------------------------
if (usb_rx_pid_out)
begin
usb_rx_accept_data <= !usb_ep_full[usb_endpoint];
usb_rx_send_nak <= usb_ep_full[usb_endpoint];
usb_rx_send_stall <= usb_ep_stall[usb_endpoint];
end
//-------------------------------
// SETUP transfer (EP0)
//-------------------------------
else if (usb_rx_pid_setup)
begin
// Must accept data!
usb_rx_accept_data <= 1'b1;
end
end
else
begin
end
end
 
//-----------------------------------------
// RX_DATA
//-----------------------------------------
STATE_RX_DATA :
begin
if (new_data_ready)
begin
// Increment index
usb_rx_count <= usb_rx_count + 1;
 
// Write incoming data to FIFO
usb_fifo_rd_in <= utmi_data_r;
 
// Push data into correct EP FIFO
usb_fifo_rd_push[usb_endpoint] <= 1'b1;
 
end
end
 
//-----------------------------------------
// RX_DATA_IGNORE
//-----------------------------------------
STATE_RX_DATA_IGNORE :
begin
end
 
//-----------------------------------------
// RX_DATA_COMPLETE
//-----------------------------------------
STATE_RX_DATA_COMPLETE :
begin
// Check for CRC error on receive data
if (crc_sum != 16'hB001)
begin
 
// Signal error and reset FIFO
usb_ep_full[usb_endpoint] <= 1'b0;
usb_ep_crc_err[usb_endpoint] <= 1'b1;
usb_fifo_rd_flush[usb_endpoint] <= 1'b1;
usb_ep_rx_count[usb_endpoint] <= 8'b0;
end
// Good CRC
else
begin
// Update status
usb_ep_full[usb_endpoint] <= 1'b1;
usb_ep_rx_count[usb_endpoint] <= usb_rx_count;
 
// Endpoint 0 is different
if (usb_endpoint == 2'b0)
begin
usb_ep0_rx_setup <= usb_rx_pid_setup;
end
end
end
 
default :
;
 
endcase
 
//-----------------------------------------------------------------
// Peripheral Registers (Write)
//-----------------------------------------------------------------
if (we_i & stb_i)
case (addr_i)
 
`USB_FUNC_EP0 :
begin
// Clear receive status?
if (data_i[`USB_EP_RX_ACK])
begin
usb_ep_full[0] <= 1'b0;
usb_ep0_rx_setup <= 1'b0;
usb_ep_crc_err[0] <= 1'b0;
usb_fifo_rd_flush[0] <= 1'b1;
end
usb_ep_iso[0] <= 1'b0;
 
// Respond with STALL on EP0?
if (data_i[`USB_EP_STALL])
usb_ep_stall[0] <= 1'b1;
end
 
`USB_FUNC_EP1 :
begin
// Clear receive status?
if (data_i[`USB_EP_RX_ACK])
begin
usb_ep_full[1] <= 1'b0;
usb_ep_crc_err[1] <= 1'b0;
usb_fifo_rd_flush[1] <= 1'b1;
end
usb_ep_iso[1] <= data_i[`USB_EP_ISO];
 
// Endpoint stalled?
usb_ep_stall[1] <= data_i[`USB_EP_STALL];
end
`USB_FUNC_EP2 :
begin
// Clear receive status?
if (data_i[`USB_EP_RX_ACK])
begin
usb_ep_full[2] <= 1'b0;
usb_ep_crc_err[2] <= 1'b0;
usb_fifo_rd_flush[2] <= 1'b1;
end
usb_ep_iso[2] <= data_i[`USB_EP_ISO];
 
// Endpoint stalled?
usb_ep_stall[2] <= data_i[`USB_EP_STALL];
end
`USB_FUNC_EP3 :
begin
// Clear receive status?
if (data_i[`USB_EP_RX_ACK])
begin
usb_ep_full[3] <= 1'b0;
usb_ep_crc_err[3] <= 1'b0;
usb_fifo_rd_flush[3] <= 1'b1;
end
usb_ep_iso[3] <= data_i[`USB_EP_ISO];
 
// Endpoint stalled?
usb_ep_stall[3] <= data_i[`USB_EP_STALL];
end
 
default :
;
endcase
 
//-----------------------------------------
// USB Bus Reset (HOST->DEVICE)
//-----------------------------------------
if (utmi_rst_i)
begin
// Reset endpoint state
usb_ep_full[0] <= 1'b0;
usb_ep_rx_count[0]<= 8'b0;
usb_ep_full[1] <= 1'b0;
usb_ep_rx_count[1]<= 8'b0;
usb_ep_full[2] <= 1'b0;
usb_ep_rx_count[2]<= 8'b0;
usb_ep_full[3] <= 1'b0;
usb_ep_rx_count[3]<= 8'b0;
 
usb_ep0_rx_setup <= 1'b0;
end
end
end
 
//-----------------------------------------------------------------
// CRC generation
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
begin
crc_sum <= 16'hFFFF;
end
else
begin
//-----------------------------------------
// State Machine
//-----------------------------------------
case (usb_state)
 
//-----------------------------------------
// IDLE
//-----------------------------------------
STATE_RX_IDLE :
begin
if (new_data_ready)
begin
// Data packet?
if (utmi_data_r == `PID_DATA0 || utmi_data_r == `PID_DATA1)
if (usb_rx_accept_data && !usb_rx_send_stall)
crc_sum <= 16'hFFFF;
end
end
 
//-----------------------------------------
// RX_DATA
//-----------------------------------------
STATE_RX_DATA :
begin
if (new_data_ready)
crc_sum <= crc_out;
end
 
//-----------------------------------------
// TX_DATA
//-----------------------------------------
STATE_TX_DATA :
begin
// Data sent?
if (utmi_txready_i)
begin
// First byte is PID (not CRC'd)
if (usb_tx_idx == 8'b0)
begin
// Reset CRC16
crc_sum <= 16'hFFFF;
end
else
begin
// Next CRC start value
crc_sum <= crc_out;
end
end
end
 
//-----------------------------------------
// TX_CRC (generate)
//-----------------------------------------
STATE_TX_CRC :
begin
// Next CRC start value
crc_sum <= crc_sum ^ 16'hFFFF;
end
 
default :
;
 
endcase
end
end
 
//-----------------------------------------------------------------
// Address / Frame / Misc
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
begin
usb_en_o <= 1'b0;
 
usb_frame_number <= 11'h000;
usb_address <= 7'h00;
usb_this_device <= 7'h00;
usb_next_address <= 7'h00;
usb_address_pending <= 1'b0;
usb_event_bus_reset <= 1'b0;
end
else
begin
//-----------------------------------------
// State Machine
//-----------------------------------------
case (usb_state)
 
//-----------------------------------------
// SOF (BYTE 2)
//-----------------------------------------
STATE_RX_SOF2 :
begin
if (new_data_ready)
usb_frame_number[7:0] <= utmi_data_r;
end
 
//-----------------------------------------
// SOF (BYTE 3)
//-----------------------------------------
STATE_RX_SOF3 :
begin
if (new_data_ready)
usb_frame_number[10:8] <= utmi_data_r[2:0];
end
 
//-----------------------------------------
// TOKEN (IN/OUT/SETUP) (Address/Endpoint)
//-----------------------------------------
STATE_RX_TOKEN2 :
begin
if (new_data_ready)
usb_address <= utmi_data_r[6:0];
end
 
//-----------------------------------------
// TX_CRC (second byte)
//-----------------------------------------
STATE_TX_CRC2 :
begin
// Data sent?
if (utmi_txready_i)
begin
// Address changes actually occur in status phase
if (usb_address_pending)
begin
usb_address_pending <= 1'b0;
usb_this_device <= usb_next_address;
 
end
end
end
 
default :
;
 
endcase
 
//-----------------------------------------------------------------
// Peripheral Registers (Write)
//-----------------------------------------------------------------
if (we_i & stb_i)
case (addr_i)
 
`USB_FUNC_CTRL :
begin
// Set new device address?
if (data_i[`USB_FUNC_CTRL_ADDR_SET])
begin
 
// Device address change occurs in the status stage
usb_next_address <= data_i[`USB_FUNC_CTRL_ADDR];
usb_address_pending <= 1'b1;
end
 
usb_en_o <= data_i[`USB_FUNC_CTRL_PULLUP_EN];
 
// Clear bus reset event status
usb_event_bus_reset <= 1'b0;
end
 
default :
;
endcase
 
//-----------------------------------------
// USB Bus Reset (HOST->DEVICE)
//-----------------------------------------
if (utmi_rst_i)
begin
usb_event_bus_reset <= 1'b1;
 
// Reset SOF
usb_frame_number <= 11'h000;
 
// Reset device address
usb_this_device <= 7'h00;
usb_address_pending <= 1'b0;
end
end
end
 
//-----------------------------------------------------------------
// Interrupts
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
begin
intr_o <= 1'b0;
 
// Interrupt control
usb_int_en_tx <= 1'b0;
usb_int_en_rx <= 1'b0;
usb_int_en_sof <= 1'b0;
end
else
begin
intr_o <= 1'b0;
 
//-----------------------------------------
// State Machine
//-----------------------------------------
case (usb_state)
 
//-----------------------------------------
// SOF (BYTE 3)
//-----------------------------------------
STATE_RX_SOF3 :
begin
if (new_data_ready)
begin
// Generate interrupt?
if (usb_int_en_sof)
intr_o <= 1'b1;
end
end
 
//-----------------------------------------
// RX_DATA_COMPLETE
//-----------------------------------------
STATE_RX_DATA_COMPLETE :
begin
// Generate interrupt on Rx complete?
if (usb_int_en_rx)
intr_o <= 1'b1;
end
 
//-----------------------------------------
// TX_CRC (second byte)
//-----------------------------------------
STATE_TX_CRC2 :
begin
// Data sent?
if (utmi_txready_i)
begin
// Generate interrupt on Tx complete?
if (usb_int_en_tx)
intr_o <= 1'b1;
end
end
 
default :
;
 
endcase
 
//-----------------------------------------------------------------
// Peripheral Registers (Write)
//-----------------------------------------------------------------
if (we_i & stb_i)
case (addr_i)
 
`USB_FUNC_CTRL :
begin
// Interrupt control
usb_int_en_tx <= data_i[`USB_FUNC_CTRL_INT_EN_TX];
usb_int_en_rx <= data_i[`USB_FUNC_CTRL_INT_EN_RX];
usb_int_en_sof <= data_i[`USB_FUNC_CTRL_INT_EN_SOF];
end
 
default :
;
endcase
end
end
 
//-----------------------------------------------------------------
// Peripheral Registers (Read)
//-----------------------------------------------------------------
always @ *
begin
case (addr_i)
 
`USB_FUNC_STAT :
begin
data_o = 32'b0;
data_o[`USB_FUNC_STAT_FRAME] = usb_frame_number;
data_o[`USB_FUNC_STAT_LS_RXP] = utmi_linestate_i[0];
data_o[`USB_FUNC_STAT_LS_RXN] = utmi_linestate_i[1];
data_o[`USB_FUNC_STAT_RST] = usb_event_bus_reset;
end
 
`USB_FUNC_EP0:
begin
data_o = 32'b0;
data_o[`USB_EP_COUNT] = usb_ep_rx_count[0];
data_o[`USB_EP_TX_READY] = usb_ep_tx_pend[0];
data_o[`USB_EP_RX_AVAIL] = usb_ep_full[0];
data_o[`USB_EP_RX_SETUP] = usb_ep0_rx_setup;
data_o[`USB_EP_RX_CRC_ERR]= usb_ep_crc_err[0];
data_o[`USB_EP_STALL] = usb_ep_stall[0];
end
 
`USB_FUNC_EP1:
begin
data_o = 32'b0;
data_o[`USB_EP_COUNT] = usb_ep_rx_count[1];
data_o[`USB_EP_TX_READY] = usb_ep_tx_pend[1];
data_o[`USB_EP_RX_AVAIL] = usb_ep_full[1];
data_o[`USB_EP_RX_CRC_ERR]= usb_ep_crc_err[1];
data_o[`USB_EP_STALL] = usb_ep_stall[1];
end
`USB_FUNC_EP2:
begin
data_o = 32'b0;
data_o[`USB_EP_COUNT] = usb_ep_rx_count[2];
data_o[`USB_EP_TX_READY] = usb_ep_tx_pend[2];
data_o[`USB_EP_RX_AVAIL] = usb_ep_full[2];
data_o[`USB_EP_RX_CRC_ERR]= usb_ep_crc_err[2];
data_o[`USB_EP_STALL] = usb_ep_stall[2];
end
`USB_FUNC_EP3:
begin
data_o = 32'b0;
data_o[`USB_EP_COUNT] = usb_ep_rx_count[3];
data_o[`USB_EP_TX_READY] = usb_ep_tx_pend[3];
data_o[`USB_EP_RX_AVAIL] = usb_ep_full[3];
data_o[`USB_EP_RX_CRC_ERR]= usb_ep_crc_err[3];
data_o[`USB_EP_STALL] = usb_ep_stall[3];
end
 
`USB_FUNC_EP0_DATA:
data_o = {24'b0, usb_fifo_rd_out[0]};
`USB_FUNC_EP1_DATA:
data_o = {24'b0, usb_fifo_rd_out[1]};
`USB_FUNC_EP2_DATA:
data_o = {24'b0, usb_fifo_rd_out[2]};
`USB_FUNC_EP3_DATA:
data_o = {24'b0, usb_fifo_rd_out[3]};
 
default :
data_o = 32'h00000000;
endcase
end
 
always @ (posedge rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
begin
usb_fifo_rd_pop[0] <= 1'b0;
usb_fifo_rd_pop[1] <= 1'b0;
usb_fifo_rd_pop[2] <= 1'b0;
usb_fifo_rd_pop[3] <= 1'b0;
end
else
begin
 
usb_fifo_rd_pop[0] <= 1'b0;
usb_fifo_rd_pop[1] <= 1'b0;
usb_fifo_rd_pop[2] <= 1'b0;
usb_fifo_rd_pop[3] <= 1'b0;
 
// Read cycle?
if (~we_i & stb_i)
case (addr_i)
`USB_FUNC_EP0_DATA:
usb_fifo_rd_pop[0] <= 1'b1;
`USB_FUNC_EP1_DATA:
usb_fifo_rd_pop[1] <= 1'b1;
`USB_FUNC_EP2_DATA:
usb_fifo_rd_pop[2] <= 1'b1;
`USB_FUNC_EP3_DATA:
usb_fifo_rd_pop[3] <= 1'b1;
 
default :
;
endcase
end
end
 
// Decode endpoint to FIFO
always @ *
begin
usb_write_data = 8'b0;
case (usb_endpoint)
0 : usb_write_data = usb_fifo_wr_out[0];
1 : usb_write_data = usb_fifo_wr_out[1];
2 : usb_write_data = usb_fifo_wr_out[2];
3 : usb_write_data = usb_fifo_wr_out[3];
endcase
end
 
//-----------------------------------------------------------------
// Assignments
//-----------------------------------------------------------------
assign utmi_data_w = (usb_state == STATE_TX_CRC1) ? crc_sum[7:0] :
(usb_state == STATE_TX_CRC2) ? crc_sum[15:8] :
utmi_txdata;
 
assign crc_data_in = (usb_state == STATE_RX_DATA || usb_state == STATE_RX_IDLE) ? utmi_data_r : usb_write_data;
 
endmodule
/trunk/rtl/usbf_fifo.v
0,0 → 1,141
//-----------------------------------------------------------------
// USB Device Core
// V0.1
// Ultra-Embedded.com
// Copyright 2014
//
// Email: admin@ultra-embedded.com
//
// License: LGPL
//-----------------------------------------------------------------
//
// Copyright (C) 2013 - 2014 Ultra-Embedded.com
//
// 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 source file is free software; you can redistribute it
// and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any
// later version.
//
// This source is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this source; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330,
// Boston, MA 02111-1307 USA
//-----------------------------------------------------------------
 
//-----------------------------------------------------------------
// Module: USB FIFO - simple FIFO
//-----------------------------------------------------------------
module usbf_fifo
(
clk_i,
rst_i,
 
data_i,
push_i,
 
full_o,
empty_o,
 
data_o,
pop_i,
 
flush_i
);
 
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
parameter WIDTH = 8;
parameter DEPTH = 4;
parameter ADDR_W = 2;
parameter COUNT_W = ADDR_W + 1;
 
//-----------------------------------------------------------------
// I/O
//-----------------------------------------------------------------
input clk_i /*verilator public*/;
input rst_i /*verilator public*/;
input [WIDTH-1:0] data_i /*verilator public*/;
input push_i /*verilator public*/;
output full_o /*verilator public*/;
output empty_o /*verilator public*/;
output [WIDTH-1:0] data_o /*verilator public*/;
input pop_i /*verilator public*/;
input flush_i /*verilator public*/;
 
//-----------------------------------------------------------------
// Registers
//-----------------------------------------------------------------
reg [WIDTH-1:0] ram [DEPTH-1:0];
reg [ADDR_W-1:0] rd_ptr;
reg [ADDR_W-1:0] wr_ptr;
reg [COUNT_W-1:0] count;
 
//-----------------------------------------------------------------
// Sequential
//-----------------------------------------------------------------
always @ (posedge clk_i or posedge rst_i)
begin
if (rst_i == 1'b1)
begin
count <= {(COUNT_W) {1'b0}};
rd_ptr <= {(ADDR_W) {1'b0}};
wr_ptr <= {(ADDR_W) {1'b0}};
end
else
begin
 
if (flush_i)
begin
count <= {(COUNT_W) {1'b0}};
rd_ptr <= {(ADDR_W) {1'b0}};
wr_ptr <= {(ADDR_W) {1'b0}};
end
 
// Push
if (push_i & ~full_o)
begin
ram[wr_ptr] <= data_i;
wr_ptr <= wr_ptr + 1;
end
 
// Pop
if (pop_i & ~empty_o)
begin
rd_ptr <= rd_ptr + 1;
end
 
// Count up
if ((push_i & ~full_o) & ~(pop_i & ~empty_o))
begin
count <= count + 1;
end
// Count down
else if (~(push_i & ~full_o) & (pop_i & ~empty_o))
begin
count <= count - 1;
end
end
end
 
//-------------------------------------------------------------------
// Combinatorial
//-------------------------------------------------------------------
assign full_o = (count == DEPTH);
assign empty_o = (count == 0);
 
assign data_o = ram[rd_ptr];
 
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.