871d087b6237dbf7d116df3c5149ef26a2146eec
[litex.git] / litex / soc / misoc / cores / minicon / core.py
1 from functools import reduce
2 from operator import or_
3
4 from migen import *
5 from migen.genlib.fsm import FSM, NextState
6 from migen.genlib.misc import WaitTimer
7
8 from misoc.interconnect import dfi as dfibus
9 from misoc.interconnect import wishbone
10
11
12 class _AddressSlicer:
13 def __init__(self, colbits, bankbits, rowbits, address_align):
14 self.colbits = colbits
15 self.bankbits = bankbits
16 self.rowbits = rowbits
17 self.address_align = address_align
18 self.addressbits = colbits - address_align + bankbits + rowbits
19
20 def row(self, address):
21 split = self.bankbits + self.colbits - self.address_align
22 if isinstance(address, int):
23 return address >> split
24 else:
25 return address[split:self.addressbits]
26
27 def bank(self, address):
28 split = self.colbits - self.address_align
29 if isinstance(address, int):
30 return (address & (2**(split + self.bankbits) - 1)) >> split
31 else:
32 return address[split:split+self.bankbits]
33
34 def col(self, address):
35 split = self.colbits - self.address_align
36 if isinstance(address, int):
37 return (address & (2**split - 1)) << self.address_align
38 else:
39 return Cat(Replicate(0, self.address_align), address[:split])
40
41
42 @ResetInserter()
43 @CEInserter()
44 class _Bank(Module):
45 def __init__(self, geom_settings):
46 self.open = Signal()
47 self.row = Signal(geom_settings.rowbits)
48
49 self.idle = Signal(reset=1)
50 self.hit = Signal()
51
52 # # #
53
54 row = Signal(geom_settings.rowbits)
55 self.sync += \
56 If(self.open,
57 self.idle.eq(0),
58 row.eq(self.row)
59 )
60 self.comb += self.hit.eq(~self.idle & (self.row == row))
61
62
63 class Minicon(Module):
64 def __init__(self, phy_settings, geom_settings, timing_settings):
65 if phy_settings.memtype in ["SDR"]:
66 burst_length = phy_settings.nphases*1 # command multiplication*SDR
67 elif phy_settings.memtype in ["DDR", "LPDDR", "DDR2", "DDR3"]:
68 burst_length = phy_settings.nphases*2 # command multiplication*DDR
69 burst_width = phy_settings.dfi_databits*phy_settings.nphases
70 address_align = log2_int(burst_length)
71
72 # # #
73
74 self.dfi = dfi = dfibus.Interface(geom_settings.addressbits,
75 geom_settings.bankbits,
76 phy_settings.dfi_databits,
77 phy_settings.nphases)
78
79 self.bus = bus = wishbone.Interface(burst_width)
80
81 rdphase = phy_settings.rdphase
82 wrphase = phy_settings.wrphase
83
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_idle = Signal()
98 bank_hit = Signal()
99
100 banks = []
101 for i in range(2**geom_settings.bankbits):
102 bank = _Bank(geom_settings)
103 self.comb += [
104 bank.open.eq(activate),
105 bank.reset.eq(precharge_all),
106 bank.row.eq(slicer.row(bus.adr))
107 ]
108 banks.append(bank)
109 self.submodules += banks
110
111 cases = {}
112 for i, bank in enumerate(banks):
113 cases[i] = [bank.ce.eq(1)]
114 self.comb += Case(slicer.bank(bus.adr), cases)
115
116 self.comb += [
117 bank_hit.eq(reduce(or_, [bank.hit & bank.ce for bank in banks])),
118 bank_idle.eq(reduce(or_, [bank.idle & bank.ce for bank in banks])),
119 ]
120
121 # Timings
122 write2precharge_timer = WaitTimer(2 + timing_settings.tWR - 1)
123 self.submodules += write2precharge_timer
124 self.comb += write2precharge_timer.wait.eq(~write)
125
126 refresh_timer = WaitTimer(timing_settings.tREFI)
127 self.submodules += refresh_timer
128 self.comb += refresh_timer.wait.eq(~refresh)
129
130 # Main FSM
131 self.submodules.fsm = fsm = FSM()
132 fsm.act("IDLE",
133 If(refresh_timer.done,
134 NextState("PRECHARGE-ALL")
135 ).Elif(bus.stb & bus.cyc,
136 If(bank_hit,
137 If(bus.we,
138 NextState("WRITE")
139 ).Else(
140 NextState("READ")
141 )
142 ).Elif(~bank_idle,
143 If(write2precharge_timer.done,
144 NextState("PRECHARGE")
145 )
146 ).Else(
147 NextState("ACTIVATE")
148 )
149 )
150 )
151 fsm.act("READ",
152 read.eq(1),
153 dfi.phases[rdphase].ras_n.eq(1),
154 dfi.phases[rdphase].cas_n.eq(0),
155 dfi.phases[rdphase].we_n.eq(1),
156 dfi.phases[rdphase].rddata_en.eq(1),
157 NextState("WAIT-READ-DONE"),
158 )
159 fsm.act("WAIT-READ-DONE",
160 If(dfi.phases[rdphase].rddata_valid,
161 bus.ack.eq(1),
162 NextState("IDLE")
163 )
164 )
165 fsm.act("WRITE",
166 write.eq(1),
167 dfi.phases[wrphase].ras_n.eq(1),
168 dfi.phases[wrphase].cas_n.eq(0),
169 dfi.phases[wrphase].we_n.eq(0),
170 dfi.phases[wrphase].wrdata_en.eq(1),
171 NextState("WRITE-LATENCY")
172 )
173 fsm.act("WRITE-ACK",
174 bus.ack.eq(1),
175 NextState("IDLE")
176 )
177 fsm.act("PRECHARGE-ALL",
178 precharge_all.eq(1),
179 dfi.phases[rdphase].ras_n.eq(0),
180 dfi.phases[rdphase].cas_n.eq(1),
181 dfi.phases[rdphase].we_n.eq(0),
182 NextState("PRE-REFRESH")
183 )
184 fsm.act("PRECHARGE",
185 # do no reset bank since we are going to re-open it
186 dfi.phases[0].ras_n.eq(0),
187 dfi.phases[0].cas_n.eq(1),
188 dfi.phases[0].we_n.eq(0),
189 NextState("TRP")
190 )
191 fsm.act("ACTIVATE",
192 activate.eq(1),
193 dfi.phases[0].ras_n.eq(0),
194 dfi.phases[0].cas_n.eq(1),
195 dfi.phases[0].we_n.eq(1),
196 NextState("TRCD"),
197 )
198 fsm.act("REFRESH",
199 refresh.eq(1),
200 dfi.phases[rdphase].ras_n.eq(0),
201 dfi.phases[rdphase].cas_n.eq(0),
202 dfi.phases[rdphase].we_n.eq(1),
203 NextState("POST-REFRESH")
204 )
205 fsm.delayed_enter("WRITE-LATENCY", "WRITE-ACK", phy_settings.write_latency-1)
206 fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP-1)
207 fsm.delayed_enter("TRCD", "IDLE", timing_settings.tRCD-1)
208 fsm.delayed_enter("PRE-REFRESH", "REFRESH", timing_settings.tRP-1)
209 fsm.delayed_enter("POST-REFRESH", "IDLE", timing_settings.tRFC-1)
210
211 # DFI commands
212 for phase in dfi.phases:
213 if hasattr(phase, "reset_n"):
214 self.comb += phase.reset_n.eq(1)
215 if hasattr(phase, "odt"):
216 self.comb += phase.odt.eq(1)
217 self.comb += [
218 phase.cke.eq(1),
219 phase.cs_n.eq(0),
220 phase.bank.eq(slicer.bank(bus.adr)),
221 If(precharge_all,
222 phase.address.eq(2**10)
223 ).Elif(activate,
224 phase.address.eq(slicer.row(bus.adr))
225 ).Elif(write | read,
226 phase.address.eq(slicer.col(bus.adr))
227 )
228 ]
229
230 # DFI datapath
231 self.comb += [
232 bus.dat_r.eq(Cat(phase.rddata for phase in dfi.phases)),
233 Cat(phase.wrdata for phase in dfi.phases).eq(bus.dat_w),
234 Cat(phase.wrdata_mask for phase in dfi.phases).eq(~bus.sel),
235 ]