Created
May 19, 2015 21:54
-
-
Save j-marjanovic/3a1285f91486eb7bd70a to your computer and use it in GitHub Desktop.
SystemVerilog FIR filter generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (C) 2014 Jan Marjanovic | |
//`define DEBUG | |
module filter #( | |
parameter IO_B = #I0_B#, // input and output data width | |
parameter INT_B = #INT_B#, // integer part of internal quotient | |
parameter FRAC_B = #FRAC_B# // integer part of internal quotient | |
) ( | |
//---------- Clock and reset----------- | |
input clk, | |
input reset_n, | |
//---------- Input -------------------- | |
input [IO_B-1:0] in_data, | |
input in_valid, | |
//---------- Output ------------------- | |
output [IO_B-1:0] out_data, | |
output logic out_valid | |
); | |
localparam Q_BITS = INT_B + FRAC_B + 1; | |
localparam signed [Q_BITS-1:0] A [#A_LEN#] = | |
{ #A# }; | |
localparam signed [Q_BITS-1:0] B [#B_LEN#] = | |
{ #B# }; | |
localparam _nr_params = $size(A) + $size (B); | |
logic [2*Q_BITS-1:0] acc; | |
logic [2*Q_BITS-1:0] mult; | |
logic signed [Q_BITS-1:0] y [$size(A)]; | |
logic signed [Q_BITS-1:0] x [$size(B)]; | |
logic [Q_BITS-1:0] out_reg; | |
assign out_data = out_reg[FRAC_B-1:(FRAC_B-IO_B)]; | |
//============================================================================= | |
// save old values | |
always_ff @ (posedge clk or negedge reset_n) begin | |
if ( !reset_n ) begin | |
for(int i = 0; i < $size(x); i++) | |
x[i] <= 0; | |
for(int i = 0; i < $size(y); i++) | |
y[i] <= 0; | |
end else begin | |
if( out_valid ) begin | |
for(int i = $size(A); i > 0; i--) begin | |
y[i] = y[i-1]; | |
end | |
y[0] = out_reg; | |
end | |
if( in_valid ) begin | |
for(int i = $size(B); i > 0; i--) begin | |
x[i] = x[i-1]; | |
end | |
//x[0] = {8'd0, in_data, 8'd0}; | |
x[0] = {{(Q_BITS-(FRAC_B-IO_B)){1'b0}}, in_data, {(FRAC_B-IO_B){1'b0}}}; | |
end | |
end | |
end | |
//============================================================================= | |
// state machine for calculation | |
logic [$clog2(_nr_params)-1:0] cntr; | |
enum { IDLE, | |
CALC_A, | |
CALC_B, | |
LAST_ACC, | |
DONE } state; | |
always_ff @ (posedge clk or negedge reset_n) begin | |
if ( !reset_n ) begin | |
state <= IDLE; | |
end else begin | |
out_valid <= 0; | |
case(state) | |
//======================================================== | |
IDLE: begin | |
if(in_valid) begin | |
state <= CALC_A; | |
cntr <= 0; | |
acc <= 0; | |
mult <= 0; | |
`ifdef DEBUG | |
$display("------------------------------"); | |
`endif | |
end | |
end | |
//======================================================== | |
CALC_A: begin | |
cntr <= cntr + 1; | |
if( cntr == $size(A) - 1 ) begin | |
state <= CALC_B; | |
cntr <= 0; | |
end | |
mult <= A[cntr] * y[cntr]; | |
acc <= acc + mult; | |
`ifdef DEBUG | |
$display("%t acc = %d",$time(), acc/2**FRAC_B); | |
`endif | |
end | |
//======================================================== | |
CALC_B: begin | |
cntr <= cntr + 1; | |
if( cntr == $size(B) - 1 ) begin | |
state <= LAST_ACC; | |
cntr <= 0; | |
end | |
mult <= B[cntr] * x[cntr]; | |
acc <= acc + mult; | |
`ifdef DEBUG | |
$display("%t acc = %d",$time(), acc/2**FRAC_B); | |
`endif | |
end | |
LAST_ACC: begin | |
acc <= acc + mult; | |
`ifdef DEBUG | |
$display("%t acc = %d",$time(), acc/2**FRAC_B); | |
`endif | |
state <= DONE; | |
end | |
//======================================================== | |
DONE: begin | |
out_valid <= 1; | |
out_reg <= acc[FRAC_B+Q_BITS-1:FRAC_B]; | |
state <= IDLE; | |
`ifdef DEBUG | |
$display("%t out = %d",$time(), acc/2**FRAC_B); | |
`endif | |
end | |
//======================================================== | |
endcase | |
end | |
end | |
endmodule |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
Copyright (C) 2014 Jan Marjanovic | |
""" | |
import scipy.signal as sig | |
import math | |
import matplotlib.pyplot as plt | |
import numpy as np | |
# 1 bit sign, 7 bits integer, 24 bit fraction | |
_bits_int = 7 | |
_bits_frac = 24 | |
_bits_io = 16 | |
Fsamp = 10000. | |
Ts = 1.0/Fsamp | |
Fpass = 15. | |
Fstop = 40. | |
gpass = 0.1 | |
gstop = 20 | |
######### | |
b,a = sig.iirdesign(wp = Fpass/(Fsamp/2.0), | |
ws = Fstop/(Fsamp/2.0), | |
gpass = gpass, | |
gstop = gstop, | |
analog = False) | |
_bits = _bits_int + _bits_frac + 1 | |
############################################################################### | |
def quantize(val): | |
if val > 255 or val < -255: | |
raise error('Invalid value') | |
val *= 2**_bits_frac | |
val = round(val) | |
val /= 2**_bits_frac | |
return val | |
def to_bits(d): | |
if d > 0: | |
hexStr = hex(int(d*2**_bits_frac)) | |
if d < 0: | |
d = int(-d*2**_bits_frac) | |
d ^= 2**(_bits)-1 | |
d += 1 | |
hexStr = hex(d) | |
hexStr = hexStr[2:] | |
nib = int(math.ceil(_bits/4.)) | |
hexStr = "0"*(nib-len(hexStr)) + hexStr | |
return str(_bits)+"'h"+hexStr | |
############################################################################### | |
def plot_step_response(a,b): | |
aq = [quantize(ai) for ai in a] | |
bq = [quantize(bi) for bi in b] | |
T = np.linspace(0,1,Fsamp) | |
u = [0.0] * 1000 | |
u.extend([0.25] * (len(a)-1+int(Fsamp)-1000)) | |
y = [0] * (len(a)-1+int(Fsamp)) | |
yq = [0] * (len(a)-1+int(Fsamp)) | |
for i in range(len(a),len(a)-1+int(Fsamp)): | |
ya = 0 | |
yb = 0 | |
for j in range(1,len(a)): | |
ya += a[j]*y[i-j] | |
for j in range(len(b)): | |
yb += b[j]*u[i-j] | |
y[i] = yb - ya | |
plt.plot(y) | |
for i in range(len(a),len(u)): | |
ya = 0 | |
yb = 0 | |
for j in range(1,len(aq)): | |
ya += quantize(-aq[j]*yq[i-j]) | |
ya = quantize(ya) | |
for j in range(len(bq)): | |
ya += quantize(bq[j]*u[i-j]) | |
ya = quantize(ya) | |
yq[i] = quantize(ya) | |
plt.plot(yq) | |
plt.show(block=True) | |
############################################################################### | |
def gen_a_b_str(a,b): | |
a_str = "" | |
a = a[1:] # first one is 1. (y[i]) | |
for ai in a: | |
a_str += ", " + to_bits(-ai) | |
a_str = a_str[1:] | |
b_str = "" | |
for bi in b: | |
b_str += ", " + to_bits(bi) | |
b_str = b_str[1:] | |
return a_str, b_str | |
############################################################################### | |
def gen_verilog_filter(): | |
print "Generating SystemVerilog filter module" | |
a_str, b_str = gen_a_b_str(a,b) | |
ftpl = open("filter.tpl", "r") | |
fsv = open("filter.sv", "w") | |
for line in ftpl: | |
line = line.replace("#I0_B#", str(_bits_io)) | |
line = line.replace("#INT_B#", str(_bits_int)) | |
line = line.replace("#FRAC_B#", str(_bits_frac)) | |
line = line.replace("#A_LEN#", str(len(a)-1)) | |
line = line.replace("#B_LEN#", str(len(b))) | |
line = line.replace("#A#", a_str) | |
line = line.replace("#B#", b_str) | |
fsv.write(line) | |
ftpl.close() | |
fsv.close() | |
############################################################################### | |
def gen_verilog_tb(): | |
print "Generating SystemVerilog testbench" | |
ftpl = open("filter_tb.tpl", "r") | |
fsv = open("filter_tb.sv", "w") | |
for line in ftpl: | |
line = line.replace("#IO_B#", str(_bits_io)) | |
line = line.replace("#SIG_LEN#", str(int(Fsamp))) | |
fsv.write(line) | |
ftpl.close() | |
fsv.close() | |
############################################################################### | |
def gen_test_signal(): | |
global Fsamp | |
T = np.linspace(0,1,Fsamp) | |
y = 2000*(np.sin(2*math.pi*5.0*T) + np.sin(2*math.pi*50.0*T) +np.sin(2*math.pi*3000.0*T))+6000 | |
f = open("signal.h","w") | |
for i in range(len(y)): | |
f.write("signal["+str(i)+"] = 16'd"+str(int(y[i]))+";\n") | |
f.close() | |
############################################################################### | |
if __name__ == '__main__': | |
plot_step_response(a,b) | |
sel = raw_input("Generate filter[y/N]?") | |
if sel[0].lower() == 'y': | |
gen_verilog_filter() | |
gen_verilog_tb() | |
gen_test_signal() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment