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
|
module ram_controller
( input bit clock
, input bit resetn
, output bit command_ready
, input bit command_valid
, input bit [23:0] command_address
, input bit command_write
, input bit [15:0] command_data
, input bit result_ready
, output bit result_valid
, output bit [15:0] result_data
, output bit ram_resetn
, output bit [1:0] ram_csn
, output bit ram_clkp
, output bit ram_clkn
, output bit ram_rwds_oe
, input bit ram_rwds_in
, output bit ram_rwds_out
, output bit ram_data_oe
, input bit [7:0] ram_data_in
, output bit [7:0] ram_data_out
);
assign ram_clkn = !ram_clkp;
bit valid;
bit [23:0] address;
bit write;
bit [15:0] data;
bit slow;
(* syn_encoding = "one-hot" *) enum
{ CHIP_SELECT
, SEND_COMMAND_1
, SEND_COMMAND_2
, SEND_COMMAND_3
, SEND_COMMAND_4
, SEND_COMMAND_5
, SEND_COMMAND_6
, LAT2_12
, LAT2_11
, LAT2_10
, LAT2_9
, LAT2_8
, LAT2_7
, LAT2_6
, LAT2_5
, LAT2_4
, LAT2_3
, LAT2_2
, LAT2_1
/* Latency blocks are 6 cycle, but you start counting after the upper
* column address is sent (SEND_COMMAND_4) so we reduce the
* lowest-latency block by one full cycle (two states).
, LAT1_12
, LAT1_11
*/
, LAT1_10
, LAT1_9
, LAT1_8
, LAT1_7
, LAT1_6
, LAT1_5
, LAT1_4
, LAT1_3
, LAT1_2
, LAT1_1
, DATA_1
, DATA_2
} state;
int reset_counter;
always @(posedge clock) begin
if (!resetn || reset_counter != 0) begin
command_ready = 0;
result_valid = 0;
result_data = 0;
ram_resetn = 0;
ram_csn[0] = 1;
ram_csn[1] = 1;
ram_clkp = 0;
ram_rwds_oe = 0;
ram_rwds_out = 0;
ram_data_oe = 0;
ram_data_out = 0;
valid = 0;
address = 0;
write = 0;
data = 0;
slow = 0;
state = state.first;
if (!resetn)
reset_counter = 5; // Spec wants >= 100ns of reset
else
reset_counter = reset_counter - 1;
end else begin
ram_resetn = 1;
ram_rwds_oe = 0;
ram_data_oe = 0;
if (result_ready) result_valid = 0;
if (command_ready && command_valid) begin
valid = 1;
address = command_address;
write = command_write;
data = command_data;
state = state.first;
end
if (!valid) begin
ram_csn[0] = 1;
ram_csn[1] = 1;
ram_clkp = 0;
end else begin
automatic bit stall = 0;
ram_clkp = !ram_clkp;
case (state)
CHIP_SELECT: begin
ram_clkp = 0; // Overriding clock to guarantee that we're starting the command with the correct clock polarity
ram_csn[address[23]] = 0;
end
SEND_COMMAND_1: begin
ram_csn[address[23]] = 0;
ram_data_oe = 1;
ram_data_out = {!write, 1'b0, 1'b0, 5'b0}; // R/W#, ADDRSPACE, BURST, RESERVED
end
SEND_COMMAND_2: begin
ram_data_oe = 1;
ram_data_out = {4'b0, address[22:19]}; // RESERVED, ROW
end
SEND_COMMAND_3: begin
ram_data_oe = 1;
ram_data_out = {address[18:11]}; // ROW
end
SEND_COMMAND_4: begin
ram_data_oe = 1;
ram_data_out = {address[10:9], address[8:3]}; // ROW, UPPERCOL
// This is the cycle immediately before the latency countdown *really* begins.
// So we capture RWDS now in order to know how many latency blocks are required.
slow = ram_rwds_in;
end
SEND_COMMAND_5: begin
ram_data_oe = 1;
ram_data_out = {8'b0}; // RESERVED
end
SEND_COMMAND_6: begin
ram_data_oe = 1;
ram_data_out = {5'b0, address[2:0]}; // RESERVED, LOWERCOL
// If we're not in "slow" mode then skip the LAT2 latency
// block. Note that the state=state.next will still happen
// below, taking us to the first state in the LAT1 block.
if (!slow) state = LAT2_1;
end
// Nothing happens on any of the LAT_* states except for
// cycling the clock and advancing state.
DATA_1, DATA_2: begin
if (write) begin
ram_rwds_oe = 1;
ram_rwds_out = 1;
ram_data_oe = 1;
ram_data_out = data[7:0];
data = data >> 8;
end else if (ram_rwds_in) begin
data = data << 8;
data[7:0] = ram_data_in;
end else begin
stall = 1;
end
end
endcase
if (!stall) begin
state = state.next;
if (state == state.first) begin
valid = 0;
if (!write) begin
// We know that this is safe because we don't accept commands unless we have result bandwidth
result_valid = 1;
result_data = data;
end
end
end
end
command_ready = !valid && !result_valid;
end
end
endmodule
|