From f4c61186f6a81a09a038cef500d07d4ca5e65a57 Mon Sep 17 00:00:00 2001 From: Matt Ettus Date: Thu, 6 Oct 2011 22:21:59 -0700 Subject: dsp_engine: new way of doing DSP operations on VITA packets. Example does 16 to 8 bit conversion --- usrp2/control_lib/dbsm.v | 164 +++++++++++++++++++++++ usrp2/control_lib/double_buffer.v | 139 +++++++++++++++++++ usrp2/control_lib/double_buffer_tb.v | 253 +++++++++++++++++++++++++++++++++++ 3 files changed, 556 insertions(+) create mode 100644 usrp2/control_lib/dbsm.v create mode 100644 usrp2/control_lib/double_buffer.v create mode 100644 usrp2/control_lib/double_buffer_tb.v (limited to 'usrp2/control_lib') diff --git a/usrp2/control_lib/dbsm.v b/usrp2/control_lib/dbsm.v new file mode 100644 index 000000000..fea51096f --- /dev/null +++ b/usrp2/control_lib/dbsm.v @@ -0,0 +1,164 @@ +// +// 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 . +// + +module dbsm + (input clk, + input reset, + input clear, + + output write_ok, + output write_ptr, + input write_done, + + output read_ok, + output read_ptr, + input read_done, + + output access_ok, + output access_ptr, + input access_done, + input access_skip_read + ); + + localparam PORT_WAIT_0 = 0; + localparam PORT_USE_0 = 1; + localparam PORT_WAIT_1 = 2; + localparam PORT_USE_1 = 3; + + reg [1:0] write_port_state, access_port_state, read_port_state; + + localparam BUFF_WRITABLE = 0; + localparam BUFF_ACCESSIBLE = 1; + localparam BUFF_READABLE = 2; + localparam BUFF_ERROR = 3; + + wire [1:0] buff_state[0:1]; + + always @(posedge clk) + if(reset | clear) + write_port_state <= PORT_WAIT_0; + else + case(write_port_state) + PORT_WAIT_0 : + if(buff_state[0]==BUFF_WRITABLE) + write_port_state <= PORT_USE_0; + PORT_USE_0 : + if(write_done) + write_port_state <= PORT_WAIT_1; + PORT_WAIT_1 : + if(buff_state[1]==BUFF_WRITABLE) + write_port_state <= PORT_USE_1; + PORT_USE_1 : + if(write_done) + write_port_state <= PORT_WAIT_0; + endcase // case (write_port_state) + + assign write_ok = (write_port_state == PORT_USE_0) | (write_port_state == PORT_USE_1); + assign write_ptr = (write_port_state == PORT_USE_1); + + always @(posedge clk) + if(reset | clear) + access_port_state <= PORT_WAIT_0; + else + case(access_port_state) + PORT_WAIT_0 : + if(buff_state[0]==BUFF_ACCESSIBLE) + access_port_state <= PORT_USE_0; + PORT_USE_0 : + if(access_done) + access_port_state <= PORT_WAIT_1; + PORT_WAIT_1 : + if(buff_state[1]==BUFF_ACCESSIBLE) + access_port_state <= PORT_USE_1; + PORT_USE_1 : + if(access_done) + access_port_state <= PORT_WAIT_0; + endcase // case (access_port_state) + + assign access_ok = (access_port_state == PORT_USE_0) | (access_port_state == PORT_USE_1); + assign access_ptr = (access_port_state == PORT_USE_1); + + always @(posedge clk) + if(reset | clear) + read_port_state <= PORT_WAIT_0; + else + case(read_port_state) + PORT_WAIT_0 : + if(buff_state[0]==BUFF_READABLE) + read_port_state <= PORT_USE_0; + PORT_USE_0 : + if(read_done) + read_port_state <= PORT_WAIT_1; + PORT_WAIT_1 : + if(buff_state[1]==BUFF_READABLE) + read_port_state <= PORT_USE_1; + PORT_USE_1 : + if(read_done) + read_port_state <= PORT_WAIT_0; + endcase // case (read_port_state) + + assign read_ok = (read_port_state == PORT_USE_0) | (read_port_state == PORT_USE_1); + assign read_ptr = (read_port_state == PORT_USE_1); + + buff_sm #(.PORT_USE_FLAG(PORT_USE_0)) buff0_sm + (.clk(clk), .reset(reset), .clear(clear), + .write_done(write_done), .access_done(access_done), .access_skip_read(access_skip_read), .read_done(read_done), + .write_port_state(write_port_state), .access_port_state(access_port_state), .read_port_state(read_port_state), + .buff_state(buff_state[0])); + + buff_sm #(.PORT_USE_FLAG(PORT_USE_1)) buff1_sm + (.clk(clk), .reset(reset), .clear(clear), + .write_done(write_done), .access_done(access_done), .access_skip_read(access_skip_read), .read_done(read_done), + .write_port_state(write_port_state), .access_port_state(access_port_state), .read_port_state(read_port_state), + .buff_state(buff_state[1])); + +endmodule // dbsm + +module buff_sm + #(parameter PORT_USE_FLAG=0) + (input clk, input reset, input clear, + input write_done, input access_done, input access_skip_read, input read_done, + input [1:0] write_port_state, input [1:0] access_port_state, input [1:0] read_port_state, + output reg [1:0] buff_state); + + localparam BUFF_WRITABLE = 0; + localparam BUFF_ACCESSIBLE = 1; + localparam BUFF_READABLE = 2; + localparam BUFF_ERROR = 3; + + always @(posedge clk) + if(reset | clear) + buff_state <= BUFF_WRITABLE; + else + case(buff_state) + BUFF_WRITABLE : + if(write_done & (write_port_state == PORT_USE_FLAG)) + buff_state <= BUFF_ACCESSIBLE; + BUFF_ACCESSIBLE : + if(access_done & (access_port_state == PORT_USE_FLAG)) + if(access_skip_read) + buff_state <= BUFF_WRITABLE; + else + buff_state <= BUFF_READABLE; + BUFF_READABLE : + if(read_done & (read_port_state == PORT_USE_FLAG)) + buff_state <= BUFF_WRITABLE; + BUFF_ERROR : + ; + endcase + +endmodule // buff_sm diff --git a/usrp2/control_lib/double_buffer.v b/usrp2/control_lib/double_buffer.v new file mode 100644 index 000000000..eabd0f956 --- /dev/null +++ b/usrp2/control_lib/double_buffer.v @@ -0,0 +1,139 @@ +// +// 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 . +// + +module double_buffer + #(parameter BUF_SIZE = 9) + (input clk, input reset, input clear, + + // Random access interface to RAM + input access_we, + input access_stb, + output access_ok, + input access_done, + input access_skip_read, + input [BUF_SIZE-1:0] access_adr, + output [BUF_SIZE-1:0] access_len, + input [35:0] access_dat_i, + output [35:0] access_dat_o, + + // Write FIFO Interface + input [35:0] data_i, + input src_rdy_i, + output dst_rdy_o, + + // Read FIFO Interface + output [35:0] data_o, + output src_rdy_o, + input dst_rdy_i + ); + + wire [35:0] data_o_0, data_o_1; + + wire read, read_ok, read_ptr, read_done; + wire write, write_ok, write_ptr, write_done; + + wire [BUF_SIZE-1:0] rw0_adr, rw1_adr; + reg [BUF_SIZE-1:0] read_adr, write_adr; + reg [BUF_SIZE-1:0] len0, len1; + + assign data_o = read_ptr ? data_o_1 : data_o_0; + assign rw0_adr = (read_ok & ~read_ptr) ? read_adr : write_adr; + assign rw1_adr = (read_ok & read_ptr) ? read_adr : write_adr; + + wire [35:0] access_dat_i, access_dat_o_0, access_dat_o_1; + wire access_ptr; + assign access_dat_o = access_ptr? access_dat_o_1 : access_dat_o_0; + + dbsm dbsm + (.clk(clk), .reset(reset), .clear(clear), + .write_ok(write_ok), .write_ptr(write_ptr), .write_done(write_done), + .access_ok(access_ok), .access_ptr(access_ptr), .access_done(access_done), .access_skip_read(access_skip_read), + .read_ok(read_ok), .read_ptr(read_ptr), .read_done(read_done)); + + // Port A for random access, Port B for FIFO read and write + ram_2port #(.DWIDTH(36),.AWIDTH(BUF_SIZE)) buffer0 + (.clka(clk),.ena(access_stb & access_ok & (access_ptr == 0)),.wea(access_we), + .addra(access_adr),.dia(access_dat_i),.doa(access_dat_o_0), + .clkb(clk),.enb((read & read_ok & ~read_ptr)|(write & write_ok & ~write_ptr) ),.web(write&write_ok&~write_ptr), + .addrb(rw0_adr),.dib(data_i),.dob(data_o_0)); + + ram_2port #(.DWIDTH(36),.AWIDTH(BUF_SIZE)) buffer1 + (.clka(clk),.ena(access_stb & access_ok & (access_ptr == 1)),.wea(access_we), + .addra(access_adr),.dia(access_dat_i),.doa(access_dat_o_1), + .clkb(clk),.enb((read & read_ok & read_ptr)|(write & write_ok & write_ptr) ),.web(write&write_ok&write_ptr), + .addrb(rw1_adr),.dib(data_i),.dob(data_o_1)); + + // Write into buffers + assign dst_rdy_o = write_ok; + assign write = src_rdy_i & write_ok; + assign write_done = write & data_i[33]; // done + always @(posedge clk) + if(reset | clear) + write_adr <= 0; + else + if(write_done) + begin + write_adr <= 0; + if(write_ptr) + len1 <= write_adr + 1; + else + len0 <= write_adr + 1; + end + else if(write) + write_adr <= write_adr + 1; + + assign access_len = access_ptr ? len1 : len0; + + reg [1:0] read_state; + localparam IDLE = 0; + localparam PRE_READ = 1; + localparam READING = 2; + + always @(posedge clk) + if(reset | clear) + begin + read_state <= IDLE; + read_adr <= 0; + end + else + case(read_state) + IDLE : + begin + read_adr <= 0; + if(read_ok) + read_state <= PRE_READ; + end + PRE_READ : + begin + read_state <= READING; + read_adr <= 1; + end + + READING : + if(dst_rdy_i) + begin + read_adr <= read_adr + 1; + if(data_o[33]) + read_state <= IDLE; + end + endcase // case (read_state) + + assign read = ~((read_state==READING)& ~dst_rdy_i); + assign read_done = data_o[33] & dst_rdy_i & src_rdy_o; + assign src_rdy_o = (read_state == READING); + +endmodule // double_buffer diff --git a/usrp2/control_lib/double_buffer_tb.v b/usrp2/control_lib/double_buffer_tb.v new file mode 100644 index 000000000..a9aae6956 --- /dev/null +++ b/usrp2/control_lib/double_buffer_tb.v @@ -0,0 +1,253 @@ +// +// 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 . +// + +module double_buffer_tb(); + + reg clk = 0; + reg rst = 1; + reg clear = 0; + initial #1000 rst = 0; + always #50 clk = ~clk; + + wire src_rdy_o; + reg src_rdy_i = 0; + wire dst_rdy_o; + + wire dst_rdy_i = 1; + wire [35:0] data_o; + reg [35:0] data_i; + + wire access_we, access_stb, access_done, access_ok, access_skip_read; + + wire [8:0] access_adr, access_len; + wire [35:0] dsp_to_buf, buf_to_dsp; + reg set_stb = 0; + + double_buffer db + (.clk(clk),.reset(rst),.clear(0), + .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(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 + (.clk(clk),.reset(rst),.clear(0), + .set_stb(set_stb), .set_addr(0), .set_data({13'h0,1'b1,18'h00400}), + .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)); + + always @(posedge clk) + if(src_rdy_o & dst_rdy_i) + begin + $display("SOF %d, EOF %d, OCC %x, DAT %x",data_o[32],data_o[33],data_o[35:34],data_o[31:0]); + if(data_o[33]) + $display(); + end + initial $dumpfile("double_buffer_tb.vcd"); + initial $dumpvars(0,double_buffer_tb); + + initial + begin + @(negedge rst); + @(posedge clk); + @(posedge clk); + @(posedge clk); + + // Passthrough + $display("Passthrough"); + src_rdy_i <= 1; + data_i <= { 2'b00,1'b0,1'b1,32'hFFFFFFFF}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h04050607}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h08090a0b}; + @(posedge clk); + data_i <= { 2'b00,1'b1,1'b0,32'h0c0d0e0f}; + @(posedge clk); + src_rdy_i <= 0; + @(posedge clk); + + 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}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h14151617}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h18191a1b}; + @(posedge clk); + data_i <= { 2'b00,1'b1,1'b0,32'h1c1d1e1f}; + @(posedge clk); + src_rdy_i <= 0; + @(posedge clk); + + while(~dst_rdy_o) + @(posedge clk); + + $display("No StreamID, No Trailer, Even"); + src_rdy_i <= 1; + data_i <= { 2'b00,1'b0,1'b1,32'h0000FFFF}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h01000200}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h03000400}; + src_rdy_i <= 0; + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + src_rdy_i <= 1; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h05000600}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h07000800}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h09000a00}; + @(posedge clk); + data_i <= { 2'b00,1'b1,1'b0,32'h0b000c00}; + @(posedge clk); + src_rdy_i <= 0; + @(posedge clk); + + while(~dst_rdy_o) + @(posedge clk); + + $display("No StreamID, No Trailer, Odd"); + src_rdy_i <= 1; + data_i <= { 2'b00,1'b0,1'b1,32'h0000FFFF}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h11001200}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h13001400}; + src_rdy_i <= 0; + @(posedge clk); + src_rdy_i <= 1; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h15001600}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h17001800}; + @(posedge clk); + data_i <= { 2'b00,1'b1,1'b0,32'h19001a00}; + @(posedge clk); + src_rdy_i <= 0; + @(posedge clk); + + 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}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h21002200}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h23002400}; + src_rdy_i <= 0; + @(posedge clk); + src_rdy_i <= 1; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h25002600}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h27002800}; + @(posedge clk); + data_i <= { 2'b00,1'b1,1'b0,32'h29002a00}; + @(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}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h31003200}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h33003400}; + src_rdy_i <= 0; + @(posedge clk); + src_rdy_i <= 1; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h35003600}; + @(posedge clk); + data_i <= { 2'b00,1'b1,1'b0,32'h39003a00}; + @(posedge clk); + src_rdy_i <= 0; + @(posedge clk); + + while(~dst_rdy_o) + @(posedge clk); + + $display("StreamID, No Trailer, Even"); + src_rdy_i <= 1; + data_i <= { 2'b00,1'b0,1'b1,32'h1000FFFF}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h11001200}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h13001400}; + src_rdy_i <= 0; + @(posedge clk); + src_rdy_i <= 1; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h15001600}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'h17001800}; + @(posedge clk); + data_i <= { 2'b00,1'b1,1'b0,32'h19001a00}; + @(posedge clk); + src_rdy_i <= 0; + @(posedge clk); + + while(~dst_rdy_o) + @(posedge clk); + + $display("StreamID, Trailer, Odd"); + src_rdy_i <= 1; + data_i <= { 2'b00,1'b0,1'b1,32'h1400FFFF}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'ha100a200}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'ha300a400}; + src_rdy_i <= 0; + @(posedge clk); + src_rdy_i <= 1; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'ha500a600}; + @(posedge clk); + data_i <= { 2'b00,1'b0,1'b0,32'ha700a800}; + @(posedge clk); + data_i <= { 2'b00,1'b1,1'b0,32'hbbb0bbb0}; + @(posedge clk); + src_rdy_i <= 0; + @(posedge clk); + + end + + initial #28000 $finish; +endmodule // double_buffer_tb -- cgit v1.2.3