Skip to content

Instantly share code, notes, and snippets.

@j-marjanovic
Created May 19, 2015 21:54
Show Gist options
  • Save j-marjanovic/3a1285f91486eb7bd70a to your computer and use it in GitHub Desktop.
Save j-marjanovic/3a1285f91486eb7bd70a to your computer and use it in GitHub Desktop.
SystemVerilog FIR filter generator
// 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
# -*- 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