Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: whitequark/Yumewatari
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 7b317ba8348c
Choose a base ref
...
head repository: whitequark/Yumewatari
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 49521769e654
Choose a head ref
  • 2 commits
  • 11 files changed
  • 1 contributor

Commits on Nov 23, 2018

  1. Copy the full SHA
    ee6c432 View commit details
  2. gateware.phy: implement most Detect, Polling and Configuration states.

    This doesn't implement Polling.Compliance, only implements upstream
    ports, doesn't yet handle every Gen2 feature, doesn't implement
    Configuration.Idle (because we cannot receive Idle data yet),
    and probably contains many bugs.
    
    But hey! LinkUp=1!!!
    whitequark committed Nov 23, 2018
    Copy the full SHA
    4952176 View commit details
58 changes: 58 additions & 0 deletions yumewatari/gateware/debug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from migen import *


__all__ = ["RingLog"]


class RingLog(Module):
def __init__(self, timestamp_width, data_width, depth):
self.width = timestamp_width + data_width
self.depth = depth

self.data_i = Signal(data_width)
self.trigger = Signal()

self.time_o = Signal(timestamp_width)
self.data_o = Signal(data_width)
self.next = Signal()

###

timestamp = Signal(timestamp_width)
self.sync += timestamp.eq(timestamp + 1)

data_i_l = Signal.like(self.data_i)
self.sync += data_i_l.eq(self.data_i)

storage = Memory(width=self.width, depth=self.depth)
self.specials += storage

wrport = storage.get_port(write_capable=True)
self.specials += wrport
self.comb += [
wrport.we.eq(~self.trigger & (self.data_i != data_i_l)),
wrport.dat_w.eq(Cat(timestamp, self.data_i))
]
self.sync += [
If(~self.trigger,
If(self.data_i != data_i_l,
wrport.adr.eq(wrport.adr + 1)
)
)
]

trigger_s = Signal.like(self.trigger)
self.sync += trigger_s.eq(self.trigger)

rdport = storage.get_port()
self.specials += rdport
self.comb += [
Cat(self.time_o, self.data_o).eq(rdport.dat_r),
]
self.sync += [
If(~self.trigger,
rdport.adr.eq(wrport.adr + 1)
).Elif(self.next,
rdport.adr.eq(rdport.adr + 1)
)
]
253 changes: 212 additions & 41 deletions yumewatari/gateware/phy.py
Original file line number Diff line number Diff line change
@@ -4,84 +4,255 @@
from .protocol import *
from .phy_rx import *
from .phy_tx import *
from .debug import RingLog


__all__ = ["PCIePHY"]


class PCIePHY(Module):
def __init__(self, lane):
def __init__(self, lane, ms_cyc):
self.submodules.rx = rx = PCIePHYRX(lane)
self.submodules.tx = tx = PCIePHYTX(lane)

self.link_up = Signal()

self.submodules.ltssm_log = RingLog(timestamp_width=32, data_width=8, depth=16)

###

self.comb += [
tx.ts.n_fts.eq(0xff),
tx.ts.rate.gen1.eq(1),
]

rx_ts_count = Signal(max=8)
rx_timer = Signal(max=64 * ms_cyc + 1)
rx_ts_count = Signal(max=16 + 1)
tx_ts_count = Signal(max=1024 + 1)

# LTSSM implemented according to PCIe Base Specification Revision 2.1.
# The Specification must be read side to side with this code in order to understand it.
# Unfortunately, the Specification is copyrighted and probably cannot be quoted here
# directly at length.
self.submodules.ltssm = ltssm = ResetInserter()(FSM())
self.comb += self.ltssm.reset.eq(self.rx.error)
self.ltssm.act("Reset",
NextValue(rx_ts_count, 7),
# Send TS1 Link=PAD Lane=PAD
self.ltssm.act("Detect.Quiet",
NextValue(tx.e_idle, 1),
NextValue(self.link_up, 0),
NextValue(rx_timer, 12 * ms_cyc),
NextState("Detect.Quiet:Timeout")
)
self.ltssm.act("Detect.Quiet:Timeout",
NextValue(rx_timer, rx_timer - 1),
If(lane.rx_present | (rx_timer == 0),
NextValue(lane.det_enable, 1),
NextState("Detect.Active")
)
)
self.ltssm.act("Detect.Active",
If(lane.det_valid,
NextValue(lane.det_enable, 0),
If(lane.det_status,
NextState("Polling.Active")
).Else(
NextState("Detect.Quiet")
)
)
)
self.ltssm.act("Polling.Active",
NextValue(tx.e_idle, 0),
# Transmit TS1 Link=PAD Lane=PAD
NextValue(tx.ts.valid, 1),
NextValue(tx.ts.ts_id, 0),
NextValue(tx.ts.link.valid, 0),
NextValue(tx.ts.lane.valid, 0),
NextState("Polling.Active")
NextValue(rx_timer, 24 * ms_cyc),
NextValue(rx_ts_count, 0),
NextValue(tx_ts_count, 0),
NextState("Polling.Active:TS")
)
self.ltssm.act("Polling.Active",
# Expect TS1 Link=PAD Lane=PAD
If(rx.ts.valid & (rx.ts.ts_id == 0) & ~rx.ts.link.valid & ~rx.ts.lane.valid,
NextValue(rx_ts_count, rx_ts_count - 1),
If(rx_ts_count == 0,
NextValue(rx_ts_count, 7),
# Send TS2 Link=PAD Lane=PAD
NextValue(tx.ts.ts_id, 1),
NextState("Polling.Configuration")
self.ltssm.act("Polling.Active:TS",
If(tx.comma,
If(tx_ts_count != 1024,
NextValue(tx_ts_count, tx_ts_count + 1)
)
),
If((tx_ts_count == 1024),
If(rx.comma,
# Accept TS1 Link=PAD Lane=PAD Compliance=0
# Accept TS1 Link=PAD Lane=PAD Loopback=1
# Accept TS2 Link=PAD Lane=PAD
If(rx.ts.valid & ~rx.ts.lane.valid & ~rx.ts.link.valid &
(((rx.ts.ts_id == 0) & ~rx.ts.ctrl.compliance) |
((rx.ts.ts_id == 0) & rx.ts.ctrl.loopback) |
(rx.ts.ts_id == 1)),
NextValue(rx_ts_count, rx_ts_count + 1),
If(rx_ts_count == 8,
NextState("Polling.Configuration")
)
).Else(
NextValue(rx_ts_count, 0)
)
)
),
NextValue(rx_timer, rx_timer - 1),
If(rx_timer == 0,
NextState("Detect.Quiet")
)
)
self.ltssm.act("Polling.Configuration",
# Expect TS2 Link=PAD Lane=PAD
If(rx.ts.valid & (rx.ts.ts_id == 1) & ~rx.ts.link.valid & ~rx.ts.lane.valid,
NextValue(rx_ts_count, rx_ts_count - 1),
# Transmit TS2 Link=PAD Lane=PAD
NextValue(tx.ts.valid, 1),
NextValue(tx.ts.ts_id, 1),
NextValue(tx.ts.link.valid, 0),
NextValue(tx.ts.lane.valid, 0),
NextValue(rx_ts_count, 0),
NextValue(tx_ts_count, 0),
NextValue(rx_timer, 48 * ms_cyc),
NextState("Polling.Configuration:TS")
)
self.ltssm.act("Polling.Configuration:TS",
If(tx.comma,
If(rx_ts_count == 0,
NextValue(rx_ts_count, 7),
# Send TS1 Link=PAD Lane=PAD
NextValue(tx.ts.ts_id, 0),
NextState("Configuration.Linkwidth.Start")
NextValue(tx_ts_count, 0)
).Else(
NextValue(tx_ts_count, tx_ts_count + 1)
)
),
If(rx.comma,
# Accept TS2 Link=PAD Lane=PAD
If(rx.ts.valid & (rx.ts.ts_id == 1) & ~rx.ts.link.valid & ~rx.ts.lane.valid,
If(rx_ts_count == 8,
If(tx_ts_count == 16,
NextValue(rx_timer, 24 * ms_cyc),
NextState("Configuration.Linkwidth.Start")
)
).Else(
NextValue(rx_ts_count, rx_ts_count + 1)
)
).Else(
NextValue(rx_ts_count, 0)
),
),
NextValue(rx_timer, rx_timer - 1),
If(rx_timer == 0,
NextState("Detect.Quiet")
)
)
self.ltssm.act("Configuration.Linkwidth.Start",
# Expect TS1 Link<>PAD Lane=PAD
# Transmit TS1 Link=PAD Lane=PAD
NextValue(tx.ts.valid, 1),
NextValue(tx.ts.ts_id, 0),
NextValue(tx.ts.link.valid, 0),
NextValue(tx.ts.lane.valid, 0),
# Accept TS1 Link=Upstream-Link Lane=PAD
If(rx.ts.valid & (rx.ts.ts_id == 0) & rx.ts.link.valid & ~rx.ts.lane.valid,
NextValue(rx_ts_count, rx_ts_count - 1),
If(rx_ts_count == 0,
NextValue(rx_ts_count, 7),
# Send TS1 Link=Upstream-Link Lane=PAD
NextValue(tx.ts.link.raw_bits(), rx.ts.link.raw_bits()),
NextState("Configuration.Linkwidth.Accept")
)
# Transmit TS1 Link=Upstream-Link Lane=PAD
NextValue(tx.ts.link.valid, 1),
NextValue(tx.ts.link.number, rx.ts.link.number),
NextValue(rx_timer, 2 * ms_cyc),
NextState("Configuration.Linkwidth.Accept")
),
NextValue(rx_timer, rx_timer - 1),
If(rx_timer == 0,
NextState("Detect.Quiet")
)
)
self.ltssm.act("Configuration.Linkwidth.Accept",
# Expect TS1 Link<>PAD Lane=PAD
If(rx.ts.valid & (rx.ts.ts_id == 0) & rx.ts.link.valid &
(rx.ts.link.number == tx.ts.link.number) & ~rx.ts.lane.valid,
NextValue(rx_ts_count, rx_ts_count - 1),
If(rx_ts_count == 0,
NextValue(rx_ts_count, 7),
# Send TS1 Link=Upstream-Link Lane=Upstream-Lane
NextValue(tx.ts.lane.raw_bits(), rx.ts.lane.raw_bits()),
# Accept TS1 Link=Upstream-Link Lane=Upstream-Lane
If(rx.ts.valid & (rx.ts.ts_id == 0) & rx.ts.link.valid & rx.ts.lane.valid,
# Accept Upstream-Lane=0
If(rx.ts.lane.number == 0,
# Transmit TS1 Link=Upstream-Link Lane=Upstream-Lane
NextValue(tx.ts.lane.valid, 1),
NextValue(tx.ts.lane.number, rx.ts.lane.number),
NextValue(rx_timer, 2 * ms_cyc),
NextState("Configuration.Lanenum.Wait")
)
),
# Accept TS1 Link=PAD Lane=PAD
If(rx.ts.valid & (rx.ts.ts_id == 0) & ~rx.ts.link.valid & ~rx.ts.lane.valid,
NextState("Detect.Quiet")
),
NextValue(rx_timer, rx_timer - 1),
If(rx_timer == 0,
NextState("Detect.Quiet")
)
)
self.ltssm.act("Configuration.Lanenum.Wait",
NextState("Configuration.Lanenum.Wait")
# Accept TS1 Link=Upstream-Link Lane=Upstream-Lane
If(rx.ts.valid & (rx.ts.ts_id == 0) & rx.ts.link.valid & rx.ts.lane.valid,
If(rx.ts.lane.number != tx.ts.lane.number,
NextState("Configuration.Lanenum.Accept")
)
),
# Accept TS2
If(rx.ts.valid & (rx.ts.ts_id == 1),
NextState("Configuration.Lanenum.Accept")
),
# Accept TS1 Link=PAD Lane=PAD
If(rx.ts.valid & (rx.ts.ts_id == 0) & ~rx.ts.link.valid & ~rx.ts.lane.valid,
NextState("Detect.Quiet")
),
NextValue(rx_timer, rx_timer - 1),
If(rx_timer == 0,
NextState("Detect.Quiet")
)
)
self.ltssm.act("Configuration.Lanenum.Accept",
# Accept TS2 Link=Upstream-Link Lane=Upstream-Lane
If(rx.ts.valid & (rx.ts.ts_id == 1) & rx.ts.link.valid & rx.ts.lane.valid,
If((rx.ts.link.number == tx.ts.link.number) &
(rx.ts.lane.number == tx.ts.lane.number),
NextState("Configuration.Complete")
).Else(
NextState("Detect.Quiet")
)
),
# Accept TS1 Link=PAD Lane=PAD
If(rx.ts.valid & (rx.ts.ts_id == 0) & ~rx.ts.link.valid & ~rx.ts.lane.valid,
NextState("Detect.Quiet")
),
)
self.ltssm.act("Configuration.Complete",
# Transmit TS2 Link=Upstream-Link Lane=Upstream-Lane
NextValue(tx.ts.ts_id, 1),
NextValue(tx.ts.n_fts, 0xff),
NextValue(rx_ts_count, 0),
NextValue(tx_ts_count, 0),
NextValue(rx_timer, 2 * ms_cyc),
NextState("Configuration.Complete:TS")
)
self.ltssm.act("Configuration.Complete:TS",
If(tx.comma,
If(rx_ts_count == 0,
NextValue(tx_ts_count, 0)
).Else(
NextValue(tx_ts_count, tx_ts_count + 1)
)
),
If(rx.comma,
# Accept TS2 Link=Upstream-Link Lane=Upstream-Lane
If(rx.ts.valid & (rx.ts.ts_id == 1) & rx.ts.link.valid & rx.ts.lane.valid &
(rx.ts.link.number == tx.ts.link.number) &
(rx.ts.lane.number == tx.ts.lane.number),
If(rx_ts_count == 8,
If(tx_ts_count == 16,
NextState("Configuration.Idle")
)
).Else(
NextValue(rx_ts_count, rx_ts_count + 1)
)
).Else(
NextValue(rx_ts_count, 0)
),
),
NextValue(rx_timer, rx_timer - 1),
If(rx_timer == 0,
NextState("Detect.Quiet")
)
)
self.ltssm.act("Configuration.Idle",
NextValue(self.link_up, 1)
)

def do_finalize(self):
self.comb += self.ltssm_log.data_i.eq(self.ltssm.state)
6 changes: 3 additions & 3 deletions yumewatari/gateware/phy_rx.py
Original file line number Diff line number Diff line change
@@ -10,9 +10,9 @@

class PCIePHYRX(Module):
def __init__(self, lane):
self.ts = Record(ts_layout)
self.comma = Signal()
self.error = Signal()
self.error = Signal()
self.comma = Signal()
self.ts = Record(ts_layout)

###

14 changes: 12 additions & 2 deletions yumewatari/gateware/phy_tx.py
Original file line number Diff line number Diff line change
@@ -10,8 +10,9 @@

class PCIePHYTX(Module):
def __init__(self, lane):
self.ts = Record(ts_layout)
self.comma = Signal()
self.e_idle = Signal()
self.comma = Signal()
self.ts = Record(ts_layout)

###

@@ -37,6 +38,15 @@ def __init__(self, lane):
]
self.emitter.rule(
name="IDLE",
cond=lambda: self.e_idle,
succ="IDLE",
action=lambda symbol: [
symbol.e_idle.eq(1)
]
)
self.emitter.rule(
name="IDLE",
cond=lambda: self.ts.valid,
succ="TSn-LINK",
action=lambda symbol: [
self.comma.eq(1),
Loading