1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use super::Bit;
use anyhow::{bail, Context, Result};

pub enum SpiDataMode {
    Single,
    Dual,
    Quad,
}

pub mod encoder {}

pub mod decoder {
    use super::*;

    #[derive(Clone, Debug)]
    struct Sample<
        const D0: u8,
        const D1: u8,
        const D2: u8,
        const D3: u8,
        const CLK: u8,
        const CS: u8,
    > {
        raw: u8,
    }

    impl<const D0: u8, const D1: u8, const D2: u8, const D3: u8, const CLK: u8, const CS: u8>
        Sample<D0, D1, D2, D3, CLK, CS>
    {
        fn d0(&self) -> Bit {
            ((self.raw >> D0) & 0x01).into()
        }
        fn d1(&self) -> Bit {
            ((self.raw >> D1) & 0x01).into()
        }
        fn d2(&self) -> Bit {
            ((self.raw >> D2) & 0x01).into()
        }
        fn d3(&self) -> Bit {
            ((self.raw >> D3) & 0x01).into()
        }
        fn clk(&self) -> Bit {
            ((self.raw >> CLK) & 0x01).into()
        }
        fn cs(&self) -> Bit {
            ((self.raw >> CS) & 0x01).into()
        }
    }

    pub struct Decoder<
        const D0: u8,
        const D1: u8,
        const D2: u8,
        const D3: u8,
        const CLK: u8,
        const CS: u8,
    > {
        pub cpol: bool,
        pub cpha: bool,
        pub data_mode: SpiDataMode,
    }

    impl<const D0: u8, const D1: u8, const D2: u8, const D3: u8, const CLK: u8, const CS: u8>
        Decoder<D0, D1, D2, D3, CLK, CS>
    {
        /// Loop sampling the cs until a low level is detected. Then the clock level is checked
        /// for correctness based on the cpol configuration.
        fn wait_cs<I>(&self, samples: &mut I) -> Result<()>
        where
            I: Iterator<Item = Sample<D0, D1, D2, D3, CLK, CS>>,
        {
            let clk_idle_level = if self.cpol { Bit::High } else { Bit::Low };

            let sample = samples
                .by_ref()
                .find(|sample| sample.cs() == Bit::Low)
                .expect("Exhausted the samples");
            if sample.clk() == clk_idle_level {
                Ok(())
            } else {
                bail!(
                    "Settings mismatch: Clock level when idle is {:?}, but cpol is {:?}",
                    sample.clk(),
                    self.cpol
                )
            }
        }
        /// Returns a sample when a raise or fall clock edge is detected depending on the cpol and cpha configuration.
        fn sample_on_edge<I>(&self, samples: &mut I) -> Option<Sample<D0, D1, D2, D3, CLK, CS>>
        where
            I: Iterator<Item = Sample<D0, D1, D2, D3, CLK, CS>>,
        {
            let (sample_level, wait_level) = if self.cpol == self.cpha {
                (Bit::High, Bit::Low)
            } else {
                (Bit::Low, Bit::High)
            };
            samples.by_ref().find(|sample| sample.clk() == wait_level);
            samples.by_ref().find(|sample| sample.clk() == sample_level)
        }

        fn decode_byte<I>(&self, samples: &mut I) -> Result<u8>
        where
            I: Iterator<Item = Sample<D0, D1, D2, D3, CLK, CS>>,
        {
            let mut byte = 0u16;
            let mut bits = 8;
            while bits > 0 {
                let sample = self.sample_on_edge(samples).context("Run out of samples")?;
                match self.data_mode {
                    SpiDataMode::Single => {
                        byte <<= 1;
                        byte |= sample.d0() as u16;
                        bits -= 1;
                    }
                    SpiDataMode::Dual => {
                        byte <<= 1;
                        byte |= sample.d1() as u16;
                        byte <<= 1;
                        byte |= sample.d0() as u16;
                        bits -= 2;
                    }
                    SpiDataMode::Quad => {
                        byte <<= 1;
                        byte |= sample.d3() as u16;
                        byte <<= 1;
                        byte |= sample.d2() as u16;
                        byte <<= 1;
                        byte |= sample.d1() as u16;
                        byte <<= 1;
                        byte |= sample.d0() as u16;
                        bits -= 4;
                    }
                }
            }

            Ok(byte as u8)
        }

        pub fn run(&mut self, samples: Vec<u8>) -> Result<Vec<u8>> {
            let mut samples = samples
                .into_iter()
                .map(|raw| Sample::<D0, D1, D2, D3, CLK, CS> { raw });
            self.wait_cs(&mut samples)?;
            let mut bytes = Vec::new();
            while let Ok(byte) = self.decode_byte(&mut samples) {
                bytes.push(byte);
            }
            Ok(bytes)
        }
    }
}