fpga: Fix overflows in quarterrate downconverter

The 1/4-rate downconverter naively negated the input signals (y = -x)
which doesn't work when the signal is at full scale. In particular,
signals that are at full negative scale get converted to zeros (even
though 2's complement would be to return the same number, although that
would also be incorrect).

This fix changes it such that the smallest negative value gets converted
to the largest positive value.

This is not a mathematical correction inversion, but a minor amplitude
distortion. However, since we're already at full scale, and thus
probably clipping, this is preferable to the incorrect resolution of the
regular inversion. Put differently, there is no better value in this
case.


Original-commit: 8bd982745e6247cf3cf3da52925c65126287428a
This commit is contained in:
Martin Braun
2022-12-02 11:42:44 -08:00
committed by michael-west
parent ddcc0b1211
commit 4e2da5912b
@@ -43,6 +43,17 @@ module quarter_rate_downconverter #(
reg [WIDTH-1:0] tmp_i = {WIDTH{1'b0}}; reg [WIDTH-1:0] tmp_i = {WIDTH{1'b0}};
reg [WIDTH-1:0] tmp_q = {WIDTH{1'b0}}; reg [WIDTH-1:0] tmp_q = {WIDTH{1'b0}};
localparam [WIDTH-1:0] MAX_NEG_VAL = -2**(WIDTH-1);
localparam [WIDTH-1:0] MAX_POS_VAL = 2**(WIDTH-1)-1;
function [WIDTH-1:0] invert_sig(
input [WIDTH-1:0] x
);
begin
invert_sig = x == MAX_NEG_VAL ? MAX_POS_VAL : -x;
end
endfunction
// State machine types and reg // State machine types and reg
localparam S0=0, S1=1, S2=2, S3=3; localparam S0=0, S1=1, S2=2, S3=3;
reg[1:0] cur_state; reg[1:0] cur_state;
@@ -108,18 +119,18 @@ module quarter_rate_downconverter #(
end end
S1: begin S1: begin
// S(t) * i = -Q(t) + iI(t): // S(t) * i = -Q(t) + iI(t):
tmp_i = -q_in; tmp_i = invert_sig(q_in);
tmp_q = i_in; tmp_q = i_in;
end end
S2: begin S2: begin
// S(t) * -1 = -I(t) - iQ(t): // S(t) * -1 = -I(t) - iQ(t):
tmp_i = -i_in; tmp_i = invert_sig(i_in);
tmp_q = -q_in; tmp_q = invert_sig(q_in);
end end
S3: begin S3: begin
// S(t) * -i = Q(t) - iI(t): // S(t) * -i = Q(t) - iI(t):
tmp_i = q_in; tmp_i = q_in;
tmp_q = -i_in; tmp_q = invert_sig(i_in);
end end
default: begin default: begin
tmp_i = i_in; tmp_i = i_in;