1b53722f58b59588791f4b1588ab3f49a8ac31b2
1 # This file is Copyright (c) 2016-2019 Florent Kermarrec <florent@enjoy-digital.fr>
2 # This file is Copyright (c) 2018 John Sully <john@csquare.ca>
3 # This file is Copyright (c) 2018 bunnie <bunnie@kosagi.com>
4 # This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
8 from functools
import reduce
9 from operator
import add
10 from collections
import OrderedDict
13 from nmigen
.asserts
import Assert
, Assume
14 from nmigen
.hdl
.rec
import *
15 from nmigen
.utils
import log2_int
17 import gram
.stream
as stream
19 # Helpers ------------------------------------------------------------------------------------------
31 def get_cl_cw(memtype
, tck
):
32 f_to_cl_cwl
= OrderedDict()
34 f_to_cl_cwl
[400e6
] = (3, 2)
35 f_to_cl_cwl
[533e6
] = (4, 3)
36 f_to_cl_cwl
[677e6
] = (5, 4)
37 f_to_cl_cwl
[800e6
] = (6, 5)
38 f_to_cl_cwl
[1066e6
] = (7, 5)
39 elif memtype
== "DDR3":
40 f_to_cl_cwl
[800e6
] = (6, 5)
41 f_to_cl_cwl
[1066e6
] = (7, 6)
42 f_to_cl_cwl
[1333e6
] = (10, 7)
43 f_to_cl_cwl
[1600e6
] = (11, 8)
44 elif memtype
== "DDR4":
45 f_to_cl_cwl
[1600e6
] = (11, 9)
48 for f
, (cl
, cwl
) in f_to_cl_cwl
.items():
54 def get_sys_latency(nphases
, cas_latency
):
55 return math
.ceil(cas_latency
/nphases
)
58 def get_sys_phases(nphases
, sys_latency
, cas_latency
):
59 dat_phase
= sys_latency
*nphases
- cas_latency
60 cmd_phase
= (dat_phase
- 1) % nphases
61 return cmd_phase
, dat_phase
63 # Settings -----------------------------------------------------------------------------------------
67 def set_attributes(self
, attributes
):
68 for k
, v
in attributes
.items():
72 class PhySettings(Settings
):
73 def __init__(self
, phytype
, memtype
, databits
, dfi_databits
,
76 rdcmdphase
, wrcmdphase
,
77 cl
, read_latency
, write_latency
, nranks
=1, cwl
=None):
78 self
.set_attributes(locals())
79 self
.cwl
= cl
if cwl
is None else cwl
82 # Optional DDR3/DDR4 electrical settings:
83 # rtt_nom: Non-Writes on-die termination impedance
84 # rtt_wr: Writes on-die termination impedance
85 # ron: Output driver impedance
86 def add_electrical_settings(self
, rtt_nom
, rtt_wr
, ron
):
87 assert self
.memtype
in ["DDR3", "DDR4"]
88 self
.set_attributes(locals())
91 class GeomSettings(Settings
):
92 def __init__(self
, bankbits
, rowbits
, colbits
):
93 self
.set_attributes(locals())
94 self
.addressbits
= max(rowbits
, colbits
)
97 class TimingSettings(Settings
):
98 def __init__(self
, tRP
, tRCD
, tWR
, tWTR
, tREFI
, tRFC
, tFAW
, tCCD
, tRRD
, tRC
, tRAS
, tZQCS
):
99 self
.set_attributes(locals())
101 # Layouts/Interface --------------------------------------------------------------------------------
104 def cmd_layout(address_width
):
106 ("valid", 1, DIR_FANOUT
),
107 ("ready", 1, DIR_FANIN
),
108 ("we", 1, DIR_FANOUT
),
109 ("addr", address_width
, DIR_FANOUT
),
110 ("lock", 1, DIR_FANIN
), # only used internally
112 ("wdata_ready", 1, DIR_FANIN
),
113 ("rdata_valid", 1, DIR_FANIN
)
117 def data_layout(data_width
):
119 ("wdata", data_width
, DIR_FANOUT
),
120 ("wdata_we", data_width
//8, DIR_FANOUT
),
121 ("rdata", data_width
, DIR_FANIN
)
125 def cmd_description(address_width
):
128 ("addr", address_width
)
132 def wdata_description(data_width
):
134 ("data", data_width
),
135 ("we", data_width
//8)
139 def rdata_description(data_width
):
140 return [("data", data_width
)]
143 def cmd_request_layout(a
, ba
):
153 def cmd_request_rw_layout(a
, ba
):
154 return cmd_request_layout(a
, ba
) + [
161 class gramInterface(Record
):
162 def __init__(self
, address_align
, settings
):
163 rankbits
= log2_int(settings
.phy
.nranks
)
164 self
.address_align
= address_align
165 self
.address_width
= settings
.geom
.rowbits
+ \
166 settings
.geom
.colbits
+ rankbits
- address_align
167 self
.data_width
= settings
.phy
.dfi_databits
*settings
.phy
.nphases
168 self
.nbanks
= settings
.phy
.nranks
*(2**settings
.geom
.bankbits
)
169 self
.nranks
= settings
.phy
.nranks
170 self
.settings
= settings
172 layout
= [("bank"+str(i
), cmd_layout(self
.address_width
))
173 for i
in range(self
.nbanks
)]
174 layout
+= data_layout(self
.data_width
)
175 Record
.__init
__(self
, layout
)
177 # Ports --------------------------------------------------------------------------------------------
180 class gramNativePort(Settings
):
181 def __init__(self
, mode
, address_width
, data_width
, clock_domain
="sync", id=0):
182 self
.set_attributes(locals())
184 if mode
not in ["both", "read", "write"]:
185 raise ValueError("mode must be either both/read/write, not {!r}".format(mode
))
189 self
.cmd
= stream
.Endpoint(cmd_description(address_width
))
190 self
.wdata
= stream
.Endpoint(wdata_description(data_width
))
191 self
.rdata
= stream
.Endpoint(rdata_description(data_width
))
193 self
.flush
= Signal()
195 self
.data_width
= data_width
197 def get_bank_address(self
, bank_bits
, cba_shift
):
198 cba_upper
= cba_shift
+ bank_bits
199 return self
.cmd
.addr
[cba_shift
:cba_upper
]
201 def get_row_column_address(self
, bank_bits
, rca_bits
, cba_shift
):
202 cba_upper
= cba_shift
+ bank_bits
203 if cba_shift
< rca_bits
:
205 return Cat(self
.cmd
.addr
[:cba_shift
], self
.cmd
.addr
[cba_upper
:])
207 return self
.cmd
.addr
[cba_upper
:]
209 return self
.cmd
.addr
[:cba_shift
]
212 # Timing Controllers -------------------------------------------------------------------------------
214 class tXXDController(Elaboratable
):
215 def __init__(self
, txxd
):
216 self
.valid
= Signal()
217 self
.ready
= ready
= Signal(reset
=txxd
is None, attrs
={"no_retiming": True})
220 def elaborate(self
, platform
):
223 if self
._txxd
is not None:
224 count
= Signal(range(max(self
._txxd
, 2)))
225 with m
.If(self
.valid
):
227 count
.eq(self
._txxd
-1),
228 self
.ready
.eq((self
._txxd
- 1) == 0),
230 with m
.Elif(~self
.ready
):
231 m
.d
.sync
+= count
.eq(count
-1)
232 with m
.If(count
== 1):
233 m
.d
.sync
+= self
.ready
.eq(1)
235 if platform
== "formal":
236 if self
._txxd
is not None and self
._txxd
> 0:
237 hasSeenValid
= Signal()
238 with m
.If(self
.valid
):
239 m
.d
.sync
+= hasSeenValid
.eq(1)
241 m
.d
.sync
+= Assert((hasSeenValid
& (count
== 0)).implies(self
.ready
== 1))
246 class tFAWController(Elaboratable
):
247 def __init__(self
, tfaw
):
248 self
.valid
= Signal()
249 self
.ready
= Signal(reset
=1, attrs
={"no_retiming": True})
252 def elaborate(self
, platform
):
255 if self
._tfaw
is not None:
256 count
= Signal(range(max(self
._tfaw
, 2)))
257 window
= Signal(self
._tfaw
)
258 m
.d
.sync
+= window
.eq(Cat(self
.valid
, window
))
259 m
.d
.comb
+= count
.eq(reduce(add
, [window
[i
] for i
in range(self
._tfaw
)]))
260 with m
.If(count
< 4):
261 with m
.If(count
== 3):
262 m
.d
.sync
+= self
.ready
.eq(~self
.valid
)
264 m
.d
.sync
+= self
.ready
.eq(1)