Initial commit
This commit is contained in:
123
source/fir_filter.sv
Normal file
123
source/fir_filter.sv
Normal file
@@ -0,0 +1,123 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
|
||||
module fir_filter #(parameter LEN = 449,
|
||||
parameter COEFFS_ROM_FILE = "fir_449_50hz_100hz_10db_40db.rom")
|
||||
(input wire clock,
|
||||
input wire reset,
|
||||
|
||||
input wire signed [15:0] data_i,
|
||||
input wire ready_i,
|
||||
|
||||
output wire signed [15:0] data_o,
|
||||
output reg valid_o);
|
||||
|
||||
localparam LEN_CW = $clog2(LEN);
|
||||
localparam MEM_LEN = 1 << LEN_CW;
|
||||
|
||||
/* Coeffs */
|
||||
logic signed [15:0] coeffs[LEN];
|
||||
initial $readmemh(COEFFS_ROM_FILE, coeffs, 0, LEN-1);
|
||||
|
||||
logic signed [15:0] coeff;
|
||||
logic [LEN_CW-1:0] coeff_addr;
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
coeff <= coeffs[coeff_addr];
|
||||
|
||||
/* Z-1 BlockRAM */
|
||||
logic signed [15:0] mem[MEM_LEN];
|
||||
logic signed [15:0] mem_wdata;
|
||||
logic signed [15:0] mem_rdata;
|
||||
logic [LEN_CW-1:0] mem_addr;
|
||||
logic mem_wr;
|
||||
|
||||
always_ff @ (posedge clock) begin
|
||||
if (mem_wr)
|
||||
mem[mem_addr] <= mem_wdata;
|
||||
mem_rdata <= mem[mem_addr];
|
||||
end
|
||||
|
||||
initial begin
|
||||
integer i;
|
||||
for (i = 0; i < MEM_LEN; i++)
|
||||
mem[i] = '0;
|
||||
end
|
||||
|
||||
/* MAC */
|
||||
logic [31:0] mac_o;
|
||||
logic signed [15:0] a;
|
||||
logic signed [15:0] b;
|
||||
logic signed [15:0] s;
|
||||
|
||||
ice40_mac16x16 #(.SIGNED(1)) mac
|
||||
(.clock, .reset,
|
||||
.a(a),
|
||||
.b(b),
|
||||
.s({s, 16'b0}),
|
||||
.sub(1'b0),
|
||||
.y(mac_o));
|
||||
|
||||
/* FSM */
|
||||
enum int unsigned {
|
||||
ST_IDLE = 0,
|
||||
ST_WRITE,
|
||||
ST_CONV,
|
||||
ST_DONE
|
||||
} state;
|
||||
|
||||
logic [LEN_CW-1:0] new_addr;
|
||||
|
||||
assign mem_wdata = data_i;
|
||||
assign data_o = s;
|
||||
assign s = coeff_addr == '0 ? '0 : mac_o[31:16];
|
||||
|
||||
always_ff @ (posedge clock, posedge reset)
|
||||
if (reset) begin
|
||||
state <= ST_IDLE;
|
||||
new_addr <= '0;
|
||||
mem_wr <= 1'b0;
|
||||
valid_o <= 1'b0;
|
||||
end
|
||||
else
|
||||
case (state)
|
||||
ST_IDLE: begin
|
||||
a <= '0;
|
||||
b <= '0;
|
||||
mem_addr <= new_addr;
|
||||
coeff_addr <= '0;
|
||||
|
||||
if (ready_i) begin
|
||||
mem_wr <= 1'b1;
|
||||
state <= ST_WRITE;
|
||||
end
|
||||
end
|
||||
|
||||
ST_WRITE: begin
|
||||
mem_wr <= 1'b0;
|
||||
state <= ST_CONV;
|
||||
end
|
||||
|
||||
ST_CONV: begin
|
||||
a <= mem_rdata;
|
||||
b <= coeff;
|
||||
|
||||
if (coeff_addr == LEN_CW'(LEN-1)) begin
|
||||
valid_o <= 1'b1;
|
||||
state <= ST_DONE;
|
||||
end
|
||||
else begin
|
||||
coeff_addr <= coeff_addr + 1'b1;
|
||||
mem_addr <= mem_addr - 1'b1;
|
||||
state <= ST_CONV;
|
||||
end
|
||||
end
|
||||
|
||||
ST_DONE: begin
|
||||
new_addr <= new_addr + 1'b1;
|
||||
valid_o <= 1'b0;
|
||||
state <= ST_IDLE;
|
||||
end
|
||||
endcase
|
||||
|
||||
endmodule // fir_filter
|
||||
Reference in New Issue
Block a user