1
1
from migen .fhdl .std import *
2
2
from migen .bus import wishbone
3
3
from migen .genlib .fsm import FSM , NextState
4
+ from migen .genlib .misc import optree , Counter , WaitTimer
4
5
5
6
from misoclib .mem .sdram .phy import dfi as dfibus
6
7
@@ -10,37 +11,56 @@ def __init__(self, colbits, bankbits, rowbits, address_align):
10
11
self .colbits = colbits
11
12
self .bankbits = bankbits
12
13
self .rowbits = rowbits
13
- self .max_a = colbits + rowbits + bankbits
14
14
self .address_align = address_align
15
+ self .addressbits = colbits - address_align + bankbits + rowbits
15
16
16
17
def row (self , address ):
17
- split = self .bankbits + self .colbits
18
+ split = self .bankbits + self .colbits - self . address_align
18
19
if isinstance (address , int ):
19
20
return address >> split
20
21
else :
21
- return address [split :self .max_a ]
22
+ return address [split :self .addressbits ]
22
23
23
24
def bank (self , address ):
24
- mask = 2 ** (self .bankbits + self .colbits ) - 1
25
- shift = self .colbits
25
+ split = self .colbits - self .address_align
26
26
if isinstance (address , int ):
27
- return (address & mask ) >> shift
27
+ return (address & ( 2 ** ( split + self . bankbits ) - 1 )) >> split
28
28
else :
29
- return address [self . colbits : self . colbits + self .bankbits ]
29
+ return address [split : split + self .bankbits ]
30
30
31
31
def col (self , address ):
32
- split = self .colbits
32
+ split = self .colbits - self . address_align
33
33
if isinstance (address , int ):
34
34
return (address & (2 ** split - 1 )) << self .address_align
35
35
else :
36
36
return Cat (Replicate (0 , self .address_align ), address [:split ])
37
37
38
38
39
+ @DecorateModule (InsertReset )
40
+ @DecorateModule (InsertCE )
41
+ class _Bank (Module ):
42
+ def __init__ (self , geom_settings ):
43
+ self .open = Signal ()
44
+ self .row = Signal (geom_settings .rowbits )
45
+
46
+ self .idle = Signal (reset = 1 )
47
+ self .hit = Signal ()
48
+
49
+ # # #
50
+
51
+ row = Signal (geom_settings .rowbits )
52
+ self .sync += \
53
+ If (self .open ,
54
+ self .idle .eq (0 ),
55
+ row .eq (self .row )
56
+ )
57
+ self .comb += self .hit .eq (~ self .idle & (self .row == row ))
58
+
59
+
39
60
class MiniconSettings :
40
61
def __init__ (self ):
41
62
pass
42
63
43
-
44
64
class Minicon (Module ):
45
65
def __init__ (self , phy_settings , geom_settings , timing_settings ):
46
66
if phy_settings .memtype in ["SDR" ]:
@@ -49,146 +69,135 @@ def __init__(self, phy_settings, geom_settings, timing_settings):
49
69
burst_length = phy_settings .nphases * 2 # command multiplication*DDR
50
70
address_align = log2_int (burst_length )
51
71
52
- nbanks = range (2 ** geom_settings .bankbits )
53
- A10_ENABLED = 0
54
- COLUMN = 1
55
- ROW = 2
56
- rdphase = phy_settings .rdphase
57
- wrphase = phy_settings .wrphase
72
+ # # #
58
73
59
74
self .dfi = dfi = dfibus .Interface (geom_settings .addressbits ,
60
75
geom_settings .bankbits ,
61
76
phy_settings .dfi_databits ,
62
77
phy_settings .nphases )
63
78
64
- self .bus = bus = wishbone .Interface (data_width = phy_settings .nphases * flen (dfi .phases [rdphase ].rddata ))
65
- slicer = _AddressSlicer (geom_settings .colbits , geom_settings .bankbits , geom_settings .rowbits , address_align )
66
- refresh_req = Signal ()
67
- refresh_ack = Signal ()
68
- refresh_counter = Signal (max = timing_settings .tREFI + 1 )
69
- hit = Signal ()
70
- row_open = Signal ()
71
- row_closeall = Signal ()
72
- addr_sel = Signal (max = 3 , reset = A10_ENABLED )
73
- has_curbank_openrow = Signal ()
79
+ self .bus = bus = wishbone .Interface ()
74
80
75
- # Extra bit means row is active when asserted
76
- self .openrow = openrow = Array (Signal (geom_settings .rowbits + 1 ) for b in nbanks )
77
-
78
- self .comb += [
79
- hit .eq (openrow [slicer .bank (bus .adr )] == Cat (slicer .row (bus .adr ), 1 )),
80
- has_curbank_openrow .eq (openrow [slicer .bank (bus .adr )][- 1 ]),
81
- bus .dat_r .eq (Cat (phase .rddata for phase in dfi .phases )),
82
- Cat (phase .wrdata for phase in dfi .phases ).eq (bus .dat_w ),
83
- Cat (phase .wrdata_mask for phase in dfi .phases ).eq (~ bus .sel ),
84
- ]
81
+ rdphase = phy_settings .rdphase
82
+ wrphase = phy_settings .wrphase
85
83
86
- for phase in dfi .phases :
84
+ precharge_all = Signal ()
85
+ activate = Signal ()
86
+ refresh = Signal ()
87
+ write = Signal ()
88
+ read = Signal ()
89
+
90
+ # Compute current column, bank and row from wishbone address
91
+ slicer = _AddressSlicer (geom_settings .colbits ,
92
+ geom_settings .bankbits ,
93
+ geom_settings .rowbits ,
94
+ address_align )
95
+
96
+ # Manage banks
97
+ bank_open = Signal ()
98
+ bank_idle = Signal ()
99
+ bank_hit = Signal ()
100
+
101
+ banks = []
102
+ for i in range (2 ** geom_settings .bankbits ):
103
+ bank = _Bank (geom_settings )
87
104
self .comb += [
88
- phase .cke .eq (1 ),
89
- phase .cs_n .eq (0 ),
90
- phase .address .eq (Array ([2 ** 10 , slicer .col (bus .adr ), slicer .row (bus .adr )])[addr_sel ]),
91
- phase .bank .eq (slicer .bank (bus .adr ))
105
+ bank .open .eq (activate ),
106
+ bank .reset .eq (precharge_all ),
107
+ bank .row .eq (slicer .row (bus .adr ))
92
108
]
109
+ banks .append (bank )
110
+ self .submodules += banks
93
111
94
- for b in nbanks :
95
- self .sync += [
96
- If (row_open & (b == slicer .bank (bus .adr )),
97
- openrow [b ].eq (Cat (slicer .row (bus .adr ), 1 )),
98
- ),
99
- If (row_closeall ,
100
- openrow [b ][- 1 ].eq (0 )
101
- )
102
- ]
112
+ cases = {}
113
+ for i , bank in enumerate (banks ):
114
+ cases [i ] = [bank .ce .eq (1 )]
115
+ self .comb += Case (slicer .bank (bus .adr ), cases )
103
116
104
- self .sync += [
105
- If (refresh_ack ,
106
- refresh_req .eq (0 )
107
- ),
108
- If (refresh_counter == 0 ,
109
- refresh_counter .eq (timing_settings .tREFI ),
110
- refresh_req .eq (1 )
111
- ).Else (
112
- refresh_counter .eq (refresh_counter - 1 )
113
- )
117
+ self .comb += [
118
+ bank_hit .eq (optree ("|" , [bank .hit & bank .ce for bank in banks ])),
119
+ bank_idle .eq (optree ("|" , [bank .idle & bank .ce for bank in banks ])),
114
120
]
115
121
116
- fsm = FSM ()
117
- self .submodules += fsm
122
+ # Timings
123
+ write2precharge_timer = WaitTimer (2 + timing_settings .tWR - 1 )
124
+ self .submodules += write2precharge_timer
125
+ self .comb += write2precharge_timer .wait .eq (~ write )
126
+
127
+ refresh_timer = WaitTimer (timing_settings .tREFI )
128
+ self .submodules += refresh_timer
129
+ self .comb += refresh_timer .wait .eq (~ refresh )
130
+
131
+ # Main FSM
132
+ self .submodules .fsm = fsm = FSM ()
118
133
fsm .act ("IDLE" ,
119
- If (refresh_req ,
120
- NextState ("PRECHARGEALL " )
134
+ If (refresh_timer . done ,
135
+ NextState ("PRECHARGE-ALL " )
121
136
).Elif (bus .stb & bus .cyc ,
122
- If (hit & bus .we ,
123
- NextState ("WRITE" )
124
- ),
125
- If (hit & ~ bus .we ,
126
- NextState ("READ" )
127
- ),
128
- If (has_curbank_openrow & ~ hit ,
129
- NextState ("PRECHARGE" )
130
- ),
131
- If (~ has_curbank_openrow ,
137
+ If (bank_hit ,
138
+ If (bus .we ,
139
+ NextState ("WRITE" )
140
+ ).Else (
141
+ NextState ("READ" )
142
+ )
143
+ ).Elif (~ bank_idle ,
144
+ If (write2precharge_timer .done ,
145
+ NextState ("PRECHARGE" )
146
+ )
147
+ ).Else (
132
148
NextState ("ACTIVATE" )
133
- ),
149
+ )
134
150
)
135
151
)
136
152
fsm .act ("READ" ,
137
- # We output Column bits at address pins so A10 is 0
138
- # to disable row Auto-Precharge
153
+ read .eq (1 ),
139
154
dfi .phases [rdphase ].ras_n .eq (1 ),
140
155
dfi .phases [rdphase ].cas_n .eq (0 ),
141
156
dfi .phases [rdphase ].we_n .eq (1 ),
142
157
dfi .phases [rdphase ].rddata_en .eq (1 ),
143
- addr_sel .eq (COLUMN ),
144
- NextState ("READ-WAIT-ACK" ),
158
+ NextState ("WAIT-READ-DONE" ),
145
159
)
146
- fsm .act ("READ- WAIT-ACK " ,
160
+ fsm .act ("WAIT-READ-DONE " ,
147
161
If (dfi .phases [rdphase ].rddata_valid ,
148
- NextState ("IDLE" ),
149
- bus .ack .eq (1 )
150
- ).Else (
151
- NextState ("READ-WAIT-ACK" )
162
+ bus .ack .eq (1 ),
163
+ NextState ("IDLE" )
152
164
)
153
165
)
154
166
fsm .act ("WRITE" ,
167
+ write .eq (1 ),
155
168
dfi .phases [wrphase ].ras_n .eq (1 ),
156
169
dfi .phases [wrphase ].cas_n .eq (0 ),
157
170
dfi .phases [wrphase ].we_n .eq (0 ),
158
171
dfi .phases [wrphase ].wrdata_en .eq (1 ),
159
- addr_sel .eq (COLUMN ),
172
+ NextState ("WRITE-LATENCY" )
173
+ )
174
+ fsm .act ("WRITE-ACK" ,
160
175
bus .ack .eq (1 ),
161
176
NextState ("IDLE" )
162
177
)
163
- fsm .act ("PRECHARGEALL " ,
164
- row_closeall .eq (1 ),
178
+ fsm .act ("PRECHARGE-ALL " ,
179
+ precharge_all .eq (1 ),
165
180
dfi .phases [rdphase ].ras_n .eq (0 ),
166
181
dfi .phases [rdphase ].cas_n .eq (1 ),
167
182
dfi .phases [rdphase ].we_n .eq (0 ),
168
- addr_sel .eq (A10_ENABLED ),
169
183
NextState ("PRE-REFRESH" )
170
184
)
171
185
fsm .act ("PRECHARGE" ,
172
- # Notes:
173
- # 1. we are presenting the column address so that A10 is low
174
- # 2. since we always go to the ACTIVATE state, we do not need
175
- # to assert row_close because it will be reopen right after.
176
- NextState ("TRP" ),
177
- addr_sel .eq (COLUMN ),
178
- dfi .phases [rdphase ].ras_n .eq (0 ),
179
- dfi .phases [rdphase ].cas_n .eq (1 ),
180
- dfi .phases [rdphase ].we_n .eq (0 )
186
+ # do no reset bank since we are going to re-open it
187
+ dfi .phases [0 ].ras_n .eq (0 ),
188
+ dfi .phases [0 ].cas_n .eq (1 ),
189
+ dfi .phases [0 ].we_n .eq (0 ),
190
+ NextState ("TRP" )
181
191
)
182
192
fsm .act ("ACTIVATE" ,
183
- row_open .eq (1 ),
193
+ activate .eq (1 ),
194
+ dfi .phases [0 ].ras_n .eq (0 ),
195
+ dfi .phases [0 ].cas_n .eq (1 ),
196
+ dfi .phases [0 ].we_n .eq (1 ),
184
197
NextState ("TRCD" ),
185
- dfi .phases [rdphase ].ras_n .eq (0 ),
186
- dfi .phases [rdphase ].cas_n .eq (1 ),
187
- dfi .phases [rdphase ].we_n .eq (1 ),
188
- addr_sel .eq (ROW )
189
198
)
190
199
fsm .act ("REFRESH" ,
191
- refresh_ack .eq (1 ),
200
+ refresh .eq (1 ),
192
201
dfi .phases [rdphase ].ras_n .eq (0 ),
193
202
dfi .phases [rdphase ].cas_n .eq (0 ),
194
203
dfi .phases [rdphase ].we_n .eq (1 ),
@@ -198,3 +207,30 @@ def __init__(self, phy_settings, geom_settings, timing_settings):
198
207
fsm .delayed_enter ("PRE-REFRESH" , "REFRESH" , timing_settings .tRP - 1 )
199
208
fsm .delayed_enter ("TRCD" , "IDLE" , timing_settings .tRCD - 1 )
200
209
fsm .delayed_enter ("POST-REFRESH" , "IDLE" , timing_settings .tRFC - 1 )
210
+ fsm .delayed_enter ("WRITE-LATENCY" , "WRITE-ACK" , phy_settings .write_latency - 1 )
211
+
212
+ # DFI commands
213
+ for phase in dfi .phases :
214
+ if hasattr (phase , "reset_n" ):
215
+ self .comb += phase .reset_n .eq (1 )
216
+ if hasattr (phase , "odt" ):
217
+ self .comb += phase .odt .eq (1 )
218
+ self .comb += [
219
+ phase .cke .eq (1 ),
220
+ phase .cs_n .eq (0 ),
221
+ phase .bank .eq (slicer .bank (bus .adr )),
222
+ If (precharge_all ,
223
+ phase .address .eq (2 ** 10 )
224
+ ).Elif (activate ,
225
+ phase .address .eq (slicer .row (bus .adr ))
226
+ ).Elif (write | read ,
227
+ phase .address .eq (slicer .col (bus .adr ))
228
+ )
229
+ ]
230
+
231
+ # DFI datapath
232
+ self .comb += [
233
+ bus .dat_r .eq (Cat (phase .rddata for phase in dfi .phases )),
234
+ Cat (phase .wrdata for phase in dfi .phases ).eq (bus .dat_w ),
235
+ Cat (phase .wrdata_mask for phase in dfi .phases ).eq (~ bus .sel ),
236
+ ]
0 commit comments