rust_hdl_widgets/spi/
mux.rs

1use rust_hdl_core::prelude::*;
2
3use crate::prelude::{SPIWiresMaster, SPIWiresSlave};
4
5// Mux N SPI slaves onto a bus
6#[derive(LogicBlock)]
7pub struct MuxSlaves<const N: usize, const A: usize> {
8    pub from_master: SPIWiresSlave,
9    pub to_slaves: [SPIWiresMaster; N],
10    pub sel: Signal<In, Bits<A>>,
11}
12
13impl<const N: usize, const A: usize> Default for MuxSlaves<N, A> {
14    fn default() -> Self {
15        assert!((1 << A) >= N);
16        Self {
17            from_master: Default::default(),
18            to_slaves: array_init::array_init(|_| Default::default()),
19            sel: Default::default(),
20        }
21    }
22}
23
24impl<const N: usize, const A: usize> Logic for MuxSlaves<N, A> {
25    #[hdl_gen]
26    fn update(&mut self) {
27        self.from_master.miso.next = false;
28        for i in 0..N {
29            self.to_slaves[i].mclk.next = true;
30            self.to_slaves[i].msel.next = true;
31            self.to_slaves[i].mosi.next = true;
32            if self.sel.val().index() == i {
33                self.to_slaves[i].mclk.next = self.from_master.mclk.val();
34                self.to_slaves[i].msel.next = self.from_master.msel.val();
35                self.to_slaves[i].mosi.next = self.from_master.mosi.val();
36                self.from_master.miso.next = self.to_slaves[i].miso.val();
37            }
38        }
39    }
40}
41
42#[test]
43fn test_spi_mux_slaves_is_synthesizable() {
44    let mut uut = MuxSlaves::<4, 2>::default();
45    uut.connect_all();
46    let vlog = generate_verilog(&uut);
47    yosys_validate("spi_mux_slaves", &vlog).unwrap();
48}
49
50// Mux N SPI masters onto a bus
51#[derive(LogicBlock)]
52pub struct MuxMasters<const N: usize, const A: usize> {
53    pub to_bus: SPIWiresMaster,
54    pub from_masters: [SPIWiresSlave; N],
55    pub sel: Signal<In, Bits<A>>,
56}
57
58impl<const N: usize, const A: usize> Default for MuxMasters<N, A> {
59    fn default() -> Self {
60        assert!((1 << A) >= N);
61        Self {
62            to_bus: Default::default(),
63            from_masters: array_init::array_init(|_| Default::default()),
64            sel: Default::default(),
65        }
66    }
67}
68
69impl<const N: usize, const A: usize> Logic for MuxMasters<N, A> {
70    #[hdl_gen]
71    fn update(&mut self) {
72        // Latch prevention
73        self.to_bus.mosi.next = true;
74        self.to_bus.msel.next = true;
75        self.to_bus.mclk.next = true;
76        for i in 0..N {
77            self.from_masters[i].miso.next = true;
78            if self.sel.val().index() == i {
79                self.to_bus.mosi.next = self.from_masters[i].mosi.val();
80                self.to_bus.msel.next = self.from_masters[i].msel.val();
81                self.to_bus.mclk.next = self.from_masters[i].mclk.val();
82                self.from_masters[i].miso.next = self.to_bus.miso.val();
83            }
84        }
85    }
86}
87
88#[test]
89fn test_spi_mux_is_synthesizable() {
90    let mut uut = MuxMasters::<4, 2>::default();
91    uut.connect_all();
92    let vlog = generate_verilog(&uut);
93    yosys_validate("spi_mux", &vlog).unwrap();
94}