1use crate::dff_setup;
2use crate::spi::master::SPIWiresMaster;
3use crate::synchronizer::BitSynchronizer;
4use crate::{dff::DFF, dff_with_init::DFFWithInit, spi::master::SPIConfig, strobe::Strobe};
5use rust_hdl_core::prelude::*;
6
7#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
8enum SPIState {
9 Idle,
10 SetMode,
11 Activate,
12 Dwell,
13 LoadBit,
14 MActive,
15 SampleMISO,
16 MIdle,
17 Finish,
18}
19
20#[derive(Copy, Clone)]
21pub struct SPIConfigDynamicMode {
22 pub clock_speed: u64,
23 pub cs_off: bool,
24 pub mosi_off: bool,
25 pub speed_hz: u64,
26}
27
28impl From<SPIConfig> for SPIConfigDynamicMode {
29 fn from(x: SPIConfig) -> Self {
30 SPIConfigDynamicMode {
31 clock_speed: x.clock_speed,
32 cs_off: x.cs_off,
33 mosi_off: x.mosi_off,
34 speed_hz: x.speed_hz,
35 }
36 }
37}
38
39impl Into<SPIConfig> for SPIConfigDynamicMode {
40 fn into(self) -> SPIConfig {
41 SPIConfig {
42 clock_speed: self.clock_speed,
43 cs_off: self.cs_off,
44 mosi_off: self.mosi_off,
45 speed_hz: self.speed_hz,
46 cpha: false,
47 cpol: false,
48 }
49 }
50}
51
52#[derive(LogicBlock)]
53pub struct SPIMasterDynamicMode<const N: usize> {
54 pub clock: Signal<In, Clock>,
55 pub bits_outbound: Signal<In, Bits<16>>,
56 pub data_outbound: Signal<In, Bits<N>>,
57 pub data_inbound: Signal<Out, Bits<N>>,
58 pub start_send: Signal<In, Bit>,
59 pub transfer_done: Signal<Out, Bit>,
60 pub continued_transaction: Signal<In, Bit>,
61 pub wires: SPIWiresMaster,
62 pub busy: Signal<Out, Bit>,
63 register_out: DFF<Bits<N>>,
64 register_in: DFF<Bits<N>>,
65 state: DFF<SPIState>,
66 strobe: Strobe<32>,
67 pointer: DFF<Bits<16>>,
68 pointerm1: Signal<Local, Bits<16>>,
69 clock_state: DFF<Bit>,
70 done_flop: DFF<Bit>,
71 msel_flop: DFFWithInit<Bit>,
72 mosi_flop: DFF<Bit>,
73 miso_synchronizer: BitSynchronizer,
74 continued_save: DFF<Bit>,
75 cs_off: Constant<Bit>,
76 mosi_off: Constant<Bit>,
77 cpha_flop: DFF<Bit>,
78 cpol_flop: DFF<Bit>,
79}
80
81impl<const N: usize> SPIMasterDynamicMode<N> {
82 pub fn new(config: SPIConfigDynamicMode) -> Self {
83 assert!(8 * config.speed_hz <= config.clock_speed);
84 Self {
85 clock: Default::default(),
86 bits_outbound: Default::default(),
87 data_outbound: Default::default(),
88 data_inbound: Default::default(),
89 start_send: Default::default(),
90 transfer_done: Default::default(),
91 continued_transaction: Default::default(),
92 wires: Default::default(),
93 busy: Default::default(),
94 register_out: Default::default(),
95 register_in: Default::default(),
96 state: Default::default(),
97 strobe: Strobe::new(config.clock_speed, 4.0 * config.speed_hz as f64),
98 pointer: Default::default(),
99 pointerm1: Default::default(),
100 clock_state: Default::default(),
101 done_flop: Default::default(),
102 msel_flop: DFFWithInit::new(config.cs_off),
103 mosi_flop: Default::default(),
104 miso_synchronizer: Default::default(),
105 continued_save: Default::default(),
106 cs_off: Constant::new(config.cs_off),
107 mosi_off: Constant::new(config.mosi_off),
108 cpha_flop: Default::default(),
109 cpol_flop: Default::default(),
110 }
111 }
112}
113
114impl<const N: usize> Logic for SPIMasterDynamicMode<N> {
115 #[hdl_gen]
116 fn update(&mut self) {
117 dff_setup!(
119 self,
120 clock,
121 register_out,
122 register_in,
123 state,
124 pointer,
125 clock_state,
126 done_flop,
127 msel_flop,
128 mosi_flop,
129 continued_save,
130 cpha_flop,
131 cpol_flop
132 );
133 clock!(self, clock, miso_synchronizer, strobe);
134 self.strobe.enable.next = true;
136 self.miso_synchronizer.sig_in.next = self.wires.miso.val();
138 self.wires.mclk.next = self.clock_state.q.val();
140 self.wires.mosi.next = self.mosi_flop.q.val();
141 self.wires.msel.next = self.msel_flop.q.val();
142 self.data_inbound.next = self.register_in.q.val();
144 self.transfer_done.next = self.done_flop.q.val();
145 self.done_flop.d.next = false;
147 self.pointerm1.next = self.pointer.q.val() - 1;
148 self.busy.next = self.state.q.val() != SPIState::Idle;
149 match self.state.q.val() {
151 SPIState::Idle => {
152 self.clock_state.d.next = self.cpol_flop.q.val();
153 if self.start_send.val() {
154 self.register_out.d.next = self.data_outbound.val();
156 self.state.d.next = SPIState::SetMode; self.pointer.d.next = self.bits_outbound.val() & 0x00FF; self.cpha_flop.d.next = self.bits_outbound.val().get_bit(9);
160 self.cpol_flop.d.next = self.bits_outbound.val().get_bit(8);
161 self.register_in.d.next = 0.into(); self.continued_save.d.next = self.continued_transaction.val();
163 } else {
164 if !self.continued_save.q.val() {
165 self.msel_flop.d.next = self.cs_off.val(); }
167 }
168 self.mosi_flop.d.next = self.mosi_off.val(); }
170 SPIState::SetMode => {
171 self.clock_state.d.next = self.cpol_flop.q.val();
172 if self.strobe.strobe.val() {
174 self.state.d.next = SPIState::Activate;
175 }
176 }
177 SPIState::Activate => {
178 if self.strobe.strobe.val() {
179 self.msel_flop.d.next = !self.cs_off.val(); self.state.d.next = SPIState::Dwell;
181 }
182 }
183 SPIState::Dwell => {
184 if self.strobe.strobe.val() {
185 self.state.d.next = SPIState::LoadBit; }
188 }
189 SPIState::LoadBit => {
190 if self.pointer.q.val().any() {
191 self.mosi_flop.d.next = self
193 .register_out
194 .q
195 .val()
196 .get_bit(self.pointerm1.val().index()); self.pointer.d.next = self.pointerm1.val(); self.state.d.next = SPIState::MActive; self.clock_state.d.next = self.cpol_flop.q.val() ^ self.cpha_flop.q.val();
200 } else {
201 self.mosi_flop.d.next = self.mosi_off.val(); self.clock_state.d.next = self.cpol_flop.q.val();
203 self.state.d.next = SPIState::Finish; }
205 }
206 SPIState::MActive => {
207 if self.strobe.strobe.val() {
208 self.state.d.next = SPIState::SampleMISO;
209 }
210 }
211 SPIState::SampleMISO => {
212 self.register_in.d.next = self.register_in.q.val().replace_bit(
213 self.pointer.q.val().index(),
214 self.miso_synchronizer.sig_out.val(),
215 );
216 self.clock_state.d.next = !self.clock_state.q.val();
217 self.state.d.next = SPIState::MIdle;
218 }
219 SPIState::MIdle => {
220 if self.strobe.strobe.val() {
221 self.state.d.next = SPIState::LoadBit;
222 }
223 }
224 SPIState::Finish => {
225 if self.strobe.strobe.val() {
226 self.done_flop.d.next = true; self.state.d.next = SPIState::Idle;
228 }
229 }
230 _ => {
231 self.state.d.next = SPIState::Idle;
232 }
233 }
234 }
235}
236
237#[test]
238fn test_spi_master_dynamic_mode_is_synthesizable() {
239 let config = SPIConfigDynamicMode {
240 clock_speed: 48_000_000,
241 cs_off: true,
242 mosi_off: false,
243 speed_hz: 1_000_000,
244 };
245 let mut dev = SPIMasterDynamicMode::<64>::new(config);
246 dev.connect_all();
247 yosys_validate("spi_master_dyn_mode", &generate_verilog(&dev)).unwrap();
248}