|
|
FIR filter (and waveforms)
A simple FIR filter can be built as follows in HDFS.
#light
open DigitalLogic
open Numeric.Ops
open Signal
open Util
open List
let fir_hw input coeffs =
let mul, _ =
fold_left (fun (taps,prev) cof ->
let tap = regc enable prev
taps @ [ regc enable (tap *+ cof) ], tap
) ([],input) coeffs
binary_tree
(fun (d:Signal) -> regc enable d.se)
(fun (x:Signal) (y:Signal) -> regc enable (x.se + y.se)) mulThe function builds the filter in two parts. The fold_left function constructs a set of taps which store previous input values for the convolution. At each cycle a new input enters the circuit and the taps shuffle along one place. The taps are then multiplied by the relevant coefficient and the result stored in a register. The function returns a list of the multiplied values.
The binary_tree function generates a pipelined adder tree to calculate the final result. Note how we dont need to worry about the number of coefficients or bit precision of any signals - this in all taken care of automatically due to the way the data is structured (as lists) and by the definition of the operators used.
Note that while this is a pretty area expensive implementation of an FIR filter it has a throughput of 1 result per cycle and as all internal arithmetic operations are registered will run at a high clock rate.
With a circuit built it must be tested to ensure correctness. In general the best way to approach that is to write a golden reference model (ie a software implementation of the filter) and check it against the hardware version in simulation.
let fir_sw coeffs inputs =
let fir_ref input taps coeffs =
let taps = lselect (input :: taps) 0 ((length coeffs) - 1)
fold_left (fun acc (t,c) -> acc + (t * c)) 0 (combine taps coeffs), taps
let rec calc i taps =
if i <> Array.length inputs then
let a,taps = fir_ref inputs.(i) taps coeffs
printf "%x\n" a
calc (i+1) taps
let taps = map (fun x -> 0) coeffs
calc 0 tapsThis function takes the filter coefficients and input data and prints the filter results to the console.
let fir_sim coeffs coeff_bits inputs input_bits =
let outputs = [ output "q" (fir_hw (input "d" input_bits) (map (consti coeff_bits) coeffs)) ]
let circuit = Circuit.create outputs
let sim = Simulator.create circuit
let sim, data = sim.record
let enable = sim.port "enable"
let d = sim.port "d"
let q = sim.port "q"
sim.reset
enable.i <- 1
for i=0 to Array.length inputs - 1 do
d.i <- inputs.(i)
sim.cycle
for i=0 to 4 do
sim.cycle
Waveform.draw2 data Waveform.HexFormatThis performs the actual hardware simulation and draws the waveform.
let coeffs = [ 1; 11; -20; 14; -5 ] let coeff_bits = 6 let inputs = [| 10; -20; 30; 40 |] let input_bits = 7 do fir_sw coeffs inputs do fir_sim coeffs coeff_bits inputs input_bits
This code configures the test (bit precision, coefficients and input test data) and runs the reference model and simulation.
Sign in to add a comment
