Add some verilog tests to filter

parent 87e3bbc5
// Combined half-band filter and decimator
// See concept1.eps for general DSP idea
// See actual2.eps for graphical DSP representation
// Half-band filter configuration is
// -1 + 9 z^{-2} + 16 z^{-3} + 9 z^{-4} - 1 z^{-6}
// Decimation is controlled by the ab input, which _must_
// be clk/2. Output d gives a results when ab is low, and
// b results when ab is high. b results are delayed one
// cycle, corresponding to something like simultaneous
// sampling at the input.
// See actual2.eps
// Total 5 cycle latency for a, 6 cycles for b.
// Uses about 172 Slice Flip Flops and 174 4LUTs in Spartan-3.
// Larry Doolittle, LBNL, Oct. 2012
`timescale 1ns / 1ns
module half2(
input clk, // timespec 5.2 ns
input signed [15:0] a,
input signed [15:0] b,
input ab,
output signed [16:0] d
);
// buffer B one cycle, provides "simultaneous sampling"
reg [15:0] bb=0; always @(posedge clk) bb <= b;
// input switch
// left and right take their names from actual2.eps
wire signed [15:0] left = ab ? a : bb;
wire signed [15:0] right = ab ? bb : a;
wire signed [15:0] dl1;
reg_delay #(.dw(16), .len(3)) l1(.clk(clk),.gate(1'b1),.din(left),.dout(dl1));
wire signed [15:0] dr1, dr2;
reg_delay #(.dw(16), .len(2)) r1(.clk(clk),.gate(1'b1),.din(right),.dout(dr1));
reg_delay #(.dw(16), .len(4)) r2(.clk(clk),.gate(1'b1),.din(dr1), .dout(dr2));
`define SAT(x,old,new) ((~|x[old:new] | &x[old:new]) ? x : {x[old],{new{~x[old]}}})
reg signed [16:0] s1=0, s2=0;
reg signed [20:0] m9=0;
reg signed [21:0] s3=0, s4=0;
always @(posedge clk) begin
s1 <= right + dr1;
s2 <= right + dr2;
m9 <= s1 + (s1<<<3);
s3 <= m9 + (dl1<<<4) + 8; // un-bias the truncation step
s4 <= s3 - s2;
end
wire signed [17:0] penult = s4[21:4]; // truncate 4 lsb
assign d = `SAT(penult,17,16); // clip 1 msb
endmodule
`timescale 1ns / 1ns
// sine-based testing of pass band on channel b is quite stringent:
// reference sine wave has no phase shift (execpt for compensation of
// the pipeline delay), and a small amplitude change (predicatble from
// theory for the non-DC input). Only +/-1 bit error is allowed, with
// almost no bias. rms error should in principle be 1/sqrt(12) = 0.29,
// we demand it be less than 0.33.
module half2_tb;
reg clk;
reg tracea=0,traceb=0;
reg peak_fail=0, avg_fail=0, rms_fail=0, fail=0;
integer cc, nsamp=0, offbyone=0, sum=0;
initial begin
if ($test$plusargs("vcd")) begin
$dumpfile("half2.vcd");
$dumpvars(5,half2_tb);
end
if ($test$plusargs("tracea")) tracea=1;
if ($test$plusargs("traceb")) traceb=1;
for (cc=0; cc<140; cc=cc+1) begin
clk=0; #5;
clk=1; #5;
end
rms_fail = offbyone > (nsamp+2)/3;
avg_fail = (sum > 4) || (sum < -4);
fail = peak_fail | avg_fail | rms_fail;
$display("x %d %d %d %d %s",nsamp,offbyone,sum,peak_fail,fail?"FAIL":"PASS");
$finish();
end
reg signed [15:0] ina=0, inb=0, sine=0;
reg signed [16:0] sineref=0;
reg ing=0;
integer noise;
integer nseed=1234;
reg ab=0;
always @(posedge clk) begin
ab <= ~ab;
sine = $floor(30000.0*$sin((cc )*0.1596)+0.5);
sineref = $floor(59992.8*$sin((cc-6)*0.1596)+0.5);
ina <= (cc==4 || cc==17) ? 1024 : 0;
//inb <= (cc>30) ? 28000 : -28000;
inb <= sine;
end
wire signed [16:0] outd;
half2 dut(.clk(clk), .a(ina), .b(inb), .ab(ab), .d(outd));
reg fault;
always @(negedge clk) begin
fault=0;
if (ab && cc>10) begin
nsamp = nsamp+1;
sum = sum + outd - sineref;
if (outd!=sineref) offbyone=offbyone+1;
fault = (outd>sineref+1) || (outd<sineref-1);
if (fault) peak_fail=1;
end
if ((tracea && (ab==0)) || (traceb && (ab==1)))
$display("%d %d %d %d %d %d", ab, ina, inb, outd, sineref, fault);
end
endmodule
// Combined half-band filter and decimator
// See concept1.eps for general DSP idea
// See actual3.eps for graphical DSP representation
// Half-band filter configuration is
// -1 + 9 z^{-2} + 16 z^{-3} + 9 z^{-4} - 1 z^{-6}
// This version set up for input streams that are already
// two-channel interleaved..
// Decimation is controlled by the ab input, which _must_
// be clk/4. Output d gives a results when ab is low, and
// b results when ab is high. b results are delayed one
// cycle, corresponding to something like simultaneous
// sampling at the input.
// Total 5 cycle latency for a, 6 cycles for b.
// Uses about 172 Slice Flip Flops and 174 4LUTs in Spartan-3.
// Larry Doolittle, LBNL, Oct. 2012
`timescale 1ns / 1ns
module half3(
input clk, // timespec 5.2 ns
input signed [15:0] a,
input signed [15:0] b,
input ab,
output signed [16:0] d
);
// buffer B two cycles, provides "simultaneous sampling"
reg [15:0] b1=0; always @(posedge clk) b1 <= b;
reg [15:0] bb=0; always @(posedge clk) bb <= b1;
// input switch
// left and right take their names from actual3.eps
wire signed [15:0] left = ab ? a : bb;
wire signed [15:0] right = ab ? bb : a;
wire signed [15:0] dl1;
reg_delay #(.dw(16), .len(6)) l1(.clk(clk),.gate(1'b1),.din(left),.dout(dl1));
wire signed [15:0] dr1, dr2;
reg_delay #(.dw(16), .len(4)) r1(.clk(clk),.gate(1'b1),.din(right),.dout(dr1));
reg_delay #(.dw(16), .len(8)) r2(.clk(clk),.gate(1'b1),.din(dr1), .dout(dr2));
`define SAT(x,old,new) ((~|x[old:new] | &x[old:new]) ? x : {x[old],{new{~x[old]}}})
reg signed [16:0] s1=0, s2=0;
reg signed [20:0] m9=0, m9d=0, m9dd=0;
reg signed [21:0] s3=0, s4=0;
always @(posedge clk) begin
s1 <= right + dr1;
s2 <= right + dr2;
m9 <= s1 + (s1<<<3);
m9d <= m9;
m9dd <= m9d;
s3 <= m9dd + (dl1<<<4) + 8; // un-bias the truncation step
s4 <= s3 - s2;
end
wire signed [17:0] penult = s4[21:4]; // truncate 4 lsb
assign d = `SAT(penult,17,16); // clip 1 msb
endmodule
`timescale 1ns / 1ns
// sine-based testing of pass band on channel b is quite stringent:
// reference sine wave has no phase shift (execpt for compensation of
// the pipeline delay), and a small amplitude change (predicatble from
// theory for the non-DC input). Only +/-1 bit error is allowed, with
// almost no bias. rms error should in principle be 1/sqrt(12) = 0.29,
// we demand it be less than 0.33.
module half3_tb;
reg clk;
reg tracex=0,tracea=0,traceb=0;
reg peak_fail=0, avg_fail=0, rms_fail=0, fail=0;
integer cc, nsamp=0, offbyone=0, sum=0;
initial begin
if ($test$plusargs("vcd")) begin
$dumpfile("half3.vcd");
$dumpvars(5,half3_tb);
end
if ($test$plusargs("tracex")) tracex=1;
if ($test$plusargs("tracea")) tracea=1;
if ($test$plusargs("traceb")) traceb=1;
for (cc=0; cc<140; cc=cc+1) begin
clk=0; #5;
clk=1; #5;
end
rms_fail = offbyone > (nsamp+2)/3;
avg_fail = (sum > 4) || (sum < -4);
fail = peak_fail | avg_fail | rms_fail;
$display("x %d %d %d %d %s",nsamp,offbyone,sum,peak_fail,fail?"FAIL":"PASS");
$finish();
end
reg signed [15:0] ina=0, inb=0, sine=0;
reg signed [16:0] sineref=0;
reg ing=0;
integer noise;
integer nseed=1234;
reg [1:0] abc=0;
wire ab=abc[1];
wire cs=abc[0]; // cos vs. sin on a and b inputs
always @(posedge clk) begin
abc <= abc+1;
sine = $floor(30000.0*$sin((cc )*0.0798)+0.5);
sineref = $floor(59992.8*$sin((cc-10)*0.0798)+0.5);
ina <= (cc==4 || cc==17 || cc==30 || cc==43) ? 1024 : 0;
//inb <= (cc>30) ? 28000 : -28000;
inb <= cs ? sine : 0;
end
wire signed [16:0] outd;
half3 dut(.clk(clk), .a(ina), .b(inb), .ab(ab), .d(outd));
reg fault;
always @(negedge clk) begin
fault=0;
if ((abc==0) && (cc>16)) begin
nsamp = nsamp+1;
sum = sum + outd - sineref;
if (outd!=sineref) offbyone=offbyone+1;
fault = (outd>sineref+1) || (outd<sineref-1);
if (fault) peak_fail=1;
end
if (tracex | (tracea & (ab==0)) | (traceb & (abc==0)))
$display("%d %d %d %d %d %d", abc, ina, inb, outd, sineref, outd-sineref);
end
endmodule
`timescale 1ns / 1ns
module reg_delay(clk, gate, din, dout);
parameter dw=16;
parameter len=4;
input clk;
input gate;
input [dw-1:0] din;
output [dw-1:0] dout;
// len clocks of delay. Xilinx should turn this into
// dw*floor((len+15)/16)
// SRL16 shift registers, since there are no resets.
generate if (len > 1) begin: usual
reg [dw*len-1:0] shifter=0;
always @(posedge clk) if (gate) shifter <= {shifter[dw*len-1-dw:0],din};
assign dout = shifter[dw*len-1:dw*len-dw];
end else if (len > 0) begin: degen1
reg [dw*len-1:0] shifter=0;
always @(posedge clk) if (gate) shifter <= din;
assign dout = shifter[dw*len-1:dw*len-dw];
end else begin: degen0
assign dout = din;
end
endgenerate
endmodule
action = "simulation"
target = "xilinx"
sim_tool = "isim"
top_module = "half2_tb"
files = [
"../../../modules/filtdec/half2_tb.v",
"../../../modules/filtdec/half2.v",
"../../../modules/filtdec/reg_delay.v"
]
vcd dumpfile half2_tb.vcd
vcd dumpvars -m half2_tb -l 1
run 100000 ns
exit
#!/bin/bash
hdlmake
make && make fuse TOP_MODULE=half2_tb && ./isim_proj -tclbatch isim_cmd
action = "simulation"
target = "altera"
sim_tool = "modelsim"
top_module = "half2_tb"
files = [
"../../../modules/filtdec/half2_tb.v",
"../../../modules/filtdec/half2.v",
"../../../modules/filtdec/reg_delay.v"
]
#!/bin/bash
hdlmake
make
vsim -c -do vsim.do half2_tb
vcd file half2_tb.vcd;
vcd add -r /*;
run 100000ns;
quit;
target = "altera"
action = "synthesis"
# Supported families on tools/quartus.py
# Quartus Web only supports the family ep2agx45:
syn_device = "ep2agx45cu"
syn_grade = "c6"
syn_package = "17"
syn_top = "half2"
syn_project = "half2"
#syn_tool = "quartus"
files = [
"../../../modules/filtdec/half2.v",
"../../../modules/filtdec/reg_delay.v"
]
#!/bin/bash
hdlmake quartus-project
# Quartus bin needs to be exported to path
quartus_sh --tcl_eval load_package flow \; project_open half2 \; execute_flow -compile
target = "xilinx"
action = "synthesis"
syn_device = "xc6slx45t"
syn_grade = "-3"
syn_package = "fgg484"
syn_top = "half2"
syn_project = "half2.xise"
syn_tool = "ise"
files = [
"../../../modules/filtdec/half2.v",
"../../../modules/filtdec/reg_delay.v"
]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment