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