3b18412e01e3540a91097be576863c0678476cec
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 def get_fragment(self
):
53 # List outstanding requests for our bank
55 for slot
in self
.slots
:
56 outstanding
= Signal()
57 comb
.append(outstanding
.eq(
58 (self
.slicer
.bank(slot
.adr
) == self
.bankn
) & \
59 (slot
.state
== SLOT_PENDING
)
61 outstandings
.append(outstanding
)
64 openrow_r
= Signal(BV(self
.slicer
.geom_settings
.row_a
))
65 openrow_n
= Signal(BV(self
.slicer
.geom_settings
.row_a
))
66 openrow
= Signal(BV(self
.slicer
.geom_settings
.row_a
))
68 openrow_n
.eq(self
.slicer
.row(self
.adr
)),
76 If(self
.stb
& self
.ack
,
77 openrow_r
.eq(openrow_n
)
81 for slot
, os
in zip(self
.slots
, outstandings
):
83 comb
.append(hit
.eq((self
.slicer
.row(slot
.adr
) == openrow
) & os
))
86 # Determine best request
87 rr
= RoundRobin(self
.nslots
, SP_CE
)
89 comb
.append(has_hit
.eq(optree("|", hits
)))
91 best_hit
= [rr
.request
[i
].eq(hit
)
92 for i
, hit
in enumerate(hits
)]
93 best_fallback
= [rr
.request
[i
].eq(os
)
94 for i
, os
in enumerate(outstandings
)]
95 select_stmt
= If(has_hit
,
101 if self
.slots
[0].time
:
102 # Implement anti-starvation timer
104 for slot
, os
in zip(self
.slots
, outstandings
):
106 comb
.append(mature
.eq(slot
.mature
& os
))
107 matures
.append(mature
)
108 has_mature
= Signal()
109 comb
.append(has_mature
.eq(optree("|", matures
)))
110 best_mature
= [rr
.request
[i
].eq(mature
)
111 for i
, mature
in enumerate(matures
)]
112 select_stmt
= If(has_mature
, *best_mature
).Else(select_stmt
)
113 comb
.append(select_stmt
)
116 state
= Signal(BV(2))
118 state
.eq(Array(slot
.state
for slot
in self
.slots
)[rr
.grant
]),
119 self
.adr
.eq(Array(slot
.adr
for slot
in self
.slots
)[rr
.grant
]),
120 self
.we
.eq(Array(slot
.we
for slot
in self
.slots
)[rr
.grant
]),
122 (self
.slicer
.bank(self
.adr
) == self
.bankn
) \
123 & (state
== SLOT_PENDING
)),
125 self
.tag
.eq(rr
.grant
)
127 comb
+= [If((rr
.grant
== i
) & self
.stb
& self
.ack
, slot
.process
.eq(1))
128 for i
, slot
in enumerate(self
.slots
)]
130 return Fragment(comb
, sync
) + rr
.get_fragment()
133 def __init__(self
, source
):
138 self
.tag
= Signal(self
.source
.tag
.bv
)
139 self
.adr
= Signal(self
.source
.adr
.bv
)
142 def get_fragment(self
):
145 en
.eq(self
.ack | ~self
.stb
),
146 self
.source
.ack
.eq(en
)
150 self
.stb
.eq(self
.source
.stb
),
151 self
.tag
.eq(self
.source
.tag
),
152 self
.adr
.eq(self
.source
.adr
),
153 self
.we
.eq(self
.source
.we
)
156 return Fragment(comb
, sync
)
159 def __init__(self
, geom_settings
, timing_settings
, address_align
, bankn
, slots
):
160 self
.geom_settings
= geom_settings
161 self
.timing_settings
= timing_settings
162 self
.address_align
= address_align
166 self
.refresh_req
= Signal()
167 self
.refresh_gnt
= Signal()
168 self
.cmd
= CommandRequestRW(geom_settings
.mux_a
, geom_settings
.bank_a
,
169 bits_for(len(slots
)-1))
171 def get_fragment(self
):
176 slicer
= _AddressSlicer(self
.geom_settings
, self
.address_align
)
177 selector
= _Selector(slicer
, self
.bankn
, self
.slots
)
178 buf
= _Buffer(selector
)
181 has_openrow
= Signal()
182 openrow
= Signal(BV(self
.geom_settings
.row_a
))
184 comb
.append(hit
.eq(openrow
== slicer
.row(buf
.adr
)))
185 track_open
= Signal()
186 track_close
= Signal()
190 openrow
.eq(slicer
.row(buf
.adr
))
200 self
.cmd
.ba
.eq(self
.bankn
),
202 self
.cmd
.a
.eq(slicer
.row(buf
.adr
))
204 self
.cmd
.a
.eq(slicer
.col(buf
.adr
))
208 comb
.append(self
.cmd
.tag
.eq(buf
.tag
))
210 # Control and command generation FSM
211 fsm
= FSM("REGULAR", "PRECHARGE", "ACTIVATE", "REFRESH", delayed_enters
=[
212 ("TRP", "ACTIVATE", self
.timing_settings
.tRP
-1),
213 ("TRCD", "REGULAR", self
.timing_settings
.tRCD
-1)
217 fsm
.next_state(fsm
.REFRESH
)
222 buf
.ack
.eq(self
.cmd
.ack
),
223 self
.cmd
.is_read
.eq(~buf
.we
),
224 self
.cmd
.is_write
.eq(buf
.we
),
225 self
.cmd
.cas_n
.eq(0),
226 self
.cmd
.we_n
.eq(~buf
.we
)
228 fsm
.next_state(fsm
.PRECHARGE
)
231 fsm
.next_state(fsm
.ACTIVATE
)
235 fsm
.act(fsm
.PRECHARGE
,
237 # 1. we are presenting the column address, A10 is always low
238 # 2. since we always go to the ACTIVATE state, we do not need
239 # to assert track_close.
241 If(self
.cmd
.ack
, fsm
.next_state(fsm
.TRP
)),
242 self
.cmd
.ras_n
.eq(0),
245 fsm
.act(fsm
.ACTIVATE
,
249 If(self
.cmd
.ack
, fsm
.next_state(fsm
.TRCD
)),
253 self
.refresh_gnt
.eq(1),
255 If(~self
.refresh_req
, fsm
.next_state(fsm
.REGULAR
))
258 return Fragment(comb
, sync
) + \
259 selector
.get_fragment() + \
260 buf
.get_fragment() + \