blob: 2a6207c968b63c31662f72585c372c8df97bc329 [file] [log] [blame]
/////////////////////////////////////////////////////////////////////
//// ////
//// Internal DMA Engine ////
//// ////
//// ////
//// Author: Rudolf Usselmann ////
//// rudi@asics.ws ////
//// ////
//// ////
//// Downloaded from: http://www.opencores.org/cores/usb1_funct/////
//// ////
/////////////////////////////////////////////////////////////////////
//// ////
//// 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: usb1_idma.v,v 1.2 2002-09-25 06:06:49 rudi Exp $
//
// $Date: 2002-09-25 06:06:49 $
// $Revision: 1.2 $
// $Author: rudi $
// $Locker: $
// $State: Exp $
//
// Change History:
// $Log: not supported by cvs2svn $
// Revision 1.1.1.1 2002/09/19 12:07:38 rudi
// Initial Checkin
//
//
//
//
//
//
`include "usb1d_defines.v"
module usb1d_idma( clk, rst,
// Packet Disassembler/Assembler interface
rx_data_valid,
rx_data_done,
send_data,
rd_next,
tx_valid,
tx_data_st_i,
tx_data_st_o,
// Protocol Engine
tx_dma_en, rx_dma_en, idma_done,
ep_sel,
// Register File Manager Interface
size,
rx_cnt, rx_done,
tx_busy,
// Block Frames
ep_bf_en, ep_bf_size,
dropped_frame, misaligned_frame,
// Memory Arb interface
mwe, mre, ep_empty, ep_empty_int, ep_full
);
// Packet Disassembler/Assembler interface
input clk, rst;
input rx_data_valid;
input rx_data_done;
output send_data;
input rd_next;
input tx_valid;
input [7:0] tx_data_st_i;
output [7:0] tx_data_st_o;
// Protocol Engine
input tx_dma_en;
input rx_dma_en;
output idma_done; // DMA is done
input [3:0] ep_sel;
// Register File Manager Interface
input [8:0] size; // MAX PL Size in bytes
output [7:0] rx_cnt;
output rx_done;
output tx_busy;
input ep_bf_en;
input [6:0] ep_bf_size;
output dropped_frame;
output misaligned_frame;
// Memory Arb interface
output mwe;
output mre;
input ep_empty;
output ep_empty_int;
input ep_full;
///////////////////////////////////////////////////////////////////
//
// Local Wires and Registers
//
reg tx_dma_en_r;
reg [8:0] sizd_c; // Internal size counter
wire adr_incw;
wire adr_incb;
wire siz_dec;
wire mwe; // Memory Write enable
wire mre; // Memory Read enable
reg mwe_r;
reg sizd_is_zero; // Indicates when all bytes have been
// transferred
wire sizd_is_zero_d;
reg idma_done; // DMA transfer is done
wire send_data; // Enable UTMI Transmitter
reg rx_data_done_r;
reg rx_data_valid_r;
wire ff_re, ff_full, ff_empty;
reg ff_we, ff_we1;
reg tx_dma_en_r1;
reg tx_dma_en_r2;
reg tx_dma_en_r3;
reg send_data_r;
wire ff_clr;
reg [7:0] rx_cnt;
reg [7:0] rx_cnt_r;
reg ep_empty_r;
reg ep_empty_latched;
wire ep_empty_int;
reg [6:0] ec;
wire ec_clr;
reg dropped_frame;
reg [6:0] rc_cnt;
wire rc_clr;
reg ep_full_latched;
wire ep_full_int;
reg misaligned_frame;
reg tx_valid_r;
wire tx_valid_e;
///////////////////////////////////////////////////////////////////
//
// For IN Block Frames transmit frames in [ep_bf_size] byte quantities
//
`ifdef USB1_BF_ENABLE
always @(posedge clk)
if(!rst) ec <= #1 7'h0;
else
if(!ep_bf_en | ec_clr) ec <= #1 7'h0;
else
if(mre) ec <= #1 ec + 7'h1;
assign ec_clr = (ec == ep_bf_size) | tx_dma_en;
always @(posedge clk)
if(!rst) ep_empty_latched <= #1 1'b0;
else
if(ec_clr) ep_empty_latched <= #1 ep_empty;
assign ep_empty_int = ep_bf_en ? ep_empty_latched : ep_empty;
`else
assign ep_empty_int = ep_empty;
`endif
///////////////////////////////////////////////////////////////////
//
// For OUT Block Frames always store in [ep_bf_size] byte chunks
// if fifo can't accept [ep_bf_size] bytes junk the entire [ep_bf_size]
// byte frame
//
`ifdef USB1_BF_ENABLE
always @(posedge clk)
if(!rst) rc_cnt <= #1 7'h0;
else
if(!ep_bf_en | rc_clr) rc_cnt <= #1 7'h0;
else
if(mwe_r) rc_cnt <= #1 rc_cnt + 7'h1;
assign rc_clr = ((rc_cnt == ep_bf_size) & mwe_r) | rx_dma_en;
always @(posedge clk)
if(!rst) ep_full_latched <= #1 1'b0;
else
if(rc_clr) ep_full_latched <= #1 ep_full;
assign ep_full_int = ep_bf_en ? ep_full_latched : ep_full;
always @(posedge clk)
dropped_frame <= #1 rc_clr & ep_full & ep_bf_en;
always @(posedge clk)
misaligned_frame <= #1 rx_data_done_r & ep_bf_en & (rc_cnt!=7'd00);
`else
assign ep_full_int = ep_full;
always @(posedge clk)
dropped_frame <= #1 1'b0;
always @(posedge clk)
misaligned_frame <= #1 1'b0;
`endif
// synopsys translate_off
`ifdef USBF_VERBOSE_DEBUG
always @(posedge dropped_frame)
$display("WARNING: BF: Droped one OUT frame (no space in FIFO) (%t)",$time);
always @(posedge misaligned_frame)
$display("WARNING: BF: Received misaligned frame (%t)",$time);
`endif
// synopsys translate_on
///////////////////////////////////////////////////////////////////
//
// FIFO interface
//
always @(posedge clk)
mwe_r <= #1 rx_data_valid;
assign mwe = mwe_r & !ep_full_int;
///////////////////////////////////////////////////////////////////
//
// Misc Logic
//
always @(posedge clk)
rx_data_valid_r <= #1 rx_data_valid;
always @(posedge clk)
rx_data_done_r <= #1 rx_data_done;
// Generate one cycle pulses for tx and rx dma enable
always @(posedge clk)
tx_dma_en_r <= #1 tx_dma_en;
always @(posedge clk)
tx_dma_en_r1 <= tx_dma_en_r;
always @(posedge clk)
tx_dma_en_r2 <= tx_dma_en_r1;
always @(posedge clk)
tx_dma_en_r3 <= tx_dma_en_r2;
// DMA Done Indicator
always @(posedge clk)
idma_done <= #1 (rx_data_done_r | sizd_is_zero_d | ep_empty_int);
///////////////////////////////////////////////////////////////////
//
// RX Size Counter
//
always @(posedge clk or negedge rst)
if(!rst) rx_cnt_r <= #1 8'h00;
else
if(rx_data_done_r) rx_cnt_r <= #1 8'h00;
else
if(rx_data_valid) rx_cnt_r <= #1 rx_cnt_r + 8'h01;
always @(posedge clk or negedge rst)
if(!rst) rx_cnt <= #1 8'h00;
else
if(rx_data_done_r) rx_cnt <= #1 rx_cnt_r;
assign rx_done = rx_data_done_r;
///////////////////////////////////////////////////////////////////
//
// Transmit Size Counter (counting backward from input size)
// For MAX packet size
//
always @(posedge clk or negedge rst)
if(!rst) sizd_c <= #1 9'h1ff;
else
if(tx_dma_en) sizd_c <= #1 size;
else
if(siz_dec) sizd_c <= #1 sizd_c - 9'h1;
assign siz_dec = (tx_dma_en_r | tx_dma_en_r1 | rd_next) & !sizd_is_zero_d;
assign sizd_is_zero_d = sizd_c == 9'h0;
always @(posedge clk)
sizd_is_zero <= #1 sizd_is_zero_d;
///////////////////////////////////////////////////////////////////
//
// TX Logic
//
assign tx_busy = send_data | tx_dma_en_r | tx_dma_en;
always @(posedge clk)
tx_valid_r <= #1 tx_valid;
assign tx_valid_e = tx_valid_r & !tx_valid;
// Since we are prefetching two entries in to our fast fifo, we
// need to know when exactly ep_empty was asserted, as we might
// only need 1 or 2 bytes. This is for ep_empty_r
always @(posedge clk or negedge rst)
if(!rst) ep_empty_r <= #1 1'b0;
else
if(!tx_valid) ep_empty_r <= #1 1'b0;
else
if(tx_dma_en_r2) ep_empty_r <= #1 ep_empty_int;
always @(posedge clk or negedge rst)
if(!rst) send_data_r <= #1 1'b0;
else
if((tx_dma_en_r & !ep_empty_int)) send_data_r <= #1 1'b1;
else
if(rd_next & (sizd_is_zero_d | (ep_empty_int & !sizd_is_zero_d)) )
send_data_r <= #1 1'b0;
assign send_data = (send_data_r & !ep_empty_r &
!(sizd_is_zero & size==9'h01)) | tx_dma_en_r1;
assign mre = (tx_dma_en_r1 | tx_dma_en_r | rd_next) &
!sizd_is_zero_d & !ep_empty_int & (send_data | tx_dma_en_r1 | tx_dma_en_r);
always @(posedge clk)
ff_we1 <= mre;
always @(posedge clk)
ff_we <= ff_we1;
assign ff_re = rd_next;
assign ff_clr = !tx_valid;
///////////////////////////////////////////////////////////////////
//
// IDMA fast prefetch fifo
//
// tx fifo
usb1d_fifo2 ff(
.clk( clk ),
.rst( rst ),
.clr( ff_clr ),
.din( tx_data_st_i ),
.we( ff_we ),
.dout( tx_data_st_o ),
.re( ff_re )
);
endmodule