kopia lustrzana https://github.com/pa3gsb/Radioberry-2.x
251 wiersze
8.8 KiB
Verilog
251 wiersze
8.8 KiB
Verilog
//
|
|
// HPSDR - High Performance Software Defined Radio
|
|
//
|
|
// Hermes code.
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
// Polyphase decimating filter
|
|
|
|
// Based on firX8R8 by James Ahlstrom, N2ADR, (C) 2011
|
|
// Modified for use with HPSDR and DC spur removed by Phil Harman, VK6APH, (C) 2013
|
|
|
|
|
|
// This is a decimate by 8 Polyphase FIR filter. Since it decimates by 8 the output signal
|
|
// level will be 1/8 the input level. The filter coeficients are distributed between the 8
|
|
// FIR filters such that the first FIR receives coeficients 0, 7, 15... the second 1, 8, 16.. the
|
|
// third 2, 9, 17.. etc. The coeficients are calculated as per normal but there is no need to
|
|
// compensate for the sinx/x shape of the preceeding CIC filters. This is because the filter
|
|
// decimates by 8 and the droop of the CIC at 1/8th its fs/2 is neglibible.
|
|
// The filter coefficients are in the file "coefL8.txt". This is split into 8 individual
|
|
// Quartus ROM *.mif files.
|
|
|
|
// The filter coefficients are also attenuated such that the result of the multiply and accumalate
|
|
// does not exceed 24 bits.
|
|
|
|
// Note: Gain is higher than previous filter code by 6dB so reduce outside this module.
|
|
// FIR filters
|
|
//
|
|
// ROM init file: REQUIRED, with 256 or 512 coefficients. See below.
|
|
// Number of taps: NTAPS.
|
|
// Input bits: 18 fixed.
|
|
// Output bits: OBITS, default 24.
|
|
// Adder bits: ABITS, default 24.
|
|
|
|
// This requires eight MifFile's.
|
|
// Maximum NTAPS is 8 * (previous and current decimation) less overhead.
|
|
// Maximum NTAPS is 2048 (or less).
|
|
|
|
module firX8R8 (
|
|
input clock,
|
|
input x_avail, // new sample is available
|
|
input signed [MBITS-1:0] x_real, // x is the sample input
|
|
input signed [MBITS-1:0] x_imag,
|
|
output reg y_avail, // new output is available
|
|
output wire signed [OBITS-1:0] y_real, // y is the filtered output
|
|
output wire signed [OBITS-1:0] y_imag);
|
|
|
|
localparam ADDRBITS = 8; // Address bits for 18/36 X 256 rom/ram blocks
|
|
localparam MBITS = 18; // multiplier bits == input bits
|
|
|
|
parameter
|
|
TAPS = NTAPS / 8, // Must be even by 8
|
|
ABITS = 24, // adder bits
|
|
OBITS = 24, // output bits
|
|
NTAPS = 976; // number of filter taps, even by 8
|
|
|
|
reg [4:0] wstate; // state machine for write samples
|
|
|
|
reg [ADDRBITS-1:0] waddr; // write sample memory address
|
|
reg weA, weB, weC, weD, weE, weF, weG, weH;
|
|
reg signed [ABITS-1:0] Racc, Iacc;
|
|
wire signed [ABITS-1:0] RaccA, RaccB, RaccC, RaccD, RaccE, RaccF, RaccG, RaccH;
|
|
wire signed [ABITS-1:0] IaccA, IaccB, IaccC, IaccD, IaccE, IaccF, IaccG, IaccH;
|
|
|
|
// Output is the result of adding 8 by 24 bit results so Racc and Iacc need to be
|
|
// 24 + log2(8) = 24 + 3 = 27 bits wide to prevent DC spur.
|
|
// However, since we decimate by 8 the output will be 1/8 the input. Hence we
|
|
// use 24 bits for the Accumulators.
|
|
|
|
assign y_real = Racc[ABITS-1:0];
|
|
assign y_imag = Iacc[ABITS-1:0];
|
|
|
|
initial
|
|
begin
|
|
wstate = 0;
|
|
waddr = 0;
|
|
end
|
|
|
|
always @(posedge clock)
|
|
begin
|
|
if (wstate == 8) wstate <= wstate + 1'd1; // used to set y_avail
|
|
if (wstate == 9) begin
|
|
wstate <= 0; // reset state machine and increment RAM write address
|
|
waddr <= waddr + 1'd1;
|
|
end
|
|
if (x_avail)
|
|
begin
|
|
wstate <= wstate + 1'd1;
|
|
case (wstate)
|
|
0: begin // wait for the first x input
|
|
Racc <= RaccA; // add accumulators
|
|
Iacc <= IaccA;
|
|
end
|
|
1: begin // wait for the next x input
|
|
Racc <= Racc + RaccB;
|
|
Iacc <= Iacc + IaccB;
|
|
end
|
|
2: begin
|
|
Racc <= Racc + RaccC;
|
|
Iacc <= Iacc + IaccC;
|
|
end
|
|
3: begin
|
|
Racc <= Racc + RaccD;
|
|
Iacc <= Iacc + IaccD;
|
|
end
|
|
4: begin
|
|
Racc <= Racc + RaccE;
|
|
Iacc <= Iacc + IaccE;
|
|
end
|
|
5: begin
|
|
Racc <= Racc + RaccF;
|
|
Iacc <= Iacc + IaccF;
|
|
end
|
|
6: begin
|
|
Racc <= Racc + RaccG;
|
|
Iacc <= Iacc + IaccG;
|
|
end
|
|
7: begin // wait for the last x input
|
|
Racc <= Racc + RaccH;
|
|
Iacc <= Iacc + IaccH;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
|
|
// Enable each FIR in sequence
|
|
assign weA = (x_avail && wstate == 0);
|
|
assign weB = (x_avail && wstate == 1);
|
|
assign weC = (x_avail && wstate == 2);
|
|
assign weD = (x_avail && wstate == 3);
|
|
assign weE = (x_avail && wstate == 4);
|
|
assign weF = (x_avail && wstate == 5);
|
|
assign weG = (x_avail && wstate == 6);
|
|
assign weH = (x_avail && wstate == 7);
|
|
|
|
// at end of sequence indicate new data is available
|
|
assign y_avail = (wstate == 8);
|
|
|
|
fir256 #("coefL8A.mif", ABITS, TAPS) A (clock, waddr, weA, x_real, x_imag, RaccA, IaccA);
|
|
fir256 #("coefL8B.mif", ABITS, TAPS) B (clock, waddr, weB, x_real, x_imag, RaccB, IaccB);
|
|
fir256 #("coefL8C.mif", ABITS, TAPS) C (clock, waddr, weC, x_real, x_imag, RaccC, IaccC);
|
|
fir256 #("coefL8D.mif", ABITS, TAPS) D (clock, waddr, weD, x_real, x_imag, RaccD, IaccD);
|
|
fir256 #("coefL8E.mif", ABITS, TAPS) E (clock, waddr, weE, x_real, x_imag, RaccE, IaccE);
|
|
fir256 #("coefL8F.mif", ABITS, TAPS) F (clock, waddr, weF, x_real, x_imag, RaccF, IaccF);
|
|
fir256 #("coefL8G.mif", ABITS, TAPS) G (clock, waddr, weG, x_real, x_imag, RaccG, IaccG);
|
|
fir256 #("coefL8H.mif", ABITS, TAPS) H (clock, waddr, weH, x_real, x_imag, RaccH, IaccH);
|
|
|
|
endmodule
|
|
|
|
|
|
// This filter waits until a new sample is written to memory at waddr. Then
|
|
// it starts by multiplying that sample by coef[0], the next prior sample
|
|
// by coef[1], (etc.) and accumulating. For R=8 decimation, coef[1] is the
|
|
// coeficient 8 prior to coef[0].
|
|
// When reading from the RAM we need to allow 3 clock pulses from presenting the
|
|
// read address until the data is available.
|
|
|
|
module fir256(
|
|
|
|
input clock,
|
|
input [ADDRBITS-1:0] waddr, // memory write address
|
|
input we, // memory write enable
|
|
input signed [MBITS-1:0] x_real, // sample to write
|
|
input signed [MBITS-1:0] x_imag,
|
|
output signed [ABITS-1:0] Raccum,
|
|
output signed [ABITS-1:0] Iaccum
|
|
);
|
|
|
|
localparam ADDRBITS = 8; // Address bits for 18/36 X 256 rom/ram blocks
|
|
localparam MBITS = 18; // multiplier bits == input bits
|
|
|
|
parameter MifFile = "xx.mif"; // ROM coefficients
|
|
parameter ABITS = 0; // adder bits
|
|
parameter TAPS = 0; // number of filter taps, max 2**ADDRBITS
|
|
|
|
reg [ADDRBITS-1:0] raddr, caddr; // read address for sample and coef
|
|
wire [MBITS*2-1:0] q; // I/Q sample read from memory
|
|
reg [MBITS*2-1:0] reg_q;
|
|
wire signed [MBITS-1:0] q_real, q_imag; // I/Q sample read from memory
|
|
wire signed [MBITS-1:0] coef; // coefficient read from memory
|
|
reg signed [MBITS-1:0] reg_coef;
|
|
reg signed [MBITS*2-1:0] Rmult, Imult; // multiplier result
|
|
reg signed [MBITS*2-1:0] RmultSum, ImultSum; // multiplier result
|
|
reg [ADDRBITS:0] counter; // count TAPS samples
|
|
|
|
//reg fir_step; // Pipeline register for fir
|
|
|
|
assign q_real = reg_q[MBITS*2-1:MBITS];
|
|
assign q_imag = reg_q[MBITS-1:0];
|
|
|
|
firromH #(MifFile) rom (caddr, clock, coef); // coefficient ROM 18 X 256
|
|
firram36 ram (clock, {x_real, x_imag}, raddr, waddr, we, q); // sample RAM 36 X 256; 36 bit == 18 bits I and 18 bits Q
|
|
|
|
always @(posedge clock)
|
|
begin
|
|
if (we) // Wait until a new sample is written to memory
|
|
begin
|
|
counter = TAPS[ADDRBITS:0] + 4; // count samples and pipeline latency (delay of 3 clocks from address being presented)
|
|
raddr = waddr; // read address -> newest sample
|
|
caddr = 1'd0; // start at coefficient zero
|
|
Raccum <= 0;
|
|
Iaccum <= 0;
|
|
Rmult <= 0;
|
|
Imult <= 0;
|
|
//fir_step <= 1'b1;
|
|
end
|
|
else
|
|
begin // main pipeline here
|
|
if (counter < (TAPS[ADDRBITS:0] + 2))
|
|
begin
|
|
//if (fir_step)
|
|
//begin
|
|
Rmult <= q_real * reg_coef;
|
|
Raccum <= Raccum + Rmult[35:12] + Rmult[11]; // truncate 36 bits down to 24 bits to prevent DC spur
|
|
//fir_step <= 1'b0;
|
|
//end
|
|
//else
|
|
//begin
|
|
Imult <= q_imag * reg_coef;
|
|
Iaccum <= Iaccum + Imult[35:12] + Imult[11];
|
|
//fir_step <= 1'b1;
|
|
//end
|
|
end
|
|
|
|
|
|
//if (~fir_step & (counter > 0))
|
|
if (counter > 0)
|
|
begin
|
|
counter <= counter - 1'd1;
|
|
raddr <= raddr - 1'd1; // move to prior sample
|
|
caddr <= caddr + 1'd1; // move to next coefficient
|
|
reg_q <= q;
|
|
reg_coef <= coef;
|
|
end
|
|
end
|
|
end
|
|
endmodule
|