sugar-lissajous/source/fir_filter.sv
2021-02-28 18:59:56 +03:00

124 lines
2.8 KiB
Systemverilog

`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