Initial commit
[gram.git] / gram / phy / dfi.py
1 # This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
2 # Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
3
4 from nmigen import *
5 from nmigen.hdl.rec import *
6
7 def phase_cmd_description(addressbits, bankbits, nranks):
8 return [
9 ("address", addressbits, DIR_FANOUT),
10 ("bank", bankbits, DIR_FANOUT),
11 ("cas_n", 1, DIR_FANOUT),
12 ("cs_n", nranks, DIR_FANOUT),
13 ("ras_n", 1, DIR_FANOUT),
14 ("we_n", 1, DIR_FANOUT),
15 ("cke", nranks, DIR_FANOUT),
16 ("odt", nranks, DIR_FANOUT),
17 ("reset_n", 1, DIR_FANOUT),
18 ("act_n", 1, DIR_FANOUT)
19 ]
20
21
22 def phase_wrdata_description(databits):
23 return [
24 ("wrdata", databits, DIR_FANOUT),
25 ("wrdata_en", 1, DIR_FANOUT),
26 ("wrdata_mask", databits//8, DIR_FANOUT)
27 ]
28
29
30 def phase_rddata_description(databits):
31 return [
32 ("rddata_en", 1, DIR_FANOUT),
33 ("rddata", databits, DIR_FANIN),
34 ("rddata_valid", 1, DIR_FANIN)
35 ]
36
37
38 def phase_description(addressbits, bankbits, nranks, databits):
39 r = phase_cmd_description(addressbits, bankbits, nranks)
40 r += phase_wrdata_description(databits)
41 r += phase_rddata_description(databits)
42 return r
43
44
45 class Interface(Record):
46 def __init__(self, addressbits, bankbits, nranks, databits, nphases=1):
47 layout = [("p"+str(i), phase_description(addressbits, bankbits, nranks, databits)) for i in range(nphases)]
48 Record.__init__(self, layout)
49 self.phases = [getattr(self, "p"+str(i)) for i in range(nphases)]
50 for p in self.phases:
51 p.cas_n.reset = 1
52 p.cs_n.reset = (2**nranks-1)
53 p.ras_n.reset = 1
54 p.we_n.reset = 1
55 p.act_n.reset = 1
56
57 # Returns pairs (DFI-mandated signal name, Migen signal object)
58 def get_standard_names(self, m2s=True, s2m=True):
59 r = []
60 add_suffix = len(self.phases) > 1
61 for n, phase in enumerate(self.phases):
62 for field, size, direction in phase.layout:
63 if (m2s and direction == DIR_FANOUT) or (s2m and direction == DIR_FANIN):
64 if add_suffix:
65 if direction == DIR_FANOUT:
66 suffix = "_p" + str(n)
67 else:
68 suffix = "_w" + str(n)
69 else:
70 suffix = ""
71 r.append(("dfi_" + field + suffix, getattr(phase, field)))
72 return r
73
74
75 class Interconnect(Elaboratable):
76 def __init__(self, master, slave):
77 self._master = master
78 self._slave = slave
79
80 def elaborate(self, platform):
81 m = Module()
82 m.d.comb += self._master.connect(self._slave)
83 return m
84
85
86 class DDR4DFIMux(Elaboratable):
87 def __init__(self, dfi_i, dfi_o):
88 self.dfi_i = dfi_i
89 self.dfi_o = dfi_o
90
91 def elaborate(self, platform):
92 m = Module()
93
94 dfi_i = self.dfi_i
95 dfi_o = self.dfi_o
96
97 for i in range(len(dfi_i.phases)):
98 p_i = dfi_i.phases[i]
99 p_o = dfi_o.phases[i]
100 m.d.comb += p_i.connect(p_o)
101 with m.If(~p_i.ras_n & p_i.cas_n & p_i.we_n):
102 m.d.comb += [
103 p_o.act_n.eq(0),
104 p_o.we_n.eq(p_i.address[14]),
105 p_o.cas_n.eq(p_i.address[15]),
106 p_o.ras_n.eq(p_i.address[16]),
107 ]
108 with m.Else():
109 m.d.comb += p_o.act_n.eq(1)
110
111 return m