Skip to content

Commit c8b0910

Browse files
committed
gateware: fix occasional IQ swap in half-band decimator
Prevent loosing track of the IQ time-multiplexing state within the FIR filter.
1 parent c178eaf commit c8b0910

File tree

2 files changed

+35
-42
lines changed

2 files changed

+35
-42
lines changed
-1021 Bytes
Binary file not shown.

firmware/fpga/dsp/fir.py

Lines changed: 35 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ def elaborate(self, platform):
5858
# Arms
5959
m.submodules.fir = fir = FIRFilter(fir_taps, shape=self.data_shape, always_ready=always_ready,
6060
num_channels=1, add_tap=len(fir_taps)//2+1)
61+
fir_out_odd = Signal()
62+
with m.If(fir.output.valid & fir.output.ready):
63+
m.d.sync += fir_out_odd.eq(~fir_out_odd)
64+
65+
odd = Signal()
66+
with m.If(self.input.valid & self.input.ready):
67+
m.d.sync += odd.eq(~odd)
68+
69+
# Only switch modes at even samples.
70+
switch_stb = Signal()
71+
m.d.comb += switch_stb.eq((~odd) ^ (self.input.valid & self.input.ready))
6172

6273
with m.FSM():
6374

@@ -70,72 +81,54 @@ def elaborate(self, platform):
7081
if not self.input.signature.always_ready:
7182
m.d.comb += self.input.ready.eq(1)
7283

73-
with m.If(self.enable):
84+
with m.If(self.enable & switch_stb):
7485
m.next = "DECIMATE"
7586

7687
with m.State("DECIMATE"):
7788

78-
# Input switching.
79-
odd = Signal()
80-
input_idx = Signal()
81-
even_valid = Signal()
89+
# I and Q channels are muxed in time, demuxed later in the output stage.
8290
even_buffer = Signal.like(self.input.p)
83-
q_inputs = Signal.like(self.input.p)
91+
odd_buffer = Signal.like(self.input.p)
92+
q_valid = Signal()
8493

8594
if not self.input.signature.always_ready:
86-
m.d.comb += self.input.ready.eq((~odd & ~even_valid) | fir.input.ready)
95+
m.d.comb += self.input.ready.eq(fir.input.ready)
8796

88-
# Even samples are buffered and used as a secondary
89-
# carry addition for the FIR filter.
90-
# I and Q channels are muxed in time, demuxed later in the output stage.
91-
with m.If(self.input.valid & self.input.ready):
92-
m.d.sync += odd.eq(~odd)
93-
with m.If(~odd):
94-
with m.If(~even_valid | fir.input.ready):
95-
m.d.sync += even_valid.eq(self.input.valid)
96-
with m.If(self.input.valid):
97-
m.d.sync += even_buffer.eq(self.input.p)
98-
99-
# Process two I samples and two Q samples in sequence.
100-
with m.If(fir.input.ready & fir.input.valid):
101-
m.d.sync += input_idx.eq(input_idx ^ 1)
102-
103-
with m.If(input_idx == 0):
97+
with m.If(self.input.ready & self.input.valid):
98+
with m.If(~odd):
99+
m.d.sync += even_buffer.eq(self.input.p)
100+
with m.Else():
101+
m.d.sync += odd_buffer.eq(self.input.p)
102+
m.d.sync += q_valid.eq(1)
103+
104+
with m.If(odd):
104105
m.d.comb += [
105106
fir.add_input .eq(even_buffer[0]),
106107
fir.input.p .eq(self.input.p[0]),
107-
fir.input.valid .eq(self.input.valid & even_valid),
108+
fir.input.valid .eq(self.input.valid),
108109
]
109-
with m.If(fir.input.ready & fir.input.valid):
110-
m.d.sync += [
111-
q_inputs[0].eq(even_buffer[1]),
112-
q_inputs[1].eq(self.input.p[1]),
113-
]
114110
with m.Else():
115111
m.d.comb += [
116-
fir.add_input .eq(q_inputs[0]),
117-
fir.input.p .eq(q_inputs[1]),
118-
fir.input.valid .eq(1),
112+
fir.add_input .eq(even_buffer[1]),
113+
fir.input.p .eq(odd_buffer[1]),
114+
fir.input.valid .eq(q_valid),
119115
]
116+
with m.If(fir.input.ready):
117+
m.d.sync += q_valid.eq(0)
120118

121119
# Output sum and demux.
122-
output_idx = Signal()
123-
124120
with m.If(~self.output.valid | self.output.ready):
125121
if not fir.output.signature.always_ready:
126122
m.d.comb += fir.output.ready.eq(1)
127-
m.d.sync += self.output.valid.eq(fir.output.valid & output_idx)
123+
m.d.sync += self.output.valid.eq(fir.output.valid & fir_out_odd)
128124
with m.If(fir.output.valid):
129125
m.d.sync += self.output.p[0].eq(self.output.p[1])
130126
m.d.sync += self.output.p[1].eq(fir.output.p[0] * fixed.Const(0.5))
131-
m.d.sync += output_idx.eq(output_idx ^ 1)
132127

133-
# Mode switch logic.
134-
with m.If(~self.enable):
135-
m.d.sync += input_idx.eq(0)
136-
m.d.sync += output_idx.eq(0)
137-
m.d.sync += odd.eq(0)
138-
m.d.sync += even_valid.eq(0)
128+
# Mode switch logic
129+
with m.If(~self.enable & switch_stb):
130+
m.d.sync += even_buffer.eq(0)
131+
m.d.sync += odd_buffer.eq(0)
139132
m.next = "BYPASS"
140133

141134
if self._domain != "sync":

0 commit comments

Comments
 (0)