rust_hdl_lib_hls/
controller.rs

1use crate::bus::{FIFOReadController, FIFOWriteController, SoCBusController};
2use rust_hdl_lib_core::prelude::*;
3use rust_hdl_lib_widgets::prelude::*;
4
5// For now, we will hard code the op codes
6// 00 - NOOP
7// 01 - PING
8// 02 - READ
9// 03 - WRITE
10// 04 - POLL
11// 05 - STREAM (send any non-zero value to stop streaming)
12
13#[derive(LogicState, Debug, Copy, Clone, PartialEq)]
14enum BaseControllerState {
15    Idle,
16    Ping,
17    ReadLoadCount,
18    Read,
19    Write,
20    WriteLoadCount,
21    PollWait,
22    Poll,
23    StreamWait,
24    Stream,
25}
26
27// This version of the SOCController takes 8-bit sequences as inputs,
28// and communicates with a 16 bit bus.  Other designs are possible,
29// but the internal logic needs to handle the differences in address
30// space bits, data widths, etc.
31#[derive(LogicBlock, Default)]
32pub struct BaseController<const A: usize> {
33    pub from_cpu: FIFOReadController<Bits<16>>, // Word-stream from the CPU
34    pub to_cpu: FIFOWriteController<Bits<16>>,  // Word-stream to the CPU
35    pub clock: Signal<In, Clock>,               // All in a single clock domain
36    state: DFF<BaseControllerState>,
37    pub bus: SoCBusController<16, { A }>,
38    counter: DFF<Bits<16>>,
39    opcode: Signal<Local, Bits<8>>,
40}
41
42impl<const A: usize> Logic for BaseController<A> {
43    #[hdl_gen]
44    fn update(&mut self) {
45        dff_setup!(self, clock, state, counter);
46        // Latch prevention
47        self.opcode.next = self.from_cpu.data.val().get_bits::<8>(8);
48        // Default values for output signals.
49        self.from_cpu.read.next = false;
50        self.to_cpu.data.next = 0.into();
51        self.to_cpu.write.next = false;
52        self.bus.clock.next = self.clock.val();
53        self.bus.from_controller.next = 0.into();
54        self.bus.strobe.next = false;
55        self.bus.address.next = 0.into();
56        self.bus.address_strobe.next = false;
57        match self.state.q.val() {
58            BaseControllerState::Idle => {
59                if !self.from_cpu.empty.val() {
60                    if self.opcode.val() == 0 {
61                        // Skip opcodes that are NOOP
62                        self.from_cpu.read.next = true;
63                    } else if self.opcode.val() == 1 {
64                        self.state.d.next = BaseControllerState::Ping;
65                    } else if self.opcode.val() == 2 {
66                        // Latch the address
67                        self.bus.address.next = self.from_cpu.data.val().get_bits::<A>(0);
68                        self.bus.address_strobe.next = true;
69                        self.from_cpu.read.next = true;
70                        self.state.d.next = BaseControllerState::ReadLoadCount;
71                    } else if self.opcode.val() == 3 {
72                        // Latch the address
73                        self.bus.address.next = self.from_cpu.data.val().get_bits::<A>(0);
74                        self.bus.address_strobe.next = true;
75                        self.from_cpu.read.next = true;
76                        self.state.d.next = BaseControllerState::WriteLoadCount;
77                    } else if self.opcode.val() == 4 {
78                        self.bus.address.next = self.from_cpu.data.val().get_bits::<A>(0);
79                        self.bus.address_strobe.next = true;
80                        self.from_cpu.read.next = true;
81                        self.state.d.next = BaseControllerState::PollWait;
82                    } else if self.opcode.val() == 5 {
83                        self.bus.address.next = self.from_cpu.data.val().get_bits::<A>(0);
84                        self.bus.address_strobe.next = true;
85                        self.from_cpu.read.next = true;
86                        self.state.d.next = BaseControllerState::StreamWait;
87                    }
88                }
89            }
90            BaseControllerState::Ping => {
91                self.to_cpu.data.next = self.from_cpu.data.val();
92                self.to_cpu.write.next = true;
93                self.from_cpu.read.next = true;
94                self.state.d.next = BaseControllerState::Idle;
95            }
96            BaseControllerState::ReadLoadCount => {
97                if !self.from_cpu.empty.val() {
98                    self.counter.d.next = self.from_cpu.data.val();
99                    self.from_cpu.read.next = true;
100                    self.state.d.next = BaseControllerState::Read;
101                }
102            }
103            BaseControllerState::Read => {
104                if self.bus.ready.val() & !self.to_cpu.full.val() {
105                    self.to_cpu.data.next = self.bus.to_controller.val();
106                    self.bus.strobe.next = true;
107                    self.to_cpu.write.next = true;
108                    self.counter.d.next = self.counter.q.val() - 1;
109                    if self.counter.q.val() == 1 {
110                        self.state.d.next = BaseControllerState::Idle;
111                    }
112                }
113            }
114            BaseControllerState::WriteLoadCount => {
115                if !self.from_cpu.empty.val() {
116                    self.counter.d.next = self.from_cpu.data.val();
117                    self.from_cpu.read.next = true;
118                    self.state.d.next = BaseControllerState::Write;
119                }
120            }
121            BaseControllerState::Write => {
122                if self.bus.ready.val() & !self.from_cpu.empty.val() {
123                    self.bus.from_controller.next = self.from_cpu.data.val();
124                    self.bus.strobe.next = true;
125                    self.from_cpu.read.next = true;
126                    self.counter.d.next = self.counter.q.val() - 1;
127                    if self.counter.q.val() == 1 {
128                        self.state.d.next = BaseControllerState::Idle;
129                    }
130                }
131            }
132            BaseControllerState::PollWait => {
133                self.state.d.next = BaseControllerState::Poll;
134            }
135            BaseControllerState::Poll => {
136                if !self.to_cpu.full.val() {
137                    self.to_cpu.data.next =
138                        bits::<16>(0xFF00) | bit_cast::<16, 1>(self.bus.ready.val().into());
139                    self.to_cpu.write.next = true;
140                    self.state.d.next = BaseControllerState::Idle;
141                }
142            }
143            BaseControllerState::StreamWait => {
144                self.state.d.next = BaseControllerState::Stream;
145            }
146            BaseControllerState::Stream => {
147                if self.bus.ready.val() & !self.to_cpu.full.val() {
148                    self.to_cpu.data.next = self.bus.to_controller.val();
149                    self.bus.strobe.next = true;
150                    self.to_cpu.write.next = true;
151                }
152                if !self.from_cpu.empty.val() {
153                    if self.from_cpu.data.val().any() {
154                        self.state.d.next = BaseControllerState::Idle;
155                    }
156                    self.from_cpu.read.next = true;
157                }
158            }
159            _ => {
160                self.state.d.next = BaseControllerState::Idle;
161            }
162        }
163    }
164}
165
166#[test]
167fn test_base_controller_is_synthesizable() {
168    let mut uut = BaseController::<4>::default();
169    uut.connect_all();
170    let vlog = generate_verilog(&uut);
171    yosys_validate("base_controller", &vlog).unwrap();
172}