1use crate::dff::DFF;
2use crate::dff_setup;
3use crate::ramrom::ram::RAM;
4use crate::ramrom::sync_rom::SyncROM;
5use rust_hdl_core::prelude::*;
6use rust_hdl_core::signed::ToSignedBits;
7
8#[derive(Clone, Debug, LogicState, Copy, PartialEq)]
9enum MACFIRState {
10 Idle,
11 Dwell,
12 Compute,
13 CenterTap,
14 Write,
15}
16
17#[derive(LogicBlock)]
18pub struct MultiplyAccumulateSymmetricFiniteImpulseResponseFilter<const ADDR_BITS: usize> {
19 pub data_in: Signal<In, Signed<16>>,
20 pub strobe_in: Signal<In, Bit>,
21 pub data_out: Signal<Out, Signed<48>>,
22 pub strobe_out: Signal<Out, Bit>,
23 pub clock: Signal<In, Clock>,
24 pub busy: Signal<Out, Bit>,
25 coeff_memory: SyncROM<Signed<16>, ADDR_BITS>,
26 left_bank: RAM<Signed<16>, ADDR_BITS>,
27 right_bank: RAM<Signed<16>, ADDR_BITS>,
28 head_ptr: DFF<Bits<ADDR_BITS>>,
30 left_ptr: Signal<Local, Bits<ADDR_BITS>>,
32 right_ptr: Signal<Local, Bits<ADDR_BITS>>,
34 index: DFF<Bits<ADDR_BITS>>,
36 iters: Constant<Bits<ADDR_BITS>>,
38 bufsize: Constant<Bits<32>>,
40 taps: Constant<Bits<32>>,
42 left_sample: Signal<Local, Signed<16>>,
44 right_sample: Signal<Local, Signed<16>>,
45 accum: DFF<Signed<48>>,
47 state: DFF<MACFIRState>,
49 mac_output: Signal<Local, Signed<48>>,
51 data_write: Signal<Local, Bits<ADDR_BITS>>,
53}
54
55impl<const ADDR_BITS: usize> Logic
56 for MultiplyAccumulateSymmetricFiniteImpulseResponseFilter<ADDR_BITS>
57{
58 #[hdl_gen]
59 fn update(&mut self) {
60 self.coeff_memory.clock.next = self.clock.val();
62 self.left_bank.read_clock.next = self.clock.val();
63 self.left_bank.write_clock.next = self.clock.val();
64 self.right_bank.read_clock.next = self.clock.val();
65 self.right_bank.write_clock.next = self.clock.val();
66 dff_setup!(self, clock, head_ptr, index, accum, state);
67 self.left_bank.write_address.next = self.head_ptr.d.val();
69 self.right_bank.write_address.next = self.head_ptr.d.val();
70 self.left_bank.write_data.next = self.data_in.val();
72 self.right_bank.write_data.next = self.data_in.val();
73 self.left_bank.write_enable.next = self.strobe_in.val();
75 self.right_bank.write_enable.next = self.strobe_in.val();
76 self.left_ptr.next = bit_cast::<{ ADDR_BITS }, 32>(
78 bit_cast::<32, { ADDR_BITS }>(self.head_ptr.q.val()) + self.bufsize.val()
79 - self.taps.val()
80 + 1
81 + bit_cast::<32, { ADDR_BITS }>(self.index.q.val()),
82 );
83 self.right_ptr.next = bit_cast::<{ ADDR_BITS }, 32>(
87 bit_cast::<32, { ADDR_BITS }>(self.head_ptr.q.val()) + self.bufsize.val()
88 - bit_cast::<32, { ADDR_BITS }>(self.index.q.val()),
89 );
90 self.left_bank.read_address.next = self.left_ptr.val();
91 self.right_bank.read_address.next = self.right_ptr.val();
92 self.coeff_memory.address.next = self.index.q.val();
93 self.left_sample.next = self.left_bank.read_data.val();
94 self.right_sample.next = self.right_bank.read_data.val();
95 if self.state.q.val() == MACFIRState::CenterTap {
96 self.right_sample.next = 0.into();
97 }
98 self.mac_output.next = signed_bit_cast::<48, 32>(
100 (self.left_sample.val() + self.right_sample.val()) * (self.coeff_memory.data.val()),
101 ) + self.accum.q.val();
102 if self.state.q.val() == MACFIRState::Idle {
103 self.mac_output.next = 0.into();
104 }
105 self.data_write.next = self.head_ptr.q.val();
107 self.data_out.next = self.accum.q.val();
109 self.strobe_out.next = false;
110 self.busy.next = self.state.q.val() != MACFIRState::Idle;
111 match self.state.q.val() {
113 MACFIRState::Idle => {
114 if self.strobe_in.val() {
115 self.state.d.next = MACFIRState::Dwell;
116 }
117 }
118 MACFIRState::Dwell => {
119 self.index.d.next = self.index.q.val() + 1;
120 self.state.d.next = MACFIRState::Compute;
121 }
122 MACFIRState::Compute => {
123 self.index.d.next = self.index.q.val() + 1;
124 self.accum.d.next = self.mac_output.val();
125 if self.index.q.val() == self.iters.val() {
126 self.state.d.next = MACFIRState::CenterTap;
127 }
128 }
129 MACFIRState::CenterTap => {
130 self.index.d.next = self.index.q.val() + 1;
131 self.accum.d.next = self.mac_output.val();
132 self.state.d.next = MACFIRState::Write;
133 }
134 MACFIRState::Write => {
135 self.strobe_out.next = true;
136 self.state.d.next = MACFIRState::Idle;
137 self.head_ptr.d.next = self.head_ptr.q.val() + 1;
139 self.index.d.next = 0.into();
141 self.accum.d.next = 0.into();
142 }
143 _ => {
144 self.state.d.next = MACFIRState::Idle;
145 }
146 }
147 self.data_write.next = self.head_ptr.q.val();
148 }
149}
150
151impl<const ADDR_BITS: usize> MultiplyAccumulateSymmetricFiniteImpulseResponseFilter<ADDR_BITS> {
152 pub fn new(coeffs: &[i16]) -> Self {
153 let taps = coeffs.len();
154 assert!({ ADDR_BITS } >= clog2(taps));
155 for ndx in 0..coeffs.len() {
157 assert_eq!(coeffs[ndx], coeffs[taps - 1 - ndx]);
158 }
159 assert_eq!(coeffs.len() % 2, 1);
161 let clen = (coeffs.len() + 1) / 2;
163 let coeff_short = coeffs[0..clen].iter().map(|x| *x).collect::<Vec<_>>();
164 let coeffs = coeff_short
165 .iter()
166 .map(|x| x.to_signed_bits())
167 .collect::<Vec<_>>();
168 Self {
169 data_in: Default::default(),
170 strobe_in: Default::default(),
171 data_out: Default::default(),
172 strobe_out: Default::default(),
173 clock: Default::default(),
174 busy: Default::default(),
175 coeff_memory: coeffs.into_iter().into(),
176 left_bank: Default::default(),
177 right_bank: Default::default(),
178 head_ptr: Default::default(),
179 left_ptr: Default::default(),
180 right_ptr: Default::default(),
181 index: Default::default(),
182 iters: Constant::new(((taps - 1) / 2).to_bits()),
183 bufsize: Constant::new(Bits::<ADDR_BITS>::count().to_bits()),
184 left_sample: Default::default(),
185 right_sample: Default::default(),
186 accum: Default::default(),
187 state: Default::default(),
188 mac_output: Default::default(),
189 data_write: Default::default(),
190 taps: Constant::new(taps.to_bits()),
191 }
192 }
193}
194
195#[test]
196fn test_fir_is_synthesizable() {
197 let coeffs = [1, -2, 3, -2, 1];
198 let mut uut = MultiplyAccumulateSymmetricFiniteImpulseResponseFilter::<3>::new(&coeffs);
199 uut.connect_all();
200 let vlog = generate_verilog(&uut);
201 yosys_validate("fir", &vlog).unwrap();
202}