6b2697031e766bf4ce8689a3d542dc50389a46a6
[litex.git] / milkymist / s6ddrphy / __init__.py
1 from migen.fhdl.structure import *
2 from migen.bus import dfi
3 from migen.bank.description import *
4 from migen.bank import csrgen
5
6 class S6DDRPHY:
7 def __init__(self, csr_address, a, ba, d):
8 ins = []
9 outs = []
10 inouts = []
11
12 for name in [
13 "clk2x_90",
14 "clk4x_wr_left",
15 "clk4x_wr_strb_left",
16 "clk4x_wr_right",
17 "clk4x_wr_strb_right",
18 "clk4x_rd_left",
19 "clk4x_rd_strb_left",
20 "clk4x_rd_right",
21 "clk4x_rd_strb_right"
22 ]:
23 s = Signal(name=name)
24 setattr(self, name, s)
25 ins.append((name, s))
26
27 self._sd_pins = []
28 sd_d = d//4
29 for name, width, l in [
30 ("sd_clk_out_p", 1, outs),
31 ("sd_clk_out_n", 1, outs),
32 ("sd_a", a, outs),
33 ("sd_ba", ba, outs),
34 ("sd_cs_n", 1, outs),
35 ("sd_cke", 1, outs),
36 ("sd_ras_n", 1, outs),
37 ("sd_cas_n", 1, outs),
38 ("sd_we_n", 1, outs),
39 ("sd_dq", sd_d, inouts),
40 ("sd_dm", sd_d//8, outs),
41 ("sd_dqs", sd_d//8, inouts)
42
43 ]:
44 s = Signal(BV(width), name=name)
45 setattr(self, name, s)
46 l.append((name, s))
47 self._sd_pins.append(s)
48
49 self.dfi = dfi.Interface(a, ba, d)
50 ins += self.dfi.get_standard_names(True, False)
51 outs += self.dfi.get_standard_names(False, True)
52
53 ins += [
54 ("reset_n", BV(1)),
55
56 ("cfg_al", BV(3)),
57 ("cfg_cl", BV(3)),
58 ("cfg_bl", BV(2)),
59 ("cfg_regdimm", BV(1)),
60
61 ("init_done", BV(1)),
62
63 ("cpg_busy", BV(1)),
64
65 ("diag_dq_recal", BV(1)),
66 ("diag_io_sel", BV(9)),
67 ("diag_disable_cal_on_startup", BV(1)),
68 ("diag_cal_bits", BV(2)),
69 ("diag_short_cal", BV(1))
70 ]
71 outs += [
72 ("phy_cal_done", BV(1)),
73
74 ("cpg_r_req", BV(1)),
75 ("cpg_w_req", BV(1)),
76 ("cpg_addr", BV(a)),
77 ("cpg_b_size", BV(4))
78 ]
79
80 self._inst = Instance("spartan6_soft_phy",
81 outs,
82 ins,
83 inouts,
84 [
85 ("DSIZE", d),
86 ("NUM_AD", a),
87 ("NUM_BA", ba),
88 ("ADDR_WIDTH", 31),
89 ("DQ_IO_LOC", Constant(2**32-1, BV(32))),
90 ("DM_IO_LOC", Constant(2**4-1, BV(4)))
91 ],
92 clkport="clk")
93
94 self._reset_n = Field("reset_n")
95 self._init_done = Field("init_done")
96 self._phy_cal_done = Field("phy_cal_done", 1, READ_ONLY, WRITE_ONLY)
97 self._status = RegisterFields("status",
98 [self._reset_n, self._init_done, self._phy_cal_done])
99 self._req = RegisterRaw("req", 2)
100 self._req_addr = RegisterField("req_addr", 8, READ_ONLY, WRITE_ONLY)
101
102 self.bank = csrgen.Bank([self._status, self._req, self._req_addr],
103 address=csr_address)
104
105 def get_fragment(self):
106 pending_r = Signal()
107 pending_w = Signal()
108 cpg_busy = Signal()
109
110 comb = [
111 self._inst.ins["cfg_al"].eq(0),
112 self._inst.ins["cfg_cl"].eq(3),
113 self._inst.ins["cfg_bl"].eq(1),
114 self._inst.ins["cfg_regdimm"].eq(0),
115
116 self._inst.ins["diag_dq_recal"].eq(0),
117 self._inst.ins["diag_io_sel"].eq(0),
118 self._inst.ins["diag_disable_cal_on_startup"].eq(0),
119 self._inst.ins["diag_cal_bits"].eq(0),
120 self._inst.ins["diag_short_cal"].eq(0),
121
122 self._inst.ins["reset_n"].eq(self._reset_n.r),
123 self._inst.ins["init_done"].eq(self._init_done.r),
124 self._phy_cal_done.w.eq(self._inst.outs["phy_cal_done"]),
125 self._req_addr.field.w.eq(self._inst.outs["cpg_addr"][2:10]),
126
127 self._req.w.eq(Cat(pending_r, pending_w)),
128 cpg_busy.eq(pending_r | pending_w),
129 self._inst.ins["cpg_busy"].eq(cpg_busy)
130 ]
131 sync = [
132 If(self._inst.outs["cpg_r_req"], pending_r.eq(1)),
133 If(self._inst.outs["cpg_w_req"], pending_w.eq(1)),
134 If(self._req.re & self._req.r[0], pending_r.eq(0)),
135 If(self._req.re & self._req.r[1], pending_w.eq(0))
136 ]
137 return Fragment(comb, sync, instances=[self._inst], pads=set(self._sd_pins)) \
138 + self.bank.get_fragment()