umtrx: updated many cores and top level, dsp still needs proper strobes

This commit is contained in:
Josh Blum
2014-04-15 14:35:14 -07:00
parent 7bdb3ac8c3
commit ca67428214
51 changed files with 2866 additions and 1940 deletions

View File

@@ -1,5 +1,5 @@
#
# Copyright 2010 Ettus Research LLC
# Copyright 2010-2012 Ettus Research LLC
#
##################################################
@@ -55,4 +55,8 @@ settings_bus_16LE.v \
atr_controller16.v \
fifo_to_wb.v \
gpio_atr.v \
user_settings.v \
settings_fifo_ctrl.v \
simple_spi_core.v \
simple_i2c_core.v \
))

View File

@@ -27,7 +27,7 @@ module double_buffer_tb();
reg src_rdy_i = 0;
wire dst_rdy_o;
wire dst_rdy_i = 1;
wire dst_rdy_i = 0;
wire [35:0] data_o;
reg [35:0] data_i;
@@ -46,9 +46,9 @@ module double_buffer_tb();
.data_i(data_i), .src_rdy_i(src_rdy_i), .dst_rdy_o(dst_rdy_o),
.data_o(data_o), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i));
dspengine_16to8 dspengine_16to8
dspengine_8to16 #(.HEADER_OFFSET(1)) dspengine_8to16
(.clk(clk),.reset(rst),.clear(0),
.set_stb(set_stb), .set_addr(0), .set_data({13'h0,1'b1,18'h00400}),
.set_stb(set_stb), .set_addr(0), .set_data(1),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(buf_to_dsp), .access_dat_o(dsp_to_buf));
@@ -69,11 +69,13 @@ module double_buffer_tb();
@(posedge clk);
@(posedge clk);
@(posedge clk);
/*
// Passthrough
$display("Passthrough");
src_rdy_i <= 1;
data_i <= { 2'b00,1'b0,1'b1,32'hFFFFFFFF};
data_i <= { 2'b00,1'b0,1'b1,32'h01234567};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'hFFFFFFFF};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h04050607};
@(posedge clk);
@@ -86,16 +88,18 @@ module double_buffer_tb();
repeat (5)
@(posedge clk);
*/
$display("Enabled");
set_stb <= 1;
@(posedge clk);
set_stb <= 0;
/*
@(posedge clk);
$display("Non-IF Data Passthrough");
src_rdy_i <= 1;
data_i <= { 2'b00,1'b0,1'b1,32'hC0000000};
data_i <= { 2'b00,1'b0,1'b1,32'h89acdef0};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'hC0000000};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h14151617};
@(posedge clk);
@@ -111,7 +115,9 @@ module double_buffer_tb();
$display("No StreamID, No Trailer, Even");
src_rdy_i <= 1;
data_i <= { 2'b00,1'b0,1'b1,32'h0000FFFF};
data_i <= { 2'b00,1'b0,1'b1,32'hAAAAAAAA};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h0000FFFF};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h01000200};
@(posedge clk);
@@ -139,7 +145,9 @@ module double_buffer_tb();
$display("No StreamID, No Trailer, Odd");
src_rdy_i <= 1;
data_i <= { 2'b00,1'b0,1'b1,32'h0000FFFF};
data_i <= { 2'b00,1'b0,1'b1,32'hBBBBBBBB};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h0000FFFF};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h11001200};
@(posedge clk);
@@ -159,30 +167,59 @@ module double_buffer_tb();
while(~dst_rdy_o)
@(posedge clk);
*/
/*
$display("No StreamID, Trailer, Even");
src_rdy_i <= 1;
data_i <= { 2'b00,1'b0,1'b1,32'h0400FFFF};
data_i <= { 2'b00,1'b0,1'b1,32'hCCCCCCCC};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h21002200};
data_i <= { 2'b00,1'b0,1'b0,32'h0400FFFF};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h23002400};
data_i <= { 2'b00,1'b0,1'b0,32'h21222324};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h25262728};
src_rdy_i <= 0;
@(posedge clk);
src_rdy_i <= 1;
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h25002600};
data_i <= { 2'b00,1'b0,1'b0,32'h292a2b2c};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h27002800};
data_i <= { 2'b00,1'b0,1'b0,32'h2d2e2f30};
@(posedge clk);
data_i <= { 2'b00,1'b1,1'b0,32'h29002a00};
data_i <= { 2'b00,1'b1,1'b0,32'hDEADBEEF};
@(posedge clk);
src_rdy_i <= 0;
@(posedge clk);
*/
while(~dst_rdy_o)
@(posedge clk);
/*
$display("No StreamID, Trailer, Odd");
src_rdy_i <= 1;
data_i <= { 2'b00,1'b0,1'b1,32'hDDDDDDDD};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h0400FFFF};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h21222324};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h25262728};
src_rdy_i <= 0;
@(posedge clk);
src_rdy_i <= 1;
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h292a2b2c};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h2d2e2f30};
@(posedge clk);
data_i <= { 2'b00,1'b1,1'b0,32'hDEBDBF0D};
@(posedge clk);
src_rdy_i <= 0;
@(posedge clk);
*/
while(~dst_rdy_o)
@(posedge clk);
/*
$display("No StreamID, Trailer, Odd");
src_rdy_i <= 1;
data_i <= { 2'b00,1'b0,1'b1,32'h0400FFFF};
@@ -226,23 +263,45 @@ module double_buffer_tb();
while(~dst_rdy_o)
@(posedge clk);
*/
$display("StreamID, Trailer, Odd");
src_rdy_i <= 1;
data_i <= { 2'b00,1'b0,1'b1,32'h1400FFFF};
data_i <= { 2'b00,1'b0,1'b1,32'hABCDEF98};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'ha100a200};
data_i <= { 2'b00,1'b0,1'b0,32'h1c034567};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'ha0a1a2a3};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'ha4a5a6a7};
// src_rdy_i <= 0;
// @(posedge clk);
// src_rdy_i <= 1;
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'ha8a9aaab};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'hacadaeaf};
@(posedge clk);
data_i <= { 2'b00,1'b1,1'b0,32'hdeadbeef};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'ha300a400};
src_rdy_i <= 0;
@(posedge clk);
src_rdy_i <= 1;
data_i <= { 2'b00,1'b0,1'b1,32'hABCDEF98};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'ha500a600};
data_i <= { 2'b00,1'b0,1'b0,32'h1c034567};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'ha700a800};
data_i <= { 2'b00,1'b0,1'b0,32'ha0a1a2a3};
@(posedge clk);
data_i <= { 2'b00,1'b1,1'b0,32'hbbb0bbb0};
data_i <= { 2'b00,1'b0,1'b0,32'ha4a5a6a7};
// src_rdy_i <= 0;
// @(posedge clk);
// src_rdy_i <= 1;
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'ha8a9aaab};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'hacadaeaf};
@(posedge clk);
data_i <= { 2'b00,1'b1,1'b0,32'hdeadbeef};
@(posedge clk);
src_rdy_i <= 0;
@(posedge clk);

View File

@@ -1,5 +1,5 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2011-2012 Ettus Research LLC
//
// 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
@@ -22,16 +22,17 @@
// the system or dsp clock on the output side
module settings_bus_crossclock
#(parameter FLOW_CTRL=0)
(input clk_i, input rst_i, input set_stb_i, input [7:0] set_addr_i, input [31:0] set_data_i,
input clk_o, input rst_o, output set_stb_o, output [7:0] set_addr_o, output [31:0] set_data_o);
input clk_o, input rst_o, output set_stb_o, output [7:0] set_addr_o, output [31:0] set_data_o, input blocked);
wire full, empty;
fifo_xlnx_16x40_2clk settings_fifo
(.rst(rst_i),
.wr_clk(clk_i), .din({set_addr_i,set_data_i}), .wr_en(set_stb_i & ~full), .full(full),
.rd_clk(clk_o), .dout({set_addr_o,set_data_o}), .rd_en(~empty), .empty(empty));
.rd_clk(clk_o), .dout({set_addr_o,set_data_o}), .rd_en(set_stb_o), .empty(empty));
assign set_stb_o = ~empty;
assign set_stb_o = ~empty & (~blocked | ~FLOW_CTRL);
endmodule // settings_bus_crossclock

View File

@@ -0,0 +1,395 @@
//
// Copyright 2012 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// A settings and readback bus controlled via fifo36 interface
module settings_fifo_ctrl
#(
parameter XPORT_HDR = 1, //extra transport hdr line
parameter PROT_DEST = 0, //protocol framer destination
parameter PROT_HDR = 1, //needs a protocol header?
parameter ACK_SID = 0 //stream ID for packet ACK
)
(
//clock and synchronous reset for all interfaces
input clock, input reset, input clear,
//current system time
input [63:0] vita_time,
//ready signal for multiple peripherals
input perfs_ready,
//input fifo36 interface control
input [35:0] in_data, input in_valid, output in_ready,
//output fifo36 interface status
output [35:0] out_data, output out_valid, input out_ready,
//32-bit settings bus outputs
output strobe, output [7:0] addr, output [31:0] data,
//16X 32-bit inputs for readback
input [31:0] word00,
input [31:0] word01,
input [31:0] word02,
input [31:0] word03,
input [31:0] word04,
input [31:0] word05,
input [31:0] word06,
input [31:0] word07,
input [31:0] word08,
input [31:0] word09,
input [31:0] word10,
input [31:0] word11,
input [31:0] word12,
input [31:0] word13,
input [31:0] word14,
input [31:0] word15,
//debug output
output [31:0] debug
);
wire reading = in_valid && in_ready;
wire writing = out_valid && out_ready;
//------------------------------------------------------------------
//-- The command fifo:
//-- Stores an individual register access command per line.
//------------------------------------------------------------------
wire [63:0] in_command_ticks, out_command_ticks;
wire [31:0] in_command_hdr, out_command_hdr;
wire [31:0] in_command_data, out_command_data;
wire in_command_has_time, out_command_has_time;
wire command_fifo_full, command_fifo_empty;
wire command_fifo_read, command_fifo_write;
shortfifo #(.WIDTH(129)) command_fifo (
.clk(clock), .rst(reset), .clear(clear),
.datain({in_command_ticks, in_command_hdr, in_command_data, in_command_has_time}),
.dataout({out_command_ticks, out_command_hdr, out_command_data, out_command_has_time}),
.write(command_fifo_write), .full(command_fifo_full), //input interface
.empty(command_fifo_empty), .read(command_fifo_read) //output interface
);
//------------------------------------------------------------------
//-- The result fifo:
//-- Stores an individual result of a command per line.
//------------------------------------------------------------------
wire [31:0] in_result_hdr, out_result_hdr;
wire [31:0] in_result_data, out_result_data;
wire result_fifo_full, result_fifo_empty;
wire result_fifo_read, result_fifo_write;
shortfifo #(.WIDTH(64)) result_fifo (
.clk(clock), .rst(reset), .clear(clear),
.datain({in_result_hdr, in_result_data}),
.dataout({out_result_hdr, out_result_data}),
.write(result_fifo_write), .full(result_fifo_full), //input interface
.empty(result_fifo_empty), .read(result_fifo_read) //output interface
);
//------------------------------------------------------------------
//-- Input state machine:
//-- Read input packet and fill a command fifo entry.
//------------------------------------------------------------------
localparam READ_LINE0 = 0;
localparam VITA_HDR = 1;
localparam VITA_SID = 2;
localparam VITA_CID0 = 3;
localparam VITA_CID1 = 4;
localparam VITA_TSI = 5;
localparam VITA_TSF0 = 6;
localparam VITA_TSF1 = 7;
localparam READ_HDR = 8;
localparam READ_DATA = 9;
localparam WAIT_EOF = 10;
localparam STORE_CMD = 11;
localparam START_STATE = (XPORT_HDR)? READ_LINE0 : VITA_HDR;
reg [4:0] in_state;
//holdover from current read inputs
reg [31:0] in_data_reg, in_hdr_reg;
reg [63:0] in_ticks_reg;
wire has_sid = in_data[28];
wire has_cid = in_data[27];
wire has_tsi = in_data[23:22] != 0;
wire has_tsf = in_data[21:20] != 0;
reg has_sid_reg, has_cid_reg, has_tsi_reg, has_tsf_reg;
assign in_ready = (in_state < STORE_CMD);
assign command_fifo_write = (in_state == STORE_CMD);
assign in_command_ticks = in_ticks_reg;
assign in_command_data = in_data_reg;
assign in_command_hdr = in_hdr_reg;
assign in_command_has_time = has_tsf_reg;
always @(posedge clock) begin
if (reset) begin
in_state <= START_STATE;
end
else begin
case (in_state)
READ_LINE0: begin
if (reading) in_state <= VITA_HDR;
end
VITA_HDR: begin
if (reading) begin
if (has_sid) in_state <= VITA_SID;
else if (has_cid) in_state <= VITA_CID0;
else if (has_tsi) in_state <= VITA_TSI;
else if (has_tsf) in_state <= VITA_TSF0;
else in_state <= READ_HDR;
end
has_sid_reg <= has_sid;
has_cid_reg <= has_cid;
has_tsi_reg <= has_tsi;
has_tsf_reg <= has_tsf;
end
VITA_SID: begin
if (reading) begin
if (has_cid_reg) in_state <= VITA_CID0;
else if (has_tsi_reg) in_state <= VITA_TSI;
else if (has_tsf_reg) in_state <= VITA_TSF0;
else in_state <= READ_HDR;
end
end
VITA_CID0: begin
if (reading) in_state <= VITA_CID1;
end
VITA_CID1: begin
if (reading) begin
if (has_tsi_reg) in_state <= VITA_TSI;
else if (has_tsf_reg) in_state <= VITA_TSF0;
else in_state <= READ_HDR;
end
end
VITA_TSI: begin
if (reading) begin
if (has_tsf_reg) in_state <= VITA_TSF0;
else in_state <= READ_HDR;
end
end
VITA_TSF0: begin
if (reading) in_state <= VITA_TSF1;
in_ticks_reg[63:32] <= in_data;
end
VITA_TSF1: begin
if (reading) in_state <= READ_HDR;
in_ticks_reg[31:0] <= in_data;
end
READ_HDR: begin
if (reading) in_state <= READ_DATA;
in_hdr_reg <= in_data[31:0];
end
READ_DATA: begin
if (reading) in_state <= (in_data[33])? STORE_CMD : WAIT_EOF;
in_data_reg <= in_data[31:0];
end
WAIT_EOF: begin
if (reading && in_data[33]) in_state <= STORE_CMD;
end
STORE_CMD: begin
if (~command_fifo_full) in_state <= START_STATE;
end
endcase //in_state
end
end
//------------------------------------------------------------------
//-- Command state machine:
//-- Read a command fifo entry, act on it, produce result.
//------------------------------------------------------------------
localparam LOAD_CMD = 0;
localparam EVENT_CMD = 1;
reg cmd_state;
reg [31:0] rb_data;
reg [63:0] command_ticks_reg;
reg [31:0] command_hdr_reg;
reg [31:0] command_data_reg;
reg [63:0] vita_time_reg;
always @(posedge clock)
vita_time_reg <= vita_time;
wire late;
`ifndef FIFO_CTRL_NO_TIME
time_compare time_compare(
.time_now(vita_time_reg), .trigger_time(command_ticks_reg), .late(late));
`else
assign late = 1;
`endif
//action occurs in the event state and when there is fifo space (should always be true)
//the third condition is that all peripherals in the perfs signal are ready/active high
//the fourth condition is that is an event time has been set, action is delayed until that time
wire time_ready = (out_command_has_time)? late : 1;
wire action = (cmd_state == EVENT_CMD) && ~result_fifo_full && perfs_ready && time_ready;
assign command_fifo_read = action;
assign result_fifo_write = action;
assign in_result_hdr = command_hdr_reg;
assign in_result_data = rb_data;
always @(posedge clock) begin
if (reset) begin
cmd_state <= LOAD_CMD;
end
else begin
case (cmd_state)
LOAD_CMD: begin
if (~command_fifo_empty) cmd_state <= EVENT_CMD;
command_ticks_reg <= out_command_ticks;
command_hdr_reg <= out_command_hdr;
command_data_reg <= out_command_data;
end
EVENT_CMD: begin // poking and peeking happens here!
if (action || clear) cmd_state <= LOAD_CMD;
end
endcase //cmd_state
end
end
//------------------------------------------------------------------
//-- assign to settings bus interface
//------------------------------------------------------------------
reg strobe_reg;
assign strobe = strobe_reg;
assign data = command_data_reg;
assign addr = command_hdr_reg[7:0];
wire poke = command_hdr_reg[8];
always @(posedge clock) begin
if (reset || clear) strobe_reg <= 0;
else strobe_reg <= action && poke;
end
//------------------------------------------------------------------
//-- readback mux
//------------------------------------------------------------------
always @(posedge clock) begin
case (out_command_hdr[3:0])
0 : rb_data <= word00;
1 : rb_data <= word01;
2 : rb_data <= word02;
3 : rb_data <= word03;
4 : rb_data <= word04;
5 : rb_data <= word05;
6 : rb_data <= word06;
7 : rb_data <= word07;
8 : rb_data <= word08;
9 : rb_data <= word09;
10: rb_data <= word10;
11: rb_data <= word11;
12: rb_data <= word12;
13: rb_data <= word13;
14: rb_data <= word14;
15: rb_data <= word15;
endcase // case(addr_reg[3:0])
end
//------------------------------------------------------------------
//-- Output state machine:
//-- Read a command fifo entry, act on it, produce ack packet.
//------------------------------------------------------------------
localparam WRITE_PROT_HDR = 0;
localparam WRITE_VRT_HDR = 1;
localparam WRITE_VRT_SID = 2;
localparam WRITE_RB_HDR = 3;
localparam WRITE_RB_DATA = 4;
//the state for the start of packet condition
localparam WRITE_PKT_HDR = (PROT_HDR)? WRITE_PROT_HDR : WRITE_VRT_HDR;
reg [2:0] out_state;
assign out_valid = ~result_fifo_empty;
assign result_fifo_read = out_data[33] && writing;
always @(posedge clock) begin
if (reset) begin
out_state <= WRITE_PKT_HDR;
end
else if (writing && out_data[33]) begin
out_state <= WRITE_PKT_HDR;
end
else if (writing) begin
out_state <= out_state + 1;
end
end
//------------------------------------------------------------------
//-- assign to output fifo interface
//------------------------------------------------------------------
wire [31:0] prot_hdr;
assign prot_hdr[15:0] = 16; //bytes in proceeding vita packet
assign prot_hdr[16] = 1; //yes frame
assign prot_hdr[18:17] = PROT_DEST;
assign prot_hdr[31:19] = 0; //nothing
reg [31:0] out_data_int;
always @* begin
case (out_state)
WRITE_PROT_HDR: out_data_int <= prot_hdr;
WRITE_VRT_HDR: out_data_int <= {12'b010100000000, out_result_hdr[19:16], 2'b0, prot_hdr[15:2]};
WRITE_VRT_SID: out_data_int <= ACK_SID;
WRITE_RB_HDR: out_data_int <= out_result_hdr;
WRITE_RB_DATA: out_data_int <= out_result_data;
default: out_data_int <= 0;
endcase //state
end
assign out_data[35:34] = 2'b0;
assign out_data[33] = (out_state == WRITE_RB_DATA);
assign out_data[32] = (out_state == WRITE_PKT_HDR);
assign out_data[31:0] = out_data_int;
//------------------------------------------------------------------
//-- debug outputs
//------------------------------------------------------------------
assign debug = {
in_state, out_state, //8
in_valid, in_ready, in_data[33:32], //4
out_valid, out_ready, out_data[33:32], //4
command_fifo_empty, command_fifo_full, //2
command_fifo_read, command_fifo_write, //2
addr, //8
strobe_reg, strobe, poke, out_command_has_time //4
};
endmodule //settings_fifo_ctrl

View File

@@ -0,0 +1,116 @@
//
// Copyright 2012 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// Simple I2C core
// Settings reg map:
//
// BASE+0 control register
// byte0 - control bits, data byte, or command bits, prescaler
// byte1 - what to do? (documented in cpp file)
// write prescaler lo
// write prescaler hi
// write control
// write data
// write command
// read data
// read status
//
// Readback:
//
// byte0 has readback value based on the last read command
//
module simple_i2c_core
#(
//settings register base address
parameter BASE = 0,
//i2c line level at reset
parameter ARST_LVL = 1
)
(
//clock and synchronous reset
input clock, input reset,
//32-bit settings bus inputs
input set_stb, input [7:0] set_addr, input [31:0] set_data,
//32-bit data readback
output reg [31:0] readback,
//read is high when i2c core can begin another transaction
output reg ready,
// I2C signals
// i2c clock line
input scl_pad_i, // SCL-line input
output scl_pad_o, // SCL-line output (always 1'b0)
output scl_padoen_o, // SCL-line output enable (active low)
// i2c data line
input sda_pad_i, // SDA-line input
output sda_pad_o, // SDA-line output (always 1'b0)
output sda_padoen_o, // SDA-line output enable (active low)
//optional debug output
output [31:0] debug
);
//declare command settings register
wire [7:0] sr_what, sr_data;
wire sr_changed;
setting_reg #(.my_addr(BASE+0),.width(16)) i2c_cmd_sr(
.clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
.out({sr_what, sr_data}),.changed(sr_changed));
//declare wb interface signals
wire [2:0] wb_addr;
wire [7:0] wb_data_mosi;
wire [7:0] wb_data_miso;
wire wb_we, wb_stb, wb_cyc;
wire wb_ack;
//create wishbone-based i2c core
i2c_master_top #(.ARST_LVL(ARST_LVL)) i2c
(.wb_clk_i(clock),.wb_rst_i(reset),.arst_i(1'b0),
.wb_adr_i(wb_addr),.wb_dat_i(wb_data_mosi),.wb_dat_o(wb_data_miso),
.wb_we_i(wb_we),.wb_stb_i(wb_stb),.wb_cyc_i(wb_cyc),
.wb_ack_o(wb_ack),.wb_inta_o(),
.scl_pad_i(scl_pad_i),.scl_pad_o(scl_pad_o),.scl_padoen_o(scl_padoen_o),
.sda_pad_i(sda_pad_i),.sda_pad_o(sda_pad_o),.sda_padoen_o(sda_padoen_o) );
//not ready between setting register and wishbone ack
always @(posedge clock) begin
if (reset || wb_ack) ready <= 1;
else if (sr_changed) ready <= 0;
end
//register wishbone data on every ack
always @(posedge clock) begin
if (wb_ack) readback <= {24'b0, wb_data_miso};
end
//assign wishbone signals
assign wb_addr = sr_what[2:0];
assign wb_stb = sr_changed;
assign wb_we = wb_stb && sr_what[3];
assign wb_cyc = wb_stb;
assign wb_data_mosi = sr_data;
endmodule //simple_i2c_core

View File

@@ -0,0 +1,214 @@
//
// Copyright 2012 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// Simple SPI core, the simplest, yet complete spi core I can think of
// Settings register controlled.
// 2 settings regs, control and data
// 1 32-bit readback and status signal
// Settings reg map:
//
// BASE+0 divider setting
// bits [15:0] spi clock divider
//
// BASE+1 configuration input
// bits [23:0] slave select, bit0 = slave0 enabled
// bits [29:24] num bits (1 through 32)
// bit [30] data input edge = in data bit latched on rising edge of clock
// bit [31] data output edge = out data bit latched on rising edge of clock
//
// BASE+2 input data
// Writing this register begins a spi transaction.
// Bits are latched out from bit 0.
// Therefore, load this register in reverse.
//
// Readback
// Bits are latched into bit 0.
// Therefore, data will be in-order.
module simple_spi_core
#(
//settings register base address
parameter BASE = 0,
//width of serial enables (up to 24 is possible)
parameter WIDTH = 8,
//idle state of the spi clock
parameter CLK_IDLE = 0,
//idle state of the serial enables
parameter SEN_IDLE = 24'hffffff
)
(
//clock and synchronous reset
input clock, input reset,
//32-bit settings bus inputs
input set_stb, input [7:0] set_addr, input [31:0] set_data,
//32-bit data readback
output [31:0] readback,
//read is high when spi core can begin another transaction
output ready,
//spi interface, slave selects, clock, data in, data out
output [WIDTH-1:0] sen,
output sclk,
output mosi,
input miso,
//optional debug output
output [31:0] debug
);
wire [15:0] sclk_divider;
setting_reg #(.my_addr(BASE+0),.width(16)) divider_sr(
.clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
.out(sclk_divider),.changed());
wire [23:0] slave_select;
wire [5:0] num_bits;
wire datain_edge, dataout_edge;
setting_reg #(.my_addr(BASE+1),.width(32)) config_sr(
.clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
.out({dataout_edge, datain_edge, num_bits, slave_select}),.changed());
wire [31:0] mosi_data;
wire trigger_spi;
setting_reg #(.my_addr(BASE+2),.width(32)) data_sr(
.clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
.out(mosi_data),.changed(trigger_spi));
localparam WAIT_TRIG = 0;
localparam PRE_IDLE = 1;
localparam CLK_REG = 2;
localparam CLK_INV = 3;
localparam POST_IDLE = 4;
localparam IDLE_SEN = 5;
reg [2:0] state;
reg ready_reg;
assign ready = ready_reg && ~trigger_spi;
//serial clock either idles or is in one of two clock states
reg sclk_reg;
assign sclk = sclk_reg;
//serial enables either idle or enabled based on state
wire sen_is_idle = (state == WAIT_TRIG) || (state == IDLE_SEN);
wire [23:0] sen24 = (sen_is_idle)? SEN_IDLE : (SEN_IDLE ^ slave_select);
reg [WIDTH-1:0] sen_reg;
always @(posedge clock) sen_reg <= sen24[WIDTH-1:0];
assign sen = sen_reg;
//data output shift register
reg [31:0] dataout_reg;
wire [31:0] dataout_next = {dataout_reg[30:0], 1'b0};
assign mosi = dataout_reg[31];
//data input shift register
reg [31:0] datain_reg;
wire [31:0] datain_next = {datain_reg[30:0], miso};
assign readback = datain_reg;
//counter for spi clock
reg [15:0] sclk_counter;
wire sclk_counter_done = (sclk_counter == sclk_divider);
wire [15:0] sclk_counter_next = (sclk_counter_done)? 0 : sclk_counter + 1;
//counter for latching bits miso/mosi
reg [6:0] bit_counter;
wire [6:0] bit_counter_next = bit_counter + 1;
wire bit_counter_done = (bit_counter_next == num_bits);
always @(posedge clock) begin
if (reset) begin
state <= WAIT_TRIG;
sclk_reg <= CLK_IDLE;
ready_reg <= 0;
end
else begin
case (state)
WAIT_TRIG: begin
if (trigger_spi) state <= PRE_IDLE;
ready_reg <= ~trigger_spi;
dataout_reg <= mosi_data;
sclk_counter <= 0;
bit_counter <= 0;
sclk_reg <= CLK_IDLE;
end
PRE_IDLE: begin
if (sclk_counter_done) state <= CLK_REG;
sclk_counter <= sclk_counter_next;
sclk_reg <= CLK_IDLE;
end
CLK_REG: begin
if (sclk_counter_done) begin
state <= CLK_INV;
if (datain_edge != CLK_IDLE) datain_reg <= datain_next;
if (dataout_edge != CLK_IDLE && bit_counter != 0) dataout_reg <= dataout_next;
sclk_reg <= ~CLK_IDLE; //transition to rising when CLK_IDLE == 0
end
sclk_counter <= sclk_counter_next;
end
CLK_INV: begin
if (sclk_counter_done) begin
state <= (bit_counter_done)? POST_IDLE : CLK_REG;
bit_counter <= bit_counter_next;
if (datain_edge == CLK_IDLE) datain_reg <= datain_next;
if (dataout_edge == CLK_IDLE && ~bit_counter_done) dataout_reg <= dataout_next;
sclk_reg <= CLK_IDLE; //transition to falling when CLK_IDLE == 0
end
sclk_counter <= sclk_counter_next;
end
POST_IDLE: begin
if (sclk_counter_done) state <= IDLE_SEN;
sclk_counter <= sclk_counter_next;
sclk_reg <= CLK_IDLE;
end
IDLE_SEN: begin
if (sclk_counter_done) state <= WAIT_TRIG;
sclk_counter <= sclk_counter_next;
sclk_reg <= CLK_IDLE;
end
default: state <= WAIT_TRIG;
endcase //state
end
end
assign debug = {
trigger_spi, state, //4
sclk, mosi, miso, ready, //4
sen[7:0], //8
1'b0, bit_counter[6:0], //8
sclk_counter_done, bit_counter_done, //2
sclk_counter[5:0] //6
};
endmodule //simple_spi_core

View File

@@ -0,0 +1,63 @@
//
// Copyright 2012 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// User settings bus
//
// Provides 8-bit address, 32-bit data write only bus for user settings, consumes to addresses in
// normal settings bus.
//
// Write user address to BASE
// Write user data to BASE+1
//
// The user_set_stb will strobe after data write, must write new address even if same as previous one.
module user_settings
#(parameter BASE=0)
(input clk,
input rst,
input set_stb,
input [7:0] set_addr,
input [31:0] set_data,
output set_stb_user,
output [7:0] set_addr_user,
output [31:0] set_data_user
);
wire addr_changed, data_changed;
reg stb_int;
setting_reg #(.my_addr(BASE+0),.width(8)) sr_0
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(set_addr_user),.changed(addr_changed) );
setting_reg #(.my_addr(BASE+1)) sr_1
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(set_data_user),.changed(data_changed) );
always @(posedge clk)
if (rst|set_stb_user)
stb_int <= 0;
else
if (addr_changed)
stb_int <= 1;
assign set_stb_user = stb_int & data_changed;
endmodule // user_settings

View File

@@ -0,0 +1,316 @@
//
// Copyright 2011-2012 Ettus Research LLC
//
// Packet dispatcher with fifo36 interface and 4 outputs.
//
// The packet dispatcher expects 2-byte padded ethernet frames.
// The frames will be inspected at ethernet, IPv4, UDP, and VRT layers.
// Packets are dispatched into the following streams:
// * tx dsp stream
// * tx control stream
// * to cpu stream
// * to external stream
// * to both cpu and external
//
// The following registers are used for dispatcher control:
// * base + 0 = this ipv4 address (32 bits)
// * base + 1 = udp control port (upper 16 bits), udp dsp port (lower 16 bits)
//
module packet_dispatcher36_x4
#(
parameter BASE = 0
)
(
//clocking and reset interface:
input clk, input rst, input clr,
//setting register interface:
input set_stb, input [7:0] set_addr, input [31:0] set_data,
//input stream interfaces:
input [35:0] com_inp_data, input com_inp_valid, output com_inp_ready,
//output stream interfaces:
output [35:0] ext_out_data, output ext_out_valid, input ext_out_ready,
output [35:0] dsp_out_data, output dsp_out_valid, input dsp_out_ready,
output [35:0] ctl_out_data, output ctl_out_valid, input ctl_out_ready,
output [35:0] cpu_out_data, output cpu_out_valid, input cpu_out_ready
);
//setting register to program the IP address
wire [31:0] my_ip_addr;
setting_reg #(.my_addr(BASE+0)) sreg_ip_addr(
.clk(clk),.rst(rst),
.strobe(set_stb),.addr(set_addr),.in(set_data),
.out(my_ip_addr),.changed()
);
//setting register to program the UDP DSP port
wire [15:0] dsp_udp_port, ctl_udp_port;
setting_reg #(.my_addr(BASE+1), .width(32)) sreg_data_port(
.clk(clk),.rst(rst),
.strobe(set_stb),.addr(set_addr),.in(set_data),
.out({ctl_udp_port, dsp_udp_port}),.changed()
);
////////////////////////////////////////////////////////////////////
// Communication input inspector
// - inspect com input and send it to DSP, EXT, CPU, or BOTH
////////////////////////////////////////////////////////////////////
localparam PD_STATE_READ_COM_PRE = 0;
localparam PD_STATE_READ_COM = 1;
localparam PD_STATE_WRITE_REGS = 2;
localparam PD_STATE_WRITE_LIVE = 3;
localparam PD_DEST_DSP = 0;
localparam PD_DEST_EXT = 1;
localparam PD_DEST_CPU = 2;
localparam PD_DEST_BOF = 3;
localparam PD_DEST_CTL = 4;
localparam PD_MAX_NUM_DREGS = 13; //padded_eth + ip + udp + seq + vrt_hdr
localparam PD_DREGS_DSP_OFFSET = 11; //offset to start dsp at
//output inspector interfaces
wire [35:0] pd_out_dsp_data;
wire pd_out_dsp_valid;
wire pd_out_dsp_ready;
wire [35:0] pd_out_ext_data;
wire pd_out_ext_valid;
wire pd_out_ext_ready;
wire [35:0] pd_out_cpu_data;
wire pd_out_cpu_valid;
wire pd_out_cpu_ready;
wire [35:0] pd_out_bof_data;
wire pd_out_bof_valid;
wire pd_out_bof_ready;
wire [35:0] pd_out_ctl_data;
wire pd_out_ctl_valid;
wire pd_out_ctl_ready;
reg [1:0] pd_state;
reg [2:0] pd_dest;
reg [3:0] pd_dreg_count; //data registers to buffer headers
wire [3:0] pd_dreg_count_next = pd_dreg_count + 1'b1;
wire pd_dreg_counter_done = (pd_dreg_count_next == PD_MAX_NUM_DREGS)? 1'b1 : 1'b0;
reg [35:0] pd_dregs [PD_MAX_NUM_DREGS-1:0];
reg is_eth_dst_mac_bcast;
reg is_eth_type_ipv4;
reg is_eth_ipv4_proto_udp;
reg is_eth_ipv4_dst_addr_here;
reg is_eth_udp_dsp_port_here;
reg is_eth_udp_ctl_port_here;
wire is_vrt_size_zero = (com_inp_data[15:0] == 16'h0); //needed on the same cycle, so it cant be registered
//Inspector output flags special case:
//Inject SOF into flags at first DSP line.
wire [3:0] pd_out_flags = (
(pd_dreg_count == PD_DREGS_DSP_OFFSET) &&
(pd_dest == PD_DEST_DSP)
)? 4'b0001 : pd_dregs[pd_dreg_count][35:32];
//The communication inspector ouput data and valid signals:
//Mux between com input and data registers based on the state.
wire [35:0] pd_out_data = (pd_state == PD_STATE_WRITE_REGS)?
{pd_out_flags, pd_dregs[pd_dreg_count][31:0]} : com_inp_data
;
wire pd_out_valid =
(pd_state == PD_STATE_WRITE_REGS)? 1'b1 : (
(pd_state == PD_STATE_WRITE_LIVE)? com_inp_valid : (
1'b0));
//The communication inspector ouput ready signal:
//Mux between the various destination ready signals.
wire pd_out_ready =
(pd_dest == PD_DEST_DSP)? pd_out_dsp_ready : (
(pd_dest == PD_DEST_EXT)? pd_out_ext_ready : (
(pd_dest == PD_DEST_CPU)? pd_out_cpu_ready : (
(pd_dest == PD_DEST_BOF)? pd_out_bof_ready : (
(pd_dest == PD_DEST_CTL)? pd_out_ctl_ready : (
1'b0)))));
//Always connected output data lines.
assign pd_out_dsp_data = pd_out_data;
assign pd_out_ext_data = pd_out_data;
assign pd_out_cpu_data = pd_out_data;
assign pd_out_bof_data = pd_out_data;
assign pd_out_ctl_data = pd_out_data;
//Destination output valid signals:
//Comes from inspector valid when destination is selected, and otherwise low.
assign pd_out_dsp_valid = (pd_dest == PD_DEST_DSP)? pd_out_valid : 1'b0;
assign pd_out_ext_valid = (pd_dest == PD_DEST_EXT)? pd_out_valid : 1'b0;
assign pd_out_cpu_valid = (pd_dest == PD_DEST_CPU)? pd_out_valid : 1'b0;
assign pd_out_bof_valid = (pd_dest == PD_DEST_BOF)? pd_out_valid : 1'b0;
assign pd_out_ctl_valid = (pd_dest == PD_DEST_CTL)? pd_out_valid : 1'b0;
//The communication inspector ouput ready signal:
//Always ready when storing to data registers,
//comes from inspector ready output when live,
//and otherwise low.
assign com_inp_ready =
(pd_state == PD_STATE_READ_COM_PRE) ? 1'b1 : (
(pd_state == PD_STATE_READ_COM) ? 1'b1 : (
(pd_state == PD_STATE_WRITE_LIVE) ? pd_out_ready : (
1'b0)));
//inspect the incoming data and mark register booleans
always @(posedge clk)
if (com_inp_ready & com_inp_valid) begin
case(pd_dreg_count)
0: begin
is_eth_dst_mac_bcast <= (com_inp_data[15:0] == 16'hffff);
end
1: begin
is_eth_dst_mac_bcast <= is_eth_dst_mac_bcast && (com_inp_data[31:0] == 32'hffffffff);
end
3: begin
is_eth_type_ipv4 <= (com_inp_data[15:0] == 16'h800);
end
6: begin
is_eth_ipv4_proto_udp <= (com_inp_data[23:16] == 8'h11);
end
8: begin
is_eth_ipv4_dst_addr_here <= (com_inp_data[31:0] == my_ip_addr);
end
9: begin
is_eth_udp_dsp_port_here <= (com_inp_data[15:0] == dsp_udp_port);
is_eth_udp_ctl_port_here <= (com_inp_data[15:0] == ctl_udp_port);
end
endcase //pd_dreg_count
end
always @(posedge clk)
if(rst | clr) begin
pd_state <= PD_STATE_READ_COM_PRE;
pd_dreg_count <= 0;
end
else begin
case(pd_state)
PD_STATE_READ_COM_PRE: begin
if (com_inp_ready & com_inp_valid & com_inp_data[32]) begin
pd_state <= PD_STATE_READ_COM;
pd_dreg_count <= pd_dreg_count_next;
pd_dregs[pd_dreg_count] <= com_inp_data;
end
end
PD_STATE_READ_COM: begin
if (com_inp_ready & com_inp_valid) begin
pd_dregs[pd_dreg_count] <= com_inp_data;
if (pd_dreg_counter_done | com_inp_data[33]) begin
pd_state <= PD_STATE_WRITE_REGS;
pd_dreg_count <= 0;
//---------- begin inspection decision -----------//
//EOF or bcast or not IPv4 or not UDP:
if (
com_inp_data[33] || is_eth_dst_mac_bcast ||
~is_eth_type_ipv4 || ~is_eth_ipv4_proto_udp
) begin
pd_dest <= PD_DEST_BOF;
end
//not my IP address:
else if (~is_eth_ipv4_dst_addr_here) begin
pd_dest <= PD_DEST_EXT;
end
//UDP control port and VRT:
else if (is_eth_udp_ctl_port_here && ~is_vrt_size_zero) begin
pd_dest <= PD_DEST_CTL;
pd_dreg_count <= PD_DREGS_DSP_OFFSET;
end
//UDP data port and VRT:
else if (is_eth_udp_dsp_port_here && ~is_vrt_size_zero) begin
pd_dest <= PD_DEST_DSP;
pd_dreg_count <= PD_DREGS_DSP_OFFSET;
end
//other:
else begin
pd_dest <= PD_DEST_CPU;
end
//---------- end inspection decision -------------//
end
else begin
pd_dreg_count <= pd_dreg_count_next;
end
end
end
PD_STATE_WRITE_REGS: begin
if (pd_out_ready & pd_out_valid) begin
if (pd_out_data[33]) begin
pd_state <= PD_STATE_READ_COM_PRE;
pd_dreg_count <= 0;
end
else if (pd_dreg_counter_done) begin
pd_state <= PD_STATE_WRITE_LIVE;
pd_dreg_count <= 0;
end
else begin
pd_dreg_count <= pd_dreg_count_next;
end
end
end
PD_STATE_WRITE_LIVE: begin
if (pd_out_ready & pd_out_valid & pd_out_data[33]) begin
pd_state <= PD_STATE_READ_COM_PRE;
end
end
endcase //pd_state
end
//connect this fast-path signals directly to the DSP out
assign dsp_out_data = pd_out_dsp_data;
assign dsp_out_valid = pd_out_dsp_valid;
assign pd_out_dsp_ready = dsp_out_ready;
assign ctl_out_data = pd_out_ctl_data;
assign ctl_out_valid = pd_out_ctl_valid;
assign pd_out_ctl_ready = ctl_out_ready;
////////////////////////////////////////////////////////////////////
// Splitter and output muxes for the bof packets
// - split the bof packets into two streams
// - mux split packets into cpu out and ext out
////////////////////////////////////////////////////////////////////
//dummy signals to join the the splitter and muxes below
wire [35:0] _split_to_ext_data, _split_to_cpu_data;
wire _split_to_ext_valid, _split_to_cpu_valid;
wire _split_to_ext_ready, _split_to_cpu_ready;
splitter36 bof_out_splitter(
.clk(clk), .rst(rst), .clr(clr),
.inp_data(pd_out_bof_data), .inp_valid(pd_out_bof_valid), .inp_ready(pd_out_bof_ready),
.out0_data(_split_to_ext_data), .out0_valid(_split_to_ext_valid), .out0_ready(_split_to_ext_ready),
.out1_data(_split_to_cpu_data), .out1_valid(_split_to_cpu_valid), .out1_ready(_split_to_cpu_ready)
);
fifo36_mux ext_out_mux(
.clk(clk), .reset(rst), .clear(clr),
.data0_i(pd_out_ext_data), .src0_rdy_i(pd_out_ext_valid), .dst0_rdy_o(pd_out_ext_ready),
.data1_i(_split_to_ext_data), .src1_rdy_i(_split_to_ext_valid), .dst1_rdy_o(_split_to_ext_ready),
.data_o(ext_out_data), .src_rdy_o(ext_out_valid), .dst_rdy_i(ext_out_ready)
);
fifo36_mux cpu_out_mux(
.clk(clk), .reset(rst), .clear(clr),
.data0_i(pd_out_cpu_data), .src0_rdy_i(pd_out_cpu_valid), .dst0_rdy_o(pd_out_cpu_ready),
.data1_i(_split_to_cpu_data), .src1_rdy_i(_split_to_cpu_valid), .dst1_rdy_o(_split_to_cpu_ready),
.data_o(cpu_out_data), .src_rdy_o(cpu_out_valid), .dst_rdy_i(cpu_out_ready)
);
endmodule // packet_dispatcher36_x3

155
fpga/fifo/packet_padder36.v Normal file
View File

@@ -0,0 +1,155 @@
//
// Copyright 2011-2012 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// The packet padder 36 for use with RX VITA stream output.
// Packet padder understands the concept of USB LUTs,
// and will forward packets through the interface,
// adding zero padding as needed to properly flush.
// The padder will never write a packet across a LUT boundary.
// When flushing, padder writes out zeros until the LUT boundary.
// Requires that the input line0 be a VITA header, and SOF set.
// Flush when the LUT is partially filled and timeout is reached,
// or when the LUT is partially filled and the DSP is inactive.
module packet_padder36
#(
parameter BASE = 0,
//default is 16K LUT
parameter DEFAULT_LINES32 = 4096,
//default about 1ms at 64MHz clock
parameter DEFAULT_IDLE_CYC = 65536
)
(
input clk, input reset,
//setting bus
input set_stb, input [7:0] set_addr, input [31:0] set_data,
//input interface
input [35:0] data_i,
input src_rdy_i,
output dst_rdy_o,
//output interface
output [35:0] data_o,
output src_rdy_o,
input dst_rdy_i,
input always_flush
);
wire lut_lines_changed;
wire [15:0] max_lut_lines32;
setting_reg #(.my_addr(BASE+0),.width(16),.at_reset(DEFAULT_LINES32)) sr_num_lines(
.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
.out(max_lut_lines32),.changed(lut_lines_changed));
wire idle_cyc_changed;
wire [17:0] idle_flush_cycles;
setting_reg #(.my_addr(BASE+1),.width(18),.at_reset(DEFAULT_IDLE_CYC)) sr_flush_cyc(
.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
.out(idle_flush_cycles),.changed(idle_cyc_changed));
//state machine definitions
localparam STATE_READ_HDR = 0;
localparam STATE_WRITE_HDR = 1;
localparam STATE_FORWARD = 2;
localparam STATE_WRITE_PAD = 3;
reg [1:0] state;
//keep track of the outgoing lines
reg [15:0] line_count;
wire line_count_done = line_count == 1;
wire lut_is_empty = line_count == max_lut_lines32;
always @(posedge clk) begin
if (reset || lut_lines_changed) begin
line_count <= max_lut_lines32;
end
else if (src_rdy_o && dst_rdy_i) begin
line_count <= (line_count_done)? max_lut_lines32 : line_count - 1;
end
end
//count the number of cycles since RX data so we can force a flush
reg [17:0] non_rx_cycles;
wire idle_timeout = (non_rx_cycles == idle_flush_cycles);
always @(posedge clk) begin
if(reset || state != STATE_READ_HDR || idle_cyc_changed) begin
non_rx_cycles <= 0;
end
else if (~idle_timeout) begin
non_rx_cycles <= non_rx_cycles + 1;
end
end
//flush when we have written data to a LUT and either idle or non active DSP
wire force_flush = ~lut_is_empty && (idle_timeout || always_flush);
//the padding state machine
reg [31:0] vita_hdr;
reg has_vita_hdr;
always @(posedge clk) begin
if (reset) begin
state <= STATE_READ_HDR;
end
else case(state)
STATE_READ_HDR: begin
if (src_rdy_i && dst_rdy_o && data_i[32]) begin
vita_hdr <= data_i[31:0];
has_vita_hdr <= 1;
state <= (data_i[15:0] > line_count)? STATE_WRITE_PAD : STATE_WRITE_HDR;
end
else if (force_flush) begin
has_vita_hdr <= 0;
state <= STATE_WRITE_PAD;
end
end
STATE_WRITE_HDR: begin
if (src_rdy_o && dst_rdy_i) begin
state <= STATE_FORWARD;
end
end
STATE_FORWARD: begin
if (src_rdy_i && dst_rdy_o && data_i[33]) begin
state <= STATE_READ_HDR;
end
end
STATE_WRITE_PAD: begin
if (src_rdy_o && dst_rdy_i && line_count_done) begin
state <= (has_vita_hdr)? STATE_WRITE_HDR : STATE_READ_HDR;
end
end
endcase //state
end
//assign outgoing signals
assign dst_rdy_o = (state == STATE_READ_HDR)? 1 : ((state == STATE_FORWARD)? dst_rdy_i : 0);
assign src_rdy_o = (state == STATE_WRITE_HDR || state == STATE_WRITE_PAD)? 1 : ((state == STATE_FORWARD )? src_rdy_i : 0);
assign data_o = (state == STATE_WRITE_HDR)? {4'b0001, vita_hdr} : ((state == STATE_FORWARD)? data_i : 0);
endmodule // packet_padder36

View File

@@ -0,0 +1,88 @@
//
// Copyright 2011-2012 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// PAD to NUM LINES
module resp_packet_padder36
#(
parameter NUM_LINES32 = 128
)
(
input clk, input reset,
//input interface
input [35:0] data_i,
input src_rdy_i,
output dst_rdy_o,
//output interface
output [35:0] data_o,
output src_rdy_o,
input dst_rdy_i
);
localparam STATE_FWD = 0;
localparam STATE_PAD = 1;
reg state;
reg [15:0] counter;
always @(posedge clk) begin
if (reset) begin
counter <= 0;
end
else if (src_rdy_o && dst_rdy_i) begin
if (data_o[33]) counter <= 0;
else counter <= counter + 1;
end
end
always @(posedge clk) begin
if (reset) begin
state <= STATE_FWD;
end
else case(state)
STATE_FWD: begin
if (src_rdy_i && dst_rdy_o && data_i[33] && ~data_o[33]) begin
state <= STATE_PAD;
end
end
STATE_PAD: begin
if (src_rdy_o && dst_rdy_i && data_o[33]) begin
state <= STATE_FWD;
end
end
endcase //state
end
//assign data out
assign data_o[31:0] = (state == STATE_FWD)? data_i[31:0] : {32'b0};
wire eof = (counter == (NUM_LINES32-1));
assign data_o[35:32] = {data_i[35:34], eof, data_i[32]};
//assign ready
assign src_rdy_o = (state == STATE_FWD)? src_rdy_i : 1'b1;
assign dst_rdy_o = (state == STATE_FWD)? dst_rdy_i : 1'b0;
endmodule // resp_packet_padder36

View File

@@ -1,14 +0,0 @@
#
# Copyright 2010 Ettus Research LLC
#
##################################################
# SERDES Sources
##################################################
GPIF_SRCS = $(abspath $(addprefix $(BASE_DIR)/../gpif/, \
gpif.v \
gpif_wr.v \
gpif_rd.v \
packet_reframer.v \
packet_splitter.v \
))

View File

@@ -1,185 +0,0 @@
//
// Copyright 2011 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
//////////////////////////////////////////////////////////////////////////////////
module gpif
#(parameter TXFIFOSIZE = 11, parameter RXFIFOSIZE = 11)
(// GPIF signals
input gpif_clk, input gpif_rst,
inout [15:0] gpif_d, input [3:0] gpif_ctl, output [3:0] gpif_rdy,
output [2:0] gpif_misc,
// Wishbone signals
input wb_clk, input wb_rst,
output [15:0] wb_adr_o, output [15:0] wb_dat_mosi, input [15:0] wb_dat_miso,
output [1:0] wb_sel_o, output wb_cyc_o, output wb_stb_o, output wb_we_o, input wb_ack_i,
input [7:0] triggers,
// FIFO interface
input fifo_clk, input fifo_rst, input clear_tx, input clear_rx,
output [35:0] tx_data_o, output tx_src_rdy_o, input tx_dst_rdy_i,
input [35:0] rx_data_i, input rx_src_rdy_i, output rx_dst_rdy_o,
input [35:0] tx_err_data_i, input tx_err_src_rdy_i, output tx_err_dst_rdy_o,
output tx_underrun, output rx_overrun,
input [7:0] frames_per_packet,
output [31:0] debug0, output [31:0] debug1
);
assign tx_underrun = 0;
assign rx_overrun = 0;
wire WR = gpif_ctl[0];
wire RD = gpif_ctl[1];
wire OE = gpif_ctl[2];
wire EP = gpif_ctl[3];
wire CF, CE, DF, DE;
assign gpif_rdy = { CF, CE, DF, DE };
wire [15:0] gpif_d_out;
assign gpif_d = OE ? gpif_d_out : 16'bz;
wire [15:0] gpif_d_copy = gpif_d;
wire [31:0] debug_rd, debug_wr, debug_split0, debug_split1;
// ////////////////////////////////////////////////////////////////////
// TX Data Path
wire [18:0] tx19_data;
wire tx19_src_rdy, tx19_dst_rdy;
wire [35:0] tx36_data;
wire tx36_src_rdy, tx36_dst_rdy;
wire [18:0] ctrl_data;
wire ctrl_src_rdy, ctrl_dst_rdy;
gpif_wr gpif_wr
(.gpif_clk(gpif_clk), .gpif_rst(gpif_rst),
.gpif_data(gpif_d), .gpif_wr(WR), .gpif_ep(EP),
.gpif_full_d(DF), .gpif_full_c(CF),
.sys_clk(fifo_clk), .sys_rst(fifo_rst),
.data_o(tx19_data), .src_rdy_o(tx19_src_rdy), .dst_rdy_i(tx19_dst_rdy),
.ctrl_o(ctrl_data), .ctrl_src_rdy_o(ctrl_src_rdy), .ctrl_dst_rdy_i(ctrl_dst_rdy),
.debug(debug_wr) );
// join vita packets which are longer than one frame, drop frame padding
wire [18:0] refr_data;
wire refr_src_rdy, refr_dst_rdy;
packet_reframer tx_packet_reframer
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
.data_i(tx19_data), .src_rdy_i(tx19_src_rdy), .dst_rdy_o(tx19_dst_rdy),
.data_o(refr_data), .src_rdy_o(refr_src_rdy), .dst_rdy_i(refr_dst_rdy));
fifo19_to_fifo36 #(.LE(1)) f19_to_f36
(.clk(fifo_clk), .reset(fifo_rst), .clear(0),
.f19_datain(refr_data), .f19_src_rdy_i(refr_src_rdy), .f19_dst_rdy_o(refr_dst_rdy),
.f36_dataout(tx36_data), .f36_src_rdy_o(tx36_src_rdy), .f36_dst_rdy_i(tx36_dst_rdy));
fifo_cascade #(.WIDTH(36), .SIZE(TXFIFOSIZE)) tx_fifo36
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
.datain(tx36_data), .src_rdy_i(tx36_src_rdy), .dst_rdy_o(tx36_dst_rdy),
.dataout(tx_data_o), .src_rdy_o(tx_src_rdy_o), .dst_rdy_i(tx_dst_rdy_i));
// ////////////////////////////////////////////
// RX Data Path
wire [35:0] rx36_data;
wire rx36_src_rdy, rx36_dst_rdy;
wire [18:0] rx19_data, splt_data;
wire rx19_src_rdy, rx19_dst_rdy, splt_src_rdy, splt_dst_rdy;
wire [18:0] resp_data, resp_int1, resp_int2;
wire resp_src_rdy, resp_dst_rdy;
wire resp_src_rdy_int1, resp_dst_rdy_int1, resp_src_rdy_int2, resp_dst_rdy_int2;
fifo_cascade #(.WIDTH(36), .SIZE(RXFIFOSIZE)) rx_fifo36
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
.datain(rx_data_i), .src_rdy_i(rx_src_rdy_i), .dst_rdy_o(rx_dst_rdy_o),
.dataout(rx36_data), .src_rdy_o(rx36_src_rdy), .dst_rdy_i(rx36_dst_rdy));
fifo36_to_fifo19 #(.LE(1)) f36_to_f19
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
.f36_datain(rx36_data), .f36_src_rdy_i(rx36_src_rdy), .f36_dst_rdy_o(rx36_dst_rdy),
.f19_dataout(rx19_data), .f19_src_rdy_o(rx19_src_rdy), .f19_dst_rdy_i(rx19_dst_rdy) );
packet_splitter #(.FRAME_LEN(256)) packet_splitter
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
.frames_per_packet(frames_per_packet),
.data_i(rx19_data), .src_rdy_i(rx19_src_rdy), .dst_rdy_o(rx19_dst_rdy),
.data_o(splt_data), .src_rdy_o(splt_src_rdy), .dst_rdy_i(splt_dst_rdy),
.debug0(debug_split0), .debug1(debug_split1));
gpif_rd gpif_rd
(.gpif_clk(gpif_clk), .gpif_rst(gpif_rst),
.gpif_data(gpif_d_out), .gpif_rd(RD), .gpif_ep(EP),
.gpif_empty_d(DE), .gpif_empty_c(CE), .gpif_flush(gpif_misc[0]),
.sys_clk(fifo_clk), .sys_rst(fifo_rst),
.data_i(splt_data), .src_rdy_i(splt_src_rdy), .dst_rdy_o(splt_dst_rdy),
.resp_i(resp_data), .resp_src_rdy_i(resp_src_rdy), .resp_dst_rdy_o(resp_dst_rdy),
.debug(debug_rd) );
// ////////////////////////////////////////////////////////////////////
// FIFO to Wishbone interface
fifo_to_wb fifo_to_wb
(.clk(fifo_clk), .reset(fifo_rst), .clear(0),
.data_i(ctrl_data), .src_rdy_i(ctrl_src_rdy), .dst_rdy_o(ctrl_dst_rdy),
.data_o(resp_int1), .src_rdy_o(resp_src_rdy_int1), .dst_rdy_i(resp_dst_rdy_int1),
.wb_adr_o(wb_adr_o), .wb_dat_mosi(wb_dat_mosi), .wb_dat_miso(wb_dat_miso), .wb_sel_o(wb_sel_o),
.wb_cyc_o(wb_cyc_o), .wb_stb_o(wb_stb_o), .wb_we_o(wb_we_o), .wb_ack_i(wb_ack_i),
.triggers(triggers),
.debug0(), .debug1());
wire [18:0] tx_err19_data;
wire tx_err19_src_rdy, tx_err19_dst_rdy;
fifo36_to_fifo19 #(.LE(1)) f36_to_f19_txerr
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
.f36_datain(tx_err_data_i), .f36_src_rdy_i(tx_err_src_rdy_i), .f36_dst_rdy_o(tx_err_dst_rdy_o),
.f19_dataout(tx_err19_data), .f19_src_rdy_o(tx_err19_src_rdy), .f19_dst_rdy_i(tx_err19_dst_rdy) );
fifo19_mux #(.prio(0)) mux_err_stream
(.clk(wb_clk), .reset(wb_rst), .clear(0),
.data0_i(resp_int1), .src0_rdy_i(resp_src_rdy_int1), .dst0_rdy_o(resp_dst_rdy_int1),
.data1_i(tx_err19_data), .src1_rdy_i(tx_err19_src_rdy), .dst1_rdy_o(tx_err19_dst_rdy),
.data_o(resp_int2), .src_rdy_o(resp_src_rdy_int2), .dst_rdy_i(resp_dst_rdy_int2));
fifo19_pad #(.LENGTH(16)) fifo19_pad
(.clk(fifo_clk), .reset(fifo_rst), .clear(0),
.data_i(resp_int2), .src_rdy_i(resp_src_rdy_int2), .dst_rdy_o(resp_dst_rdy_int2),
.data_o(resp_data), .src_rdy_o(resp_src_rdy), .dst_rdy_i(resp_dst_rdy));
// ////////////////////////////////////////////
// DEBUG
//assign debug0 = { rx19_src_rdy, rx19_dst_rdy, resp_src_rdy, resp_dst_rdy, gpif_ctl[3:0], gpif_rdy[3:0],
// gpif_d_copy[15:0] };
//assign debug1 = { { debug_rd[15:8] },
// { debug_rd[7:0] },
// { rx_src_rdy_i, rx_dst_rdy_o, rx36_src_rdy, rx36_dst_rdy, rx19_src_rdy, rx19_dst_rdy, resp_src_rdy, resp_dst_rdy},
// { tx_src_rdy_o, tx_dst_rdy_i, tx19_src_rdy, tx19_dst_rdy, tx36_src_rdy, tx36_dst_rdy, ctrl_src_rdy, ctrl_dst_rdy} };
assign debug0 = { gpif_ctl[3:0], gpif_rdy[3:0], debug_split0[23:0] };
assign debug1 = { gpif_misc[0], debug_rd[14:0], debug_split1[15:8], debug_split1[7:0] };
endmodule // gpif

View File

@@ -1,111 +0,0 @@
//
// Copyright 2011 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
module gpif_rd
(input gpif_clk, input gpif_rst,
output [15:0] gpif_data, input gpif_rd, input gpif_ep,
output reg gpif_empty_d, output reg gpif_empty_c,
output reg gpif_flush,
input sys_clk, input sys_rst,
input [18:0] data_i, input src_rdy_i, output dst_rdy_o,
input [18:0] resp_i, input resp_src_rdy_i, output resp_dst_rdy_o,
output [31:0] debug
);
wire [18:0] data_o; // occ bit indicates flush
wire [17:0] resp_o; // no occ bit
wire final_rdy_data, final_rdy_resp;
// 33/257 Bug Fix
reg [8:0] read_count;
always @(negedge gpif_clk)
if(gpif_rst)
read_count <= 0;
else if(gpif_rd)
read_count <= read_count + 1;
else
read_count <= 0;
// Data Path
wire [18:0] data_int;
wire src_rdy_int, dst_rdy_int;
fifo_2clock_cascade #(.WIDTH(19), .SIZE(4)) rd_fifo_2clk
(.wclk(sys_clk), .datain(data_i[18:0]), .src_rdy_i(src_rdy_i), .dst_rdy_o(dst_rdy_o), .space(),
.rclk(~gpif_clk), .dataout(data_int), .src_rdy_o(src_rdy_int), .dst_rdy_i(dst_rdy_int), .occupied(),
.arst(sys_rst));
reg [7:0] packet_count;
wire consume_data_line = gpif_rd & ~gpif_ep & ~read_count[8];
wire produce_eop = src_rdy_int & dst_rdy_int & data_int[17];
wire consume_sop = consume_data_line & final_rdy_data & data_o[16];
wire consume_eop = consume_data_line & final_rdy_data & data_o[17];
fifo_cascade #(.WIDTH(19), .SIZE(10)) rd_fifo
(.clk(~gpif_clk), .reset(gpif_rst), .clear(0),
.datain(data_int), .src_rdy_i(src_rdy_int), .dst_rdy_o(dst_rdy_int), .space(),
.dataout(data_o), .src_rdy_o(final_rdy_data), .dst_rdy_i(consume_data_line), .occupied());
always @(negedge gpif_clk)
if(gpif_rst)
packet_count <= 0;
else
if(produce_eop & ~consume_sop)
packet_count <= packet_count + 1;
else if(consume_sop & ~produce_eop)
packet_count <= packet_count - 1;
always @(negedge gpif_clk)
if(gpif_rst)
gpif_empty_d <= 1;
else
gpif_empty_d <= ~|packet_count;
// Use occ bit to signal a gpif flush
always @(negedge gpif_clk)
if(gpif_rst)
gpif_flush <= 0;
else if(consume_eop & data_o[18])
gpif_flush <= ~gpif_flush;
// Response Path
wire [15:0] resp_fifolevel;
wire consume_resp_line = gpif_rd & gpif_ep & ~read_count[4];
fifo_2clock_cascade #(.WIDTH(18), .SIZE(4)) resp_fifo_2clk
(.wclk(sys_clk), .datain(resp_i[17:0]), .src_rdy_i(resp_src_rdy_i), .dst_rdy_o(resp_dst_rdy_o), .space(),
.rclk(~gpif_clk), .dataout(resp_o),
.src_rdy_o(final_rdy_resp), .dst_rdy_i(consume_resp_line), .occupied(resp_fifolevel),
.arst(sys_rst));
// FIXME -- handle short packets
always @(negedge gpif_clk)
if(gpif_rst)
gpif_empty_c <= 1;
else
gpif_empty_c <= resp_fifolevel < 16;
// Output Mux
assign gpif_data = gpif_ep ? resp_o[15:0] : data_o[15:0];
assign debug = { { 16'd0 },
{ data_int[17:16], data_o[17:16], packet_count[3:0] },
{ consume_sop, consume_eop, final_rdy_data, data_o[18], consume_data_line, consume_resp_line, src_rdy_int, dst_rdy_int} };
endmodule // gpif_rd

View File

@@ -1,142 +0,0 @@
//
// Copyright 2011 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
module gpif_tb();
reg sys_clk = 0;
reg sys_rst = 1;
reg gpif_clk = 0;
reg gpif_rst = 1;
reg [15:0] gpif_data;
reg WR = 0, EP = 0;
wire CF, DF;
wire gpif_full_d, gpif_full_c;
wire [18:0] data_o, ctrl_o, data_splt;
wire src_rdy, dst_rdy, src_rdy_splt, dst_rdy_splt;
wire ctrl_src_rdy, ctrl_dst_rdy;
assign ctrl_dst_rdy = 1;
initial $dumpfile("gpif_tb.vcd");
initial $dumpvars(0,gpif_tb);
initial #1000 gpif_rst = 0;
initial #1000 sys_rst = 0;
always #64 gpif_clk <= ~gpif_clk;
always #47.9 sys_clk <= ~sys_clk;
wire [18:0] data_int;
wire src_rdy_int, dst_rdy_int;
assign dst_rdy_splt = 1;
gpif_wr gpif_write
(.gpif_clk(gpif_clk), .gpif_rst(gpif_rst),
.gpif_data(gpif_data), .gpif_wr(WR), .gpif_ep(EP),
.gpif_full_d(DF), .gpif_full_c(CF),
.sys_clk(sys_clk), .sys_rst(sys_rst),
.data_o(data_int), .src_rdy_o(src_rdy_int), .dst_rdy_i(dst_rdy_int),
.ctrl_o(ctrl_o), .ctrl_src_rdy_o(ctrl_src_rdy), .ctrl_dst_rdy_i(ctrl_dst_rdy) );
packet_reframer tx_packet_reframer
(.clk(sys_clk), .reset(sys_rst), .clear(0),
.data_i(data_int), .src_rdy_i(src_rdy_int), .dst_rdy_o(dst_rdy_int),
.data_o(data_o), .src_rdy_o(src_rdy), .dst_rdy_i(dst_rdy));
packet_splitter #(.FRAME_LEN(256)) rx_packet_splitter
(.clk(sys_clk), .reset(sys_rst), .clear(0),
.frames_per_packet(2),
.data_i(data_o), .src_rdy_i(src_rdy), .dst_rdy_o(dst_rdy),
.data_o(data_splt), .src_rdy_o(src_rdy_splt), .dst_rdy_i(dst_rdy_splt));
always @(posedge sys_clk)
if(ctrl_src_rdy & ctrl_dst_rdy)
$display("CTRL: %x",ctrl_o);
always @(posedge sys_clk)
if(src_rdy_splt & dst_rdy_splt)
begin
if(data_splt[16])
$display("<-------- DATA SOF--------->");
$display("DATA: %x",data_splt);
if(data_splt[17])
$display("<-------- DATA EOF--------->");
end
initial
begin
#10000;
repeat (1)
begin
@(posedge gpif_clk);
WR <= 1;
gpif_data <= 256; // Length
@(posedge gpif_clk);
gpif_data <= 16'h00;
@(posedge gpif_clk);
repeat(254)
begin
gpif_data <= gpif_data + 1;
@(posedge gpif_clk);
end
WR <= 0;
while(DF)
@(posedge gpif_clk);
repeat (16)
@(posedge gpif_clk);
WR <= 1;
repeat(256)
begin
gpif_data <= gpif_data - 1;
@(posedge gpif_clk);
end
WR <= 0;
/*
while(DF)
@(posedge gpif_clk);
repeat (20)
@(posedge gpif_clk);
WR <= 1;
gpif_data <= 16'h5;
@(posedge gpif_clk);
gpif_data <= 16'h00;
@(posedge gpif_clk);
repeat(254)
begin
gpif_data <= gpif_data - 1;
@(posedge gpif_clk);
end
WR <= 0;
*/
end
end // initial begin
initial #200000 $finish;
endmodule // gpif_tb

View File

@@ -1,95 +0,0 @@
//
// Copyright 2011 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
module gpif_wr
(input gpif_clk, input gpif_rst,
input [15:0] gpif_data, input gpif_wr, input gpif_ep,
output reg gpif_full_d, output reg gpif_full_c,
input sys_clk, input sys_rst,
output [18:0] data_o, output src_rdy_o, input dst_rdy_i,
output [18:0] ctrl_o, output ctrl_src_rdy_o, input ctrl_dst_rdy_i,
output [31:0] debug );
reg wr_reg, ep_reg;
reg [15:0] gpif_data_reg;
always @(posedge gpif_clk)
begin
ep_reg <= gpif_ep;
wr_reg <= gpif_wr;
gpif_data_reg <= gpif_data;
end
reg [9:0] write_count;
always @(posedge gpif_clk)
if(gpif_rst)
write_count <= 0;
else if(wr_reg)
write_count <= write_count + 1;
else
write_count <= 0;
reg sop;
wire eop = (write_count == 255);
wire eop_ctrl = (write_count == 15);
always @(posedge gpif_clk)
sop <= gpif_wr & ~wr_reg;
// Data Path
wire [15:0] fifo_space;
always @(posedge gpif_clk)
if(gpif_rst)
gpif_full_d <= 1;
else
gpif_full_d <= fifo_space < 256;
wire [17:0] data_int;
wire src_rdy_int, dst_rdy_int;
fifo_cascade #(.WIDTH(18), .SIZE(10)) wr_fifo
(.clk(gpif_clk), .reset(gpif_rst), .clear(0),
.datain({eop,sop,gpif_data_reg}), .src_rdy_i(~ep_reg & wr_reg & ~write_count[8]), .dst_rdy_o(), .space(fifo_space),
.dataout(data_int), .src_rdy_o(src_rdy_int), .dst_rdy_i(dst_rdy_int), .occupied());
fifo_2clock_cascade #(.WIDTH(18), .SIZE(4)) wr_fifo_2clk
(.wclk(gpif_clk), .datain(data_int), .src_rdy_i(src_rdy_int), .dst_rdy_o(dst_rdy_int), .space(),
.rclk(sys_clk), .dataout(data_o[17:0]), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i), .occupied(),
.arst(sys_rst));
assign data_o[18] = 1'b0;
// Control Path
wire [15:0] ctrl_fifo_space;
always @(posedge gpif_clk)
if(gpif_rst)
gpif_full_c <= 1;
else
gpif_full_c <= ctrl_fifo_space < 16;
fifo_2clock_cascade #(.WIDTH(19), .SIZE(4)) ctrl_fifo_2clk
(.wclk(gpif_clk), .datain({1'b0,eop_ctrl,sop,gpif_data_reg}),
.src_rdy_i(ep_reg & wr_reg & ~write_count[4]), .dst_rdy_o(), .space(ctrl_fifo_space),
.rclk(sys_clk), .dataout(ctrl_o[18:0]),
.src_rdy_o(ctrl_src_rdy_o), .dst_rdy_i(ctrl_dst_rdy_i), .occupied(),
.arst(sys_rst));
assign debug = { 16'd0, ep_reg, wr_reg, eop, sop, (~ep_reg & wr_reg & ~write_count[8]), src_rdy_int, dst_rdy_int, write_count[8:0]};
endmodule // gpif_wr

View File

@@ -1,110 +0,0 @@
//
// Copyright 2011 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
module gpif_wr_tb();
reg sys_clk = 0;
reg sys_rst = 1;
reg gpif_clk = 0;
reg gpif_rst = 1;
reg [15:0] gpif_data;
reg WR = 0, EP = 0;
wire CF, DF;
wire gpif_full_d, gpif_full_c;
wire [18:0] data_o, ctrl_o;
wire src_rdy, dst_rdy;
wire ctrl_src_rdy, ctrl_dst_rdy;
assign ctrl_dst_rdy = 1;
assign dst_rdy = 1;
initial $dumpfile("gpif_wr_tb.vcd");
initial $dumpvars(0,gpif_wr_tb);
initial #1000 gpif_rst = 0;
initial #1000 sys_rst = 0;
always #64 gpif_clk <= ~gpif_clk;
always #47.9 sys_clk <= ~sys_clk;
wire [18:0] data_int;
wire src_rdy_int, dst_rdy_int;
gpif_wr gpif_write
(.gpif_clk(gpif_clk), .gpif_rst(gpif_rst),
.gpif_data(gpif_data), .gpif_wr(WR), .gpif_ep(EP),
.gpif_full_d(DF), .gpif_full_c(CF),
.sys_clk(sys_clk), .sys_rst(sys_rst),
.data_o(data_int), .src_rdy_o(src_rdy_int), .dst_rdy_i(dst_rdy_int),
.ctrl_o(ctrl_o), .ctrl_src_rdy_o(ctrl_src_rdy), .ctrl_dst_rdy_i(ctrl_dst_rdy) );
packet_reframer tx_packet_reframer
(.clk(sys_clk), .reset(sys_rst), .clear(0),
.data_i(data_int), .src_rdy_i(src_rdy_int), .dst_rdy_o(dst_rdy_int),
.data_o(data_o), .src_rdy_o(src_rdy), .dst_rdy_i(dst_rdy));
always @(posedge sys_clk)
if(ctrl_src_rdy & ctrl_dst_rdy)
$display("CTRL: %x",ctrl_o);
always @(posedge sys_clk)
if(src_rdy & dst_rdy)
begin
if(data_o[16])
$display("<-------- DATA SOF--------->");
$display("DATA: %x",data_o);
if(data_o[17])
$display("<-------- DATA EOF--------->");
end
initial
begin
#10000;
repeat (1)
begin
WR <= 1;
gpif_data <= 10; // Length
@(posedge gpif_clk);
gpif_data <= 16'h00;
@(posedge gpif_clk);
repeat(254)
begin
gpif_data <= gpif_data + 1;
@(posedge gpif_clk);
end
WR <= 0;
repeat (20)
@(posedge gpif_clk);
WR <= 1;
gpif_data <= 16'h5;
@(posedge gpif_clk);
repeat(254)
begin
gpif_data <= gpif_data - 1;
@(posedge gpif_clk);
end
end
end // initial begin
initial #100000 $finish;
endmodule // gpif_wr_tb

View File

@@ -1,2 +0,0 @@
iverilog -Wall -y . -y ../fifo/ -y ../control_lib/ -y ../models/ -y ../coregen/ -y ../simple_gemac/ -y ../sdr_lib/ -y ../vrt/ gpif.v 2>&1 | grep -v coregen | grep -v models

View File

@@ -1,79 +0,0 @@
//
// Copyright 2011 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// Join vita packets longer than one GPIF frame, drop padding on short frames
module packet_reframer
(input clk, input reset, input clear,
input [18:0] data_i,
input src_rdy_i,
output dst_rdy_o,
output [18:0] data_o,
output src_rdy_o,
input dst_rdy_i);
reg [1:0] state;
reg [15:0] length;
localparam RF_IDLE = 0;
localparam RF_PKT = 1;
localparam RF_DUMP = 2;
always @(posedge clk)
if(reset | clear)
state <= 0;
else
if(src_rdy_i & dst_rdy_i)
case(state)
RF_IDLE :
begin
length <= {data_i[14:0],1'b0};
state <= RF_PKT;
end
RF_PKT :
begin
if(length == 2)
if(data_i[17])
state <= RF_IDLE;
else
state <= RF_DUMP;
else
length <= length - 1;
end
RF_DUMP :
if(data_i[17])
state <= RF_IDLE;
default :
state<= RF_IDLE;
endcase // case (state)
assign dst_rdy_o = dst_rdy_i; // this is a little pessimistic but ok
assign src_rdy_o = src_rdy_i & (state != RF_DUMP);
wire occ_out = 0;
wire eof_out = (state == RF_PKT) & (length == 2);
wire sof_out = (state == RF_IDLE);
wire [15:0] data_out = data_i[15:0];
assign data_o = {occ_out, eof_out, sof_out, data_out};
endmodule // packet_reframer

View File

@@ -1,123 +0,0 @@
//
// Copyright 2011 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// Split vita packets longer than one GPIF frame, add padding on short frames
module packet_splitter
#(parameter FRAME_LEN=256)
(input clk, input reset, input clear,
input [7:0] frames_per_packet,
input [18:0] data_i,
input src_rdy_i,
output dst_rdy_o,
output [18:0] data_o,
output src_rdy_o,
input dst_rdy_i,
output [31:0] debug0,
output [31:0] debug1);
reg [1:0] state;
reg [15:0] length;
reg [15:0] frame_len;
reg [7:0] frame_count;
localparam PS_IDLE = 0;
localparam PS_FRAME = 1;
localparam PS_NEW_FRAME = 2;
localparam PS_PAD = 3;
wire eof_i = data_i[17];
always @(posedge clk)
if(reset | clear)
begin
state <= PS_IDLE;
frame_count <= 0;
end
else
case(state)
PS_IDLE :
if(src_rdy_i & dst_rdy_i)
begin
length <= { data_i[14:0],1'b0};
frame_len <= FRAME_LEN;
state <= PS_FRAME;
frame_count <= 1;
end
PS_FRAME :
if(src_rdy_i & dst_rdy_i)
if((frame_len == 2) & ((length == 2) | eof_i))
state <= PS_IDLE;
else if(frame_len == 2)
begin
length <= length - 1;
state <= PS_NEW_FRAME;
frame_count <= frame_count + 1;
end
else if((length == 2)|eof_i)
begin
frame_len <= frame_len - 1;
state <= PS_PAD;
end
else
begin
frame_len <= frame_len - 1;
length <= length - 1;
end
PS_NEW_FRAME :
if(src_rdy_i & dst_rdy_i)
begin
frame_len <= FRAME_LEN;
if((length == 2)|eof_i)
state <= PS_PAD;
else
begin
state <= PS_FRAME;
length <= length - 1;
end // else: !if((length == 2)|eof_i)
end // if (src_rdy_i & dst_rdy_i)
PS_PAD :
if(dst_rdy_i)
if(frame_len == 2)
state <= PS_IDLE;
else
frame_len <= frame_len - 1;
endcase // case (state)
wire next_state_is_idle = dst_rdy_i & (frame_len==2) &
( (state==PS_PAD) | ( (state==PS_FRAME) & src_rdy_i & ((length==2)|eof_i) ) );
assign dst_rdy_o = dst_rdy_i & (state != PS_PAD);
assign src_rdy_o = src_rdy_i | (state == PS_PAD);
wire eof_out = (frame_len == 2) & (state != PS_IDLE) & (state != PS_NEW_FRAME);
wire sof_out = (state == PS_IDLE) | (state == PS_NEW_FRAME);
wire occ_out = eof_out & next_state_is_idle & (frames_per_packet != frame_count);
wire [15:0] data_out = data_i[15:0];
assign data_o = {occ_out, eof_out, sof_out, data_out};
assign debug0 = { 8'd0, dst_rdy_o, src_rdy_o, next_state_is_idle, eof_out, sof_out, occ_out, state[1:0], frame_count[7:0], frames_per_packet[7:0] };
assign debug1 = { length[15:0], frame_len[15:0] };
endmodule // packet_splitter

View File

@@ -1,137 +0,0 @@
//
// Copyright 2011 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
module packet_splitter_tb();
reg sys_clk = 0;
reg sys_rst = 1;
reg gpif_clk = 0;
reg gpif_rst = 1;
reg [15:0] gpif_data;
reg WR = 0, EP = 0;
wire CF, DF;
wire gpif_full_d, gpif_full_c;
wire [18:0] data_o, ctrl_o, data_splt;
wire src_rdy, dst_rdy, src_rdy_splt, dst_rdy_splt;
wire ctrl_src_rdy, ctrl_dst_rdy;
assign ctrl_dst_rdy = 1;
initial $dumpfile("packet_splitter_tb.vcd");
initial $dumpvars(0,packet_splitter_tb);
initial #1000 gpif_rst = 0;
initial #1000 sys_rst = 0;
always #64 gpif_clk <= ~gpif_clk;
always #47.9 sys_clk <= ~sys_clk;
wire [35:0] data_int;
wire src_rdy_int, dst_rdy_int;
assign dst_rdy_splt = 1;
vita_pkt_gen vita_pkt_gen
(.clk(sys_clk), .reset(sys_rst) , .clear(0),
.len(512),.data_o(data_int), .src_rdy_o(src_rdy_int), .dst_rdy_i(dst_rdy_int));
fifo36_to_fifo19 #(.LE(1)) f36_to_f19
(.clk(sys_clk), .reset(sys_rst), .clear(0),
.f36_datain(data_int), .f36_src_rdy_i(src_rdy_int), .f36_dst_rdy_o(dst_rdy_int),
.f19_dataout(data_o), .f19_src_rdy_o(src_rdy), .f19_dst_rdy_i(dst_rdy));
packet_splitter #(.FRAME_LEN(13)) rx_packet_splitter
(.clk(sys_clk), .reset(sys_rst), .clear(0),
.frames_per_packet(4),
.data_i(data_o), .src_rdy_i(src_rdy), .dst_rdy_o(dst_rdy),
.data_o(data_splt), .src_rdy_o(src_rdy_splt), .dst_rdy_i(dst_rdy_splt));
always @(posedge sys_clk)
if(ctrl_src_rdy & ctrl_dst_rdy)
$display("CTRL: %x",ctrl_o);
always @(posedge sys_clk)
if(src_rdy_splt & dst_rdy_splt)
begin
if(data_splt[16])
$display("<-------- DATA SOF--------->");
$display("DATA: %x",data_splt);
if(data_splt[17])
$display("<-------- DATA EOF--------->");
end
initial
begin
#10000;
repeat (1)
begin
@(posedge gpif_clk);
WR <= 1;
gpif_data <= 256; // Length
@(posedge gpif_clk);
gpif_data <= 16'h00;
@(posedge gpif_clk);
repeat(254)
begin
gpif_data <= gpif_data + 1;
@(posedge gpif_clk);
end
WR <= 0;
while(DF)
@(posedge gpif_clk);
repeat (16)
@(posedge gpif_clk);
WR <= 1;
repeat(256)
begin
gpif_data <= gpif_data - 1;
@(posedge gpif_clk);
end
WR <= 0;
/*
while(DF)
@(posedge gpif_clk);
repeat (20)
@(posedge gpif_clk);
WR <= 1;
gpif_data <= 16'h5;
@(posedge gpif_clk);
gpif_data <= 16'h00;
@(posedge gpif_clk);
repeat(254)
begin
gpif_data <= gpif_data - 1;
@(posedge gpif_clk);
end
WR <= 0;
*/
end
end // initial begin
initial #200000 $finish;
endmodule // packet_splitter_tb

View File

@@ -1,2 +0,0 @@
*.gif

View File

@@ -1,14 +0,0 @@
#
# Copyright 2010-2011 Ettus Research LLC
#
##################################################
# GPMC Sources
##################################################
GPMC_SRCS = $(abspath $(addprefix $(BASE_DIR)/../gpmc/, \
cross_clock_reader.v \
fifo_to_gpmc.v \
gpmc.v \
gpmc_to_fifo.v \
gpmc_wb.v \
))

View File

@@ -1,42 +0,0 @@
//
// Copyright 2011 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
module cross_clock_reader
#(
parameter WIDTH = 1,
parameter DEFAULT = 0
)
(
input clk, input rst,
input [WIDTH-1:0] in,
output reg [WIDTH-1:0] out
);
reg [WIDTH-1:0] shadow;
always @(posedge clk) begin
if (rst) begin
out <= DEFAULT;
shadow <= DEFAULT;
end
else if (shadow == in) begin
out <= shadow;
end
shadow <= in;
end
endmodule //cross_clock_reader

View File

@@ -1,159 +0,0 @@
//
// Copyright 2011 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
////////////////////////////////////////////////////////////////////////
// FIFO to GPMC
//
// Reads frames from FIFO interface and writes them into BRAM pages.
// The GPMC is asynchronously alerted when a BRAM page has been filled.
//
// EM_CLK:
// A GPMC read transaction consists of two EM_CLK cycles (idle low).
//
// EM_OE:
// Output enable is actually the combination of ~NOE & ~NCS.
// The output enable is only active for the second rising edge,
// to ensure one edge per transaction to transition on.
//
// EM_D:
// The BRAM performs a read on the first rising edge into EM_D.
// Then, data will then be read on the next rising edge by GPMC.
//
// EM_A:
// On the first rising edge of EM_CLK, the address is held.
// On the second rising edge, the address is set for the next transaction.
////////////////////////////////////////////////////////////////////////
module fifo_to_gpmc
#(parameter PTR_WIDTH = 2, parameter ADDR_WIDTH = 10)
(input clk, input reset, input clear, input arst,
input [17:0] data_i, input src_rdy_i, output dst_rdy_o,
output [15:0] EM_D, input [ADDR_WIDTH:1] EM_A, input EM_CLK, input EM_OE,
output reg data_available);
//states for the GPMC side of things
wire [17:0] data_o;
reg gpmc_state;
reg [ADDR_WIDTH:1] addr;
reg [PTR_WIDTH:0] gpmc_ptr, next_gpmc_ptr;
localparam GPMC_STATE_START = 0;
localparam GPMC_STATE_EMPTY = 1;
//states for the FIFO side of things
reg fifo_state;
reg [ADDR_WIDTH-1:0] counter;
reg [PTR_WIDTH:0] fifo_ptr;
localparam FIFO_STATE_CLAIM = 0;
localparam FIFO_STATE_FILL = 1;
//------------------------------------------------------------------
// State machine to control the data from GPMC to BRAM
//------------------------------------------------------------------
always @(posedge EM_CLK or posedge arst) begin
if (arst) begin
gpmc_state <= GPMC_STATE_START;
gpmc_ptr <= 0;
next_gpmc_ptr <= 0;
addr <= 0;
end
else if (EM_OE) begin
addr <= EM_A + 1;
case(gpmc_state)
GPMC_STATE_START: begin
if (EM_A == 0) begin
gpmc_state <= GPMC_STATE_EMPTY;
next_gpmc_ptr <= gpmc_ptr + 1;
end
end
GPMC_STATE_EMPTY: begin
if (EM_A == 10'h3ff) begin
gpmc_state <= GPMC_STATE_START;
gpmc_ptr <= next_gpmc_ptr;
end
end
endcase //gpmc_state
end //EM_WE
end //always
//------------------------------------------------------------------
// High when the gpmc pointer has not caught up to the fifo pointer.
//------------------------------------------------------------------
wire [PTR_WIDTH:0] safe_gpmc_ptr;
cross_clock_reader #(.WIDTH(PTR_WIDTH+1)) read_gpmc_ptr
(.clk(clk), .rst(reset | clear), .in(gpmc_ptr), .out(safe_gpmc_ptr));
wire bram_available_to_fill = (fifo_ptr ^ (1 << PTR_WIDTH)) != safe_gpmc_ptr;
//------------------------------------------------------------------
// Glich free generation of data available signal:
// Data is available when the pointers dont match.
//------------------------------------------------------------------
wire [PTR_WIDTH:0] safe_next_gpmc_ptr;
cross_clock_reader #(.WIDTH(PTR_WIDTH+1)) read_next_gpmc_ptr
(.clk(clk), .rst(reset | clear), .in(next_gpmc_ptr), .out(safe_next_gpmc_ptr));
always @(posedge clk)
if (reset | clear) data_available <= 0;
else data_available <= safe_next_gpmc_ptr != fifo_ptr;
//------------------------------------------------------------------
// State machine to control the data from BRAM to FIFO
//------------------------------------------------------------------
always @(posedge clk) begin
if (reset | clear) begin
fifo_state <= FIFO_STATE_CLAIM;
fifo_ptr <= 0;
counter <= 0;
end
else begin
case(fifo_state)
FIFO_STATE_CLAIM: begin
if (bram_available_to_fill) fifo_state <= FIFO_STATE_FILL;
counter <= 0;
end
FIFO_STATE_FILL: begin
if (src_rdy_i && dst_rdy_o && data_i[17]) begin
fifo_state <= FIFO_STATE_CLAIM;
fifo_ptr <= fifo_ptr + 1;
end
if (src_rdy_i && dst_rdy_o) begin
counter <= counter + 1;
end
end
endcase //fifo_state
end
end //always
assign dst_rdy_o = fifo_state == FIFO_STATE_FILL;
//assign data from bram output
assign EM_D = data_o[15:0];
//instantiate dual ported bram for async read + write
ram_2port #(.DWIDTH(18),.AWIDTH(PTR_WIDTH + ADDR_WIDTH)) async_fifo_bram
(.clka(clk),.ena(1'b1),.wea(src_rdy_i && dst_rdy_o),
.addra({fifo_ptr[PTR_WIDTH-1:0], counter}),.dia(data_i),.doa(),
.clkb(EM_CLK),.enb(1'b1),.web(1'b0),
.addrb({gpmc_ptr[PTR_WIDTH-1:0], addr}),.dib(18'h3ffff),.dob(data_o));
endmodule // fifo_to_gpmc

View File

@@ -1,159 +0,0 @@
//
// Copyright 2011 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
//////////////////////////////////////////////////////////////////////////////////
module gpmc
#(parameter TXFIFOSIZE = 11,
parameter RXFIFOSIZE = 11,
parameter ADDR_WIDTH = 10,
parameter BUSDEBUG = 1)
(// GPMC signals
input arst,
input EM_CLK, inout [15:0] EM_D, input [ADDR_WIDTH:1] EM_A, input [1:0] EM_NBE,
input EM_WAIT0, input EM_NCS4, input EM_NCS6, input EM_NWE, input EM_NOE,
// GPIOs for FIFO signalling
output rx_have_data, output tx_have_space,
// Wishbone signals
input wb_clk, input wb_rst,
output [ADDR_WIDTH:0] wb_adr_o, output [15:0] wb_dat_mosi, input [15:0] wb_dat_miso,
output [1:0] wb_sel_o, output wb_cyc_o, output wb_stb_o, output wb_we_o, input wb_ack_i,
// FIFO interface
input fifo_clk, input fifo_rst, input clear_tx, input clear_rx,
output [35:0] tx_data_o, output tx_src_rdy_o, input tx_dst_rdy_i,
input [35:0] rx_data_i, input rx_src_rdy_i, output rx_dst_rdy_o,
output tx_underrun, output rx_overrun,
input [7:0] test_rate, input [3:0] test_ctrl,
output [31:0] debug
);
wire EM_output_enable = (~EM_NOE & (~EM_NCS4 | ~EM_NCS6));
wire [15:0] EM_D_fifo;
wire [15:0] EM_D_wb;
assign EM_D = ~EM_output_enable ? 16'bz : ~EM_NCS4 ? EM_D_fifo : EM_D_wb;
// CS4 is RAM_2PORT for DATA PATH (high-speed data)
// Writes go into one RAM, reads come from the other
// CS6 is for CONTROL PATH (wishbone)
// ////////////////////////////////////////////
// TX Data Path
wire [17:0] tx18_data;
wire tx18_src_rdy, tx18_dst_rdy;
wire [35:0] tx_data, txb_data;
wire tx_src_rdy, tx_dst_rdy;
wire txb_src_rdy, txb_dst_rdy;
gpmc_to_fifo #(.ADDR_WIDTH(ADDR_WIDTH)) gpmc_to_fifo
(.EM_D(EM_D), .EM_A(EM_A), .EM_CLK(EM_CLK), .EM_WE(~EM_NCS4 & ~EM_NWE),
.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx), .arst(fifo_rst | clear_tx | arst),
.data_o(tx18_data), .src_rdy_o(tx18_src_rdy), .dst_rdy_i(tx18_dst_rdy),
.have_space(tx_have_space));
fifo19_to_fifo36 #(.LE(1)) f19_to_f36 // Little endian because ARM is LE
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
.f19_datain({1'b0,tx18_data}), .f19_src_rdy_i(tx18_src_rdy), .f19_dst_rdy_o(tx18_dst_rdy),
.f36_dataout(txb_data), .f36_src_rdy_o(txb_src_rdy), .f36_dst_rdy_i(txb_dst_rdy));
fifo_cascade #(.WIDTH(36), .SIZE(TXFIFOSIZE)) tx_buffering(
.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
.datain(txb_data), .src_rdy_i(txb_src_rdy), .dst_rdy_o(txb_dst_rdy),
.dataout(tx_data), .src_rdy_o(tx_src_rdy), .dst_rdy_i(tx_dst_rdy)
);
// ////////////////////////////////////////////
// RX Data Path
wire [17:0] rx18_data;
wire rx18_src_rdy, rx18_dst_rdy;
wire [35:0] rx_data, rxb_data;
wire rx_src_rdy, rx_dst_rdy;
wire rxb_src_rdy, rxb_dst_rdy;
wire dummy;
fifo_cascade #(.WIDTH(36), .SIZE(RXFIFOSIZE)) rx_buffering(
.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
.datain(rx_data), .src_rdy_i(rx_src_rdy), .dst_rdy_o(rx_dst_rdy),
.dataout(rxb_data), .src_rdy_o(rxb_src_rdy), .dst_rdy_i(rxb_dst_rdy)
);
fifo36_to_fifo19 #(.LE(1)) f36_to_f19 // Little endian because ARM is LE
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
.f36_datain(rxb_data), .f36_src_rdy_i(rxb_src_rdy), .f36_dst_rdy_o(rxb_dst_rdy),
.f19_dataout({dummy,rx18_data}), .f19_src_rdy_o(rx18_src_rdy), .f19_dst_rdy_i(rx18_dst_rdy) );
fifo_to_gpmc #(.ADDR_WIDTH(ADDR_WIDTH)) fifo_to_gpmc
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx), .arst(fifo_rst | clear_rx | arst),
.data_i(rx18_data), .src_rdy_i(rx18_src_rdy), .dst_rdy_o(rx18_dst_rdy),
.EM_D(EM_D_fifo), .EM_A(EM_A), .EM_CLK(EM_CLK), .EM_OE(~EM_NCS4 & ~EM_NOE),
.data_available(rx_have_data));
// ////////////////////////////////////////////
// Control path on CS6
gpmc_wb gpmc_wb
(.EM_CLK(EM_CLK), .EM_D_in(EM_D), .EM_D_out(EM_D_wb), .EM_A(EM_A), .EM_NBE(EM_NBE),
.EM_WE(~EM_NCS6 & ~EM_NWE), .EM_OE(~EM_NCS6 & ~EM_NOE),
.wb_clk(wb_clk), .wb_rst(wb_rst),
.wb_adr_o(wb_adr_o), .wb_dat_mosi(wb_dat_mosi), .wb_dat_miso(wb_dat_miso),
.wb_sel_o(wb_sel_o), .wb_cyc_o(wb_cyc_o), .wb_stb_o(wb_stb_o), .wb_we_o(wb_we_o),
.wb_ack_i(wb_ack_i) );
// ////////////////////////////////////////////
// Test support, traffic generator, loopback, etc.
// RX side muxes test data into the same stream
wire [35:0] loopbackrx_data, testrx_data;
wire [35:0] loopbacktx_data, testtx_data;
wire loopbackrx_src_rdy, loopbackrx_dst_rdy;
wire loopbacktx_src_rdy, loopbacktx_dst_rdy;
wire sel_testtx = test_ctrl[0];
fifo36_mux rx_test_mux_lvl_2
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
.data0_i(loopbackrx_data), .src0_rdy_i(loopbackrx_src_rdy), .dst0_rdy_o(loopbackrx_dst_rdy),
.data1_i(rx_data_i), .src1_rdy_i(rx_src_rdy_i), .dst1_rdy_o(rx_dst_rdy_o),
.data_o(rx_data), .src_rdy_o(rx_src_rdy), .dst_rdy_i(rx_dst_rdy));
fifo_short #(.WIDTH(36)) loopback_fifo
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx | clear_rx),
.datain(loopbacktx_data), .src_rdy_i(loopbacktx_src_rdy), .dst_rdy_o(loopbacktx_dst_rdy),
.dataout(loopbackrx_data), .src_rdy_o(loopbackrx_src_rdy), .dst_rdy_i(loopbackrx_dst_rdy));
// Crossbar used as a demux for switching TX stream to main DSP or to test logic
crossbar36 tx_crossbar_lvl_1
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
.cross(sel_testtx),
.data0_i(tx_data), .src0_rdy_i(tx_src_rdy), .dst0_rdy_o(tx_dst_rdy),
.data1_i(tx_data), .src1_rdy_i(1'b0), .dst1_rdy_o(), // No 2nd input
.data0_o(tx_data_o), .src0_rdy_o(tx_src_rdy_o), .dst0_rdy_i(tx_dst_rdy_i),
.data1_o(loopbacktx_data), .src1_rdy_o(loopbacktx_src_rdy), .dst1_rdy_i(loopbacktx_dst_rdy) );
assign debug = {
EM_D, //16
EM_A, //10
EM_CLK, EM_NCS4, EM_NWE, EM_NOE, //4
EM_NCS6, wb_ack_i
};
endmodule // gpmc

View File

@@ -1,157 +0,0 @@
//
// Copyright 2011 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
////////////////////////////////////////////////////////////////////////
// GPMC to FIFO
//
// Reads frames from BRAM pages and writes them into FIFO interface.
// The GPMC is asynchronously alerted when a BRAM page is available.
//
// EM_CLK:
// A GPMC read transaction consists of one EM_CLK cycle (idle low).
//
// EM_WE:
// Write enable is actually the combination of ~NWE & ~NCS.
// The write enable is active for the entire transaction.
//
// EM_D:
// Data is set on the rising edge and written into BRAM on the falling edge.
//
// EM_A:
// Address is set on the rising edge and read by BRAM on the falling edge.
////////////////////////////////////////////////////////////////////////
module gpmc_to_fifo
#(parameter PTR_WIDTH = 2, parameter ADDR_WIDTH = 10)
(input [15:0] EM_D, input [ADDR_WIDTH:1] EM_A, input EM_CLK, input EM_WE,
input clk, input reset, input clear, input arst,
output [17:0] data_o, output src_rdy_o, input dst_rdy_i,
output reg have_space);
//states for the GPMC side of things
wire [17:0] data_i;
reg gpmc_state;
reg [ADDR_WIDTH:1] last_addr;
reg [PTR_WIDTH:0] gpmc_ptr, next_gpmc_ptr;
localparam GPMC_STATE_START = 0;
localparam GPMC_STATE_FILL = 1;
//states for the FIFO side of things
reg fifo_state;
reg [ADDR_WIDTH-1:0] counter;
reg [PTR_WIDTH:0] fifo_ptr;
localparam FIFO_STATE_CLAIM = 0;
localparam FIFO_STATE_EMPTY = 1;
//------------------------------------------------------------------
// State machine to control the data from GPMC to BRAM
//------------------------------------------------------------------
always @(negedge EM_CLK or posedge arst) begin
if (arst) begin
gpmc_state <= GPMC_STATE_START;
gpmc_ptr <= 0;
next_gpmc_ptr <= 0;
end
else if (EM_WE) begin
case(gpmc_state)
GPMC_STATE_START: begin
if (EM_A == 0) begin
gpmc_state <= GPMC_STATE_FILL;
last_addr <= {EM_D[ADDR_WIDTH-2:0], 1'b0} - 1'b1;
next_gpmc_ptr <= gpmc_ptr + 1;
end
end
GPMC_STATE_FILL: begin
if (data_i[17]) begin
gpmc_state <= GPMC_STATE_START;
gpmc_ptr <= next_gpmc_ptr;
end
end
endcase //gpmc_state
end //EM_WE
end //always
//------------------------------------------------------------------
// A block ram is available to empty when the pointers dont match.
//------------------------------------------------------------------
wire [PTR_WIDTH:0] safe_gpmc_ptr;
cross_clock_reader #(.WIDTH(PTR_WIDTH+1)) read_gpmc_ptr
(.clk(clk), .rst(reset | clear), .in(gpmc_ptr), .out(safe_gpmc_ptr));
wire bram_available_to_empty = safe_gpmc_ptr != fifo_ptr;
//------------------------------------------------------------------
// Glich free generation of have space signal:
// High when the fifo pointer has not caught up to the gpmc pointer.
//------------------------------------------------------------------
wire [PTR_WIDTH:0] safe_next_gpmc_ptr;
cross_clock_reader #(.WIDTH(PTR_WIDTH+1)) read_next_gpmc_ptr
(.clk(clk), .rst(reset | clear), .in(next_gpmc_ptr), .out(safe_next_gpmc_ptr));
always @(posedge clk)
if (reset | clear) have_space <= 0;
else have_space <= (fifo_ptr ^ (1 << PTR_WIDTH)) != safe_next_gpmc_ptr;
//------------------------------------------------------------------
// State machine to control the data from BRAM to FIFO
//------------------------------------------------------------------
always @(posedge clk) begin
if (reset | clear) begin
fifo_state <= FIFO_STATE_CLAIM;
fifo_ptr <= 0;
counter <= 0;
end
else begin
case(fifo_state)
FIFO_STATE_CLAIM: begin
if (bram_available_to_empty) fifo_state <= FIFO_STATE_EMPTY;
counter <= 0;
end
FIFO_STATE_EMPTY: begin
if (src_rdy_o && dst_rdy_i && data_o[17]) begin
fifo_state <= FIFO_STATE_CLAIM;
fifo_ptr <= fifo_ptr + 1;
end
if (src_rdy_o && dst_rdy_i) begin
counter <= counter + 1;
end
end
endcase //fifo_state
end
end //always
assign src_rdy_o = fifo_state == FIFO_STATE_EMPTY;
//assign data and frame bits to bram input
assign data_i[15:0] = EM_D;
assign data_i[16] = (gpmc_state == GPMC_STATE_START);
assign data_i[17] = (EM_A == last_addr);
//instantiate dual ported bram for async read + write
ram_2port #(.DWIDTH(18),.AWIDTH(PTR_WIDTH + ADDR_WIDTH)) async_fifo_bram
(.clka(~EM_CLK),.ena(1'b1),.wea(EM_WE),
.addra({gpmc_ptr[PTR_WIDTH-1:0], EM_A}),.dia(data_i),.doa(),
.clkb(~clk),.enb(1'b1),.web(1'b0),
.addrb({fifo_ptr[PTR_WIDTH-1:0], counter}),.dib(18'h3ffff),.dob(data_o));
endmodule // gpmc_to_fifo

View File

@@ -1,79 +0,0 @@
//
// Copyright 2011 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
module gpmc_wb
(input EM_CLK, input [15:0] EM_D_in, output [15:0] EM_D_out, input [10:1] EM_A, input [1:0] EM_NBE,
input EM_WE, input EM_OE,
input wb_clk, input wb_rst,
output reg [10:0] wb_adr_o, output reg [15:0] wb_dat_mosi, input [15:0] wb_dat_miso,
output reg [1:0] wb_sel_o, output wb_cyc_o, output reg wb_stb_o, output reg wb_we_o, input wb_ack_i);
// ////////////////////////////////////////////
// Control Path, Wishbone bus bridge (wb master)
reg [1:0] we_del, oe_del;
// Synchronize the async control signals
always @(posedge wb_clk)
if (wb_rst) begin
we_del <= 2'b0;
oe_del <= 2'b0;
end
else begin
we_del <= { we_del[0], EM_WE };
oe_del <= { oe_del[0], EM_OE };
end
wire writing = we_del == 2'b01;
wire reading = oe_del == 2'b01;
always @(posedge wb_clk)
if(writing || reading)
wb_adr_o <= { EM_A, 1'b0 };
always @(posedge wb_clk)
if(writing)
begin
wb_dat_mosi <= EM_D_in;
wb_sel_o <= ~EM_NBE;
end
reg [15:0] EM_D_hold;
always @(posedge wb_clk)
if(wb_ack_i)
EM_D_hold <= wb_dat_miso;
assign EM_D_out = wb_ack_i ? wb_dat_miso : EM_D_hold;
assign wb_cyc_o = wb_stb_o;
always @(posedge wb_clk)
if(writing)
wb_we_o <= 1;
else if(wb_ack_i) // Turn off we when done. Could also use we_del[0], others...
wb_we_o <= 0;
always @(posedge wb_clk)
if(writing || reading)
wb_stb_o <= 1;
else if(wb_ack_i)
wb_stb_o <= 0;
endmodule // gpmc_wb

View File

@@ -1,5 +1,5 @@
#
# Copyright 2010 Ettus Research LLC
# Copyright 2010-2012 Ettus Research LLC
#
##################################################
@@ -23,10 +23,10 @@ clip_reg.v \
cordic.v \
cordic_z24.v \
cordic_stage.v \
dsp_core_rx.v \
dsp_core_tx.v \
ddc_chain.v \
duc_chain.v \
dspengine_16to8.v \
frontend_sw.v \
dspengine_8to16.v \
hb_dec.v \
hb_interp.v \
pipectrl.v \
@@ -40,4 +40,7 @@ sign_extend.v \
small_hb_dec.v \
small_hb_int.v \
tx_frontend.v \
dsp_tx_glue.v \
dsp_rx_glue.v \
frontend_sw.v \
))

View File

@@ -119,8 +119,6 @@ module cordic_z24(clock, reset, enable, xi, yi, zi, xo, yo, zo );
assign xo = x20[bitwidth:1];
assign yo = y20[bitwidth:1];
assign zo = z20;
//assign xo = x20[bitwidth+1:2]; // CORDIC gain is ~1.6, plus gain from rotating vectors
//assign yo = y20[bitwidth+1:2];
endmodule // cordic

190
fpga/sdr_lib/ddc_chain.v Normal file
View File

@@ -0,0 +1,190 @@
//
// Copyright 2011-2012 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
//! The USRP digital down-conversion chain
module ddc_chain
#(
parameter BASE = 0,
parameter DSPNO = 0,
parameter WIDTH = 24
)
(input clk, input rst, input clr,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user,
// From RX frontend
input [WIDTH-1:0] rx_fe_i,
input [WIDTH-1:0] rx_fe_q,
// To RX control
output [31:0] sample,
input run,
output strobe,
output [31:0] debug
);
localparam cwidth = 25;
localparam zwidth = 24;
wire ddc_enb;
wire [31:0] phase_inc;
reg [31:0] phase;
wire [17:0] scale_factor;
wire [cwidth-1:0] i_cordic, q_cordic;
wire [WIDTH-1:0] i_cordic_clip, q_cordic_clip;
wire [WIDTH-1:0] i_cic, q_cic;
wire [WIDTH-1:0] i_hb1, q_hb1;
wire [WIDTH-1:0] i_hb2, q_hb2;
wire strobe_cic, strobe_hb1, strobe_hb2;
wire enable_hb1, enable_hb2;
wire [7:0] cic_decim_rate;
reg [WIDTH-1:0] rx_fe_i_mux, rx_fe_q_mux;
wire realmode;
wire swap_iq;
setting_reg #(.my_addr(BASE+0)) sr_0
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(phase_inc),.changed());
setting_reg #(.my_addr(BASE+1), .width(18)) sr_1
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(scale_factor),.changed());
setting_reg #(.my_addr(BASE+2), .width(10)) sr_2
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out({enable_hb1, enable_hb2, cic_decim_rate}),.changed());
setting_reg #(.my_addr(BASE+3), .width(2)) sr_3
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out({realmode,swap_iq}),.changed());
// MUX so we can do realmode signals on either input
always @(posedge clk)
if(swap_iq)
begin
rx_fe_i_mux <= rx_fe_q;
rx_fe_q_mux <= realmode ? 0 : rx_fe_i;
end
else
begin
rx_fe_i_mux <= rx_fe_i;
rx_fe_q_mux <= realmode ? 0 : rx_fe_q;
end
// NCO
always @(posedge clk)
if(rst)
phase <= 0;
else if(~ddc_enb)
phase <= 0;
else
phase <= phase + phase_inc;
//sign extension of cordic input
wire [WIDTH-1:0] to_ddc_chain_i, to_ddc_chain_q;
wire [cwidth-1:0] to_cordic_i, to_cordic_q;
sign_extend #(.bits_in(WIDTH), .bits_out(cwidth)) sign_extend_cordic_i (.in(to_ddc_chain_i), .out(to_cordic_i));
sign_extend #(.bits_in(WIDTH), .bits_out(cwidth)) sign_extend_cordic_q (.in(to_ddc_chain_q), .out(to_cordic_q));
// CORDIC 24-bit I/O
cordic_z24 #(.bitwidth(cwidth))
cordic(.clock(clk), .reset(rst), .enable(ddc_enb),
.xi(to_cordic_i),. yi(to_cordic_q), .zi(phase[31:32-zwidth]),
.xo(i_cordic),.yo(q_cordic),.zo() );
clip_reg #(.bits_in(cwidth), .bits_out(WIDTH)) clip_i
(.clk(clk), .in(i_cordic), .strobe_in(1'b1), .out(i_cordic_clip));
clip_reg #(.bits_in(cwidth), .bits_out(WIDTH)) clip_q
(.clk(clk), .in(q_cordic), .strobe_in(1'b1), .out(q_cordic_clip));
// CIC decimator 24 bit I/O
cic_strober cic_strober(.clock(clk),.reset(rst),.enable(ddc_enb),.rate(cic_decim_rate),
.strobe_fast(1),.strobe_slow(strobe_cic) );
cic_decim #(.bw(WIDTH))
decim_i (.clock(clk),.reset(rst),.enable(ddc_enb),
.rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic),
.signal_in(i_cordic_clip),.signal_out(i_cic));
cic_decim #(.bw(WIDTH))
decim_q (.clock(clk),.reset(rst),.enable(ddc_enb),
.rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic),
.signal_in(q_cordic_clip),.signal_out(q_cic));
// First (small) halfband 24 bit I/O
small_hb_dec #(.WIDTH(WIDTH)) small_hb_i
(.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(ddc_enb),
.stb_in(strobe_cic),.data_in(i_cic),.stb_out(strobe_hb1),.data_out(i_hb1));
small_hb_dec #(.WIDTH(WIDTH)) small_hb_q
(.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(ddc_enb),
.stb_in(strobe_cic),.data_in(q_cic),.stb_out(),.data_out(q_hb1));
// Second (large) halfband 24 bit I/O
wire [8:0] cpi_hb = enable_hb1 ? {cic_decim_rate,1'b0} : {1'b0,cic_decim_rate};
hb_dec #(.WIDTH(WIDTH)) hb_i
(.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(ddc_enb),.cpi(cpi_hb),
.stb_in(strobe_hb1),.data_in(i_hb1),.stb_out(strobe_hb2),.data_out(i_hb2));
hb_dec #(.WIDTH(WIDTH)) hb_q
(.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(ddc_enb),.cpi(cpi_hb),
.stb_in(strobe_hb1),.data_in(q_hb1),.stb_out(),.data_out(q_hb2));
//scalar operation (gain of 6 bits)
wire [35:0] prod_i, prod_q;
MULT18X18S mult_i
(.P(prod_i), .A(i_hb2[WIDTH-1:WIDTH-18]), .B(scale_factor), .C(clk), .CE(strobe_hb2), .R(rst) );
MULT18X18S mult_q
(.P(prod_q), .A(q_hb2[WIDTH-1:WIDTH-18]), .B(scale_factor), .C(clk), .CE(strobe_hb2), .R(rst) );
//pipeline for the multiplier (gain of 10 bits)
reg [WIDTH-1:0] prod_reg_i, prod_reg_q;
reg strobe_mult;
always @(posedge clk) begin
strobe_mult <= strobe_hb2;
prod_reg_i <= prod_i[33:34-WIDTH];
prod_reg_q <= prod_q[33:34-WIDTH];
end
// Round final answer to 16 bits
wire [31:0] ddc_chain_out;
wire ddc_chain_stb;
round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(16)) round_i
(.clk(clk),.reset(rst), .in(prod_reg_i),.strobe_in(strobe_mult), .out(ddc_chain_out[31:16]), .strobe_out(ddc_chain_stb));
round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(16)) round_q
(.clk(clk),.reset(rst), .in(prod_reg_q),.strobe_in(strobe_mult), .out(ddc_chain_out[15:0]), .strobe_out());
dsp_rx_glue #(.DSPNO(DSPNO), .WIDTH(WIDTH)) custom(
.clock(clk), .reset(rst), .clear(clr), .enable(run),
.set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user),
.frontend_i(rx_fe_i_mux), .frontend_q(rx_fe_q_mux),
.ddc_in_i(to_ddc_chain_i), .ddc_in_q(to_ddc_chain_q),
.ddc_out_sample(ddc_chain_out), .ddc_out_strobe(ddc_chain_stb), .ddc_out_enable(ddc_enb),
.bb_sample(sample), .bb_strobe(strobe));
assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_hb1, strobe_hb2};
endmodule // ddc_chain

View File

@@ -1,6 +1,6 @@
`timescale 1ns/1ns
module dsp_core_rx_tb();
module ddc_chain_tb();
reg clk, rst;
@@ -9,8 +9,8 @@ module dsp_core_rx_tb();
initial clk = 0;
always #5 clk = ~clk;
initial $dumpfile("dsp_core_rx_tb.vcd");
initial $dumpvars(0,dsp_core_rx_tb);
initial $dumpfile("ddc_chain_tb.vcd");
initial $dumpvars(0,ddc_chain_tb);
reg signed [23:0] adc_in;
wire signed [15:0] adc_out_i, adc_out_q;
@@ -27,7 +27,7 @@ module dsp_core_rx_tb();
reg [7:0] set_addr;
reg [31:0] set_data;
dsp_core_rx #(.BASE(0)) dsp_core_rx
ddc_chain #(.BASE(0)) ddc_chain
(.clk(clk),.rst(rst),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
.adc_i(adc_in), .adc_ovf_i(0),
@@ -70,4 +70,4 @@ module dsp_core_rx_tb();
adc_in <= adc_in + 4;
//adc_in <= (($random % 473) + 23)/4;
*/
endmodule // dsp_core_rx_tb
endmodule // ddc_chain_tb

View File

@@ -0,0 +1,98 @@
//
// Copyright 2012 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
//The following module effects the IO of the DDC chain.
//By default, this entire module is a simple pass-through.
module dsp_rx_glue
#(
//the dsp unit number: 0, 1, 2...
parameter DSPNO = 0,
//frontend bus width
parameter WIDTH = 24
)
(
//control signals
input clock, input reset, input clear, input enable,
//user settings bus, controlled through user setting regs API
input set_stb, input [7:0] set_addr, input [31:0] set_data,
//full rate inputs directly from the RX frontend
input [WIDTH-1:0] frontend_i,
input [WIDTH-1:0] frontend_q,
//full rate outputs directly to the DDC chain
output [WIDTH-1:0] ddc_in_i,
output [WIDTH-1:0] ddc_in_q,
//strobed samples {I16,Q16} from the RX DDC chain
input [31:0] ddc_out_sample,
input ddc_out_strobe, //high on valid sample
output ddc_out_enable, //enables DDC module
//strobbed baseband samples {I16,Q16} from this module
output [31:0] bb_sample,
output bb_strobe, //high on valid sample
//debug output (optional)
output [31:0] debug
);
generate
if (DSPNO==0) begin
`ifndef RX_DSP0_MODULE
assign ddc_in_i = frontend_i;
assign ddc_in_q = frontend_q;
assign bb_sample = ddc_out_sample;
assign bb_strobe = ddc_out_strobe;
assign ddc_out_enable = enable;
`else
`RX_DSP0_MODULE #(.WIDTH(WIDTH)) rx_dsp0_custom
(
.clock(clock), .reset(reset), .clear(clear), .enable(enable),
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
.frontend_i(frontend_i), .frontend_q(frontend_q),
.ddc_in_i(ddc_in_i), .ddc_in_q(ddc_in_q),
.ddc_out_sample(ddc_out_sample), .ddc_out_strobe(ddc_out_strobe), .ddc_out_enable(ddc_out_enable),
.bb_sample(bb_sample), .bb_strobe(bb_strobe)
);
`endif
end
else begin
`ifndef RX_DSP1_MODULE
assign ddc_in_i = frontend_i;
assign ddc_in_q = frontend_q;
assign bb_sample = ddc_out_sample;
assign bb_strobe = ddc_out_strobe;
assign ddc_out_enable = enable;
`else
`RX_DSP1_MODULE #(.WIDTH(WIDTH)) rx_dsp1_custom
(
.clock(clock), .reset(reset), .clear(clear), .enable(enable),
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
.frontend_i(frontend_i), .frontend_q(frontend_q),
.ddc_in_i(ddc_in_i), .ddc_in_q(ddc_in_q),
.ddc_out_sample(ddc_out_sample), .ddc_out_strobe(ddc_out_strobe), .ddc_out_enable(ddc_out_enable),
.bb_sample(bb_sample), .bb_strobe(bb_strobe)
);
`endif
end
endgenerate
endmodule //dsp_rx_glue

View File

@@ -0,0 +1,98 @@
//
// Copyright 2012 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
//The following module effects the IO of the DUC chain.
//By default, this entire module is a simple pass-through.
module dsp_tx_glue
#(
//the dsp unit number: 0, 1, 2...
parameter DSPNO = 0,
//frontend bus width
parameter WIDTH = 24
)
(
//control signals
input clock, input reset, input clear, input enable,
//user settings bus, controlled through user setting regs API
input set_stb, input [7:0] set_addr, input [31:0] set_data,
//full rate outputs directly to the TX frontend
output [WIDTH-1:0] frontend_i,
output [WIDTH-1:0] frontend_q,
//full rate outputs directly from the DUC chain
input [WIDTH-1:0] duc_out_i,
input [WIDTH-1:0] duc_out_q,
//strobed samples {I16,Q16} to the TX DUC chain
output [31:0] duc_in_sample,
input duc_in_strobe, //this is a backpressure signal
output duc_in_enable, //enables DUC module
//strobbed baseband samples {I16,Q16} to this module
input [31:0] bb_sample,
output bb_strobe, //this is a backpressure signal
//debug output (optional)
output [31:0] debug
);
generate
if (DSPNO==0) begin
`ifndef TX_DSP0_MODULE
assign frontend_i = duc_out_i;
assign frontend_q = duc_out_q;
assign duc_in_sample = bb_sample;
assign bb_strobe = duc_in_strobe;
assign duc_in_enable = enable;
`else
`TX_DSP0_MODULE #(.WIDTH(WIDTH)) tx_dsp0_custom
(
.clock(clock), .reset(reset), .clear(clear), .enable(enable),
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
.frontend_i(frontend_i), .frontend_q(frontend_q),
.duc_out_i(duc_out_i), .duc_out_q(duc_out_q),
.duc_in_sample(duc_in_sample), .duc_in_strobe(duc_in_strobe), .duc_in_enable(duc_in_enable),
.bb_sample(bb_sample), .bb_strobe(bb_strobe)
);
`endif
end
else begin
`ifndef TX_DSP1_MODULE
assign frontend_i = duc_out_i;
assign frontend_q = duc_out_q;
assign duc_in_sample = bb_sample;
assign bb_strobe = duc_in_strobe;
assign duc_in_enable = enable;
`else
`TX_DSP1_MODULE #(.WIDTH(WIDTH)) tx_dsp1_custom
(
.clock(clock), .reset(reset), .clear(clear), .enable(enable),
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
.frontend_i(frontend_i), .frontend_q(frontend_q),
.duc_out_i(duc_out_i), .duc_out_q(duc_out_q),
.duc_in_sample(duc_in_sample), .duc_in_strobe(duc_in_strobe), .duc_in_enable(duc_in_enable),
.bb_sample(bb_sample), .bb_strobe(bb_strobe)
);
`endif
end
endgenerate
endmodule //dsp_tx_glue

View File

@@ -1,5 +1,5 @@
// Copyright 2011 Ettus Research LLC
// Copyright 2011-2013 Ettus Research LLC
//
// 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
@@ -32,13 +32,11 @@ module dspengine_16to8
input [35:0] access_dat_i
);
wire convert;
wire [17:0] scale_factor;
setting_reg #(.my_addr(BASE),.width(19)) sr_16to8
wire convert;
setting_reg #(.my_addr(BASE),.width(1)) sr_16to8
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out({convert,scale_factor}),.changed());
.in(set_data),.out(convert),.changed());
reg [2:0] dsp_state;
localparam DSP_IDLE = 0;
localparam DSP_PARSE_HEADER = 1;
@@ -63,7 +61,7 @@ module dspengine_16to8
wire [15:0] scaled_i, scaled_q;
wire [7:0] i8, q8;
reg [7:0] i8_reg, q8_reg;
wire stb_read, stb_mult, stb_clip, stb_round, val_read, val_mult, val_clip, val_round;
wire stb_read, stb_clip, val_read, val_clip;
wire stb_out, stb_reg;
reg even;
@@ -183,8 +181,8 @@ module dspengine_16to8
assign access_dat_o = (dsp_state == DSP_WRITE_HEADER) ? { 4'h1, new_header } :
(dsp_state == DSP_WRITE_TRAILER) ? { 4'h2, new_trailer } :
(last_o&~even_o) ? {4'h0, 16'd0, i8, q8 } :
{4'h0, i8, q8, i8_reg, q8_reg };
(last_o&~even_o) ? {4'h0, i8, q8, 16'd0 } :
{4'h0, i8_reg, q8_reg, i8, q8 };
assign access_adr = (stb_write|(dsp_state == DSP_WRITE_HEADER)|(dsp_state == DSP_WRITE_TRAILER)) ? write_adr : read_adr;
@@ -193,29 +191,21 @@ module dspengine_16to8
wire [15:0] i16 = access_dat_i[31:16];
wire [15:0] q16 = access_dat_i[15:0];
pipectrl #(.STAGES(4), .TAGWIDTH(2)) pipectrl
pipectrl #(.STAGES(2), .TAGWIDTH(2)) pipectrl
(.clk(clk), .reset(reset),
.src_rdy_i(send_to_pipe), .dst_rdy_o(), // dst_rdy_o will always be 1 since dst_rdy_i is 1, below
.src_rdy_o(stb_out), .dst_rdy_i(1), // always accept output of chain
.strobes({stb_round,stb_clip,stb_mult,stb_read}), .valids({val_round,val_clip,val_mult,val_read}),
.strobes({stb_clip,stb_read}), .valids({val_clip,val_read}),
.tag_i({last,even}), .tag_o({last_o,even_o}));
always @(posedge clk)
if(stb_out & ~even_o)
{i8_reg,q8_reg} <= {i8,q8};
MULT18X18S mult_i
(.P(prod_i), .A(scale_factor), .B({i16,2'b00}), .C(clk), .CE(stb_mult), .R(reset) );
clip_reg #(.bits_in(24),.bits_out(16),.STROBED(1)) clip_i
(.clk(clk), .in(prod_i[35:12]), .out(scaled_i), .strobe_in(stb_clip), .strobe_out());
round_sd #(.WIDTH_IN(16),.WIDTH_OUT(8),.DISABLE_SD(1)) round_i
(.clk(clk), .reset(reset), .in(scaled_i), .strobe_in(stb_round), .out(i8), .strobe_out());
MULT18X18S mult_q
(.P(prod_q), .A(scale_factor), .B({q16,2'b00}), .C(clk), .CE(stb_mult), .R(reset) );
clip_reg #(.bits_in(24),.bits_out(16),.STROBED(1)) clip_q
(.clk(clk), .in(prod_q[35:12]), .out(scaled_q), .strobe_in(stb_clip), .strobe_out());
round_sd #(.WIDTH_IN(16),.WIDTH_OUT(8),.DISABLE_SD(1)) round_q
(.clk(clk), .reset(reset), .in(scaled_q), .strobe_in(stb_round), .out(q8), .strobe_out());
clip_reg #(.bits_in(16),.bits_out(8),.STROBED(1)) clip_i
(.clk(clk), .in(i16), .out(i8), .strobe_in(stb_clip), .strobe_out());
clip_reg #(.bits_in(16),.bits_out(8),.STROBED(1)) clip_q
(.clk(clk), .in(q16), .out(q8), .strobe_in(stb_clip), .strobe_out());
endmodule // dspengine_16to8

View File

@@ -0,0 +1,203 @@
// Copyright 2012-2013 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
module dspengine_8to16
#(parameter BASE = 0,
parameter BUF_SIZE = 9,
parameter HEADER_OFFSET = 0)
(input clk, input reset, input clear,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
output access_we,
output access_stb,
input access_ok,
output access_done,
output access_skip_read,
output [BUF_SIZE-1:0] access_adr,
input [BUF_SIZE-1:0] access_len,
output [35:0] access_dat_o,
input [35:0] access_dat_i
);
wire convert;
setting_reg #(.my_addr(BASE),.width(1)) sr_8to16
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(convert),.changed());
reg [3:0] dsp_state;
localparam DSP_IDLE = 0;
localparam DSP_IDLE_RD = 1;
localparam DSP_PARSE_HEADER = 2;
localparam DSP_READ = 3;
localparam DSP_READ_WAIT = 4;
localparam DSP_WRITE_1 = 5;
localparam DSP_WRITE_0 = 6;
localparam DSP_READ_TRAILER = 7;
localparam DSP_WRITE_TRAILER = 8;
localparam DSP_WRITE_HEADER = 9;
localparam DSP_DONE = 10;
// Parse VITA header
wire is_if_data = (access_dat_i[31:29] == 3'b000);
wire has_streamid = access_dat_i[28];
wire has_classid = access_dat_i[27];
wire has_trailer = access_dat_i[26];
// 25:24 reserved, aka SOB/EOB
wire has_secs = |access_dat_i[23:22];
wire has_tics = |access_dat_i[21:20];
wire [3:0] hdr_length = 1 + has_streamid + has_classid + has_classid + has_secs + has_tics + has_tics;
reg [15:0] hdr_length_reg;
reg odd;
reg [BUF_SIZE-1:0] read_adr, write_adr;
reg has_trailer_reg;
reg [31:0] new_header, new_trailer, trailer_mask;
reg wait_for_trailer;
reg [15:0] data_in_len;
wire is_odd = access_dat_i[22] & access_dat_i[10];
wire [15:0] data_in_lenx2 = {data_in_len[14:0], 1'b0} - is_odd;
reg [7:0] i8_0, q8_0;
wire [7:0] i8_1 = access_dat_i[15:8];
wire [7:0] q8_1 = access_dat_i[7:0];
reg skip;
always @(posedge clk)
{ i8_0, q8_0 } <= access_dat_i[31:16];
always @(posedge clk)
if(reset | clear)
dsp_state <= DSP_IDLE;
else
case(dsp_state)
DSP_IDLE :
begin
read_adr <= HEADER_OFFSET;
write_adr <= HEADER_OFFSET;
if(access_ok)
dsp_state <= DSP_IDLE_RD;
end
DSP_IDLE_RD: //extra idle state for read to become valid
dsp_state <= DSP_PARSE_HEADER;
DSP_PARSE_HEADER :
begin
has_trailer_reg <= has_trailer;
new_header[31:0] <= access_dat_i[31:0];
hdr_length_reg <= hdr_length;
if(~is_if_data | ~convert | ~has_trailer)
// ~convert is valid (16 bit mode) but both ~trailer and ~is_if_data are both
// really error conditions on the TX side. We shouldn't ever see them in the TX chain
dsp_state <= DSP_WRITE_HEADER;
else
begin
read_adr <= access_dat_i[15:0] + HEADER_OFFSET - 1; // point to trailer
dsp_state <= DSP_READ_TRAILER;
wait_for_trailer <= 0;
data_in_len <= access_dat_i[15:0] - hdr_length - 1 /*trailer*/;
end
end
DSP_READ_TRAILER :
begin
wait_for_trailer <= 1;
if(wait_for_trailer)
dsp_state <= DSP_WRITE_TRAILER;
new_trailer <= access_dat_i[31:0]; // Leave trailer unchanged
odd <= is_odd;
write_adr <= hdr_length_reg + data_in_lenx2 + HEADER_OFFSET;
end
DSP_WRITE_TRAILER :
begin
dsp_state <= DSP_READ;
write_adr <= write_adr - 1;
read_adr <= read_adr - 1;
new_header[15:0] <= write_adr + (1 - HEADER_OFFSET); // length = addr of trailer + 1
end
DSP_READ :
begin
read_adr <= read_adr - 1;
if(odd)
dsp_state <= DSP_READ_WAIT;
else
dsp_state <= DSP_WRITE_1;
odd <= 0;
end
DSP_READ_WAIT :
dsp_state <= DSP_WRITE_0;
DSP_WRITE_1 :
begin
write_adr <= write_adr - 1;
if(write_adr == (hdr_length_reg+HEADER_OFFSET))
begin
write_adr <= HEADER_OFFSET;
dsp_state <= DSP_WRITE_HEADER;
end
dsp_state <= DSP_WRITE_0;
end
DSP_WRITE_0 :
begin
write_adr <= write_adr - 1;
if(write_adr == (hdr_length_reg+HEADER_OFFSET))
begin
write_adr <= HEADER_OFFSET;
dsp_state <= DSP_WRITE_HEADER;
end
else
dsp_state <= DSP_READ;
end
DSP_WRITE_HEADER :
dsp_state <= DSP_DONE;
DSP_DONE :
begin
read_adr <= HEADER_OFFSET;
write_adr <= HEADER_OFFSET;
dsp_state <= DSP_IDLE;
end
endcase // case (dsp_state)
assign access_skip_read = 0;
assign access_done = (dsp_state == DSP_DONE);
assign access_stb = 1;
assign access_we = (dsp_state == DSP_WRITE_HEADER) |
(dsp_state == DSP_WRITE_TRAILER) |
(dsp_state == DSP_WRITE_0) |
(dsp_state == DSP_WRITE_1);
assign access_dat_o = (dsp_state == DSP_WRITE_HEADER) ? { 4'h0, new_header } :
(dsp_state == DSP_WRITE_TRAILER) ? { 4'h2, new_trailer } :
(dsp_state == DSP_WRITE_0) ? { 4'h0, i8_0, 8'd0, q8_0, 8'd0 } :
(dsp_state == DSP_WRITE_1) ? { 4'h0, i8_1, 8'd0, q8_1, 8'd0 } :
34'h0DEADBEEF;
assign access_adr = access_we ? write_adr : read_adr;
endmodule // dspengine_16to8

165
fpga/sdr_lib/duc_chain.v Normal file
View File

@@ -0,0 +1,165 @@
//
// Copyright 2011-2012 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
//! The USRP digital up-conversion chain
module duc_chain
#(
parameter BASE = 0,
parameter DSPNO = 0,
parameter WIDTH = 24
)
(input clk, input rst, input clr,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user,
// To TX frontend
output [WIDTH-1:0] tx_fe_i,
output [WIDTH-1:0] tx_fe_q,
// From TX control
input [31:0] sample,
input run,
output strobe,
output [31:0] debug
);
wire duc_enb;
wire [17:0] scale_factor;
wire [31:0] phase_inc;
reg [31:0] phase;
wire [7:0] interp_rate;
wire [3:0] tx_femux_a, tx_femux_b;
wire enable_hb1, enable_hb2;
wire rate_change;
setting_reg #(.my_addr(BASE+0)) sr_0
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(phase_inc),.changed());
setting_reg #(.my_addr(BASE+1), .width(18)) sr_1
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(scale_factor),.changed());
setting_reg #(.my_addr(BASE+2), .width(10)) sr_2
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out({enable_hb1, enable_hb2, interp_rate}),.changed(rate_change));
// Strobes are all now delayed by 1 cycle for timing reasons
wire strobe_cic_pre, strobe_hb1_pre, strobe_hb2_pre;
reg strobe_cic = 1;
reg strobe_hb1 = 1;
reg strobe_hb2 = 1;
cic_strober #(.WIDTH(8))
cic_strober(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(interp_rate),
.strobe_fast(1),.strobe_slow(strobe_cic_pre) );
cic_strober #(.WIDTH(2))
hb2_strober(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(enable_hb2 ? 2 : 1),
.strobe_fast(strobe_cic_pre),.strobe_slow(strobe_hb2_pre) );
cic_strober #(.WIDTH(2))
hb1_strober(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(enable_hb1 ? 2 : 1),
.strobe_fast(strobe_hb2_pre),.strobe_slow(strobe_hb1_pre) );
always @(posedge clk) strobe_hb1 <= strobe_hb1_pre;
always @(posedge clk) strobe_hb2 <= strobe_hb2_pre;
always @(posedge clk) strobe_cic <= strobe_cic_pre;
// NCO
always @(posedge clk)
if(rst)
phase <= 0;
else if(~duc_enb)
phase <= 0;
else
phase <= phase + phase_inc;
wire signed [17:0] da, db;
wire signed [35:0] prod_i, prod_q;
wire [15:0] bb_i;
wire [15:0] bb_q;
wire [17:0] i_interp, q_interp;
wire [17:0] hb1_i, hb1_q, hb2_i, hb2_q;
wire [7:0] cpo = enable_hb2 ? ({interp_rate,1'b0}) : interp_rate;
// Note that max CIC rate is 128, which would give an overflow on cpo if enable_hb2 is true,
// but the default case inside hb_interp handles this
hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(WIDTH)) hb_interp_i
(.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in({bb_i, 2'b0}),.stb_out(strobe_hb2),.data_out(hb1_i));
hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(WIDTH)) hb_interp_q
(.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in({bb_q, 2'b0}),.stb_out(strobe_hb2),.data_out(hb1_q));
small_hb_int #(.WIDTH(18)) small_hb_interp_i
(.clk(clk),.rst(rst),.bypass(~enable_hb2),.stb_in(strobe_hb2),.data_in(hb1_i),
.output_rate(interp_rate),.stb_out(strobe_cic),.data_out(hb2_i));
small_hb_int #(.WIDTH(18)) small_hb_interp_q
(.clk(clk),.rst(rst),.bypass(~enable_hb2),.stb_in(strobe_hb2),.data_in(hb1_q),
.output_rate(interp_rate),.stb_out(strobe_cic),.data_out(hb2_q));
cic_interp #(.bw(18),.N(4),.log2_of_max_rate(7))
cic_interp_i(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(interp_rate),
.strobe_in(strobe_cic),.strobe_out(1),
.signal_in(hb2_i),.signal_out(i_interp));
cic_interp #(.bw(18),.N(4),.log2_of_max_rate(7))
cic_interp_q(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(interp_rate),
.strobe_in(strobe_cic),.strobe_out(1),
.signal_in(hb2_q),.signal_out(q_interp));
localparam cwidth = WIDTH; // was 18
localparam zwidth = 24; // was 16
wire [cwidth-1:0] da_c, db_c;
cordic_z24 #(.bitwidth(cwidth))
cordic(.clock(clk), .reset(rst), .enable(duc_enb),
.xi({i_interp,{(cwidth-18){1'b0}}}),.yi({q_interp,{(cwidth-18){1'b0}}}),
.zi(phase[31:32-zwidth]),
.xo(da_c),.yo(db_c),.zo() );
MULT18X18S MULT18X18S_inst
(.P(prod_i), // 36-bit multiplier output
.A(da_c[cwidth-1:cwidth-18]), // 18-bit multiplier input
.B(scale_factor), // 18-bit multiplier input
.C(clk), // Clock input
.CE(1), // Clock enable input
.R(rst) // Synchronous reset input
);
MULT18X18S MULT18X18S_inst_2
(.P(prod_q), // 36-bit multiplier output
.A(db_c[cwidth-1:cwidth-18]), // 18-bit multiplier input
.B(scale_factor), // 18-bit multiplier input
.C(clk), // Clock input
.CE(1), // Clock enable input
.R(rst) // Synchronous reset input
);
dsp_tx_glue #(.DSPNO(DSPNO), .WIDTH(WIDTH)) dsp_tx_glue(
.clock(clk), .reset(rst), .clear(clr), .enable(run),
.set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user),
.frontend_i(tx_fe_i), .frontend_q(tx_fe_q),
.duc_out_i(prod_i[33:34-WIDTH]), .duc_out_q(prod_q[33:34-WIDTH]),
.duc_in_sample({bb_i, bb_q}), .duc_in_strobe(strobe_hb1), .duc_in_enable(duc_enb),
.bb_sample(sample), .bb_strobe(strobe));
assign debug = {strobe_cic, strobe_hb1, strobe_hb2,run};
endmodule // dsp_core

View File

@@ -76,4 +76,4 @@ module dummy_rx
q_out <= q_out + 1;
endmodule // dsp_core_rx
endmodule // ddc_chain

View File

@@ -3,7 +3,6 @@ module rx_frontend
#(parameter BASE = 0,
parameter IQCOMP_EN = 1)
(input clk, input rst,
input adc_clk,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
input [15:0] adc_a, input adc_ovf_a,
@@ -23,7 +22,7 @@ module rx_frontend
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(swap_iq),.changed());
always @(posedge adc_clk)
always @(posedge clk)
if(swap_iq) // Swap
{adc_i,adc_q} <= {adc_b,adc_a};
else
@@ -41,37 +40,37 @@ module rx_frontend
if(IQCOMP_EN == 1)
begin
rx_dcoffset #(.WIDTH(18),.ADDR(BASE+3)) rx_dcoffset_i
(.clk(adc_clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
(.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
.in({adc_i,2'b00}),.out(adc_i_ofs));
rx_dcoffset #(.WIDTH(18),.ADDR(BASE+4)) rx_dcoffset_q
(.clk(adc_clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
(.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
.in({adc_q,2'b00}),.out(adc_q_ofs));
MULT18X18S mult_mag_corr
(.P(corr_i), .A(adc_i_ofs), .B(mag_corr), .C(adc_clk), .CE(1), .R(rst) );
(.P(corr_i), .A(adc_i_ofs), .B(mag_corr), .C(clk), .CE(1), .R(rst) );
MULT18X18S mult_phase_corr
(.P(corr_q), .A(adc_i_ofs), .B(phase_corr), .C(adc_clk), .CE(1), .R(rst) );
(.P(corr_q), .A(adc_i_ofs), .B(phase_corr), .C(clk), .CE(1), .R(rst) );
add2_and_clip_reg #(.WIDTH(24)) add_clip_i
(.clk(adc_clk), .rst(rst),
(.clk(clk), .rst(rst),
.in1({adc_i_ofs,6'd0}), .in2(corr_i[35:12]), .strobe_in(1'b1),
.sum(i_out), .strobe_out());
add2_and_clip_reg #(.WIDTH(24)) add_clip_q
(.clk(adc_clk), .rst(rst),
(.clk(clk), .rst(rst),
.in1({adc_q_ofs,6'd0}), .in2(corr_q[35:12]), .strobe_in(1'b1),
.sum(q_out), .strobe_out());
end // if (IQCOMP_EN == 1)
else
begin
rx_dcoffset #(.WIDTH(24),.ADDR(BASE+3)) rx_dcoffset_i
(.clk(adc_clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
(.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
.in({adc_i,8'b00}),.out(i_out));
rx_dcoffset #(.WIDTH(24),.ADDR(BASE+4)) rx_dcoffset_q
(.clk(adc_clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
(.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
.in({adc_q,8'b00}),.out(q_out));
end // else: !if(IQCOMP_EN == 1)
endgenerate

View File

@@ -1,11 +1,7 @@
module tx_frontend
#(parameter BASE=0,
`ifndef LMS602D_FRONTEND
parameter WIDTH_OUT=16,
`else
parameter WIDTH_OUT=12,
`endif // !`ifndef LMS602D_FRONTEND
parameter IQCOMP_EN=1)
(input clk, input rst,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
@@ -47,18 +43,18 @@ module tx_frontend
begin
// IQ Balance
MULT18X18S mult_mag_corr
(.P(corr_i), .A(tx_i[23:6]), .B(mag_corr), .C(clk), .CE(1), .R(rst) );
(.P(corr_i), .A(tx_i[23:6]), .B(mag_corr), .C(clk), .CE(1), .R(rst) );
MULT18X18S mult_phase_corr
(.P(corr_q), .A(tx_i[23:6]), .B(phase_corr), .C(clk), .CE(1), .R(rst) );
add2_and_clip_reg #(.WIDTH(24)) add_clip_i
(.clk(clk), .rst(rst),
(.clk(clk), .rst(rst),
.in1(tx_i), .in2(corr_i[35:12]), .strobe_in(1'b1),
.sum(i_bal), .strobe_out());
add2_and_clip_reg #(.WIDTH(24)) add_clip_q
(.clk(clk), .rst(rst),
(.clk(clk), .rst(rst),
.in1(tx_q), .in2(corr_q[35:12]), .strobe_in(1'b1),
.sum(q_bal), .strobe_out());

View File

@@ -168,14 +168,14 @@ module u2plus_core
// FIFO Sizes, 9 = 512 lines, 10 = 1024, 11 = 2048
// all (most?) are 36 bits wide, so 9 is 1 BRAM, 10 is 2, 11 is 4 BRAMs
// localparam DSP_TX_FIFOSIZE = 9; unused -- DSPTX uses extram fifo
localparam DSP_RX_FIFOSIZE = 10;
localparam DSP_TX_FIFOSIZE = 10;
localparam ETH_TX_FIFOSIZE = 9;
localparam ETH_RX_FIFOSIZE = 11;
wire [7:0] set_addr, set_addr_dsp, set_addr_sys;
wire [31:0] set_data, set_data_dsp, set_data_sys;
wire set_stb, set_stb_dsp, set_stb_sys;
wire [7:0] set_addr, set_addr_dsp, set_addr_sys, set_addr_user;
wire [31:0] set_data, set_data_dsp, set_data_sys, set_data_user;
wire set_stb, set_stb_dsp, set_stb_sys, set_stb_user;
reg wb_rst;
wire dsp_rst, sys_rst;
@@ -619,7 +619,6 @@ module u2plus_core
rx_frontend #(.BASE(SR_RX_FRONT0)) rx_frontend0
(.clk(dsp_clk),.rst(dsp_rst),
.adc_clk(dsp_clk),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
.adc_a({adc0_a,4'b00}),.adc_ovf_a(adc_ovf_i_0_mux),
.adc_b({adc0_b,4'b00}),.adc_ovf_b(adc_ovf_q_0_mux),
@@ -627,7 +626,6 @@ module u2plus_core
rx_frontend #(.BASE(SR_RX_FRONT1)) rx_frontend1
(.clk(dsp_clk),.rst(dsp_rst),
.adc_clk(dsp_clk),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
.adc_a({adc1_a,4'b00}),.adc_ovf_a(adc_ovf_i_1_mux),
.adc_b({adc1_b,4'b00}),.adc_ovf_b(adc_ovf_q_1_mux),
@@ -650,77 +648,68 @@ module u2plus_core
// /////////////////////////////////////////////////////////////////////////
// DSP RX 0
wire [31:0] sample_rx0;
wire clear_rx0, strobe_rx0;
wire [31:0] sample_rx0;
wire strobe_rx0, clear_rx0;
wire [35:0] rx0_vita_data;
wire rx0_vita1_valid, rx0_vita1_ready;
wire rx0_vita_valid, rx0_vita_ready;
always @(posedge dsp_clk)
always @(posedge dsp_clk)
run_rx0_d1 <= run_rx0;
dsp_core_rx #(.BASE(SR_RX_DSP0)) dsp_core_rx0
(.clk(dsp_clk),.rst(dsp_rst),
.adc_clk(dsp_clk),
ddc_chain #(.BASE(SR_RX_DSP0), .DSPNO(0)) ddc_chain0
(.clk(dsp_clk), .rst(dsp_rst), .clr(clear_rx0),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
.adc_i(i_0_mux),.adc_ovf_i(adc_ovf_i_0_mux),.adc_q(q_0_mux),.adc_ovf_q(adc_ovf_q_0_mux),
.set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.rx_fe_i(i_0_mux),.rx_fe_q(q_0_mux),
.sample(sample_rx0), .run(run_rx0_d1), .strobe(strobe_rx0),
.debug() );
setting_reg #(.my_addr(SR_RX_CTRL0+3)) sr_clear_rx0
(.clk(dsp_clk),.rst(dsp_rst),
.strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp),
.out(),.changed(clear_rx0));
vita_rx_chain #(.BASE(SR_RX_CTRL0),.UNIT(0),.FIFOSIZE(DSP_RX_FIFOSIZE)) vita_rx_chain0
(.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx0),
vita_rx_chain #(.BASE(SR_RX_CTRL0),.UNIT(0),.FIFOSIZE(DSP_RX_FIFOSIZE), .DSP_NUMBER(0)) vita_rx_chain0
(.clk(dsp_clk), .reset(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
.set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.vita_time(vita_time), .overrun(overrun0),
.sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0),
.rx_data_o(rx0_vita_data), .rx_src_rdy_o(rx0_vita1_valid), .rx_dst_rdy_i(rx0_vita1_ready),
.sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0), .clear_o(clear_rx0),
.rx_data_o(rx0_vita_data), .rx_src_rdy_o(rx0_vita_valid), .rx_dst_rdy_i(rx0_vita_ready),
.debug() );
fifo_2clock #(.WIDTH(36)) fifo_2clock_rx0
(
.wclk(dsp_clk), .datain(rx0_vita_data), .src_rdy_i(rx0_vita1_valid), .dst_rdy_o(rx0_vita1_ready),
.wclk(dsp_clk), .datain(rx0_vita_data), .src_rdy_i(rx0_vita_valid), .dst_rdy_o(rx0_vita_ready),
.rclk(sys_clk), .dataout(wr1_dat), .src_rdy_o(wr1_ready_i), .dst_rdy_i(wr1_ready_o),
.arst(dsp_rst | sys_rst)
);
// /////////////////////////////////////////////////////////////////////////
// DSP RX 1
wire [31:0] sample_rx1;
wire clear_rx1, strobe_rx1;
wire [31:0] sample_rx1;
wire strobe_rx1, clear_rx1;
wire [35:0] rx1_vita_data;
wire rx1_vita1_valid, rx1_vita1_ready;
wire rx1_vita_valid, rx1_vita_ready;
always @(posedge dsp_clk)
always @(posedge dsp_clk)
run_rx1_d1 <= run_rx1;
dsp_core_rx #(.BASE(SR_RX_DSP1)) dsp_core_rx1
(.clk(dsp_clk),.rst(dsp_rst),
.adc_clk(dsp_clk),
ddc_chain #(.BASE(SR_RX_DSP1), .DSPNO(1)) ddc_chain1
(.clk(dsp_clk), .rst(dsp_rst), .clr(clear_rx1),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
.adc_i(i_1_mux),.adc_ovf_i(adc_ovf_i_1_mux),.adc_q(q_1_mux),.adc_ovf_q(adc_ovf_q_1_mux),
.set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.rx_fe_i(i_1_mux),.rx_fe_q(q_1_mux),
.sample(sample_rx1), .run(run_rx1_d1), .strobe(strobe_rx1),
.debug() );
setting_reg #(.my_addr(SR_RX_CTRL1+3)) sr_clear_rx1
(.clk(dsp_clk),.rst(dsp_rst),
.strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp),
.out(),.changed(clear_rx1));
vita_rx_chain #(.BASE(SR_RX_CTRL1),.UNIT(2),.FIFOSIZE(DSP_RX_FIFOSIZE)) vita_rx_chain1
(.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx1),
vita_rx_chain #(.BASE(SR_RX_CTRL1),.UNIT(2),.FIFOSIZE(DSP_RX_FIFOSIZE), .DSP_NUMBER(1)) vita_rx_chain1
(.clk(dsp_clk), .reset(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
.set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.vita_time(vita_time), .overrun(overrun1),
.sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1),
.rx_data_o(rx1_vita_data), .rx_src_rdy_o(rx1_vita1_valid), .rx_dst_rdy_i(rx1_vita1_ready),
.sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1), .clear_o(clear_rx1),
.rx_data_o(rx1_vita_data), .rx_src_rdy_o(rx1_vita_valid), .rx_dst_rdy_i(rx1_vita_ready),
.debug() );
fifo_2clock #(.WIDTH(36)) fifo_2clock_rx1
(
.wclk(dsp_clk), .datain(rx1_vita_data), .src_rdy_i(rx1_vita1_valid), .dst_rdy_o(rx1_vita1_ready),
.wclk(dsp_clk), .datain(rx1_vita_data), .src_rdy_i(rx1_vita_valid), .dst_rdy_o(rx1_vita_ready),
.rclk(sys_clk), .dataout(wr3_dat), .src_rdy_o(wr3_ready_i), .dst_rdy_i(wr3_ready_o),
.arst(dsp_rst | sys_rst)
);
@@ -732,12 +721,8 @@ module u2plus_core
wire tx_src_rdy, tx_dst_rdy;
wire [35:0] tx_data_1;
wire tx_src_rdy_1, tx_dst_rdy_1;
wire [31:0] debug_vt;
wire clear_tx;
setting_reg #(.my_addr(SR_TX_CTRL+1)) sr_clear_tx
(.clk(dsp_clk),.rst(dsp_rst),.strobe(set_stb_dsp),.addr(set_addr_dsp),
.in(set_data_dsp),.out(),.changed(clear_tx));
wire clear_tx1;
`ifndef NO_EXT_FIFO
assign RAM_A[20:19] = 2'b0;
@@ -747,7 +732,7 @@ module u2plus_core
ext_fifo_i1
(.int_clk(sys_clk),
.ext_clk(sys_clk),
.rst(sys_rst | clear_tx),
.rst(sys_rst | clear_tx | clear_tx1),
`ifndef NO_EXT_FIFO
.RAM_D_pi(RAM_D_pi),
.RAM_D_po(RAM_D_po),
@@ -784,37 +769,12 @@ module u2plus_core
.debug2(debug_extfifo2) );
// /////////////////////////////////////////////////////////////////////////
// DSP TX 0
// DAC Frontend
wire [23:0] tx_i, tx_q;
wire [23:0] tx1_i, tx1_q;
wire [23:0] front_i_0, front_q_0;
wire [23:0] front_i_1, front_q_1;
wire [35:0] tx0_vita_data;
wire tx0_vita1_valid, tx0_vita1_ready;
fifo_2clock #(.WIDTH(36)) fifo_2clock_tx0
(
.wclk(sys_clk), .datain(tx_data), .src_rdy_i(tx_src_rdy), .dst_rdy_o(tx_dst_rdy),
.rclk(dsp_clk), .dataout(tx0_vita_data), .src_rdy_o(tx1_vita0_valid), .dst_rdy_i(tx0_vita1_ready),
.arst(dsp_rst | sys_rst)
);
vita_tx_chain #(.BASE_CTRL(SR_TX_CTRL), .BASE_DSP(SR_TX_DSP),
.REPORT_ERROR(1), .DO_FLOW_CONTROL(1),
.PROT_ENG_FLAGS(1), .USE_TRANS_HEADER(1),
.DSP_NUMBER(0))
vita_tx_chain
(.clk(dsp_clk), .reset(dsp_rst),
.dac_clk(dsp_clk),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
.vita_time(vita_time),
.tx_data_i(tx0_vita_data), .tx_src_rdy_i(tx1_vita0_valid), .tx_dst_rdy_o(tx0_vita1_ready),
.err_data_o(tx_err_data), .err_src_rdy_o(tx_err_src_rdy), .err_dst_rdy_i(tx_err_dst_rdy),
.tx_i(tx_i),.tx_q(tx_q),
.underrun(underrun), .run(run_tx),
.debug(debug_vt));
frontend_sw #(.BASE(SR_TX_FRONT_SW)) tx_frontend_sw
(
.clk(dsp_clk), .rst(dsp_rst),
@@ -837,34 +797,6 @@ module u2plus_core
.tx_i(front_i_0), .tx_q(front_q_0), .run(1'b1),
.dac_a(dac0_a), .dac_b(dac0_b));
// /////////////////////////////////////////////////////////////////////////
// DSP TX 1
wire [35:0] tx1_vita_data;
wire tx1_vita1_valid, tx1_vita1_ready;
fifo_2clock #(.WIDTH(36)) fifo_2clock_tx1
(
.wclk(sys_clk), .datain(tx_data_1), .src_rdy_i(tx_src_rdy_1), .dst_rdy_o(tx_dst_rdy_1),
.rclk(dsp_clk), .dataout(tx1_vita_data), .src_rdy_o(tx1_vita1_valid), .dst_rdy_i(tx1_vita1_ready),
.arst(dsp_rst | sys_rst)
);
vita_tx_chain #(.BASE_CTRL(SR_TX1_CTRL), .BASE_DSP(SR_TX1_DSP),
.REPORT_ERROR(1), .DO_FLOW_CONTROL(1),
.PROT_ENG_FLAGS(1), .USE_TRANS_HEADER(1),
.DSP_NUMBER(1))
vita_tx1_chain
(.clk(dsp_clk), .reset(dsp_rst),
.dac_clk(dsp_clk),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
.vita_time(vita_time),
.tx_data_i(tx1_vita_data), .tx_src_rdy_i(tx1_vita_data), .tx_dst_rdy_o(tx1_vita1_ready),
.err_data_o(tx1_err_data), .err_src_rdy_o(tx1_err_src_rdy), .err_dst_rdy_i(tx1_err_dst_rdy),
.tx_i(tx1_i),.tx_q(tx1_q),
.underrun(underrun1), .run(run_tx1),
.debug());
tx_frontend #(.BASE(SR_TX1_FRONT)) tx1_frontend
(
.clk(dsp_clk), .rst(dsp_rst),
@@ -872,6 +804,80 @@ module u2plus_core
.tx_i(front_i_1), .tx_q(front_q_1), .run(1'b1),
.dac_a(dac1_a), .dac_b(dac1_b));
// /////////////////////////////////////////////////////////////////////////
// DSP TX 0
wire [31:0] sample_tx0;
wire strobe_tx0;
wire [35:0] tx0_vita_data;
wire tx0_vita_valid, tx0_vita_ready;
fifo_2clock #(.WIDTH(36)) fifo_2clock_tx0
(
.wclk(sys_clk), .datain(tx_data), .src_rdy_i(tx_src_rdy), .dst_rdy_o(tx_dst_rdy),
.rclk(dsp_clk), .dataout(tx0_vita_data), .src_rdy_o(tx1_vita0_valid), .dst_rdy_i(tx0_vita_ready),
.arst(dsp_rst | sys_rst)
);
vita_tx_chain #(.BASE(SR_TX_CTRL), .FIFOSIZE(DSP_TX_FIFOSIZE),
.REPORT_ERROR(1), .DO_FLOW_CONTROL(1),
.PROT_ENG_FLAGS(1), .USE_TRANS_HEADER(1),
.DSP_NUMBER(0))
vita_tx_chain
(.clk(dsp_clk), .reset(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
.set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.vita_time(vita_time),
.tx_data_i(tx0_vita_data), .tx_src_rdy_i(tx1_vita0_valid), .tx_dst_rdy_o(tx0_vita_ready),
.err_data_o(tx_err_data), .err_src_rdy_o(tx_err_src_rdy), .err_dst_rdy_i(tx_err_dst_rdy),
.sample(sample_tx0), .strobe(strobe_tx0),
.underrun(underrun), .run(run_tx), .clear_o(clear_tx),
.debug());
duc_chain #(.BASE(SR_TX_DSP), .DSPNO(0)) duc_chain
(.clk(dsp_clk),.rst(dsp_rst), .clr(clear_tx),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
.set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.tx_fe_i(tx_i),.tx_fe_q(tx_q),
.sample(sample_tx0), .run(run_tx0), .strobe(strobe_tx0),
.debug() );
// /////////////////////////////////////////////////////////////////////////
// DSP TX 1
wire [31:0] sample_tx1;
wire strobe_tx1;
wire [35:0] tx1_vita_data;
wire tx1_vita_valid, tx1_vita_ready;
fifo_2clock #(.WIDTH(36)) fifo_2clock_tx1
(
.wclk(sys_clk), .datain(tx_data_1), .src_rdy_i(tx_src_rdy_1), .dst_rdy_o(tx_dst_rdy_1),
.rclk(dsp_clk), .dataout(tx1_vita_data), .src_rdy_o(tx1_vita_valid), .dst_rdy_i(tx1_vita_ready),
.arst(dsp_rst | sys_rst)
);
vita_tx_chain #(.BASE(SR_TX1_CTRL), .FIFOSIZE(DSP_TX_FIFOSIZE),
.REPORT_ERROR(1), .DO_FLOW_CONTROL(1),
.PROT_ENG_FLAGS(1), .USE_TRANS_HEADER(1),
.DSP_NUMBER(1))
vita_tx_chain1
(.clk(dsp_clk), .reset(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
.set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.vita_time(vita_time),
.tx_data_i(tx1_vita_data), .tx_src_rdy_i(tx1_vita_valid), .tx_dst_rdy_o(tx1_vita_ready),
.err_data_o(tx1_err_data), .err_src_rdy_o(tx1_err_src_rdy), .err_dst_rdy_i(tx1_err_dst_rdy),
.sample(sample_tx1), .strobe(strobe_tx1),
.underrun(underrun1), .run(run_tx1), .clear_o(clear_tx1),
.debug());
duc_chain #(.BASE(SR_TX1_DSP), .DSPNO(1)) duc_chain1
(.clk(dsp_clk),.rst(dsp_rst), .clr(clear_tx1),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
.set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.tx_fe_i(tx1_i),.tx_fe_q(tx1_q),
.sample(sample_tx1), .run(run_tx1), .strobe(strobe_tx1),
.debug() );
// ///////////////////////////////////////////////////////////////////////////////////
// SERDES

View File

@@ -191,13 +191,13 @@ wire DivSw1, DivSw2;
TX2D_reg <= dac2_b; //DAC_Q signal
TX1IQSEL_reg <= ~dac1_strobe;
TX2IQSEL_reg <= ~dac0_strobe;
TX2IQSEL_reg <= ~dac2_strobe;
end
reg dsp_clk_div2_tx=0; // DSP clock signal devided by 2
always @(negedge lms_clk) dsp_clk_div2_tx = ~dsp_clk_div2_tx;
assign dac1_strobe = dsp_clk_div2_tx;
assign dac0_strobe = dsp_clk_div2_tx;
assign dac2_strobe = dsp_clk_div2_tx;
// Handle Clocks

View File

@@ -15,4 +15,6 @@ vita_tx_chain.v \
gen_context_pkt.v \
trigger_context_pkt.v \
vita_pkt_gen.v \
vita_rx_engine_glue.v \
vita_tx_engine_glue.v \
))

View File

@@ -32,12 +32,11 @@ module gen_context_pkt
localparam CTXT_PROT_ENG = 1;
localparam CTXT_HEADER = 2;
localparam CTXT_STREAMID = 3;
localparam CTXT_SECS = 4;
localparam CTXT_TICS = 5;
localparam CTXT_TICS2 = 6;
localparam CTXT_MESSAGE = 7;
localparam CTXT_FLOWCTRL = 8;
localparam CTXT_DONE = 9;
localparam CTXT_TICS = 4;
localparam CTXT_TICS2 = 5;
localparam CTXT_MESSAGE = 6;
localparam CTXT_FLOWCTRL = 7;
localparam CTXT_DONE = 8;
reg [33:0] data_int;
wire src_rdy_int, dst_rdy_int;
@@ -88,11 +87,10 @@ module gen_context_pkt
always @*
case(ctxt_state)
CTXT_PROT_ENG : data_int <= { 2'b01, 13'b0, DSP_NUMBER[0], 1'b1, 1'b1, 16'd28 }; // UDP port 1 or 3
CTXT_HEADER : data_int <= { 1'b0, (PROT_ENG_FLAGS ? 1'b0 : 1'b1), 12'b010100001101, seqno, 16'd7 };
CTXT_PROT_ENG : data_int <= { 2'b01, 13'b0, DSP_NUMBER[0], 1'b1, 1'b1, 16'd24 }; // UDP port 1 or 3
CTXT_HEADER : data_int <= { 1'b0, (PROT_ENG_FLAGS ? 1'b0 : 1'b1), 12'b010100000001, seqno, 16'd6 };
CTXT_STREAMID : data_int <= { 2'b00, streamid };
CTXT_SECS : data_int <= { 2'b00, err_time[63:32] };
CTXT_TICS : data_int <= { 2'b00, 32'd0 };
CTXT_TICS : data_int <= { 2'b00, err_time[63:32] };
CTXT_TICS2 : data_int <= { 2'b00, err_time[31:0] };
CTXT_MESSAGE : data_int <= { 2'b00, message };
CTXT_FLOWCTRL : data_int <= { 2'b10, seqnum };

View File

@@ -0,0 +1,102 @@
//
// Copyright 2012 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
//demux an input stream based on the SID
//output packet has SID removed from header
module vita_packet_demux36
#(
parameter NUMCHAN = 1,
parameter SID_BASE = 0
)
(
input clk, input rst,
input [35:0] in_data,
input in_src_rdy,
output in_dst_rdy,
output [35:0] out_data,
output [NUMCHAN-1:0] out_src_rdy,
input [NUMCHAN-1:0] out_dst_rdy
);
reg [1:0] state;
localparam STATE_WAIT_HDR = 0;
localparam STATE_PROC_SID = 1;
localparam STATE_WRITE_HDR = 2;
localparam STATE_FORWARD = 3;
reg [31:0] hdr;
reg [NUMCHAN-1:0] sid;
wire has_sid = in_data[28];
reg has_sid_reg;
wire my_out_dst_rdy = out_dst_rdy[sid];
wire my_out_src_rdy = out_src_rdy[sid];
always @(posedge clk) begin
if (rst) begin
state <= STATE_WAIT_HDR;
end
else case(state)
STATE_WAIT_HDR: begin
if (in_src_rdy && in_dst_rdy && in_data[32]) begin
state <= (has_sid)? STATE_PROC_SID : STATE_WRITE_HDR;
end
sid <= 0;
hdr <= in_data[31:0];
has_sid_reg <= has_sid;
end
STATE_PROC_SID: begin
if (in_src_rdy && in_dst_rdy) begin
state <= STATE_WRITE_HDR;
sid <= in_data[31:0] - SID_BASE;
hdr[28] <= 1'b0; //clear has sid
hdr[15:0] <= hdr[15:0] - 1'b1; //subtract a line
end
end
STATE_WRITE_HDR: begin
if (my_out_src_rdy && my_out_dst_rdy) begin
state <= STATE_FORWARD;
end
end
STATE_FORWARD: begin
if (my_out_src_rdy && my_out_dst_rdy && out_data[33]) begin
state <= STATE_WAIT_HDR;
end
end
endcase //state
end
assign out_data = (state == STATE_WRITE_HDR)? {4'b0001, hdr} : in_data;
wire out_src_rdy_i = (state == STATE_WRITE_HDR)? 1'b1 : ((state == STATE_FORWARD)? in_src_rdy : 1'b0);
assign in_dst_rdy = (state == STATE_WAIT_HDR || state == STATE_PROC_SID)? 1'b1 : ((state == STATE_FORWARD)? my_out_dst_rdy : 1'b0);
genvar i;
generate
for(i = 0; i < NUMCHAN; i = i + 1) begin:valid_assign
assign out_src_rdy[i] = (i == sid)? out_src_rdy_i : 1'b0;
end
endgenerate
endmodule //vita_packet_demux36

View File

@@ -1,5 +1,5 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2011-2012 Ettus Research LLC
//
// 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
@@ -20,21 +20,31 @@ module vita_rx_chain
#(parameter BASE=0,
parameter UNIT=0,
parameter FIFOSIZE=10,
parameter PROT_ENG_FLAGS=1)
(input clk, input reset, input clear,
parameter PROT_ENG_FLAGS=1,
parameter DSP_NUMBER=0)
(input clk, input reset,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
input [63:0] vita_time, output overrun,
input [31:0] sample, output run, input strobe,
input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user,
input [63:0] vita_time,
input [31:0] sample, input strobe,
output [35:0] rx_data_o, output rx_src_rdy_o, input rx_dst_rdy_i,
output overrun, output run, output clear_o,
output [31:0] debug );
wire [100:0] sample_data;
wire sample_dst_rdy, sample_src_rdy;
wire [31:0] vrc_debug, vrf_debug;
wire [35:0] rx_data_int;
wire rx_src_rdy_int, rx_dst_rdy_int;
wire clear;
assign clear_o = clear;
wire clear_int;
setting_reg #(.my_addr(BASE+8)) sr
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(),.changed(clear_int));
vita_rx_control #(.BASE(BASE), .WIDTH(32)) vita_rx_control
(.clk(clk), .reset(reset), .clear(clear),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
@@ -65,9 +75,10 @@ module vita_rx_chain
.data_i(rx_data_int), .src_rdy_i(rx_src_rdy_int), .dst_rdy_o(rx_dst_rdy_int),
.data_o(rx_data_int2), .src_rdy_o(rx_src_rdy_int2), .dst_rdy_i(rx_dst_rdy_int2));
dspengine_16to8 #(.BASE(BASE+9), .BUF_SIZE(FIFOSIZE)) dspengine_16to8
(.clk(clk),.reset(reset),.clear(clear),
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
vita_rx_engine_glue #(.DSPNO(DSP_NUMBER), .MAIN_SETTINGS_BASE(BASE+3), .BUF_SIZE(FIFOSIZE)) dspengine_rx
(.clock(clk),.reset(reset),.clear(clear),
.set_stb_main(set_stb), .set_addr_main(set_addr), .set_data_main(set_data),
.set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(buf_to_dsp), .access_dat_o(dsp_to_buf));
@@ -78,6 +89,26 @@ module vita_rx_chain
.data_i(rx_data_int2), .src_rdy_i(rx_src_rdy_int2), .dst_rdy_o(rx_dst_rdy_int2),
.data_o(rx_data_o), .src_rdy_o(rx_src_rdy_o), .dst_rdy_i(rx_dst_rdy_i) );
//only clear once a full packet has passed through the output interface
reg xfer_pkt, clear_oneshot;
assign clear = (clear_oneshot)? ~xfer_pkt : 0;
always @(posedge clk) begin
if (reset || clear) begin
clear_oneshot <= 0;
end
else if (clear_int) begin
clear_oneshot <= 1;
end
if (reset || clear) begin
xfer_pkt <= 0;
end
else if (rx_src_rdy_o && rx_dst_rdy_i) begin
xfer_pkt <= ~rx_data_o[33];
end
end
assign debug = vrc_debug; // | vrf_debug;
endmodule // vita_rx_chain

View File

@@ -0,0 +1,95 @@
//
// Copyright 2012 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
//The following module is used to re-write receive packets to the host.
//This module provides a packet-based ram interface for manipulating packets.
//By default, this module uses the built-in 16 to 8 bit converter engine.
module vita_rx_engine_glue
#(
//the dsp unit number: 0, 1, 2...
parameter DSPNO = 0,
//buffer size for ram interface engine
parameter BUF_SIZE = 10,
//base address for built-in settings registers used in this module
parameter MAIN_SETTINGS_BASE = 0
)
(
//control signals
input clock, input reset, input clear,
//main settings bus for built-in modules
input set_stb_main, input [7:0] set_addr_main, input [31:0] set_data_main,
//user settings bus, controlled through user setting regs API
input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user,
//ram interface for engine
output access_we,
output access_stb,
input access_ok,
output access_done,
output access_skip_read,
output [BUF_SIZE-1:0] access_adr,
input [BUF_SIZE-1:0] access_len,
output [35:0] access_dat_o,
input [35:0] access_dat_i,
//debug output (optional)
output [31:0] debug
);
generate
if (DSPNO==0) begin
`ifndef RX_ENG0_MODULE
dspengine_16to8 #(.BASE(MAIN_SETTINGS_BASE), .BUF_SIZE(BUF_SIZE)) dspengine_16to8
(.clk(clock),.reset(reset),.clear(clear),
.set_stb(set_stb_main), .set_addr(set_addr_main), .set_data(set_data_main),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
`else
`RX_ENG0_MODULE #(.BUF_SIZE(BUF_SIZE)) rx_eng0_custom
(.clock(clock),.reset(reset),.clear(clear),
.set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
`endif
end
else begin
`ifndef RX_ENG1_MODULE
dspengine_16to8 #(.BASE(MAIN_SETTINGS_BASE), .BUF_SIZE(BUF_SIZE)) dspengine_16to8
(.clk(clock),.reset(reset),.clear(clear),
.set_stb(set_stb_main), .set_addr(set_addr_main), .set_data(set_data_main),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
`else
`RX_ENG1_MODULE #(.BUF_SIZE(BUF_SIZE)) rx_eng1_custom
(.clock(clock),.reset(reset),.clear(clear),
.set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
`endif
end
endgenerate
endmodule //vita_rx_engine_glue

View File

@@ -1,5 +1,5 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2011-2012 Ettus Research LLC
//
// 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
@@ -85,26 +85,26 @@ module vita_rx_framer
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(samples_per_packet),.changed());
setting_reg #(.my_addr(BASE+8),.width(4), .at_reset(1)) sr_numchan
assign numchan = 0;/*
setting_reg #(.my_addr(BASE+8),.width(4), .at_reset(0)) sr_numchan
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(numchan),.changed());
*/
// Output FIFO for packetized data
localparam VITA_IDLE = 0;
localparam VITA_HEADER = 1;
localparam VITA_STREAMID = 2;
localparam VITA_SECS = 3;
localparam VITA_TICS = 4;
localparam VITA_TICS2 = 5;
localparam VITA_PAYLOAD = 6;
localparam VITA_TRAILER = 7;
localparam VITA_ERR_HEADER = 9; // All ERR at 4'b1000 or'ed with base
localparam VITA_ERR_STREAMID = 10;
localparam VITA_ERR_SECS = 11;
localparam VITA_ERR_TICS = 12;
localparam VITA_ERR_TICS2 = 13;
localparam VITA_ERR_PAYLOAD = 14;
localparam VITA_ERR_TRAILER = 15; // Extension context packets have no trailer
localparam VITA_TICS = 3;
localparam VITA_TICS2 = 4;
localparam VITA_PAYLOAD = 5;
localparam VITA_TRAILER = 6;
localparam VITA_ERR_HEADER = 7; // All ERR at 4'b1000 or'ed with base
localparam VITA_ERR_STREAMID = 8;
localparam VITA_ERR_TICS = 9;
localparam VITA_ERR_TICS2 = 10;
localparam VITA_ERR_PAYLOAD = 11;
localparam VITA_ERR_TRAILER = 12; // Extension context packets have no trailer
always @(posedge clk)
if(reset | clear | clear_pkt_count)
@@ -122,17 +122,15 @@ module vita_rx_framer
VITA_HEADER : pkt_fifo_line <= {2'b01,3'b000,vita_header[28],2'b01,vita_header[25:24],
vita_header[23:20],pkt_count[3:0],vita_pkt_len[15:0]};
VITA_STREAMID : pkt_fifo_line <= {2'b00,vita_streamid};
VITA_SECS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]};
VITA_TICS : pkt_fifo_line <= {2'b00,32'd0};
VITA_TICS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]};
VITA_TICS2 : pkt_fifo_line <= {2'b00,vita_time_fifo_o[31:0]};
VITA_PAYLOAD : pkt_fifo_line <= {2'b00,data_fifo_o};
VITA_TRAILER : pkt_fifo_line <= {2'b10,vita_trailer[31:21],1'b1,vita_trailer[19:9],trl_eob,8'd0};
// Error packets are Extension Context packets, which have no trailer
VITA_ERR_HEADER : pkt_fifo_line <= {2'b01,4'b0101,4'b0000,vita_header[23:20],pkt_count,16'd6};
VITA_ERR_HEADER : pkt_fifo_line <= {2'b01,4'b0101,4'b0000,vita_header[23:20],pkt_count,16'd5};
VITA_ERR_STREAMID : pkt_fifo_line <= {2'b00,vita_streamid};
VITA_ERR_SECS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]};
VITA_ERR_TICS : pkt_fifo_line <= {2'b00,32'd0};
VITA_ERR_TICS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]};
VITA_ERR_TICS2 : pkt_fifo_line <= {2'b00,vita_time_fifo_o[31:0]};
VITA_ERR_PAYLOAD : pkt_fifo_line <= {2'b10,27'd0,flags_fifo_o};
//VITA_ERR_TRAILER : pkt_fifo_line <= {2'b11,vita_trailer};
@@ -164,11 +162,11 @@ module vita_rx_framer
if(has_streamid)
vita_state <= VITA_STREAMID;
else
vita_state <= VITA_SECS;
vita_state <= VITA_TICS;
VITA_PAYLOAD :
if(sample_fifo_src_rdy_i)
begin
if(sample_phase == (numchan-4'd1))
if(sample_phase == numchan)
begin
sample_phase <= 0;
sample_ctr <= sample_ctr + 1;
@@ -194,12 +192,12 @@ module vita_rx_framer
case(vita_state)
VITA_IDLE :
req_write_pkt_fifo <= 0;
VITA_HEADER, VITA_STREAMID, VITA_SECS, VITA_TICS, VITA_TICS2, VITA_TRAILER :
VITA_HEADER, VITA_STREAMID, VITA_TICS, VITA_TICS2, VITA_TRAILER :
req_write_pkt_fifo <= 1;
VITA_PAYLOAD :
// Write if sample ready and no error flags
req_write_pkt_fifo <= (sample_fifo_src_rdy_i & ~|flags_fifo_o[4:1]);
VITA_ERR_HEADER, VITA_ERR_STREAMID, VITA_ERR_SECS, VITA_ERR_TICS, VITA_ERR_TICS2, VITA_ERR_PAYLOAD :
VITA_ERR_HEADER, VITA_ERR_STREAMID, VITA_ERR_TICS, VITA_ERR_TICS2, VITA_ERR_PAYLOAD :
req_write_pkt_fifo <= 1;
default :
req_write_pkt_fifo <= 0;
@@ -217,7 +215,7 @@ module vita_rx_framer
assign data_o[35:34] = 2'b00; // Always write full lines
assign sample_fifo_dst_rdy_o = pkt_fifo_rdy &
( ((vita_state==VITA_PAYLOAD) &
(sample_phase == (numchan-4'd1)) &
(sample_phase == numchan) &
~|flags_fifo_o[4:1]) |
(vita_state==VITA_ERR_PAYLOAD));

View File

@@ -1,5 +1,5 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2011-2012 Ettus Research LLC
//
// 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
@@ -17,21 +17,22 @@
module vita_tx_chain
#(parameter BASE_CTRL=0,
parameter BASE_DSP=0,
#(parameter BASE=0,
parameter FIFOSIZE=10,
parameter POST_ENGINE_FIFOSIZE=10,
parameter REPORT_ERROR=0,
parameter DO_FLOW_CONTROL=0,
parameter PROT_ENG_FLAGS=0,
parameter USE_TRANS_HEADER=0,
parameter DSP_NUMBER=0)
(input clk, input reset,
input dac_clk,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user,
input [63:0] vita_time,
input [35:0] tx_data_i, input tx_src_rdy_i, output tx_dst_rdy_o,
output [35:0] err_data_o, output err_src_rdy_o, input err_dst_rdy_i,
output [23:0] tx_i, output [23:0] tx_q,
output underrun, output run,
output [31:0] sample, input strobe,
output underrun, output run, output clear_o,
output [31:0] debug);
localparam MAXCHAN = 1;
@@ -39,8 +40,6 @@ module vita_tx_chain
wire [FIFOWIDTH-1:0] tx1_data;
wire tx1_src_rdy, tx1_dst_rdy;
wire clear_vita;
wire [31:0] sample_tx;
wire [31:0] streamid, message;
wire trigger, sent;
wire [31:0] debug_vtc, debug_vtd, debug_tx_dsp;
@@ -49,62 +48,104 @@ module vita_tx_chain
wire [31:0] error_code;
wire clear_seqnum;
wire [31:0] current_seqnum;
wire strobe_tx;
wire clear, flush;
assign clear_o = clear;
assign underrun = error;
assign message = error_code;
setting_reg #(.my_addr(BASE_CTRL+1)) sr
(.clk(dac_clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(),.changed(clear_vita));
setting_reg #(.my_addr(BASE_CTRL+2), .at_reset(0)) sr_streamid
(.clk(dac_clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
setting_reg #(.my_addr(BASE+0), .width(1)) sr
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(flush),.changed(clear));
setting_reg #(.my_addr(BASE+2), .at_reset(0)) sr_streamid
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(streamid),.changed(clear_seqnum));
vita_tx_deframer #(.BASE(BASE_CTRL),
//flush control - full rate vacuum of input until flush cleared
wire tx_dst_rdy_int, tx_src_rdy_int;
wire [35:0] tx_data_int;
valve36 flusher_valve
(.clk(clk), .reset(reset), .clear(clear & flush), .shutoff(flush),
.data_i(tx_data_i), .src_rdy_i(tx_src_rdy_i), .dst_rdy_o(tx_dst_rdy_o),
.data_o(tx_data_int), .src_rdy_o(tx_src_rdy_int), .dst_rdy_i(tx_dst_rdy_int));
wire [35:0] tx_data_int1;
wire tx_src_rdy_int1, tx_dst_rdy_int1;
generate
if (FIFOSIZE==0) begin
assign tx_data_int1 = tx_data_int;
assign tx_src_rdy_int1 = tx_src_rdy_int;
assign tx_dst_rdy_int = tx_dst_rdy_int1;
end
else begin
wire [FIFOSIZE-1:0] access_adr, access_len;
wire access_we, access_stb, access_ok, access_done, access_skip_read;
wire [35:0] dsp_to_buf, buf_to_dsp;
wire [35:0] tx_data_int0;
wire tx_src_rdy_int0, tx_dst_rdy_int0;
double_buffer #(.BUF_SIZE(FIFOSIZE)) db
(.clk(clk),.reset(reset),.clear(clear),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(dsp_to_buf), .access_dat_o(buf_to_dsp),
.data_i(tx_data_int), .src_rdy_i(tx_src_rdy_int), .dst_rdy_o(tx_dst_rdy_int),
.data_o(tx_data_int0), .src_rdy_o(tx_src_rdy_int0), .dst_rdy_i(tx_dst_rdy_int0));
vita_tx_engine_glue #(.DSPNO(DSP_NUMBER), .MAIN_SETTINGS_BASE(BASE+1), .BUF_SIZE(FIFOSIZE), .HEADER_OFFSET(USE_TRANS_HEADER)) dspengine_tx
(.clock(clk),.reset(reset),.clear(clear),
.set_stb_main(set_stb), .set_addr_main(set_addr), .set_data_main(set_data),
.set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(buf_to_dsp), .access_dat_o(dsp_to_buf));
fifo_cascade #(.WIDTH(36), .SIZE(POST_ENGINE_FIFOSIZE)) post_engine_buffering(
.clk(clk), .reset(reset), .clear(clear),
.datain(tx_data_int0), .src_rdy_i(tx_src_rdy_int0), .dst_rdy_o(tx_dst_rdy_int0),
.dataout(tx_data_int1), .src_rdy_o(tx_src_rdy_int1), .dst_rdy_i(tx_dst_rdy_int1));
end
endgenerate
vita_tx_deframer #(.BASE(BASE),
.MAXCHAN(MAXCHAN),
.USE_TRANS_HEADER(USE_TRANS_HEADER))
vita_tx_deframer
(.clk(dac_clk), .reset(reset), .clear(clear_vita), .clear_seqnum(clear_seqnum),
(.clk(clk), .reset(reset), .clear(clear), .clear_seqnum(clear_seqnum),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
.data_i(tx_data_i), .src_rdy_i(tx_src_rdy_i), .dst_rdy_o(tx_dst_rdy_o),
.data_i(tx_data_int1), .src_rdy_i(tx_src_rdy_int1), .dst_rdy_o(tx_dst_rdy_int1),
.sample_fifo_o(tx1_data), .sample_fifo_src_rdy_o(tx1_src_rdy), .sample_fifo_dst_rdy_i(tx1_dst_rdy),
.current_seqnum(current_seqnum),
.debug(debug_vtd) );
vita_tx_control #(.BASE(BASE_CTRL), .WIDTH(32*MAXCHAN)) vita_tx_control
(.clk(clk), .reset(reset), .clear(clear_vita),
.dac_clk(dac_clk),
vita_tx_control #(.BASE(BASE), .WIDTH(32*MAXCHAN)) vita_tx_control
(.clk(clk), .reset(reset), .clear(clear),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
.vita_time(vita_time), .error(error), .ack(ack), .error_code(error_code),
.sample_fifo_i(tx1_data), .sample_fifo_src_rdy_i(tx1_src_rdy), .sample_fifo_dst_rdy_o(tx1_dst_rdy),
.sample(sample_tx), .run(run), .strobe(strobe_tx), .packet_consumed(packet_consumed),
.sample(sample), .run(run), .strobe(strobe), .packet_consumed(packet_consumed),
.debug(debug_vtc) );
dsp_core_tx #(.BASE(BASE_DSP)) dsp_core_tx
(.clk(dac_clk),.rst(reset),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
.sample(sample_tx), .run(run), .strobe(strobe_tx),
.tx_i(tx_i),.tx_q(tx_q),
.debug(debug_tx_dsp) );
wire [35:0] flow_data, err_data_int;
wire flow_src_rdy, flow_dst_rdy, err_src_rdy_int, err_dst_rdy_int;
gen_context_pkt #(.PROT_ENG_FLAGS(PROT_ENG_FLAGS),.DSP_NUMBER(DSP_NUMBER)) gen_flow_pkt
(.clk(clk), .reset(reset), .clear(clear_vita),
(.clk(clk), .reset(reset), .clear(clear),
.trigger(trigger & (DO_FLOW_CONTROL==1)), .sent(),
.streamid(streamid), .vita_time(vita_time), .message(32'd0),
.seqnum(current_seqnum),
.data_o(flow_data), .src_rdy_o(flow_src_rdy), .dst_rdy_i(flow_dst_rdy));
trigger_context_pkt #(.BASE(BASE_CTRL)) trigger_context_pkt
(.clk(clk), .reset(reset), .clear(clear_vita),
trigger_context_pkt #(.BASE(BASE)) trigger_context_pkt
(.clk(clk), .reset(reset), .clear(clear),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
.packet_consumed(packet_consumed), .trigger(trigger));
gen_context_pkt #(.PROT_ENG_FLAGS(PROT_ENG_FLAGS),.DSP_NUMBER(DSP_NUMBER)) gen_tx_err_pkt
(.clk(clk), .reset(reset), .clear(clear_vita),
(.clk(clk), .reset(reset), .clear(clear),
.trigger((error|ack) & (REPORT_ERROR==1)), .sent(),
.streamid(streamid), .vita_time(vita_time), .message(message),
.seqnum(current_seqnum),

View File

@@ -20,7 +20,6 @@ module vita_tx_control
#(parameter BASE=0,
parameter WIDTH=32)
(input clk, input reset, input clear,
input dac_clk,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
input [63:0] vita_time,
@@ -51,21 +50,19 @@ module vita_tx_control
wire now, early, late, too_early;
// FIXME ignore too_early for now for timing reasons
assign too_early = 0;
time_compare
time_compare (.time_now(vita_time), .trigger_time(send_time),
.now(now), .early(early), .late(late), .too_early());
.now(now), .early(early), .late(late), .too_early(too_early));
reg late_qual, late_del;
always @(posedge dac_clk)
always @(posedge clk)
if(reset | clear)
late_del <= 0;
else
late_del <= late;
always @(posedge dac_clk)
always @(posedge clk)
if(reset | clear)
late_qual <= 0;
else
@@ -89,7 +86,7 @@ module vita_tx_control
wire [31:0] error_policy;
setting_reg #(.my_addr(BASE+3)) sr_error_policy
(.clk(dac_clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(error_policy),.changed());
wire policy_wait = error_policy[0];
@@ -97,7 +94,7 @@ module vita_tx_control
wire policy_next_burst = error_policy[2];
reg send_error, send_ack;
always @(posedge dac_clk)
always @(posedge clk)
if(reset | clear)
begin
ibs_state <= IBS_IDLE;
@@ -188,21 +185,25 @@ module vita_tx_control
assign sample_fifo_dst_rdy_o = (ibs_state == IBS_ERROR) | (strobe & (ibs_state == IBS_RUN)); // FIXME also cleanout
assign sample = (ibs_state == IBS_RUN) ? sample_fifo_i[5+64+16+WIDTH-1:5+64+16] : {WIDTH{1'b0}};
//assign run = (ibs_state == IBS_RUN) | (ibs_state == IBS_CONT_BURST);
//register the output sample
reg [31:0] sample_held;
assign sample = sample_held;
always @(posedge clk)
if(reset | clear)
sample_held <= 0;
else if (~run)
sample_held <= 0;
else if (strobe)
sample_held <= sample_fifo_i[5+64+16+WIDTH-1:5+64+16];
assign error = send_error;
assign ack = send_ack;
`ifndef LMS602D_FRONTEND
localparam MAX_IDLE = 1000000;
// approx 10 ms timeout with a 100 MHz clock, but burning samples will slow that down
`else
localparam MAX_IDLE = 130000;
// approx 10 ms timeout with a 13 MHz clock, but burning samples will slow that down
`endif // !`ifndef LMS602D_FRONTEND
reg [19:0] countdown;
always @(posedge dac_clk)
always @(posedge clk)
if(reset | clear)
begin
run <= 0;

View File

@@ -1,5 +1,5 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2011-2012 Ettus Research LLC
//
// 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
@@ -43,10 +43,11 @@ module vita_tx_deframer
localparam FIFOWIDTH = 5+64+16+(32*MAXCHAN);
wire [1:0] numchan;
wire [1:0] numchan = 0;/*
setting_reg #(.my_addr(BASE), .at_reset(0), .width(2)) sr_numchan
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(numchan),.changed());
*/
reg [3:0] vita_state;
wire has_streamid, has_classid, has_secs, has_tics, has_trailer;
@@ -85,7 +86,6 @@ module vita_tx_deframer
localparam VITA_TICS = 6;
localparam VITA_TICS2 = 7;
localparam VITA_PAYLOAD = 8;
localparam VITA_STORE = 9;
localparam VITA_TRAILER = 10;
localparam VITA_DUMP = 11;
@@ -118,21 +118,7 @@ module vita_tx_deframer
<= 0;
seqnum_err <= 0;
end
else
if((vita_state == VITA_STORE) & fifo_space)
if(vita_eof)
if(eof)
vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER;
else if(has_trailer_reg)
vita_state <= VITA_TRAILER;
else
vita_state <= VITA_DUMP;
else
begin
vita_state <= VITA_PAYLOAD;
pkt_len <= pkt_len - 1;
end
else if(src_rdy_i)
else if(src_rdy_i & dst_rdy_o) begin //valid read
case(vita_state)
VITA_TRANS_HEADER :
begin
@@ -184,14 +170,33 @@ module vita_tx_deframer
vita_state <= VITA_TICS2;
VITA_TICS2 :
vita_state <= VITA_PAYLOAD;
VITA_PAYLOAD :
if(line_done)
begin
vector_phase <= 0;
vita_state <= VITA_STORE;
end
else
vector_phase <= vector_phase + 1;
VITA_PAYLOAD : begin
//step through each element until line done, then reset
vector_phase <= (line_done)? 0: vector_phase + 1;
//decrement the packet count after each line
pkt_len <= (line_done)? pkt_len - 1 : pkt_len;
//end of frame reached, determine next state
//otherwise, keep processing through the payload
if (line_done && vita_eof) begin
if (eof) begin
vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER;
end
else if (has_trailer_reg) begin
vita_state <= VITA_TRAILER;
end
else begin
vita_state <= VITA_DUMP;
end
end //line_done && vita_eof
end //end VITA_PAYLOAD
VITA_TRAILER :
if(eof)
vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER;
@@ -200,46 +205,53 @@ module vita_tx_deframer
VITA_DUMP :
if(eof)
vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER;
VITA_STORE :
;
default :
vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER;
endcase // case (vita_state)
assign line_done = (vector_phase == numchan);
end //valid read
assign line_done = (MAXCHAN == 1)? 1 : (vector_phase == numchan);
wire [FIFOWIDTH-1:0] fifo_i;
reg [63:0] send_time;
reg [31:0] sample_a, sample_b, sample_c, sample_d;
always @(posedge clk)
case(vita_state)
VITA_SECS :
VITA_TICS :
send_time[63:32] <= data_i[31:0];
VITA_TICS2 :
send_time[31:0] <= data_i[31:0];
endcase // case (vita_state)
//sample registers for de-framing a vector input
reg [31:0] sample_reg [1:0];
always @(posedge clk)
if(vita_state == VITA_PAYLOAD)
case(vector_phase)
0: sample_a <= data_i[31:0];
1: sample_b <= data_i[31:0];
2: sample_c <= data_i[31:0];
3: sample_d <= data_i[31:0];
endcase // case (vector_phase)
wire store = (vita_state == VITA_STORE);
if(src_rdy_i && dst_rdy_o)
sample_reg[vector_phase] <= data_i[31:0];
wire store = (vita_state == VITA_PAYLOAD)? (src_rdy_i && line_done) : 0;
assign dst_rdy_o = (vita_state == VITA_PAYLOAD)? fifo_space : 1;
fifo_short #(.WIDTH(FIFOWIDTH)) short_tx_q
(.clk(clk), .reset(reset), .clear(clear),
.datain(fifo_i), .src_rdy_i(store), .dst_rdy_o(fifo_space),
.dataout(sample_fifo_o), .src_rdy_o(sample_fifo_src_rdy_o), .dst_rdy_i(sample_fifo_dst_rdy_i) );
// sob, eob, has_secs (send_at) ignored on all lines except first
assign fifo_i = {sample_d,sample_c,sample_b,sample_a,seqnum_err,has_secs_reg,is_sob_reg,is_eob_reg,eop,
12'd0,seqnum_reg[3:0],send_time};
//assign registered/live data to the samples vector
//the numchan'th sample vector is muxed to live data
wire [(32*MAXCHAN)-1:0] samples;
generate
genvar i;
for (i=0; i < MAXCHAN; i = i +1) begin : assign_samples
wire live_data = (i == (MAXCHAN-1))? 1 : numchan == i;
assign samples[32*i + 31:32*i] = (live_data)? data_i[31:0] : sample_reg[i];
end
endgenerate
assign dst_rdy_o = ~(vita_state == VITA_PAYLOAD) & ~((vita_state==VITA_STORE)& ~fifo_space) ;
// sob, eob, has_tics (send_at) ignored on all lines except first
assign fifo_i = {samples,seqnum_err,has_tics_reg,is_sob_reg,is_eob_reg,eop,
12'd0,seqnum_reg[3:0],send_time};
assign debug = { { 8'b0 },
{ 8'b0 },

View File

@@ -0,0 +1,99 @@
//
// Copyright 2012 Ettus Research LLC
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
//The following module is used to re-write transmit packets from the host.
//This module provides a packet-based ram interface for manipulating packets.
//By default, this module uses the built-in 8 to 16 bit converter engine.
module vita_tx_engine_glue
#(
//the dsp unit number: 0, 1, 2...
parameter DSPNO = 0,
//buffer size for ram interface engine
parameter BUF_SIZE = 10,
//base address for built-in settings registers used in this module
parameter MAIN_SETTINGS_BASE = 0,
//the number of 32bit lines between start of buffer and vita header
//the metadata before the header should be preserved by the engine
parameter HEADER_OFFSET = 0
)
(
//control signals
input clock, input reset, input clear,
//main settings bus for built-in modules
input set_stb_main, input [7:0] set_addr_main, input [31:0] set_data_main,
//user settings bus, controlled through user setting regs API
input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user,
//ram interface for engine
output access_we,
output access_stb,
input access_ok,
output access_done,
output access_skip_read,
output [BUF_SIZE-1:0] access_adr,
input [BUF_SIZE-1:0] access_len,
output [35:0] access_dat_o,
input [35:0] access_dat_i,
//debug output (optional)
output [31:0] debug
);
generate
if (DSPNO==0) begin
`ifndef TX_ENG0_MODULE
dspengine_8to16 #(.BASE(MAIN_SETTINGS_BASE), .BUF_SIZE(BUF_SIZE), .HEADER_OFFSET(HEADER_OFFSET)) dspengine_8to16
(.clk(clock),.reset(reset),.clear(clear),
.set_stb(set_stb_main), .set_addr(set_addr_main), .set_data(set_data_main),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
`else
`TX_ENG0_MODULE #(.BUF_SIZE(BUF_SIZE), .HEADER_OFFSET(HEADER_OFFSET)) tx_eng0_custom
(.clock(clock),.reset(reset),.clear(clear),
.set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
`endif
end
else begin
`ifndef TX_ENG1_MODULE
dspengine_8to16 #(.BASE(MAIN_SETTINGS_BASE), .BUF_SIZE(BUF_SIZE), .HEADER_OFFSET(HEADER_OFFSET)) dspengine_8to16
(.clk(clock),.reset(reset),.clear(clear),
.set_stb(set_stb_main), .set_addr(set_addr_main), .set_data(set_data_main),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
`else
`TX_ENG1_MODULE #(.BUF_SIZE(BUF_SIZE), .HEADER_OFFSET(HEADER_OFFSET)) tx_eng1_custom
(.clock(clock),.reset(reset),.clear(clear),
.set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
`endif
end
endgenerate
endmodule //vita_tx_engine_glue