setup.py: Removed deps as per bug #1086#c7.
[gram.git] / gram / common.py
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>
5 # License: BSD
6
7 import math
8 from functools import reduce
9 from operator import add
10 from collections import OrderedDict
11
12 from nmigen import *
13 from nmigen.asserts import Assert, Assume
14 from nmigen.hdl.rec import *
15 from nmigen.utils import log2_int
16
17 import gram.stream as stream
18
19 # Helpers ------------------------------------------------------------------------------------------
20
21 burst_lengths = {
22 "SDR": 1,
23 "DDR": 4,
24 "LPDDR": 4,
25 "DDR2": 4,
26 "DDR3": 8,
27 "DDR4": 8
28 }
29
30
31 def get_cl_cw(memtype, tck):
32 f_to_cl_cwl = OrderedDict()
33 if memtype == "DDR2":
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)
46 else:
47 raise ValueError
48 for f, (cl, cwl) in f_to_cl_cwl.items():
49 if tck >= 2/f:
50 return cl, cwl
51 raise ValueError
52
53
54 def get_sys_latency(nphases, cas_latency):
55 return math.ceil(cas_latency/nphases)
56
57 def get_sys_phase(nphases, sys_latency, cas_latency):
58 return sys_latency*nphases - cas_latency
59
60 def get_sys_phases(nphases, sys_latency, cas_latency):
61 dat_phase = sys_latency*nphases - cas_latency
62 cmd_phase = (dat_phase - 1) % nphases
63 return cmd_phase, dat_phase
64
65 # BitSlip ---------------------------------------------------------------
66
67 class BitSlip(Elaboratable):
68 """BitSlip: provides a delay-buffer by N clock cycles for data of width dw
69 * rst will reset the delay back to zero
70 * slp will increment the counter. it must be held for {cycles} cycles
71 for the input data to appear on the output buffer
72 """
73 def __init__(self, dw, rst=None, slp=None, cycles=1):
74 self.i = Signal(dw)
75 self.o = Signal(dw)
76 #self.rst = Signal() if rst is None else rst
77 self.slp = Signal() if slp is None else slp
78 self.dw = dw
79 self.cycles = cycles
80
81 def elaborate(self, platform):
82 m = Module()
83 comb, sync = m.d.comb, m.d.sync
84 vcount = self.cycles * self.dw
85 value = Signal(vcount.bit_length())
86
87 #with m.If(self.rst):
88 # sync += value.eq(0)
89 #with m.Elif(self.slp):
90 # sync += value.eq(value+1)
91 comb += value.eq(self.slp)
92
93 # Shift Register using input i.
94 r = Signal((self.cycles+1)*self.dw, reset_less=True)
95 sync += r.eq(Cat(r[self.dw:], self.i))
96
97 # note the slightly strange arrangement: whilst the shift register
98 # shuffles along by {dw} bits, if dw is not 1, the output can contain
99 # parts of data from previous clocks.
100 with m.Switch(value):
101 for i in range(self.cycles*self.dw):
102 with m.Case(i):
103 comb += self.o.eq(r[i:self.dw+i])
104 return m
105
106 # Settings -----------------------------------------------------------------------------------------
107
108
109 class Settings:
110 def set_attributes(self, attributes):
111 for k, v in attributes.items():
112 setattr(self, k, v)
113
114
115 class PhySettings(Settings):
116 def __init__(self, phytype, memtype, databits, dfi_databits,
117 nphases,
118 rdphase, wrphase,
119 rdcmdphase, wrcmdphase,
120 cl, read_latency, write_latency, nranks=1, cwl=None):
121 self.set_attributes(locals())
122 self.cwl = cl if cwl is None else cwl
123 self.is_rdimm = False
124
125 # Optional DDR3/DDR4 electrical settings:
126 # rtt_nom: Non-Writes on-die termination impedance
127 # rtt_wr: Writes on-die termination impedance
128 # ron: Output driver impedance
129 def add_electrical_settings(self, rtt_nom, rtt_wr, ron):
130 assert self.memtype in ["DDR3", "DDR4"]
131 self.set_attributes(locals())
132
133
134 class GeomSettings(Settings):
135 def __init__(self, bankbits, rowbits, colbits):
136 self.set_attributes(locals())
137 self.addressbits = max(rowbits, colbits)
138
139
140 class TimingSettings(Settings):
141 def __init__(self, tRP, tRCD, tWR, tWTR, tREFI, tRFC, tFAW, tCCD, tRRD, tRC, tRAS, tZQCS):
142 self.set_attributes(locals())
143
144 # Layouts/Interface --------------------------------------------------------------------------------
145
146
147 def cmd_layout(address_width):
148 return [
149 ("valid", 1, DIR_FANOUT),
150 ("ready", 1, DIR_FANIN),
151 ("we", 1, DIR_FANOUT),
152 ("addr", address_width, DIR_FANOUT),
153 ("lock", 1, DIR_FANIN), # only used internally
154
155 ("wdata_ready", 1, DIR_FANIN),
156 ("rdata_valid", 1, DIR_FANIN)
157 ]
158
159
160 def data_layout(data_width):
161 return [
162 ("wdata", data_width, DIR_FANOUT),
163 ("wdata_we", data_width//8, DIR_FANOUT),
164 ("rdata", data_width, DIR_FANIN)
165 ]
166
167
168 def cmd_description(address_width):
169 return [
170 ("we", 1),
171 ("addr", address_width)
172 ]
173
174
175 def wdata_description(data_width):
176 return [
177 ("data", data_width),
178 ("we", data_width//8)
179 ]
180
181
182 def rdata_description(data_width):
183 return [("data", data_width)]
184
185
186 def cmd_request_layout(a, ba):
187 return [
188 ("a", a),
189 ("ba", ba),
190 ("cas", 1),
191 ("ras", 1),
192 ("we", 1)
193 ]
194
195
196 def cmd_request_rw_layout(a, ba):
197 return cmd_request_layout(a, ba) + [
198 ("is_cmd", 1),
199 ("is_read", 1),
200 ("is_write", 1)
201 ]
202
203
204 class gramInterface(Record):
205 def __init__(self, address_align, settings):
206 rankbits = log2_int(settings.phy.nranks)
207 self.address_align = address_align
208 self.address_width = settings.geom.rowbits + \
209 settings.geom.colbits + rankbits - address_align
210 self.data_width = settings.phy.dfi_databits*settings.phy.nphases
211 self.nbanks = settings.phy.nranks*(2**settings.geom.bankbits)
212 self.nranks = settings.phy.nranks
213 self.settings = settings
214
215 layout = [("bank"+str(i), cmd_layout(self.address_width))
216 for i in range(self.nbanks)]
217 layout += data_layout(self.data_width)
218 Record.__init__(self, layout)
219
220 # Ports --------------------------------------------------------------------------------------------
221
222
223 class gramNativePort(Settings):
224 def __init__(self, mode, address_width, data_width, clock_domain="sync", id=0):
225 self.set_attributes(locals())
226
227 if mode not in ["both", "read", "write"]:
228 raise ValueError("mode must be either both/read/write, not {!r}".format(mode))
229
230 self.lock = Signal()
231
232 self.cmd = stream.Endpoint(cmd_description(address_width))
233 self.wdata = stream.Endpoint(wdata_description(data_width))
234 self.rdata = stream.Endpoint(rdata_description(data_width))
235
236 self.flush = Signal()
237
238 self.data_width = data_width
239
240 def get_bank_address(self, bank_bits, cba_shift):
241 cba_upper = cba_shift + bank_bits
242 return self.cmd.addr[cba_shift:cba_upper]
243
244 def get_row_column_address(self, bank_bits, rca_bits, cba_shift):
245 cba_upper = cba_shift + bank_bits
246 if cba_shift < rca_bits:
247 if cba_shift:
248 return Cat(self.cmd.addr[:cba_shift], self.cmd.addr[cba_upper:])
249 else:
250 return self.cmd.addr[cba_upper:]
251 else:
252 return self.cmd.addr[:cba_shift]
253
254
255 # Timing Controllers -------------------------------------------------------------------------------
256
257 class tXXDController(Elaboratable):
258 def __init__(self, txxd):
259 self.valid = Signal()
260 self.ready = ready = Signal(reset=txxd is None, attrs={"no_retiming": True})
261 self._txxd = txxd
262
263 def elaborate(self, platform):
264 m = Module()
265
266 if self._txxd is not None:
267 count = Signal(range(max(self._txxd, 2)))
268 with m.If(self.valid):
269 m.d.sync += [
270 count.eq(self._txxd-1),
271 self.ready.eq((self._txxd - 1) == 0),
272 ]
273 with m.Elif(~self.ready):
274 m.d.sync += count.eq(count-1)
275 with m.If(count == 1):
276 m.d.sync += self.ready.eq(1)
277
278 if platform == "formal":
279 if self._txxd is not None and self._txxd > 0:
280 hasSeenValid = Signal()
281 with m.If(self.valid):
282 m.d.sync += hasSeenValid.eq(1)
283
284 m.d.sync += Assert((hasSeenValid & (count == 0)).implies(self.ready == 1))
285
286 return m
287
288
289 class tFAWController(Elaboratable):
290 def __init__(self, tfaw):
291 self.valid = Signal()
292 self.ready = Signal(reset=1, attrs={"no_retiming": True})
293 self._tfaw = tfaw
294
295 def elaborate(self, platform):
296 m = Module()
297
298 if self._tfaw is not None:
299 count = Signal(range(max(self._tfaw, 2)))
300 window = Signal(self._tfaw)
301 m.d.sync += window.eq(Cat(self.valid, window))
302 m.d.comb += count.eq(reduce(add, [window[i] for i in range(self._tfaw)]))
303 with m.If(count < 4):
304 with m.If(count == 3):
305 m.d.sync += self.ready.eq(~self.valid)
306 with m.Else():
307 m.d.sync += self.ready.eq(1)
308
309 return m