make ctrl/datapath in phy vendor agnostics and simplify imports
[litex.git] / lib / sata / phy / datapath.py
1 from lib.sata.common import *
2
3 from migen.genlib.misc import chooser
4
5 class SATAPHYDatapathRX(Module):
6 def __init__(self):
7 self.sink = Sink(phy_description(16))
8 self.source = Source(phy_description(32))
9
10 ###
11
12 # bytes alignment
13
14 # shift register
15 data_sr = Signal(32+8)
16 charisk_sr = Signal(4+1)
17 data_sr_d = Signal(32+8)
18 charisk_sr_d = Signal(4+1)
19 self.comb += [
20 data_sr.eq(Cat(data_sr_d[16:], self.sink.data)),
21 charisk_sr.eq(Cat(charisk_sr_d[2:], self.sink.charisk))
22 ]
23 self.sync.sata_rx += [
24 data_sr_d.eq(data_sr),
25 charisk_sr_d.eq(charisk_sr)
26 ]
27
28 # alignment
29 alignment = Signal()
30 valid = Signal()
31 self.sync.sata_rx += [
32 If(self.sink.charisk !=0,
33 alignment.eq(self.sink.charisk[1]),
34 valid.eq(0)
35 ).Else(
36 valid.eq(~valid)
37 )
38 ]
39
40 # 16 to 32
41 data = Signal(32)
42 charisk = Signal(4)
43 self.comb += [
44 If(alignment,
45 data.eq(data_sr[0:32]),
46 charisk.eq(charisk_sr[0:4])
47 ).Else(
48 data.eq(data_sr[8:40]),
49 charisk.eq(charisk_sr[1:5])
50 )
51 ]
52
53 # clock domain crossing
54 # (SATA3) 300MHz sata_rx clk to sys_clk
55 # (SATA2) 150MHz sata_rx clk to sys_clk
56 # (SATA1) 75MHz sata_rx clk to sys_clk
57 # requirements:
58 # due to the convertion ratio of 2, sys_clk need to be > sata_rx/2
59 # source destination is always able to accept data (ack always 1)
60 fifo = AsyncFIFO(phy_description(32), 4)
61 self.submodules.fifo = RenameClockDomains(fifo, {"write": "sata_rx", "read": "sys"})
62 self.comb += [
63 fifo.sink.stb.eq(valid),
64 fifo.sink.data.eq(data),
65 fifo.sink.charisk.eq(charisk),
66 ]
67 self.comb += Record.connect(fifo.source, self.source)
68
69 class SATAPHYDatapathTX(Module):
70 def __init__(self):
71 self.sink = Sink(phy_description(32))
72 self.source = Source(phy_description(16))
73
74 ###
75
76 # clock domain crossing
77 # (SATA3) sys_clk to 300MHz sata_tx clk
78 # (SATA2) sys_clk to 150MHz sata_tx clk
79 # (SATA1) sys_clk to 75MHz sata_tx clk
80 # requirements:
81 # source destination is always able to accept data (ack always 1)
82 fifo = AsyncFIFO(phy_description(32), 4)
83 self.submodules.fifo = RenameClockDomains(fifo, {"write": "sys", "read": "sata_tx"})
84 self.comb += Record.connect(self.sink, fifo.sink)
85
86 # 32 to 16
87 mux = Signal()
88 last = Signal()
89 self.comb += [
90 last.eq(mux == 1),
91 self.source.stb.eq(fifo.source.stb),
92 fifo.source.ack.eq(last),
93 ]
94 self.sync.sata_tx += [
95 If(self.source.stb,
96 If(last,
97 mux.eq(0)
98 ).Else(
99 mux.eq(mux + 1)
100 )
101 )
102 ]
103 self.comb += [
104 chooser(fifo.source.data, mux, self.source.data),
105 chooser(fifo.source.charisk, mux, self.source.charisk)
106 ]
107
108 class SATAPHYDatapath(Module):
109 def __init__(self, trx, ctrl):
110 self.sink = Sink(phy_description(32))
111 self.source = Source(phy_description(32))
112
113 ###
114
115 # change data width & cross domain crossing
116 rx = SATAPHYDatapathRX()
117 tx = SATAPHYDatapathTX()
118 self.submodules += rx, tx
119 self.comb += [
120 trx.source.connect(rx.sink),
121 tx.source.connect(trx.sink)
122 ]
123
124 # Align cnt (send 2 Align DWORDs every 256 DWORDs)
125 align_cnt = Signal(8)
126 self.sync += \
127 If(~ctrl.ready,
128 align_cnt.eq(0)
129 ).Elif(tx.sink.stb & tx.sink.ack,
130 align_cnt.eq(align_cnt+1)
131 )
132 send_align = (align_cnt < 2)
133
134 receive_align = Signal()
135 self.comb += receive_align.eq(rx.source.stb &
136 (rx.source.charisk == 0b0001) &
137 (rx.source.data == primitives["ALIGN"]))
138
139 # user / ctrl mux
140 self.comb += [
141 # user
142 If(ctrl.ready,
143 If(send_align,
144 tx.sink.stb.eq(1),
145 tx.sink.data.eq(primitives["ALIGN"]),
146 tx.sink.charisk.eq(0b0001),
147 self.sink.ack.eq(0)
148 ).Else(
149 tx.sink.stb.eq(self.sink.stb),
150 tx.sink.data.eq(self.sink.data),
151 tx.sink.charisk.eq(self.sink.charisk),
152 self.sink.ack.eq(tx.sink.ack)
153 ),
154 If(receive_align,
155 rx.source.ack.eq(1)
156 ).Else(
157 self.source.stb.eq(rx.source.stb),
158 self.source.data.eq(rx.source.data),
159 self.source.charisk.eq(rx.source.charisk),
160 rx.source.ack.eq(1)
161 )
162 # ctrl
163 ).Else(
164 tx.sink.stb.eq(ctrl.source.stb),
165 tx.sink.data.eq(ctrl.source.data),
166 tx.sink.charisk.eq(ctrl.source.charisk),
167
168 ctrl.sink.stb.eq(rx.source.stb),
169 ctrl.sink.data.eq(rx.source.data),
170 rx.source.ack.eq(1),
171 )
172 ]