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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
use crate::core::prelude::*;
use crate::dff_setup;
use crate::widgets::prelude::{
    AsynchronousFIFO, MemoryTimings, OutputBuffer, SDRAMBurstController, DFF,
};
use crate::widgets::sdram::SDRAMDriver;
#[derive(Copy, Clone, Debug, PartialEq, LogicState)]
enum State {
    Idle,
    Read,
    Write,
    Busy,
}
#[derive(LogicBlock)]
pub struct SDRAMFIFOController<
    const R: usize, 
    const C: usize, 
    const L: u32,   
    const D: usize, 
    const A: usize, 
> {
    pub clock: Signal<In, Clock>,
    pub sdram: SDRAMDriver<D>,
    pub ram_clock: Signal<In, Clock>,
    
    pub data_in: Signal<In, Bits<D>>,
    pub write: Signal<In, Bit>,
    pub full: Signal<Out, Bit>,
    pub data_out: Signal<Out, Bits<D>>,
    pub read: Signal<In, Bit>,
    pub empty: Signal<Out, Bit>,
    pub overflow: Signal<Out, Bit>,
    pub underflow: Signal<Out, Bit>,
    pub status: Signal<Out, Bits<8>>,
    controller: SDRAMBurstController<R, C, L, D>,
    fp: AsynchronousFIFO<Bits<D>, 5, 6, L>,
    bp: AsynchronousFIFO<Bits<D>, 5, 6, L>,
    can_write: DFF<Bit>,
    can_read: DFF<Bit>,
    read_pointer: DFF<Bits<A>>,
    write_pointer: DFF<Bits<A>>,
    dram_is_empty: DFF<Bit>,
    dram_is_full: DFF<Bit>,
    state: DFF<State>,
    line_to_word_ratio: Constant<Bits<A>>,
    fill: DFF<Bits<A>>,
}
impl<const R: usize, const C: usize, const L: u32, const D: usize, const A: usize>
    SDRAMFIFOController<R, C, L, D, A>
{
    pub fn new(cas_delay: u32, timings: MemoryTimings, buffer: OutputBuffer) -> Self {
        assert_eq!((1 << C) % L, 0);
        assert_eq!(A, C + R + 2);
        assert!(L < 32);
        Self {
            clock: Default::default(),
            sdram: Default::default(),
            ram_clock: Default::default(),
            data_in: Default::default(),
            write: Default::default(),
            full: Default::default(),
            data_out: Default::default(),
            read: Default::default(),
            empty: Default::default(),
            overflow: Default::default(),
            underflow: Default::default(),
            status: Default::default(),
            controller: SDRAMBurstController::new(cas_delay, timings, buffer),
            fp: Default::default(),
            bp: Default::default(),
            can_write: Default::default(),
            can_read: Default::default(),
            read_pointer: Default::default(),
            write_pointer: Default::default(),
            dram_is_empty: Default::default(),
            dram_is_full: Default::default(),
            state: Default::default(),
            line_to_word_ratio: Constant::new(L.into()),
            fill: Default::default(),
        }
    }
}
impl<const R: usize, const C: usize, const L: u32, const D: usize, const A: usize> Logic
    for SDRAMFIFOController<R, C, L, D, A>
{
    #[hdl_gen]
    fn update(&mut self) {
        clock!(self, ram_clock, controller);
        SDRAMDriver::<D>::link(&mut self.sdram, &mut self.controller.sdram);
        dff_setup!(
            self,
            ram_clock,
            read_pointer,
            write_pointer,
            dram_is_empty,
            dram_is_full,
            can_read,
            can_write,
            state,
            fill
        );
        
        self.fp.write_clock.next = self.clock.val();
        self.fp.read_clock.next = self.ram_clock.val();
        
        self.bp.write_clock.next = self.ram_clock.val();
        self.bp.read_clock.next = self.clock.val();
        
        self.fp.data_in.next = self.data_in.val();
        self.fp.write.next = self.write.val();
        self.full.next = self.fp.full.val();
        self.overflow.next = self.fp.overflow.val();
        
        self.data_out.next = self.bp.data_out.val();
        self.bp.read.next = self.read.val();
        self.empty.next = self.bp.empty.val();
        self.underflow.next = self.bp.underflow.val();
        
        
        
        self.controller.data_in.next = self.fp.data_out.val();
        self.fp.read.next = self.controller.data_strobe.val();
        
        self.bp.data_in.next = self.controller.data_out.val();
        self.bp.write.next = self.controller.data_valid.val();
        
        
        self.dram_is_empty.d.next = self.read_pointer.q.val() == self.write_pointer.q.val();
        self.dram_is_full.d.next = (self.write_pointer.q.val() + self.line_to_word_ratio.val())
            == self.read_pointer.q.val();
        self.can_write.d.next = !self.dram_is_full.q.val() & !self.fp.almost_empty.val();
        self.can_read.d.next = !self.dram_is_empty.q.val() & !self.bp.almost_full.val();
        self.controller.cmd_address.next = 0_usize.into();
        self.controller.write_not_read.next = false;
        self.controller.cmd_strobe.next = false;
        self.fill.clock.next = self.ram_clock.val();
        self.fill.d.next = self.fill.q.val();
        match self.state.q.val() {
            State::Idle => {
                if !self.controller.busy.val() {
                    if self.can_read.q.val() {
                        self.state.d.next = State::Read;
                        self.controller.cmd_address.next =
                            bit_cast::<32, A>(self.read_pointer.q.val());
                        self.controller.write_not_read.next = false;
                        self.controller.cmd_strobe.next = true;
                    } else if self.can_write.q.val() {
                        self.state.d.next = State::Write;
                        self.controller.cmd_address.next =
                            bit_cast::<32, A>(self.write_pointer.q.val());
                        self.controller.write_not_read.next = true;
                        self.controller.cmd_strobe.next = true;
                    }
                }
            }
            State::Read => {
                self.read_pointer.d.next =
                    self.read_pointer.q.val() + self.line_to_word_ratio.val();
                self.fill.d.next = self.fill.q.val() - 1_usize;
                self.state.d.next = State::Busy;
            }
            State::Write => {
                self.write_pointer.d.next =
                    self.write_pointer.q.val() + self.line_to_word_ratio.val();
                self.fill.d.next = self.fill.q.val() + 1_usize;
                self.state.d.next = State::Busy;
            }
            State::Busy => {
                if !self.controller.busy.val() {
                    self.state.d.next = State::Idle;
                }
            }
            _ => {
                self.state.d.next = State::Idle;
            }
        }
        self.status.next = 0_usize.into();
        
        
        
        
        
        
        
        if self.fill.q.val() > bits::<A>(838860) {
            self.status.next = self.status.val() | 1_usize;
        }
        if self.fill.q.val() > bits::<A>(1677721) {
            self.status.next = self.status.val() | 2_usize;
        }
        if self.fill.q.val() > bits::<A>(2516582) {
            self.status.next = self.status.val() | 4_usize;
        }
        if self.fill.q.val() > bits::<A>(3355443) {
            self.status.next = self.status.val() | 8_usize;
        }
        if self.underflow.val() | self.overflow.val() {
            self.status.next = self.status.val() | 16_usize;
        }
        if self.dram_is_empty.q.val() {
            self.status.next = self.status.val() | 32_usize;
        }
        if self.fp.empty.val() {
            self.status.next = self.status.val() | 64_usize;
        }
        if self.bp.full.val() {
            self.status.next = self.status.val() | 128_usize;
        }
    }
}