1 # This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
4 # SDRAM simulation PHY at DFI level
5 # tested with SDR/DDR/DDR2/LPDDR/DDR3
7 # - add $display support to Migen and manage timing violations?
10 from migen
.fhdl
.specials
import *
11 from misoc
.mem
.sdram
.phy
.dfi
import *
12 from misoc
.mem
import sdram
16 def __init__(self
, data_width
, nrows
, ncols
, burst_length
):
17 self
.activate
= Signal()
18 self
.activate_row
= Signal(max=nrows
)
19 self
.precharge
= Signal()
22 self
.write_col
= Signal(max=ncols
)
23 self
.write_data
= Signal(data_width
)
24 self
.write_mask
= Signal(data_width
//8)
27 self
.read_col
= Signal(max=ncols
)
28 self
.read_data
= Signal(data_width
)
32 row
= Signal(max=nrows
)
39 row
.eq(self
.activate_row
)
42 self
.specials
.mem
= mem
= Memory(data_width
, nrows
*ncols
//burst_length
)
43 self
.specials
.write_port
= write_port
= mem
.get_port(write_capable
=True,
45 self
.specials
.read_port
= read_port
= mem
.get_port(async_read
=True)
48 write_port
.adr
.eq(row
*ncols | self
.write_col
),
49 write_port
.dat_w
.eq(self
.write_data
),
50 write_port
.we
.eq(Replicate(self
.write
, data_width
//8) & ~self
.write_mask
),
52 read_port
.adr
.eq(row
*ncols | self
.read_col
),
53 self
.read_data
.eq(read_port
.dat_r
)
59 class DFIPhase(Module
):
60 def __init__(self
, dfi
, n
):
61 phase
= getattr(dfi
, "p"+str(n
))
63 self
.bank
= phase
.bank
64 self
.address
= phase
.address
66 self
.wrdata
= phase
.wrdata
67 self
.wrdata_mask
= phase
.wrdata_mask
69 self
.rddata
= phase
.rddata
70 self
.rddata_valid
= phase
.rddata_valid
72 self
.activate
= Signal()
73 self
.precharge
= Signal()
79 If(~phase
.cs_n
& ~phase
.ras_n
& phase
.cas_n
,
80 self
.activate
.eq(phase
.we_n
),
81 self
.precharge
.eq(~phase
.we_n
)
83 If(~phase
.cs_n
& phase
.ras_n
& ~phase
.cas_n
,
84 self
.write
.eq(~phase
.we_n
),
85 self
.read
.eq(phase
.we_n
)
90 class SDRAMPHYSim(Module
):
91 def __init__(self
, module
, settings
):
92 if settings
.memtype
in ["SDR"]:
93 burst_length
= settings
.nphases
*1 # command multiplication*SDR
94 elif settings
.memtype
in ["DDR", "LPDDR", "DDR2", "DDR3"]:
95 burst_length
= settings
.nphases
*2 # command multiplication*DDR
97 addressbits
= module
.geom_settings
.addressbits
98 bankbits
= module
.geom_settings
.bankbits
99 rowbits
= module
.geom_settings
.rowbits
100 colbits
= module
.geom_settings
.colbits
102 self
.settings
= settings
105 self
.dfi
= Interface(addressbits
, bankbits
, self
.settings
.dfi_databits
, self
.settings
.nphases
)
111 data_width
= self
.settings
.dfi_databits
*self
.settings
.nphases
114 phases
= [DFIPhase(self
.dfi
, n
) for n
in range(self
.settings
.nphases
)]
115 self
.submodules
+= phases
118 banks
= [Bank(data_width
, nrows
, ncols
, burst_length
) for i
in range(nbanks
)]
119 self
.submodules
+= banks
121 # connect DFI phases to banks (cmds, write datapath)
122 for nb
, bank
in enumerate(banks
):
124 activates
= Signal(len(phases
))
126 for np
, phase
in enumerate(phases
):
127 self
.comb
+= activates
[np
].eq(phase
.activate
)
129 bank
.activate
.eq(phase
.bank
== nb
),
130 bank
.activate_row
.eq(phase
.address
)
132 self
.comb
+= Case(activates
, cases
)
135 precharges
= Signal(len(phases
))
137 for np
, phase
in enumerate(phases
):
138 self
.comb
+= precharges
[np
].eq(phase
.precharge
)
140 bank
.precharge
.eq((phase
.bank
== nb
) | phase
.address
[10])
142 self
.comb
+= Case(precharges
, cases
)
145 writes
= Signal(len(phases
))
147 for np
, phase
in enumerate(phases
):
148 self
.comb
+= writes
[np
].eq(phase
.write
)
150 bank
.write
.eq(phase
.bank
== nb
),
151 bank
.write_col
.eq(phase
.address
)
153 self
.comb
+= Case(writes
, cases
)
155 bank
.write_data
.eq(Cat(*[phase
.wrdata
for phase
in phases
])),
156 bank
.write_mask
.eq(Cat(*[phase
.wrdata_mask
for phase
in phases
]))
160 reads
= Signal(len(phases
))
162 for np
, phase
in enumerate(phases
):
163 self
.comb
+= reads
[np
].eq(phase
.read
)
165 bank
.read
.eq(phase
.bank
== nb
),
166 bank
.read_col
.eq(phase
.address
)
168 self
.comb
+= Case(reads
, cases
)
170 # connect banks to DFI phases (cmds, read datapath)
171 banks_read
= Signal()
172 banks_read_data
= Signal(data_width
)
174 banks_read
.eq(optree("|", [bank
.read
for bank
in banks
])),
175 banks_read_data
.eq(optree("|", [bank
.read_data
for bank
in banks
]))
177 # simulate read latency
178 for i
in range(self
.settings
.read_latency
):
179 new_banks_read
= Signal()
180 new_banks_read_data
= Signal(data_width
)
182 new_banks_read
.eq(banks_read
),
183 new_banks_read_data
.eq(banks_read_data
)
185 banks_read
= new_banks_read
186 banks_read_data
= new_banks_read_data
189 Cat(*[phase
.rddata_valid
for phase
in phases
]).eq(banks_read
),
190 Cat(*[phase
.rddata
for phase
in phases
]).eq(banks_read_data
)