diff options
author | Matt Ettus <matt@ettus.com> | 2011-10-06 22:21:59 -0700 |
---|---|---|
committer | Matt Ettus <matt@ettus.com> | 2011-10-26 15:57:22 -0700 |
commit | f4c61186f6a81a09a038cef500d07d4ca5e65a57 (patch) | |
tree | 47d9244d4761d50ee87067324d4ba3ea38b4a028 /usrp2/sdr_lib | |
parent | c215afef149acf35cca87d1a5053d2c48957652c (diff) | |
download | uhd-f4c61186f6a81a09a038cef500d07d4ca5e65a57.tar.gz uhd-f4c61186f6a81a09a038cef500d07d4ca5e65a57.tar.bz2 uhd-f4c61186f6a81a09a038cef500d07d4ca5e65a57.zip |
dsp_engine: new way of doing DSP operations on VITA packets. Example does 16 to 8 bit conversion
Diffstat (limited to 'usrp2/sdr_lib')
-rw-r--r-- | usrp2/sdr_lib/clip_reg.v | 14 | ||||
-rw-r--r-- | usrp2/sdr_lib/dspengine_16to8.v | 221 | ||||
-rw-r--r-- | usrp2/sdr_lib/pipectrl.v | 66 | ||||
-rw-r--r-- | usrp2/sdr_lib/pipestage.v | 45 |
4 files changed, 343 insertions, 3 deletions
diff --git a/usrp2/sdr_lib/clip_reg.v b/usrp2/sdr_lib/clip_reg.v index d5e98d982..9098fd5b8 100644 --- a/usrp2/sdr_lib/clip_reg.v +++ b/usrp2/sdr_lib/clip_reg.v @@ -23,16 +23,24 @@ module clip_reg #(parameter bits_in=0, - parameter bits_out=0) + parameter bits_out=0, + parameter STROBED=1'b0) (input clk, input [bits_in-1:0] in, - output reg [bits_out-1:0] out); + output reg [bits_out-1:0] out, + input strobe_in, + output reg strobe_out); wire [bits_out-1:0] temp; clip #(.bits_in(bits_in),.bits_out(bits_out)) clip (.in(in),.out(temp)); + + always @(posedge clk) + strobe_out <= strobe_in; + always @(posedge clk) - out <= temp; + if(strobe_in | ~STROBED) + out <= temp; endmodule // clip_reg diff --git a/usrp2/sdr_lib/dspengine_16to8.v b/usrp2/sdr_lib/dspengine_16to8.v new file mode 100644 index 000000000..8f1b939a9 --- /dev/null +++ b/usrp2/sdr_lib/dspengine_16to8.v @@ -0,0 +1,221 @@ + +// 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 dspengine_16to8 + #(parameter BASE = 0, + parameter BUF_SIZE = 9) + (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; + wire [17:0] scale_factor; + + setting_reg #(.my_addr(BASE),.width(19)) sr_16to8 + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out({convert,scale_factor}),.changed()); + + reg [2:0] dsp_state; + localparam DSP_IDLE = 0; + localparam DSP_PARSE_HEADER = 1; + localparam DSP_CONVERT = 2; + localparam DSP_CONVERT_DRAIN_PIPE = 3; + localparam DSP_READ_TRAILER = 4; + localparam DSP_WRITE_TRAILER = 5; + localparam DSP_WRITE_HEADER = 6; + localparam DSP_DONE = 7; + + // 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; + + wire [35:0] prod_i, prod_q; + 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_out, stb_reg; + reg even; + + reg [BUF_SIZE-1:0] read_adr, write_adr; + reg has_trailer_reg; + + wire last = (read_adr + 1) == (access_len - has_trailer_reg); + wire last_o, even_o; + + wire stb_write = stb_out & (even_o | last_o); + wire send_to_pipe = ~stb_write & (dsp_state == DSP_CONVERT); + reg [31:0] new_header, new_trailer, trailer_mask; + reg [15:0] length; + reg wait_for_trailer; + + always @(posedge clk) + if(reset | clear) + dsp_state <= DSP_IDLE; + else + case(dsp_state) + DSP_IDLE : + begin + read_adr <= 0; + write_adr <= 0; + even <= 0; + if(access_ok) + dsp_state <= DSP_PARSE_HEADER; + end + + DSP_PARSE_HEADER : + begin + has_trailer_reg <= has_trailer; + new_header[31:16] <= access_dat_i[31:16]; + new_header[15:0] <= access_len; + length <= access_len; + if(is_if_data & convert) + begin + read_adr <= hdr_length; + write_adr <= hdr_length; + dsp_state <= DSP_CONVERT; + end + else + dsp_state <= DSP_WRITE_HEADER; + end + + DSP_CONVERT: + begin + new_header[26] <= 1'b1; // all converted packets have a trailer + if(stb_write) + write_adr <= write_adr + 1; + else if(stb_read) // should always be 1 if we are here + begin + read_adr <= read_adr + 1; + even <= ~even; + if(last) + begin + dsp_state <= DSP_CONVERT_DRAIN_PIPE; + if(~even) + trailer_mask <= 32'h00010001; + else + trailer_mask <= 32'h00010000; + end + end + end + + DSP_CONVERT_DRAIN_PIPE : + if(stb_write) + begin + write_adr <= write_adr + 1; + if(last_o) + if(has_trailer_reg) + begin + dsp_state <= DSP_READ_TRAILER; + wait_for_trailer <= 0; + end + else + begin + dsp_state <= DSP_WRITE_TRAILER; + new_trailer <= trailer_mask; + 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] | trailer_mask; + end + + DSP_WRITE_TRAILER : + begin + dsp_state <= DSP_WRITE_HEADER; + write_adr <= 0; + new_header[15:0] <= write_adr + 1; + end + + DSP_WRITE_HEADER : + dsp_state <= DSP_DONE; + + DSP_DONE : + begin + read_adr <= 0; + write_adr <= 0; + 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) | + stb_write; + + 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 }; + + assign access_adr = (stb_write|(dsp_state == DSP_WRITE_HEADER)|(dsp_state == DSP_WRITE_TRAILER)) ? write_adr : read_adr; + + // DSP Pipeline + + wire [15:0] i16 = access_dat_i[31:16]; + wire [15:0] q16 = access_dat_i[15:0]; + + pipectrl #(.STAGES(4), .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}), + .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)) 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)) round_q + (.clk(clk), .reset(reset), .in(scaled_q), .strobe_in(stb_round), .out(q8), .strobe_out()); + +endmodule // dspengine_16to8 diff --git a/usrp2/sdr_lib/pipectrl.v b/usrp2/sdr_lib/pipectrl.v new file mode 100644 index 000000000..85d0ce04f --- /dev/null +++ b/usrp2/sdr_lib/pipectrl.v @@ -0,0 +1,66 @@ +// +// 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/>. +// + +// Control DSP pipeline with 1 cycle per stage. Minimum 2 stages or this won't work +module pipectrl + #(parameter STAGES = 2, + parameter TAGWIDTH = 1) + (input clk, + input reset, + input src_rdy_i, + output dst_rdy_o, + output src_rdy_o, + input dst_rdy_i, + output [STAGES-1:0] strobes, + output [STAGES-1:0] valids, + input [TAGWIDTH-1:0] tag_i, + output [TAGWIDTH-1:0] tag_o); + + wire new_input = src_rdy_i & dst_rdy_o; + wire new_output = src_rdy_o & dst_rdy_i; + wire [TAGWIDTH-1:0] tags [STAGES-1:0]; + + assign dst_rdy_o = ~valids[0] | strobes[1]; + + pipestage #(.TAGWIDTH(TAGWIDTH)) head + (.clk(clk),.reset(reset), .stb_in(strobes[0]), .stb_out(strobes[1]),.valid(valids[0]), + .tag_in(tag_i), .tag_out(tags[0])); + assign strobes[0] = src_rdy_i & (~valids[0] | strobes[1]); + + genvar i; + generate + for(i = 1; i < STAGES - 1; i = i + 1) + begin : gen_stages + pipestage #(.TAGWIDTH(TAGWIDTH)) pipestage + (.clk(clk),.reset(reset), .stb_in(strobes[i]),.stb_out(strobes[i+1]),.valid(valids[i]), + .tag_in(tags[i-1]),.tag_out(tags[i])); + assign strobes[i] = valids[i-1] & (~valids[i] | strobes[i+1]); + end + endgenerate + + pipestage #(.TAGWIDTH(TAGWIDTH)) tail + (.clk(clk),.reset(reset), .stb_in(strobes[STAGES-1]), .stb_out(dst_rdy_i),.valid(valids[STAGES-1]), + .tag_in(tags[STAGES-2]), .tag_out(tags[STAGES-1])); + assign strobes[STAGES-1] = valids[STAGES-2] & (~valids[STAGES-1] | new_output); + + assign src_rdy_o = valids[STAGES-1]; + + assign tag_o = tags[STAGES-1]; + +endmodule // pipectrl + + diff --git a/usrp2/sdr_lib/pipestage.v b/usrp2/sdr_lib/pipestage.v new file mode 100644 index 000000000..011afb1ba --- /dev/null +++ b/usrp2/sdr_lib/pipestage.v @@ -0,0 +1,45 @@ +// +// 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 pipestage + #(parameter TAGWIDTH = 1) + (input clk, + input reset, + input stb_in, + input stb_out, + output reg valid, + input [TAGWIDTH-1:0] tag_in, + output reg [TAGWIDTH-1:0] tag_out); + + always @(posedge clk) + if(reset) + begin + valid <= 0; + tag_out <= 0; + end + else if(stb_in) + begin + valid <= 1; + tag_out <= tag_in; + end + else if(stb_out) + begin + valid <= 0; + tag_out <= 0; + end + +endmodule // pipestage |