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
use crate::core::prelude::*;
use crate::hls::bridge::Bridge;
use crate::hls::bus::{SoCBusResponder, SoCPortController};
use crate::hls::miso_wide_port::MISOWidePort;
use crate::hls::prelude::{MOSIPort, MOSIWidePort};
use crate::hls::HLSNamedPorts;
use crate::widgets::prelude::*;

#[derive(LogicBlock)]
pub struct SDRAMController<const R: usize, const C: usize> {
    pub dram: SDRAMDriver<16>,
    pub upstream: SoCBusResponder<16, 8>,
    local_bridge: Bridge<16, 8, 4>,
    data_in: MOSIWidePort<64, 16>,
    address: MOSIWidePort<32, 16>,
    cmd: MOSIPort<16>,
    data_out: MISOWidePort<64, 16>,
    controller: SDRAMBaseController<R, C, 64, 16>,
}

impl<const R: usize, const C: usize> SDRAMController<R, C> {
    pub fn new(
        cas_delay: u32,
        timings: MemoryTimings,
        buffer: OutputBuffer,
    ) -> SDRAMController<R, C> {
        Self {
            dram: Default::default(),
            upstream: Default::default(),
            local_bridge: Bridge::new(["data_in", "address", "cmd", "data_out"]),
            data_in: Default::default(),
            address: Default::default(),
            cmd: Default::default(),
            data_out: Default::default(),
            controller: SDRAMBaseController::new(cas_delay, timings, buffer),
        }
    }
}

impl<const R: usize, const C: usize> HLSNamedPorts for SDRAMController<R, C> {
    fn ports(&self) -> Vec<String> {
        self.local_bridge.ports()
    }
}

impl<const R: usize, const C: usize> Logic for SDRAMController<R, C> {
    #[hdl_gen]
    fn update(&mut self) {
        SoCBusResponder::<16, 8>::link(&mut self.upstream, &mut self.local_bridge.upstream);
        SDRAMDriver::<16>::link(&mut self.dram, &mut self.controller.sdram);
        self.controller.clock.next = self.upstream.clock.val();
        SoCPortController::<16>::join(&mut self.local_bridge.nodes[0], &mut self.data_in.bus);
        SoCPortController::<16>::join(&mut self.local_bridge.nodes[1], &mut self.address.bus);
        SoCPortController::<16>::join(&mut self.local_bridge.nodes[2], &mut self.cmd.bus);
        SoCPortController::<16>::join(&mut self.local_bridge.nodes[3], &mut self.data_out.bus);
        self.data_out.port_in.next = self.controller.data_out.val();
        self.data_out.strobe_in.next = self.controller.data_valid.val();
        self.controller.data_in.next = self.data_in.port_out.val();
        self.controller.cmd_address.next = self.address.port_out.val();
        self.controller.write_not_read.next = self.cmd.port_out.val().any();
        self.controller.cmd_strobe.next = self.cmd.strobe_out.val();
        self.cmd.ready.next = !self.controller.busy.val();
    }
}

#[test]
fn test_sdram_controller_synthesizes() {
    let mut uut =
        SDRAMController::<6, 4>::new(3, MemoryTimings::fast_boot_sim(100e6), OutputBuffer::Wired);
    uut.connect_all();
    yosys_validate("sdram_controller_hls", &generate_verilog(&uut)).unwrap();
}