forked from BerkeleyLab/Bedrock
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcomplex_freq_tb.v
129 lines (121 loc) · 3.19 KB
/
complex_freq_tb.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
`timescale 1ns / 1ns
module complex_freq_tb;
reg clk;
integer cc;
reg fail=0;
initial begin
if ($test$plusargs("vcd")) begin
$dumpfile("complex_freq.vcd");
$dumpvars(5, complex_freq_tb);
end
for (cc=0; cc<20000; cc=cc+1) begin
clk=0; #5;
clk=1; #5;
end
if (fail) begin
$display("FAIL");
$stop(); // When run from Icarus vvp -N,
// at least, this results in an exit code of 1
// that can be detected as a failure by make(1).
end else $display("PASS");
$finish();
end
// White-noise generator
reg [19:0] noisebits;
integer noise, ix;
task new_noise;
begin
noisebits = $random;
noise = 0;
for (ix=0; ix<20; ix=ix+2)
noise = noise + noisebits[ix] - noisebits[ix+1];
end
endtask
// Create stimulus
reg signed [17:0] sdata;
reg sgate;
real theta, st, ct;
parameter tperiod=30; // each sample pair needs about 22 cycles to process
integer amp=1000;
real dtheta=1.0;
always @(posedge clk) begin
sdata <= 18'bx;
sgate <= 0;
if (cc%tperiod == 10) begin
sgate <= 1;
sdata <= st;
end else if (cc%tperiod == 11) begin
sgate <= 1;
sdata <= ct;
end else if (cc%tperiod == 9) begin
theta = theta + dtheta;
// sin
new_noise;
st = amp*$sin(theta) + noise;
// cos
new_noise;
ct = amp*$cos(theta) + noise;
end
if (cc==tperiod*32*4) dtheta = -0.75;
if (cc==tperiod*32*5) amp = 131060;
if (cc==tperiod*32*8) dtheta = 1.90; // purposefully invalid
if (cc==tperiod*32*12) dtheta = 0.50;
if (cc==tperiod*32*17) amp = 0;
end
// Instantiate DUT
parameter refcnt_w = 5;
wire signed [refcnt_w-1:0] freq;
wire freq_valid, updated, timing_err;
wire [16:0] amp_max, amp_min;
complex_freq #(.refcnt_w(refcnt_w)) dut(
.clk(clk), .sdata(sdata), .sgate(sgate),
.freq(freq), .freq_valid(freq_valid),
.amp_max(amp_max), .amp_min(amp_min),
.updated(updated), .timing_err(timing_err)
);
// Check for transitions at the wrong time
reg [16:0] amp_max_d, amp_min_d;
reg [refcnt_w-1:0] freq_d;
reg bad=0;
always @(posedge clk) begin
freq_d <= freq;
amp_max_d <= amp_max;
amp_min_d <= amp_min;
bad <= 0;
if (~updated) begin
if (freq_d != freq) bad <= 1;
if (amp_max_d != amp_max) bad <= 1;
if (amp_min_d != amp_min) bad <= 1;
end
if (timing_err) bad <= 1;
if (bad) fail = 1;
end
// Check the output
integer amp_d1, tmp;
reg fault;
integer scount=0;
always @(negedge clk) if (updated) begin
fault = 0;
tmp = amp; if (amp_d1 > amp) tmp = amp_d1; // $display(tmp, amp_max);
tmp = amp_max - tmp - 2; if (tmp < 0) tmp = -tmp; if (tmp > 6) fault = 1;
tmp = amp; if (amp_d1 < amp) tmp = amp_d1; // $display(tmp, amp_min);
tmp = tmp - amp_min - 2; if (tmp < 0) tmp = -tmp; if (tmp > 6) fault = 1;
// Expected frequency range crudely tracks dtheta
case (scount)
2: if (freq > -9 || freq < -11) fault=1;
3: if (freq > -9 || freq < -11) fault=1;
6: if (freq > 9 || freq < 7) fault=1;
7: if (freq > 9 || freq < 7) fault=1;
10: if (freq_valid) fault=1;
11: if (freq_valid) fault=1;
14: if (freq > -4 || freq < -6) fault=1;
15: if (freq > -4 || freq < -6) fault=1;
19: if (freq_valid) fault=1;
endcase
$display("%2d %d %d %d %d %d %d %s", scount, freq, freq_valid,
amp_max, amp_min, amp, amp_d1, fault ? "FAULT" : " .");
amp_d1 = amp;
if (fault) fail = 1;
scount = scount + 1;
end
endmodule