From 0d0c4952a864d083b3b450bdee6fce89d5a27445 Mon Sep 17 00:00:00 2001 From: Dan Kirkham Date: Sat, 16 Mar 2024 01:05:19 -0500 Subject: [PATCH] Fix FIR multiplication On Icarus, iCE40 (Yosys/nextpnr), and Quartus/Cyclone II tools the bit extension happens before the multiply. Operand 1 0xabcd becomes 0x0000_0000_abcd Operand 2 0x1234 becomes 0x0000_0000_1234 To fit into 16x16 multiplier, other tools are truncating the less-significant bits, resulting in a 0x0000_0000 * 0x0000_0000 multiplicaton. An unfortunate side effect is that now addition is now actually occuring, my iCE40 designs no longer meet timing. A pipeline stage may have to be added, but I am not sure how to make that play nice with the BRAMs. --- rust-hdl-widgets/src/mac_fir.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rust-hdl-widgets/src/mac_fir.rs b/rust-hdl-widgets/src/mac_fir.rs index 1017a000..8c6468b5 100644 --- a/rust-hdl-widgets/src/mac_fir.rs +++ b/rust-hdl-widgets/src/mac_fir.rs @@ -46,6 +46,8 @@ pub struct MultiplyAccumulateSymmetricFiniteImpulseResponseFilter>, // FIR state state: DFF, + // The output of the Multiply + multiply_output: Signal>, // The output of the MAC slice mac_output: Signal>, // The next write location for data @@ -96,9 +98,8 @@ impl Logic self.right_sample.next = 0.into(); } // Wire up the accumulator - self.mac_output.next = signed_bit_cast::<48, 32>( - (self.left_sample.val() + self.right_sample.val()) * (self.coeff_memory.data.val()), - ) + self.accum.q.val(); + self.multiply_output.next = (self.left_sample.val() + self.right_sample.val()) * self.coeff_memory.data.val(); + self.mac_output.next = signed_bit_cast::<48, 32>(self.multiply_output.val()) + self.accum.q.val(); if self.state.q.val() == MACFIRState::Idle { self.mac_output.next = 0.into(); } @@ -185,6 +186,7 @@ impl MultiplyAccumulateSymmetricFiniteImpulseResponseFil right_sample: Default::default(), accum: Default::default(), state: Default::default(), + multiply_output: Default::default(), mac_output: Default::default(), data_write: Default::default(), taps: Constant::new(taps.to_bits()),