summaryrefslogtreecommitdiff
path: root/hdl/ram_controller.sv
diff options
context:
space:
mode:
authorJulian Blake Kongslie2022-02-27 17:21:05 -0800
committerJulian Blake Kongslie2022-02-27 17:21:05 -0800
commit0553c4839c06011bd044f69b4913e5c793fdd2ec (patch)
treed11e69863532621fe1fa55cc7e8aa2a8cfa3b727 /hdl/ram_controller.sv
downloadmultipdp8-0553c4839c06011bd044f69b4913e5c793fdd2ec.tar.xz
Initial commit.
Diffstat (limited to '')
-rw-r--r--hdl/ram_controller.sv240
1 files changed, 240 insertions, 0 deletions
diff --git a/hdl/ram_controller.sv b/hdl/ram_controller.sv
new file mode 100644
index 0000000..6eeb46d
--- /dev/null
+++ b/hdl/ram_controller.sv
@@ -0,0 +1,240 @@
1`include "defs.svh"
2
3module ram_controller
4 ( input bit clock
5 , input bit reset
6
7 , output bit command_ready
8 , input bit command_valid
9 , input ram_command_t command_data
10
11 , input bit result_ready
12 , output bit result_valid
13 , output ram_read_response_t result_data
14
15 , output bit ram_resetn
16 , output bit ram_csn
17 , output bit ram_clkp
18 , output bit ram_clkn
19 , output bit ram_rwds_oe
20 , input bit ram_rwds_in
21 , output bit ram_rwds_out
22 , output bit ram_data_oe
23 , input bit [7:0] ram_data_in
24 , output bit [7:0] ram_data_out
25 );
26
27 assign ram_clkn = !ram_clkp;
28
29 bit valid;
30 ram_command_t command;
31 ram_word_address_t base_address;
32
33 bit slow;
34 ram_word_count_t word_count;
35
36 (* syn_encoding = "one-hot" *) enum int unsigned
37 { CHIP_SELECT
38
39 , SEND_COMMAND_1
40 , SEND_COMMAND_2
41 , SEND_COMMAND_3
42 , SEND_COMMAND_4
43 , SEND_COMMAND_5
44 , SEND_COMMAND_6
45
46 , LAT2_12
47 , LAT2_11
48 , LAT2_10
49 , LAT2_9
50 , LAT2_8
51 , LAT2_7
52 , LAT2_6
53 , LAT2_5
54 , LAT2_4
55 , LAT2_3
56 , LAT2_2
57 , LAT2_1
58
59 /* Latency blocks are 6 cycle, but you start counting after the upper
60 * column address is sent (SEND_COMMAND_4) so we reduce the
61 * lowest-latency block by one full cycle (two states).
62 , LAT1_12
63 , LAT1_11
64 */
65 , LAT1_10
66 , LAT1_9
67 , LAT1_8
68 , LAT1_7
69 , LAT1_6
70 , LAT1_5
71 , LAT1_4
72 , LAT1_3
73 , LAT1_2
74 , LAT1_1
75
76 , DATA_1
77 , DATA_2
78 } state;
79
80 (* syn_encoding = "compact" *) enum bit
81 { SETUP_OUTPUTS
82 , TOGGLE_CLOCK
83 } half_state;
84
85 bit [2:0] reset_counter;
86
87 bit prev_rwds;
88
89 always @(posedge clock) begin
90 if (reset || reset_counter != 0) begin
91 command_ready = 0;
92 result_valid = 0;
93 ram_resetn = 0;
94 ram_csn = 1;
95 ram_clkp = 0;
96 ram_rwds_oe = 0;
97 ram_rwds_out = 0;
98 ram_data_oe = 0;
99 ram_data_out = 0;
100 base_address = 0;
101 slow = 0;
102 word_count = `RAM_LINE_WORDS;
103 state = state.first;
104 half_state = half_state.first;
105 if (reset)
106 reset_counter = 5; // Spec wants >= 100ns of reset
107 else
108 reset_counter = reset_counter - 1;
109 end else begin
110 ram_resetn = 1;
111
112 if (result_ready) result_valid = 0;
113 if (command_ready && command_valid) begin
114 valid = 1;
115 command = command_data;
116 base_address = 0;
117 base_address[`RAM_ADDRESS_BITS-1:$clog2(`RAM_LINE_WORDS)] = command.address;
118 word_count = `RAM_LINE_WORDS;
119 state = state.first;
120 end
121
122 if (!valid) begin
123 ram_rwds_oe = 0;
124 ram_data_oe = 0;
125 ram_csn = 1;
126 ram_clkp = 0;
127 end else if (half_state == TOGGLE_CLOCK) begin
128 half_state = half_state.next;
129 if (state != CHIP_SELECT && state != SEND_COMMAND_1)
130 ram_clkp = !ram_clkp;
131 end else if (half_state == SETUP_OUTPUTS) begin
132 automatic bit stall = 0;
133 half_state = half_state.next;
134 ram_rwds_oe = 0;
135 ram_data_oe = 0;
136 case (state)
137
138 CHIP_SELECT: begin
139 ram_clkp = 0; // Overriding clock to guarantee that we're starting the command with the correct clock polarity
140 ram_csn = 0;
141 end
142
143 SEND_COMMAND_1: begin
144 ram_data_oe = 1;
145 ram_data_out = {!command.write, 1'b0, 1'b1, 5'b0}; // R/W#, ADDRSPACE, BURST, RESERVED
146 end
147
148 SEND_COMMAND_2: begin
149 ram_data_oe = 1;
150 ram_data_out = {4'b0, base_address[22:19]}; // RESERVED, ROW
151 end
152
153 SEND_COMMAND_3: begin
154 ram_data_oe = 1;
155 ram_data_out = {base_address[18:11]}; // ROW
156 end
157
158 SEND_COMMAND_4: begin
159 ram_data_oe = 1;
160 ram_data_out = {base_address[10:9], base_address[8:3]}; // ROW, UPPERCOL
161 // This is the cycle immediately before the latency countdown *really* begins.
162 // So we capture RWDS now in order to know how many latency blocks are required.
163 slow = ram_rwds_in;
164 end
165
166 SEND_COMMAND_5: begin
167 ram_data_oe = 1;
168 ram_data_out = {8'b0}; // RESERVED
169 end
170
171 SEND_COMMAND_6: begin
172 ram_data_oe = 1;
173 ram_data_out = {5'b0, base_address[2:0]}; // RESERVED, LOWERCOL
174 // If we're not in "slow" mode then skip the LAT2 latency
175 // block. Note that the state=state.next will still happen
176 // below, taking us to the first state in the LAT1 block.
177 if (!slow) state = LAT2_1;
178 end
179
180 // Nothing happens on any of the LAT_* states except for
181 // cycling the clock and advancing state.
182
183 DATA_1: begin
184 if (command.write) begin
185 ram_rwds_oe = 1;
186 ram_rwds_out = !command.mask[word_count - 1][0];
187 ram_data_oe = 1;
188 ram_data_out = command.data[word_count - 1][0];
189 end else if (prev_rwds != ram_rwds_in) begin
190 command.data[word_count - 1][0] = ram_data_in;
191 end else begin
192 stall = 1;
193 end
194 end
195
196 DATA_2: begin
197 if (command.write) begin
198 ram_rwds_oe = 1;
199 ram_rwds_out = !command.mask[word_count - 1][1];
200 ram_data_oe = 1;
201 ram_data_out = command.data[word_count - 1][1];
202 word_count = word_count - 1;
203 if (word_count != 0) begin
204 stall = 1;
205 state = DATA_1;
206 end
207 end else if (prev_rwds != ram_rwds_in) begin
208 command.data[word_count - 1][1] = ram_data_in;
209 word_count = word_count - 1;
210 if (word_count != 0) begin
211 stall = 1;
212 state = DATA_1;
213 end
214 end else begin
215 stall = 1;
216 end
217 end
218
219 endcase
220 if (!stall) begin
221 state = state.next;
222 if (state == state.first) begin
223 valid = 0;
224 if (!command.write) begin
225 // We know that this is safe because we don't accept commands unless we have result bandwidth
226 result_valid = 1;
227 result_data.address = command.address;
228 result_data.data = command.data;
229 result_data.tag = command.tag;
230 end
231 end
232 end
233 end
234
235 prev_rwds = ram_rwds_in;
236 command_ready = !valid && !result_valid;
237 end
238 end
239
240endmodule