From 4e2da5912b4761caf269e72d3d29771867a3e6f2 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Wed, 16 Nov 2022 11:02:10 +0100 Subject: [PATCH] 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 --- .../quarter_rate_downconverter.v | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/rfnoc/blocks/rfnoc_block_radio/quarter_rate_downconverter.v b/lib/rfnoc/blocks/rfnoc_block_radio/quarter_rate_downconverter.v index ded9a8c..4a17570 100644 --- a/lib/rfnoc/blocks/rfnoc_block_radio/quarter_rate_downconverter.v +++ b/lib/rfnoc/blocks/rfnoc_block_radio/quarter_rate_downconverter.v @@ -43,6 +43,17 @@ module quarter_rate_downconverter #( reg [WIDTH-1:0] tmp_i = {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 localparam S0=0, S1=1, S2=2, S3=3; reg[1:0] cur_state; @@ -108,18 +119,18 @@ module quarter_rate_downconverter #( end S1: begin // S(t) * i = -Q(t) + iI(t): - tmp_i = -q_in; - tmp_q = i_in; + tmp_i = invert_sig(q_in); + tmp_q = i_in; end S2: begin // S(t) * -1 = -I(t) - iQ(t): - tmp_i = -i_in; - tmp_q = -q_in; + tmp_i = invert_sig(i_in); + tmp_q = invert_sig(q_in); end S3: begin // S(t) * -i = Q(t) - iI(t): - tmp_i = q_in; - tmp_q = -i_in; + tmp_i = q_in; + tmp_q = invert_sig(i_in); end default: begin tmp_i = i_in;