module usb_fifo ( input wire usb_clk, inout wire [7:0] usb_data, input wire usb_full, usb_empty, output wire usb_wrreq, usb_rdreq, usb_rden, usb_pktend, output wire [1:0] usb_addr, input wire clk, aclr, input wire tx_wrreq, rx_rdreq, input wire [7:0] tx_data, output wire tx_full, rx_empty, output wire [7:0] rx_q ); wire int_rx_full, int_tx_empty; wire rx_ready, tx_ready; wire int_rdreq, int_wrreq, int_pktend; reg is_rx_addr_ok; reg [8:0] byte_counter; reg [4:0] idle_counter; wire [7:0] int_rx_data = usb_data; wire [7:0] int_tx_q; dcfifo #( .intended_device_family("Cyclone III"), .lpm_numwords(16), .lpm_showahead("ON"), .lpm_type("dcfifo"), .lpm_width(8), .lpm_widthu(4), .rdsync_delaypipe(4), .wrsync_delaypipe(4), .overflow_checking("ON"), .underflow_checking("ON"), .use_eab("ON"), .write_aclr_synch("OFF")) fifo_tx ( .aclr(aclr), .data(tx_data), .rdclk(usb_clk), .rdreq(int_wrreq), .wrclk(clk), .wrreq(tx_wrreq), .q(int_tx_q), .rdempty(int_tx_empty), .wrfull(tx_full), .rdfull(), .rdusedw(), .wrempty(), .wrusedw()); dcfifo #( .intended_device_family("Cyclone III"), .lpm_numwords(16), .lpm_showahead("ON"), .lpm_type("dcfifo"), .lpm_width(8), .lpm_widthu(4), .rdsync_delaypipe(4), .wrsync_delaypipe(4), .overflow_checking("ON"), .underflow_checking("ON"), .use_eab("ON"), .write_aclr_synch("OFF")) fifo_rx ( .aclr(aclr), .data(int_rx_data), .rdclk(clk), .rdreq(rx_rdreq), .wrclk(usb_clk), .wrreq(int_rdreq), .q(rx_q), .rdempty(rx_empty), .wrfull(int_rx_full), .rdfull(), .rdusedw(), .wrempty(), .wrusedw()); assign rx_ready = (~usb_empty) & (~int_rx_full) & (~int_pktend); assign tx_ready = (~rx_ready) & (~usb_full) & (~int_tx_empty) & (~int_pktend); assign int_rdreq = (rx_ready) & (is_rx_addr_ok); assign int_wrreq = (tx_ready) & (~is_rx_addr_ok); assign int_pktend = (&idle_counter); always @ (posedge usb_clk) begin // respect 1 clock delay between fifo selection // and data transfer operations is_rx_addr_ok <= rx_ready; // assert pktend if buffer contains unsent data // and fifo_tx_unit stays empty for more than 30 clocks if (int_pktend) begin byte_counter <= 9'd0; idle_counter <= 5'd0; end else if (int_wrreq) begin byte_counter <= byte_counter + 9'd1; idle_counter <= 5'd0; end else if ((|byte_counter) & (int_tx_empty) & (~rx_ready)) begin byte_counter <= byte_counter; idle_counter <= idle_counter + 5'd1; end end assign usb_pktend = int_pktend; assign usb_rdreq = int_rdreq; assign usb_wrreq = int_wrreq; assign usb_rden = int_rdreq; assign usb_addr = {1'b1, ~rx_ready}; assign usb_data = int_wrreq ? int_tx_q : 8'bz; endmodule