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: a2065818a5ab
Choose a base ref
...
head repository: whitequark/Yumewatari
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: c2ab023b9e17
Choose a head ref
  • 1 commit
  • 3 files changed
  • 1 contributor

Commits on Nov 12, 2018

  1. Copy the full SHA
    c2ab023 View commit details
Showing with 136 additions and 52 deletions.
  1. +65 −18 yumewatari/gateware/parser.py
  2. +32 −21 yumewatari/gateware/phy.py
  3. +39 −13 yumewatari/test/phy.py
83 changes: 65 additions & 18 deletions yumewatari/gateware/parser.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from collections import defaultdict, namedtuple
from migen import *
from migen.fhdl.structure import _Value, _Statement
@@ -7,6 +8,9 @@
__all__ = ["Parser", "Memory", "NextMemory"]


_DEBUG = os.getenv("DEBUG_PARSER")


class Memory(_Value):
def __init__(self, target):
self.target = target
@@ -30,7 +34,7 @@ def _get_memory_control(self, memory):
break
else:
next_value_ce = Signal(related=memory)
next_value = Signal.like(memory)
next_value = Signal(memory.nbits, related=memory)
self.memories.append((memory, next_value_ce, next_value))
return next_value_ce, next_value

@@ -55,38 +59,81 @@ def _finalize_sync(self, ls):
self.sync += If(next_value_ce, memory.eq(next_value))


_Rule = namedtuple("_Rule", ("cond", "succ", "action"))
_Rule = namedtuple("_Rule", ("name", "cond", "succ", "action"))


class Parser(Module):
def __init__(self, symbol_width, reset_rule):
def __init__(self, symbol_size, word_size, reset_rule):
self.reset = Signal()
self.error = Signal()
self.i = Signal(symbol_width)
self.i = Signal(symbol_size * word_size)

###

self._reset_rule = reset_rule
self._symbol_size = symbol_size
self._word_size = word_size
self._reset_rule = reset_rule
# name -> [(cond, succ, action)]
self._grammar = defaultdict(lambda: [])

def rule(self, name, cond, succ, action=lambda symbol: []):
self._grammar[name].append(_Rule(cond, succ, action))
self._grammar[name].append(_Rule(name, cond, succ, action))

def _get_rule_tuples(self, rule_name, rule_tuples, rule_path=()):
if len(rule_path) == self._word_size:
rule_tuples.add(rule_path)
return

for rule in self._grammar[rule_name]:
self._get_rule_tuples(rule.succ, rule_tuples, rule_path + (rule,))

def do_finalize(self):
self.submodules.fsm = ResetInserter()(_ParserFSM(reset_state=self._reset_rule))
self.submodules.fsm = ResetInserter()(_ParserFSM())
self.comb += self.fsm.reset.eq(self.reset | self.error)

for (name, rules) in self._grammar.items():
conds = Cat(rule.cond(self.i) for rule in rules)
self.fsm.act(name, [
self.error.eq(1),
Case(conds, {
(1 << n): [
NextState(rule.succ),
*rule.action(self.i),
self.error.eq(0),
if _DEBUG:
print("Parser layout:")
worklist = {self._reset_rule}
processed = set()
while worklist:
rule_name = worklist.pop()
processed.add(rule_name)

if _DEBUG:
print(" State %s" % rule_name)

rule_tuples = set()
self._get_rule_tuples(rule_name, rule_tuples)

conds = []
actions = []
for i, rule_tuple in enumerate(rule_tuples):
if _DEBUG:
print(" Input #%d %s -> %s" %
(i, rule_name, " -> ".join(rule.succ for rule in rule_tuple)))

succ = rule_tuple[-1].succ
cond = 1
action = [
self.error.eq(0),
NextState(succ)
]
for j, rule in enumerate(reversed(rule_tuple)):
symbol = self.i.part((self._word_size - j - 1) * self._symbol_size,
self._symbol_size)
action = [
If(rule.cond(symbol),
rule.action(symbol),
*action
),
]
for n, rule in enumerate(rules)
})

conds.append(cond)
actions.append(action)
if succ not in processed:
worklist.add(succ)

self.fsm.act(rule_name, [
self.error.eq(1),
*actions
])
53 changes: 32 additions & 21 deletions yumewatari/gateware/phy.py
Original file line number Diff line number Diff line change
@@ -52,17 +52,12 @@ def __init__(self, lane):
ts_id = Signal(9)
ts_inv = Signal()

self.submodules.parser = Parser(symbol_width=9, reset_rule="COMMA")
self.submodules.parser = Parser(symbol_size=9, word_size=lane.ratio, reset_rule="COMMA")
self.comb += [
self.parser.reset.eq(~lane.rx_valid),
self.parser.i.eq(lane.rx_symbol),
self.error.eq(self.parser.error)
]
self.parser.rule(
name="COMMA",
cond=lambda symbol: symbol == D(0,0),
succ="COMMA"
)
self.parser.rule(
name="COMMA",
cond=lambda symbol: symbol == K(28,5),
@@ -143,24 +138,40 @@ def __init__(self, lane):
)
self.parser.rule(
name="TSn-ID0",
cond=lambda symbol: (symbol == D(10,2)) |
(symbol == D( 5,2)) |
(symbol == D(21,5)) |
(symbol == D(26,5)),
cond=lambda symbol: symbol == D(10,2),
succ="TSn-ID1",
action=lambda symbol: [
NextMemory(ts_id, symbol),
NextValue(ts_inv, 0),
NextValue(self._tsZ.ts_id, 0),
]
)
self.parser.rule(
name="TSn-ID0",
cond=lambda symbol: symbol == D(5,2),
succ="TSn-ID1",
action=lambda symbol: [
NextMemory(ts_id, symbol),
NextValue(ts_inv, 0),
NextValue(self._tsZ.ts_id, 1),
]
)
self.parser.rule(
name="TSn-ID0",
cond=lambda symbol: symbol == D(21,5),
succ="TSn-ID1",
action=lambda symbol: [
NextMemory(ts_id, symbol),
NextValue(ts_inv, 1),
]
)
self.parser.rule(
name="TSn-ID0",
cond=lambda symbol: symbol == D(26,5),
succ="TSn-ID1",
action=lambda symbol: [
NextMemory(ts_id, symbol),
If(symbol == D(10,2),
NextValue(ts_inv, 0),
NextValue(self._tsZ.ts_id, 0),
).Elif(symbol == D(5,2),
NextValue(ts_inv, 0),
NextValue(self._tsZ.ts_id, 1),
).Elif(symbol == D(21,5),
NextValue(ts_inv, 1),
).Elif(symbol == D(26,5),
NextValue(ts_inv, 1),
)
NextValue(ts_inv, 1),
]
)
for n in range(1, 9):
52 changes: 39 additions & 13 deletions yumewatari/test/phy.py
Original file line number Diff line number Diff line change
@@ -6,9 +6,17 @@
from . import simulation_test


class _PHYTestCase(unittest.TestCase):
def assertState(self, tb, state):
self.assertEqual((yield from tb.phy_state()), state)

def assertSignal(self, signal, value):
self.assertEqual((yield signal), value)


class PCIeRXPHYTestbench(Module):
def __init__(self):
self.submodules.lane = PCIeSERDESInterface()
def __init__(self, ratio=1):
self.submodules.lane = PCIeSERDESInterface(ratio)
self.submodules.phy = PCIeRXPHY(self.lane)

def do_finalize(self):
@@ -18,25 +26,24 @@ def phy_state(self):
return self.states[(yield self.phy.parser.fsm.state)]

def transmit(self, symbols):
for symbol in symbols:
assert (yield self.phy.error) == 0
yield self.lane.rx_symbol.eq(symbol)
for i, word in enumerate(symbols):
if i > 0:
assert (yield self.phy.error) == 0
if isinstance(word, tuple):
for j, symbol in enumerate(word):
yield self.lane.rx_symbol.part(j * 9, 9).eq(symbol)
else:
yield self.lane.rx_symbol.eq(word)
yield


class PCIeRXPHYTestCase(unittest.TestCase):
class PCIeRXPHYTestCase(_PHYTestCase):
def setUp(self):
self.tb = PCIeRXPHYTestbench()

def simulationSetUp(self, tb):
yield tb.lane.rx_valid.eq(1)

def assertState(self, tb, state):
self.assertEqual((yield from tb.phy_state()), state)

def assertSignal(self, signal, value):
self.assertEqual((yield signal), value)

@simulation_test
def test_rx_tsn_cycle_by_cycle(self, tb):
yield tb.lane.rx_symbol.eq(K(28,5))
@@ -292,6 +299,25 @@ def test_rx_ts1_skp_ts1_valid(self, tb):
yield from self.assertSignal(tb.phy.ts.valid, 1)


class PCIeRXPHYGear2xTestCase(_PHYTestCase):
def setUp(self):
self.tb = PCIeRXPHYTestbench(ratio=2)

def simulationSetUp(self, tb):
yield tb.lane.rx_valid.eq(1)

@simulation_test
def test_rx_ts1_2x_same_valid(self, tb):
yield from self.tb.transmit([
(K(28,5), 0xaa), (0x1a, 0xff), (0b0010, 0b0000),
*[(D(10,2), D(10,2)) for _ in range(5)],
(K(28,5), 0xaa), (0x1a, 0xff), (0b0010, 0b0000),
*[(D(10,2), D(10,2)) for _ in range(5)],
(K(28,5), K(28,0)),
])
yield from self.assertSignal(tb.phy.ts.valid, 1)


class PCIeTXPHYTestbench(Module):
def __init__(self):
self.submodules.lane = PCIeSERDESInterface()
@@ -311,7 +337,7 @@ def receive(self, count):
return symbols


class PCIeTXPHYTestCase(unittest.TestCase):
class PCIeTXPHYTestCase(_PHYTestCase):
def setUp(self):
self.tb = PCIeTXPHYTestbench()