1 from migen
.fhdl
.structure
import *
2 from migen
.bus
.asmibus
import *
3 from migen
.corelogic
.roundrobin
import *
4 from migen
.corelogic
.fsm
import FSM
5 from migen
.corelogic
.misc
import optree
7 from milkymist
.asmicon
.multiplexer
import *
9 # Row:Bank:Col address mapping
11 def __init__(self
, geom_settings
, address_align
):
12 self
.geom_settings
= geom_settings
13 self
.address_align
= address_align
15 self
._b
1 = self
.geom_settings
.col_a
- self
.address_align
16 self
._b
2 = self
._b
1 + self
.geom_settings
.bank_a
18 def row(self
, address
):
19 if isinstance(address
, int):
20 return address
>> self
._b
2
22 return address
[self
._b
2:]
24 def bank(self
, address
):
25 if isinstance(address
, int):
26 return (address
& (2**self
._b
2 - 1)) >> self
._b
1
28 return address
[self
._b
1:self
._b
2]
30 def col(self
, address
):
31 if isinstance(address
, int):
32 return (address
& (2**self
._b
1 - 1)) << self
.address_align
34 return Cat(Constant(0, BV(self
.address_align
)), address
[:self
._b
1])
37 def __init__(self
, slicer
, bankn
, slots
):
42 self
.nslots
= len(self
.slots
)
45 self
.tag
= Signal(BV(bits_for(self
.nslots
-1)))
46 self
.adr
= Signal(self
.slots
[0].adr
.bv
)
49 # derived classes should drive rr.request
50 self
.rr
= RoundRobin(self
.nslots
, SP_CE
)
52 def get_fragment(self
):
59 state
.eq(Array(slot
.state
for slot
in self
.slots
)[rr
.grant
]),
60 self
.adr
.eq(Array(slot
.adr
for slot
in self
.slots
)[rr
.grant
]),
61 self
.we
.eq(Array(slot
.we
for slot
in self
.slots
)[rr
.grant
]),
63 (self
.slicer
.bank(self
.adr
) == self
.bankn
) \
64 & (state
== SLOT_PENDING
)),
68 comb
+= [If((rr
.grant
== i
) & self
.stb
& self
.ack
, slot
.process
.eq(1))
69 for i
, slot
in enumerate(self
.slots
)]
71 return Fragment(comb
) + rr
.get_fragment()
73 class _SimpleSelector(_Selector
):
74 def get_fragment(self
):
76 for i
, slot
in enumerate(self
.slots
):
77 comb
.append(self
.rr
.request
[i
].eq(
78 (self
.slicer
.bank(slot
.adr
) == self
.bankn
) & \
79 (slot
.state
== SLOT_PENDING
)
82 return Fragment(comb
) + super().get_fragment()
84 class _FullSelector(_Selector
):
85 def get_fragment(self
):
90 # List outstanding requests for our bank
92 for slot
in self
.slots
:
93 outstanding
= Signal()
94 comb
.append(outstanding
.eq(
95 (self
.slicer
.bank(slot
.adr
) == self
.bankn
) & \
96 (slot
.state
== SLOT_PENDING
)
98 outstandings
.append(outstanding
)
101 openrow_r
= Signal(BV(self
.slicer
.geom_settings
.row_a
))
102 openrow_n
= Signal(BV(self
.slicer
.geom_settings
.row_a
))
103 openrow
= Signal(BV(self
.slicer
.geom_settings
.row_a
))
105 openrow_n
.eq(self
.slicer
.row(self
.adr
)),
107 openrow
.eq(openrow_n
)
109 openrow
.eq(openrow_r
)
113 If(self
.stb
& self
.ack
,
114 openrow_r
.eq(openrow_n
)
118 for slot
, os
in zip(self
.slots
, outstandings
):
120 comb
.append(hit
.eq((self
.slicer
.row(slot
.adr
) == openrow
) & os
))
123 # Determine best request
124 rr
= RoundRobin(self
.nslots
, SP_CE
)
126 comb
.append(has_hit
.eq(optree("|", hits
)))
128 best_hit
= [rr
.request
[i
].eq(hit
)
129 for i
, hit
in enumerate(hits
)]
130 best_fallback
= [rr
.request
[i
].eq(os
)
131 for i
, os
in enumerate(outstandings
)]
132 select_stmt
= If(has_hit
,
138 if self
.slots
[0].time
:
139 # Implement anti-starvation timer
141 for slot
, os
in zip(self
.slots
, outstandings
):
143 comb
.append(mature
.eq(slot
.mature
& os
))
144 matures
.append(mature
)
145 has_mature
= Signal()
146 comb
.append(has_mature
.eq(optree("|", matures
)))
147 best_mature
= [rr
.request
[i
].eq(mature
)
148 for i
, mature
in enumerate(matures
)]
149 select_stmt
= If(has_mature
, *best_mature
).Else(select_stmt
)
150 comb
.append(select_stmt
)
152 return Fragment(comb
, sync
) + super().get_fragment()
155 def __init__(self
, source
):
160 self
.tag
= Signal(self
.source
.tag
.bv
)
161 self
.adr
= Signal(self
.source
.adr
.bv
)
164 def get_fragment(self
):
167 en
.eq(self
.ack | ~self
.stb
),
168 self
.source
.ack
.eq(en
)
172 self
.stb
.eq(self
.source
.stb
),
173 self
.tag
.eq(self
.source
.tag
),
174 self
.adr
.eq(self
.source
.adr
),
175 self
.we
.eq(self
.source
.we
)
178 return Fragment(comb
, sync
)
181 def __init__(self
, geom_settings
, timing_settings
, address_align
, bankn
, slots
, full_selector
=False):
182 self
.geom_settings
= geom_settings
183 self
.timing_settings
= timing_settings
184 self
.address_align
= address_align
187 self
.full_selector
= full_selector
189 self
.refresh_req
= Signal()
190 self
.refresh_gnt
= Signal()
191 self
.cmd
= CommandRequestRW(geom_settings
.mux_a
, geom_settings
.bank_a
,
192 bits_for(len(slots
)-1))
194 def get_fragment(self
):
199 slicer
= _AddressSlicer(self
.geom_settings
, self
.address_align
)
200 if self
.full_selector
:
201 selector
= _FullSelector(slicer
, self
.bankn
, self
.slots
)
203 selector
= _SimpleSelector(slicer
, self
.bankn
, self
.slots
)
204 buf
= _Buffer(selector
)
207 has_openrow
= Signal()
208 openrow
= Signal(BV(self
.geom_settings
.row_a
))
210 comb
.append(hit
.eq(openrow
== slicer
.row(buf
.adr
)))
211 track_open
= Signal()
212 track_close
= Signal()
216 openrow
.eq(slicer
.row(buf
.adr
))
226 self
.cmd
.ba
.eq(self
.bankn
),
228 self
.cmd
.a
.eq(slicer
.row(buf
.adr
))
230 self
.cmd
.a
.eq(slicer
.col(buf
.adr
))
234 comb
.append(self
.cmd
.tag
.eq(buf
.tag
))
236 # Control and command generation FSM
237 fsm
= FSM("REGULAR", "PRECHARGE", "ACTIVATE", "REFRESH", delayed_enters
=[
238 ("TRP", "ACTIVATE", self
.timing_settings
.tRP
-1),
239 ("TRCD", "REGULAR", self
.timing_settings
.tRCD
-1)
243 fsm
.next_state(fsm
.REFRESH
)
248 buf
.ack
.eq(self
.cmd
.ack
),
249 self
.cmd
.is_read
.eq(~buf
.we
),
250 self
.cmd
.is_write
.eq(buf
.we
),
251 self
.cmd
.cas_n
.eq(0),
252 self
.cmd
.we_n
.eq(~buf
.we
)
254 fsm
.next_state(fsm
.PRECHARGE
)
257 fsm
.next_state(fsm
.ACTIVATE
)
261 fsm
.act(fsm
.PRECHARGE
,
263 # 1. we are presenting the column address, A10 is always low
264 # 2. since we always go to the ACTIVATE state, we do not need
265 # to assert track_close.
267 If(self
.cmd
.ack
, fsm
.next_state(fsm
.TRP
)),
268 self
.cmd
.ras_n
.eq(0),
271 fsm
.act(fsm
.ACTIVATE
,
275 If(self
.cmd
.ack
, fsm
.next_state(fsm
.TRCD
)),
279 self
.refresh_gnt
.eq(1),
281 If(~self
.refresh_req
, fsm
.next_state(fsm
.REGULAR
))
284 return Fragment(comb
, sync
) + \
285 selector
.get_fragment() + \
286 buf
.get_fragment() + \