Skip to content

Commit f40140d

Browse files
committedMay 29, 2015
sdram: refactor minicon and fix issues with DDRx memories
- simplify code - fix AddressSlicer - manage write latency and write to precharge timings - add odt/reset_n signals
1 parent a8b9c12 commit f40140d

File tree

2 files changed

+143
-108
lines changed

2 files changed

+143
-108
lines changed
 
+138-102
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from migen.fhdl.std import *
22
from migen.bus import wishbone
33
from migen.genlib.fsm import FSM, NextState
4+
from migen.genlib.misc import optree, Counter, WaitTimer
45

56
from misoclib.mem.sdram.phy import dfi as dfibus
67

@@ -10,37 +11,56 @@ def __init__(self, colbits, bankbits, rowbits, address_align):
1011
self.colbits = colbits
1112
self.bankbits = bankbits
1213
self.rowbits = rowbits
13-
self.max_a = colbits + rowbits + bankbits
1414
self.address_align = address_align
15+
self.addressbits = colbits - address_align + bankbits + rowbits
1516

1617
def row(self, address):
17-
split = self.bankbits + self.colbits
18+
split = self.bankbits + self.colbits - self.address_align
1819
if isinstance(address, int):
1920
return address >> split
2021
else:
21-
return address[split:self.max_a]
22+
return address[split:self.addressbits]
2223

2324
def bank(self, address):
24-
mask = 2**(self.bankbits + self.colbits) - 1
25-
shift = self.colbits
25+
split = self.colbits - self.address_align
2626
if isinstance(address, int):
27-
return (address & mask) >> shift
27+
return (address & (2**(split + self.bankbits) - 1)) >> split
2828
else:
29-
return address[self.colbits:self.colbits+self.bankbits]
29+
return address[split:split+self.bankbits]
3030

3131
def col(self, address):
32-
split = self.colbits
32+
split = self.colbits - self.address_align
3333
if isinstance(address, int):
3434
return (address & (2**split - 1)) << self.address_align
3535
else:
3636
return Cat(Replicate(0, self.address_align), address[:split])
3737

3838

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+
3960
class MiniconSettings:
4061
def __init__(self):
4162
pass
4263

43-
4464
class Minicon(Module):
4565
def __init__(self, phy_settings, geom_settings, timing_settings):
4666
if phy_settings.memtype in ["SDR"]:
@@ -49,146 +69,135 @@ def __init__(self, phy_settings, geom_settings, timing_settings):
4969
burst_length = phy_settings.nphases*2 # command multiplication*DDR
5070
address_align = log2_int(burst_length)
5171

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+
# # #
5873

5974
self.dfi = dfi = dfibus.Interface(geom_settings.addressbits,
6075
geom_settings.bankbits,
6176
phy_settings.dfi_databits,
6277
phy_settings.nphases)
6378

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()
7480

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
8583

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)
87104
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))
92108
]
109+
banks.append(bank)
110+
self.submodules += banks
93111

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)
103116

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])),
114120
]
115121

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()
118133
fsm.act("IDLE",
119-
If(refresh_req,
120-
NextState("PRECHARGEALL")
134+
If(refresh_timer.done,
135+
NextState("PRECHARGE-ALL")
121136
).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(
132148
NextState("ACTIVATE")
133-
),
149+
)
134150
)
135151
)
136152
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),
139154
dfi.phases[rdphase].ras_n.eq(1),
140155
dfi.phases[rdphase].cas_n.eq(0),
141156
dfi.phases[rdphase].we_n.eq(1),
142157
dfi.phases[rdphase].rddata_en.eq(1),
143-
addr_sel.eq(COLUMN),
144-
NextState("READ-WAIT-ACK"),
158+
NextState("WAIT-READ-DONE"),
145159
)
146-
fsm.act("READ-WAIT-ACK",
160+
fsm.act("WAIT-READ-DONE",
147161
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")
152164
)
153165
)
154166
fsm.act("WRITE",
167+
write.eq(1),
155168
dfi.phases[wrphase].ras_n.eq(1),
156169
dfi.phases[wrphase].cas_n.eq(0),
157170
dfi.phases[wrphase].we_n.eq(0),
158171
dfi.phases[wrphase].wrdata_en.eq(1),
159-
addr_sel.eq(COLUMN),
172+
NextState("WRITE-LATENCY")
173+
)
174+
fsm.act("WRITE-ACK",
160175
bus.ack.eq(1),
161176
NextState("IDLE")
162177
)
163-
fsm.act("PRECHARGEALL",
164-
row_closeall.eq(1),
178+
fsm.act("PRECHARGE-ALL",
179+
precharge_all.eq(1),
165180
dfi.phases[rdphase].ras_n.eq(0),
166181
dfi.phases[rdphase].cas_n.eq(1),
167182
dfi.phases[rdphase].we_n.eq(0),
168-
addr_sel.eq(A10_ENABLED),
169183
NextState("PRE-REFRESH")
170184
)
171185
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")
181191
)
182192
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),
184197
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)
189198
)
190199
fsm.act("REFRESH",
191-
refresh_ack.eq(1),
200+
refresh.eq(1),
192201
dfi.phases[rdphase].ras_n.eq(0),
193202
dfi.phases[rdphase].cas_n.eq(0),
194203
dfi.phases[rdphase].we_n.eq(1),
@@ -198,3 +207,30 @@ def __init__(self, phy_settings, geom_settings, timing_settings):
198207
fsm.delayed_enter("PRE-REFRESH", "REFRESH", timing_settings.tRP-1)
199208
fsm.delayed_enter("TRCD", "IDLE", timing_settings.tRCD-1)
200209
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+
]

‎misoclib/soc/sdram.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ def register_sdram_phy(self, phy):
3131
if self._sdram_phy_registered:
3232
raise FinalizeError
3333
self._sdram_phy_registered = True
34-
if isinstance(self.sdram_controller_settings, MiniconSettings) and phy.settings.memtype != "SDR":
35-
raise NotImplementedError("Minicon only supports SDR memtype for now (" + phy.settings.memtype + ")")
3634

3735
# Core
3836
self.submodules.sdram = SDRAMCore(phy,
@@ -72,14 +70,15 @@ def register_sdram_phy(self, phy):
7270

7371
# MINICON frontend
7472
elif isinstance(self.sdram_controller_settings, MiniconSettings):
75-
if sdram_width == 32:
73+
burst_width = phy.settings.dfi_databits*phy.settings.nphases
74+
if burst_width == 32:
7675
self.register_mem("main_ram", self.mem_map["main_ram"], self.sdram.controller.bus, main_ram_size)
77-
elif sdram_width < 32:
78-
self.submodules.downconverter = downconverter = wishbone.DownConverter(32, sdram_width)
76+
elif burst_width < 32:
77+
self.submodules.downconverter = downconverter = wishbone.DownConverter(32, burst_width)
7978
self.comb += Record.connect(downconverter.wishbone_o, self.sdram.controller.bus)
8079
self.register_mem("main_ram", self.mem_map["main_ram"], downconverter.wishbone_i, main_ram_size)
8180
else:
82-
raise NotImplementedError("Unsupported SDRAM width of {} > 32".format(sdram_width))
81+
raise NotImplementedError("Unsupported burst width of {} > 32".format(burst_width))
8382

8483
def do_finalize(self):
8584
if not self.integrated_main_ram_size:

0 commit comments

Comments
 (0)
Please sign in to comment.