uhd/fpga/usrp1/sdr_lib/tx_buffer.v

170 lines
4.5 KiB
Verilog

// -*- verilog -*-
//
// USRP - Universal Software Radio Peripheral
//
// Copyright (C) 2003 Matt Ettus
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
//
// Interface to Cypress FX2 bus
// A packet is 512 Bytes. Each fifo line is 2 bytes
// Fifo has 1024 or 2048 lines
module tx_buffer
( // USB Side
input usbclk,
input bus_reset, // Used here for the 257-Hack to fix the FX2 bug
input [15:0] usbdata,
input wire WR,
output reg have_space,
output reg tx_underrun,
input clear_status,
// DSP Side
input txclk,
input reset, // standard DSP-side reset
input wire [3:0] channels,
output reg [15:0] tx_i_0,
output reg [15:0] tx_q_0,
output reg [15:0] tx_i_1,
output reg [15:0] tx_q_1,
input txstrobe,
output wire tx_empty,
output [31:0] debugbus
);
wire [11:0] txfifolevel;
wire [15:0] fifodata;
wire rdreq;
reg [3:0] phase;
wire sop_f, iq_f;
reg sop;
// USB Side of FIFO
reg [15:0] usbdata_reg;
reg wr_reg;
reg [8:0] write_count;
always @(posedge usbclk)
have_space <= (txfifolevel < (4092-256)); // be extra conservative
always @(posedge usbclk)
begin
wr_reg <= WR;
usbdata_reg <= usbdata;
end
always @(posedge usbclk)
if(bus_reset)
write_count <= 0;
else if(wr_reg)
write_count <= write_count + 1;
else
write_count <= 0;
always @(posedge usbclk)
sop <= WR & ~wr_reg; // Edge detect
// FIFO
fifo_4k_18 txfifo
( // USB Write Side
.data ( {sop,write_count[0],usbdata_reg} ),
.wrreq ( wr_reg & ~write_count[8] ),
.wrclk ( usbclk ),
.wrfull ( ),
.wrempty ( ),
.wrusedw ( txfifolevel ),
// DSP Read Side
.q ( {sop_f, iq_f, fifodata} ),
.rdreq ( rdreq ),
.rdclk ( txclk ),
.rdfull ( ),
.rdempty ( tx_empty ),
.rdusedw ( ),
// Async, shared
.aclr ( reset ) );
// DAC Side of FIFO
always @(posedge txclk)
if(reset)
begin
{tx_i_0,tx_q_0,tx_i_1,tx_q_1} <= 64'h0;
phase <= 4'd0;
end
else if(phase == channels)
begin
if(txstrobe)
phase <= 4'd0;
end
else
if(~tx_empty)
begin
case(phase)
4'd0 : tx_i_0 <= fifodata;
4'd1 : tx_q_0 <= fifodata;
4'd2 : tx_i_1 <= fifodata;
4'd3 : tx_q_1 <= fifodata;
endcase // case(phase)
phase <= phase + 4'd1;
end
assign rdreq = ((phase != channels) & ~tx_empty);
// Detect Underruns, cross clock domains
reg clear_status_dsp, tx_underrun_dsp;
always @(posedge txclk)
clear_status_dsp <= clear_status;
always @(posedge usbclk)
tx_underrun <= tx_underrun_dsp;
always @(posedge txclk)
if(reset)
tx_underrun_dsp <= 1'b0;
else if(txstrobe & (phase != channels))
tx_underrun_dsp <= 1'b1;
else if(clear_status_dsp)
tx_underrun_dsp <= 1'b0;
// TX debug bus
//
// 15:0 txclk domain => TXA [15:0]
// 31:16 usbclk domain => RXA [15:0]
assign debugbus[0] = reset;
assign debugbus[1] = txstrobe;
assign debugbus[2] = rdreq;
assign debugbus[6:3] = phase;
assign debugbus[7] = tx_empty;
assign debugbus[8] = tx_underrun_dsp;
assign debugbus[9] = iq_f;
assign debugbus[10] = sop_f;
assign debugbus[14:11] = 0;
assign debugbus[15] = txclk;
assign debugbus[16] = bus_reset;
assign debugbus[17] = WR;
assign debugbus[18] = wr_reg;
assign debugbus[19] = have_space;
assign debugbus[20] = write_count[8];
assign debugbus[21] = write_count[0];
assign debugbus[22] = sop;
assign debugbus[23] = tx_underrun;
assign debugbus[30:24] = 0;
assign debugbus[31] = usbclk;
endmodule // tx_buffer