- use sys_clk of 166.66MHz and using it instead of sata clk.
- rename clocking to CRG since it also handles resets.
- create datapath and move code from gtx.
from migen.flow.actor import Sink, Source
from lib.sata.k7sataphy.std import *
-from lib.sata.k7sataphy.gtx import K7SATAPHYGTX, K7SATAPHYRXAlign
-from lib.sata.k7sataphy.gtx import K7SATAPHYRXConvert, K7SATAPHYTXConvert
-from lib.sata.k7sataphy.clocking import K7SATAPHYClocking
+from lib.sata.k7sataphy.gtx import K7SATAPHYGTX
+from lib.sata.k7sataphy.crg import K7SATAPHYCRG
from lib.sata.k7sataphy.ctrl import K7SATAPHYHostCtrl, K7SATAPHYDeviceCtrl
+from lib.sata.k7sataphy.datapath import K7SATAPHYRXAlign
+from lib.sata.k7sataphy.datapath import K7SATAPHYRXConvert, K7SATAPHYTXConvert
class K7SATAPHY(Module):
def __init__(self, pads, clk_freq, host=True,):
gtx.rxrate.eq(0b000),
gtx.txrate.eq(0b000),
]
- clocking = K7SATAPHYClocking(pads, gtx, clk_freq)
+ clocking = K7SATAPHYCRG(pads, gtx, clk_freq)
rxalign = K7SATAPHYRXAlign()
rxconvert = K7SATAPHYRXConvert()
txconvert = K7SATAPHYTXConvert()
+++ /dev/null
-from math import ceil
-
-from migen.fhdl.std import *
-from migen.genlib.resetsync import AsyncResetSynchronizer
-from migen.genlib.fsm import FSM, NextState
-
-from lib.sata.k7sataphy.std import *
-
-class K7SATAPHYReconfig(Module):
- def __init__(self, channel_drp, mmcm_drp):
- self.speed = Signal(3)
- ###
- speed_r = Signal(3)
- speed_change = Signal()
- self.sync += speed_r.eq(self.speed)
- self.comb += speed_change.eq(self.speed != speed_r)
-
- drp_sel = Signal()
- drp = DRPBus()
- self.comb += \
- If(drp_sel,
- drp.connect(mmcm_drp)
- ).Else(
- drp.connect(channel_drp)
- )
-
-class K7SATAPHYClocking(Module):
- def __init__(self, pads, gtx, clk_freq):
- self.reset = Signal()
-
- self.clock_domains.cd_sata = ClockDomain()
- self.clock_domains.cd_sata_tx = ClockDomain()
- self.clock_domains.cd_sata_rx = ClockDomain()
-
- # CPLL
- # (SATA3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps
- # (SATA2 & SATA1) VCO still @ 3 GHz, Line rate is decreased with output divivers.
- # When changing rate, reconfiguration of the CPLL over DRP is needed to:
- # - update the output divider
- # - update the equalizer configuration (specific for each line rate).
- refclk = Signal()
- self.specials += Instance("IBUFDS_GTE2",
- i_CEB=0,
- i_I=pads.refclk_p,
- i_IB=pads.refclk_n,
- o_O=refclk
- )
- self.comb += gtx.gtrefclk0.eq(refclk)
-
- # TX clocking
- # (SATA3) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 300MHz (16-bits), sata clk @ 150MHz (32-bits)
- # (SATA2) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 150MHz (16-bits), sata clk @ 75MHz (32-bits)
- # (SATA1) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 75MHz (16-bits), sata clk @ 37.5MHz (32-bits)
- # When changing rate, reconfiguration of the MMCM is needed to update the output divider.
- mmcm_reset = Signal()
- mmcm_locked = Signal()
- mmcm_drp = DRPBus()
- mmcm_fb = Signal()
- mmcm_clk_i = Signal()
- mmcm_clk0_o = Signal()
- mmcm_clk1_o = Signal()
- self.specials += [
- Instance("BUFG", i_I=gtx.txoutclk, o_O=mmcm_clk_i),
- Instance("MMCME2_ADV",
- p_BANDWIDTH="HIGH", p_COMPENSATION="ZHOLD", i_RST=mmcm_reset, o_LOCKED=mmcm_locked,
-
- # DRP
- i_DCLK=mmcm_drp.clk, i_DEN=mmcm_drp.en, o_DRDY=mmcm_drp.rdy, i_DWE=mmcm_drp.we,
- i_DADDR=mmcm_drp.addr, i_DI=mmcm_drp.di, o_DO=mmcm_drp.do,
-
- # VCO
- p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=6.666,
- p_CLKFBOUT_MULT_F=8.000, p_CLKFBOUT_PHASE=0.000, p_DIVCLK_DIVIDE=1,
- i_CLKIN1=mmcm_clk_i, i_CLKFBIN=mmcm_fb, o_CLKFBOUT=mmcm_fb,
-
- # CLK0
- p_CLKOUT0_DIVIDE_F=4.000, p_CLKOUT0_PHASE=0.000, o_CLKOUT0=mmcm_clk0_o,
-
- # CLK1
- p_CLKOUT1_DIVIDE=8, p_CLKOUT1_PHASE=0.000, o_CLKOUT1=mmcm_clk1_o,
- ),
- Instance("BUFG", i_I=mmcm_clk0_o, o_O=self.cd_sata_tx.clk),
- Instance("BUFG", i_I=mmcm_clk1_o, o_O=self.cd_sata.clk),
- ]
- self.comb += [
- gtx.txusrclk.eq(self.cd_sata_tx.clk),
- gtx.txusrclk2.eq(self.cd_sata_tx.clk)
- ]
-
- # RX clocking
- # (SATA3) sata_rx recovered clk @ 300MHz from CPLL RXOUTCLK
- # (SATA2) sata_rx recovered clk @ 150MHz from CPLL RXOUTCLK
- # (SATA1) sata_rx recovered clk @ 150MHz from CPLL RXOUTCLK
- self.specials += [
- Instance("BUFG", i_I=gtx.rxoutclk, o_O=self.cd_sata_rx.clk),
- ]
- self.comb += [
- gtx.rxusrclk.eq(self.cd_sata_rx.clk),
- gtx.rxusrclk2.eq(self.cd_sata_rx.clk)
- ]
-
- # TX buffer bypass logic
- self.comb += [
- gtx.txphdlyreset.eq(0),
- gtx.txphalignen.eq(0),
- gtx.txdlyen.eq(0),
- gtx.txphalign.eq(0),
- gtx.txphinit.eq(0)
- ]
-
- # RX buffer bypass logic
- self.comb += [
- gtx.rxphdlyreset.eq(0),
- gtx.rxdlyen.eq(0),
- gtx.rxphalign.eq(0),
- gtx.rxphalignen.eq(0),
- ]
-
-
- # Configuration Reset
- # After configuration, GTX resets can not be asserted for 500ns
- # See AR43482
- reset_en = Signal()
- clk_period_ns = 1000000000/clk_freq
- reset_en_cnt_max = ceil(500/clk_period_ns)
- reset_en_cnt = Signal(max=reset_en_cnt_max, reset=reset_en_cnt_max-1)
- self.sync += If(~reset_en, reset_en_cnt.eq(reset_en_cnt-1))
- self.comb += reset_en.eq(reset_en_cnt == 0)
-
-
- # once channel TX is reseted, reset TX buffer
- txbuffer_reseted = Signal()
- self.sync += \
- If(gtx.txresetdone,
- If(~txbuffer_reseted,
- gtx.txdlysreset.eq(1),
- txbuffer_reseted.eq(1)
- ).Else(
- gtx.txdlysreset.eq(0)
- )
- )
-
- # once channel RX is reseted, reset RX buffer
- rxbuffer_reseted = Signal()
- self.sync += \
- If(gtx.rxresetdone,
- If(~rxbuffer_reseted,
- gtx.rxdlysreset.eq(1),
- rxbuffer_reseted.eq(1)
- ).Else(
- gtx.rxdlysreset.eq(0)
- )
- )
-
- # Reset
- # initial reset generation
- rst_cnt = Signal(8)
- rst_cnt_done = Signal()
- self.sync += \
- If(~rst_cnt_done,
- rst_cnt.eq(rst_cnt+1)
- )
- self.comb += rst_cnt_done.eq(rst_cnt==255)
-
- self.comb += [
- # GTXE2
- gtx.rxuserrdy.eq(gtx.cplllock),
- gtx.txuserrdy.eq(gtx.cplllock),
- # TX
- gtx.gttxreset.eq(reset_en & (self.reset | ~gtx.cplllock)),
- # RX
- gtx.gtrxreset.eq(reset_en & (self.reset | ~gtx.cplllock)),
- # PLL
- gtx.cpllreset.eq(self.reset | ~reset_en)
- ]
- # SATA TX/RX clock domains
- self.specials += [
- AsyncResetSynchronizer(self.cd_sata_tx, ~mmcm_locked | ~gtx.txresetdone),
- AsyncResetSynchronizer(self.cd_sata_rx, ~gtx.cplllock | ~gtx.rxphaligndone),
- AsyncResetSynchronizer(self.cd_sata, ResetSignal("sata_tx") | ResetSignal("sata_rx")),
- ]
-
- # Dynamic Reconfiguration
- self.submodules.reconfig = K7SATAPHYReconfig(mmcm_drp, gtx.drp)
--- /dev/null
+from math import ceil
+
+from migen.fhdl.std import *
+from migen.genlib.resetsync import AsyncResetSynchronizer
+from migen.genlib.fsm import FSM, NextState
+
+from lib.sata.k7sataphy.std import *
+
+class K7SATAPHYReconfig(Module):
+ def __init__(self, channel_drp, mmcm_drp):
+ self.speed = Signal(3)
+ ###
+ speed_r = Signal(3)
+ speed_change = Signal()
+ self.sync += speed_r.eq(self.speed)
+ self.comb += speed_change.eq(self.speed != speed_r)
+
+ drp_sel = Signal()
+ drp = DRPBus()
+ self.comb += \
+ If(drp_sel,
+ drp.connect(mmcm_drp)
+ ).Else(
+ drp.connect(channel_drp)
+ )
+
+class K7SATAPHYCRG(Module):
+ def __init__(self, pads, gtx, clk_freq):
+ self.reset = Signal()
+
+ self.clock_domains.cd_sata_tx = ClockDomain()
+ self.clock_domains.cd_sata_rx = ClockDomain()
+
+ # CPLL
+ # (SATA3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps
+ # (SATA2 & SATA1) VCO still @ 3 GHz, Line rate is decreased with output divivers.
+ # When changing rate, reconfiguration of the CPLL over DRP is needed to:
+ # - update the output divider
+ # - update the equalizer configuration (specific for each line rate).
+ refclk = Signal()
+ self.specials += Instance("IBUFDS_GTE2",
+ i_CEB=0,
+ i_I=pads.refclk_p,
+ i_IB=pads.refclk_n,
+ o_O=refclk
+ )
+ self.comb += gtx.gtrefclk0.eq(refclk)
+
+ # TX clocking
+ # (SATA3) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 300MHz (16-bits), sata clk @ 150MHz (32-bits)
+ # (SATA2) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 150MHz (16-bits), sata clk @ 75MHz (32-bits)
+ # (SATA1) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 75MHz (16-bits), sata clk @ 37.5MHz (32-bits)
+ # When changing rate, reconfiguration of the MMCM is needed to update the output divider.
+ mmcm_reset = Signal()
+ mmcm_locked = Signal()
+ mmcm_drp = DRPBus()
+ mmcm_fb = Signal()
+ mmcm_clk_i = Signal()
+ mmcm_clk0_o = Signal()
+ mmcm_clk1_o = Signal()
+ self.specials += [
+ Instance("BUFG", i_I=gtx.txoutclk, o_O=mmcm_clk_i),
+ Instance("MMCME2_ADV",
+ p_BANDWIDTH="HIGH", p_COMPENSATION="ZHOLD", i_RST=mmcm_reset, o_LOCKED=mmcm_locked,
+
+ # DRP
+ i_DCLK=mmcm_drp.clk, i_DEN=mmcm_drp.en, o_DRDY=mmcm_drp.rdy, i_DWE=mmcm_drp.we,
+ i_DADDR=mmcm_drp.addr, i_DI=mmcm_drp.di, o_DO=mmcm_drp.do,
+
+ # VCO
+ p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=6.666,
+ p_CLKFBOUT_MULT_F=8.000, p_CLKFBOUT_PHASE=0.000, p_DIVCLK_DIVIDE=1,
+ i_CLKIN1=mmcm_clk_i, i_CLKFBIN=mmcm_fb, o_CLKFBOUT=mmcm_fb,
+
+ # CLK0
+ p_CLKOUT0_DIVIDE_F=4.000, p_CLKOUT0_PHASE=0.000, o_CLKOUT0=mmcm_clk0_o,
+
+ # CLK1
+ p_CLKOUT1_DIVIDE=8, p_CLKOUT1_PHASE=0.000, o_CLKOUT1=mmcm_clk1_o,
+ ),
+ Instance("BUFG", i_I=mmcm_clk0_o, o_O=self.cd_sata_tx.clk),
+ Instance("BUFG", i_I=mmcm_clk1_o, o_O=self.cd_sata.clk),
+ ]
+ self.comb += [
+ gtx.txusrclk.eq(self.cd_sata_tx.clk),
+ gtx.txusrclk2.eq(self.cd_sata_tx.clk)
+ ]
+
+ # RX clocking
+ # (SATA3) sata_rx recovered clk @ 300MHz from CPLL RXOUTCLK
+ # (SATA2) sata_rx recovered clk @ 150MHz from CPLL RXOUTCLK
+ # (SATA1) sata_rx recovered clk @ 150MHz from CPLL RXOUTCLK
+ self.specials += [
+ Instance("BUFG", i_I=gtx.rxoutclk, o_O=self.cd_sata_rx.clk),
+ ]
+ self.comb += [
+ gtx.rxusrclk.eq(self.cd_sata_rx.clk),
+ gtx.rxusrclk2.eq(self.cd_sata_rx.clk)
+ ]
+
+ # TX buffer bypass logic
+ self.comb += [
+ gtx.txphdlyreset.eq(0),
+ gtx.txphalignen.eq(0),
+ gtx.txdlyen.eq(0),
+ gtx.txphalign.eq(0),
+ gtx.txphinit.eq(0)
+ ]
+
+ # RX buffer bypass logic
+ self.comb += [
+ gtx.rxphdlyreset.eq(0),
+ gtx.rxdlyen.eq(0),
+ gtx.rxphalign.eq(0),
+ gtx.rxphalignen.eq(0),
+ ]
+
+
+ # Configuration Reset
+ # After configuration, GTX resets have to stay low for at least 500ns
+ # See AR43482
+ reset_en = Signal()
+ clk_period_ns = 1000000000/clk_freq
+ reset_en_cnt_max = ceil(500/clk_period_ns)
+ reset_en_cnt = Signal(max=reset_en_cnt_max, reset=reset_en_cnt_max-1)
+ self.sync += If(~reset_en, reset_en_cnt.eq(reset_en_cnt-1))
+ self.comb += reset_en.eq(reset_en_cnt == 0)
+
+
+ # once channel TX is reseted, reset TX buffer
+ txbuffer_reseted = Signal()
+ self.sync += \
+ If(gtx.txresetdone,
+ If(~txbuffer_reseted,
+ gtx.txdlysreset.eq(1),
+ txbuffer_reseted.eq(1)
+ ).Else(
+ gtx.txdlysreset.eq(0)
+ )
+ )
+
+ # once channel RX is reseted, reset RX buffer
+ rxbuffer_reseted = Signal()
+ self.sync += \
+ If(gtx.rxresetdone,
+ If(~rxbuffer_reseted,
+ gtx.rxdlysreset.eq(1),
+ rxbuffer_reseted.eq(1)
+ ).Else(
+ gtx.rxdlysreset.eq(0)
+ )
+ )
+
+ # Reset
+ # initial reset generation
+ rst_cnt = Signal(8)
+ rst_cnt_done = Signal()
+ self.sync += \
+ If(~rst_cnt_done,
+ rst_cnt.eq(rst_cnt+1)
+ )
+ self.comb += rst_cnt_done.eq(rst_cnt==255)
+
+ self.comb += [
+ # GTXE2
+ gtx.rxuserrdy.eq(gtx.cplllock),
+ gtx.txuserrdy.eq(gtx.cplllock),
+ # TX
+ gtx.gttxreset.eq(reset_en & (self.reset | ~gtx.cplllock)),
+ # RX
+ gtx.gtrxreset.eq(reset_en & (self.reset | ~gtx.cplllock)),
+ # PLL
+ gtx.cpllreset.eq(self.reset | ~reset_en)
+ ]
+ # SATA TX/RX clock domains
+ self.specials += [
+ AsyncResetSynchronizer(self.cd_sata_tx, ~mmcm_locked | ~gtx.txresetdone),
+ AsyncResetSynchronizer(self.cd_sata_rx, ~gtx.cplllock | ~gtx.rxphaligndone),
+ AsyncResetSynchronizer(self.cd_sata, ResetSignal("sata_tx") | ResetSignal("sata_rx")),
+ ]
+
+ # Dynamic Reconfiguration
+ self.submodules.reconfig = K7SATAPHYReconfig(mmcm_drp, gtx.drp)
txcominit_d = Signal()
txcomwake_d = Signal()
- self.sync.sata += [
+ self.sync += [
txcominit_d.eq(txcominit),
txcomwake_d.eq(txcomwake),
gtx.txcominit.eq(txcominit & ~txcominit_d),
self.comb += align_detect.eq(self.rxdata == ALIGN_VAL);
align_timeout_cnt = Signal(16)
- self.sync.sata += \
+ self.sync += \
If(fsm.ongoing("RESET"),
If(self.speed == 0b100,
align_timeout_cnt.eq(us(873, "SATA3"))
)
self.comb += align_timeout.eq(align_timeout_cnt == 0)
- self.sync.sata += \
+ self.sync += \
If(fsm.ongoing("RESET") | fsm.ongoing("AWAIT_NO_COMINIT"),
If(self.speed == 0b100,
retry_cnt.eq(us(10000, "SATA3"))
retry_cnt.eq(retry_cnt-1)
)
- self.sync.sata += \
+ self.sync += \
If(fsm.ongoing("SEND_ALIGN"),
If(self.rxdata[0:8] == K28_5,
non_align_cnt.eq(non_align_cnt + 1)
txcominit_d = Signal()
txcomwake_d = Signal()
- self.sync.sata += [
+ self.sync += [
txcominit_d.eq(txcominit),
txcomwake_d.eq(txcomwake),
gtx.txcominit.eq(txcominit & ~txcominit_d),
self.comb += align_detect.eq(self.rxdata == ALIGN_VAL);
align_timeout_cnt = Signal(16)
- self.sync.sata += \
+ self.sync += \
If(fsm.ongoing("RESET"),
If(self.speed == 0b100,
align_timeout_cnt.eq(us(55, "SATA3"))
--- /dev/null
+from migen.fhdl.std import *
+from migen.actorlib.fifo import AsyncFIFO
+from migen.actorlib.structuring import Converter
+from migen.flow.actor import Sink, Source
+
+from lib.sata.k7sataphy.std import *
+
+class K7SATAPHYRXAlign(Module):
+ def __init__(self, dw=16):
+ self.rxdata_i = Signal(dw)
+ self.rxcharisk_i = Signal(dw//8)
+
+ self.rxdata_o = Signal(dw)
+ self.rxcharisk_o = Signal(dw//8)
+
+ ###
+
+ rxdata_r = Signal(dw)
+ rxcharisk_r = Signal(dw//8)
+ self.sync.sata_rx += [
+ rxdata_r.eq(self.rxdata_i),
+ rxcharisk_r.eq(self.rxcharisk_i)
+ ]
+ cases = {}
+ cases[1<<0] = [
+ self.rxdata_o.eq(rxdata_r[0:dw]),
+ self.rxcharisk_o.eq(rxcharisk_r[0:dw//8])
+ ]
+ for i in range(1, dw//8):
+ cases[1<<i] = [
+ self.rxdata_o.eq(Cat(self.rxdata_i[8*i:dw], rxdata_r[0:8*i])),
+ self.rxcharisk_o.eq(Cat(self.rxcharisk_i[i:dw//8], rxcharisk_r[0:i]))
+ ]
+ self.comb += Case(rxcharisk_r, cases)
+
+class K7SATAPHYRXConvert(Module):
+ def __init__(self):
+ self.rxdata = Signal(16)
+ self.rxcharisk = Signal(2)
+
+ self.source = Source([("data", 32), ("charisk", 4)])
+ ###
+
+ # convert data widths
+ rx_converter = RenameClockDomains(Converter([("raw", 16+2)], [("raw", 32+4)]), "sata_rx")
+ self.submodules += rx_converter
+ self.comb += [
+ rx_converter.sink.stb.eq(1),
+ rx_converter.sink.raw.eq(Cat(self.rxdata , self.rxcharisk)),
+ rx_converter.source.ack.eq(1)
+ ]
+
+
+ # clock domain crossing
+ # SATA device is supposed to lock its tx frequency to its received rx frequency, so this
+ # ensure that sata_rx and sata_tx clock have the same frequency with only not the same
+ # phase and thus ensute the rx_fifo will never be full.
+ rx_fifo = AsyncFIFO([("raw", 36)], 16)
+ self.submodules.rx_fifo = RenameClockDomains(rx_fifo, {"write": "sata_rx", "read": "sys"})
+ self.comb += [
+ rx_converter.source.connect(self.rx_fifo.sink),
+ self.rx_fifo.source.ack.eq(1),
+ ]
+
+ # rearrange data
+ self.comb += [
+ self.source.stb.eq(self.rx_fifo.source.stb),
+ self.source.payload.data.eq(Cat(rx_fifo.source.raw[0:16], rx_fifo.source.raw[18:18+16])),
+ self.source.payload.charisk.eq(Cat(rx_fifo.source.raw[16:18], rx_fifo.source.raw[18+16:18+18])),
+ self.rx_fifo.source.ack.eq(self.source.ack),
+ ]
+
+class K7SATAPHYTXConvert(Module):
+ def __init__(self):
+ self.sink = Sink([("data", 32), ("charisk", 4)])
+
+ self.txdata = Signal(16)
+ self.txcharisk = Signal(2)
+ ###
+
+ # convert data widths
+ tx_converter = RenameClockDomains(Converter([("raw", 32+4)], [("raw", 16+2)]), "sata_tx")
+ self.submodules += tx_converter
+ self.comb += [
+ Cat(self.txdata, self.txcharisk).eq(tx_converter.source.raw),
+ tx_converter.source.ack.eq(1),
+ ]
+
+ # clock domain crossing
+ tx_fifo = AsyncFIFO([("raw", 36)], 16)
+ self.submodules.tx_fifo = RenameClockDomains(tx_fifo, {"write": "sys", "read": "sata_tx"})
+ self.comb += [
+ tx_fifo.source.connect(tx_converter.sink),
+ self.tx_fifo.sink.stb.eq(1),
+ ]
+
+ # rearrange data
+ self.comb += [
+ self.tx_fifo.sink.stb.eq(self.sink.stb),
+ self.tx_fifo.sink.raw.eq(Cat(self.sink.data[0:16], self.sink.charisk[0:2],
+ self.sink.data[16:32], self.sink.charisk[2:4])),
+ self.sink.ack.eq(self.tx_fifo.sink.ack),
+ ]
**gtxe2_channel_parameters
)
-
-class K7SATAPHYRXAlign(Module):
- def __init__(self, dw=16):
- self.rxdata_i = Signal(dw)
- self.rxcharisk_i = Signal(dw//8)
-
- self.rxdata_o = Signal(dw)
- self.rxcharisk_o = Signal(dw//8)
-
- ###
-
- rxdata_r = Signal(dw)
- rxcharisk_r = Signal(dw//8)
- self.sync.sata_rx += [
- rxdata_r.eq(self.rxdata_i),
- rxcharisk_r.eq(self.rxcharisk_i)
- ]
- cases = {}
- cases[1<<0] = [
- self.rxdata_o.eq(rxdata_r[0:dw]),
- self.rxcharisk_o.eq(rxcharisk_r[0:dw//8])
- ]
- for i in range(1, dw//8):
- cases[1<<i] = [
- self.rxdata_o.eq(Cat(self.rxdata_i[8*i:dw], rxdata_r[0:8*i])),
- self.rxcharisk_o.eq(Cat(self.rxcharisk_i[i:dw//8], rxcharisk_r[0:i]))
- ]
- self.comb += Case(rxcharisk_r, cases)
-
-class K7SATAPHYRXConvert(Module):
- def __init__(self):
- self.rxdata = Signal(16)
- self.rxcharisk = Signal(2)
-
- self.source = Source([("data", 32), ("charisk", 4)])
- ###
-
- # convert data widths
- rx_converter = RenameClockDomains(Converter([("raw", 16+2)], [("raw", 32+4)]), "sata_rx")
- self.submodules += rx_converter
- self.comb += [
- rx_converter.sink.stb.eq(1),
- rx_converter.sink.raw.eq(Cat(self.rxdata , self.rxcharisk)),
- rx_converter.source.ack.eq(1)
- ]
-
-
- # clock domain crossing
- # SATA device is supposed to lock its tx frequency to its received rx frequency, so this
- # ensure that sata_rx and sata_tx clock have the same frequency with only not the same
- # phase and thus ensute the rx_fifo will never be full.
- rx_fifo = AsyncFIFO([("raw", 36)], 16)
- self.submodules.rx_fifo = RenameClockDomains(rx_fifo, {"write": "sata_rx", "read": "sata"})
- self.comb += [
- rx_converter.source.connect(self.rx_fifo.sink),
- self.rx_fifo.source.ack.eq(1),
- ]
-
- # rearrange data
- self.comb += [
- self.source.stb.eq(self.rx_fifo.source.stb),
- self.source.payload.data.eq(Cat(rx_fifo.source.raw[0:16], rx_fifo.source.raw[18:18+16])),
- self.source.payload.charisk.eq(Cat(rx_fifo.source.raw[16:18], rx_fifo.source.raw[18+16:18+18])),
- self.rx_fifo.source.ack.eq(self.source.ack),
- ]
-
-class K7SATAPHYTXConvert(Module):
- def __init__(self):
- self.sink = Sink([("data", 32), ("charisk", 4)])
-
- self.txdata = Signal(16)
- self.txcharisk = Signal(2)
- ###
-
- # convert data widths
- tx_converter = RenameClockDomains(Converter([("raw", 32+4)], [("raw", 16+2)]), "sata_tx")
- self.submodules += tx_converter
- self.comb += [
- Cat(self.txdata, self.txcharisk).eq(tx_converter.source.raw),
- tx_converter.source.ack.eq(1),
- ]
-
- # clock domain crossing
- tx_fifo = AsyncFIFO([("raw", 36)], 16)
- self.submodules.tx_fifo = RenameClockDomains(tx_fifo, {"write": "sata", "read": "sata_tx"})
- self.comb += [
- tx_fifo.source.connect(tx_converter.sink),
- self.tx_fifo.sink.stb.eq(1),
- ]
-
- # rearrange data
- self.comb += [
- self.tx_fifo.sink.stb.eq(self.sink.stb),
- self.tx_fifo.sink.raw.eq(Cat(self.sink.data[0:16], self.sink.charisk[0:2],
- self.sink.data[16:32], self.sink.charisk[2:4])),
- self.sink.ack.eq(self.tx_fifo.sink.ack),
- ]
p_CLKFBOUT_MULT=5, p_DIVCLK_DIVIDE=1,
i_CLKIN1=clk200_se, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb,
- # 125MHz
- p_CLKOUT0_DIVIDE=8, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys,
+ # 166.66MHz
+ p_CLKOUT0_DIVIDE=6, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys,
p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, #o_CLKOUT1=,
default_platform = "kc705"
def __init__(self, platform):
- clk_freq = 125*1000000
+ clk_freq = 166666*1000
UART2WB.__init__(self, platform, clk_freq)
self.submodules.crg = _CRG(platform)