interconnect/stream: add PipeValid and PipeWait to cut timing paths.
This commit is contained in:
parent
b22ad1acfb
commit
f3f9808d1f
|
@ -1,5 +1,5 @@
|
||||||
# This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
|
# This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
|
||||||
# This file is Copyright (c) 2015-2019 Florent Kermarrec <florent@enjoy-digital.fr>
|
# This file is Copyright (c) 2015-2020 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||||
# This file is Copyright (c) 2018 Tim 'mithro' Ansell <me@mith.ro>
|
# This file is Copyright (c) 2018 Tim 'mithro' Ansell <me@mith.ro>
|
||||||
# License: BSD
|
# License: BSD
|
||||||
|
|
||||||
|
@ -607,6 +607,59 @@ class Buffer(PipelinedActor):
|
||||||
self.source.param.eq(self.sink.param)
|
self.source.param.eq(self.sink.param)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Pipe ---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class PipeValid(Module):
|
||||||
|
"""Pipe valid/payload to cut timing path"""
|
||||||
|
def __init__(self, layout):
|
||||||
|
self.sink = sink = Endpoint(layout)
|
||||||
|
self.source = source = Endpoint(layout)
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
# Pipe when source is not valid or is ready.
|
||||||
|
self.sync += [
|
||||||
|
If(~source.valid | source.ready,
|
||||||
|
source.valid.eq(sink.valid),
|
||||||
|
source.first.eq(sink.first),
|
||||||
|
source.last.eq(sink.last),
|
||||||
|
source.payload.eq(sink.payload),
|
||||||
|
source.param.eq(sink.param),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
self.comb += sink.ready.eq(~source.valid | source.ready)
|
||||||
|
|
||||||
|
|
||||||
|
class PipeReady(Module):
|
||||||
|
"""Pipe ready to cut timing path"""
|
||||||
|
def __init__(self, layout):
|
||||||
|
self.sink = sink = Endpoint(layout)
|
||||||
|
self.source = source = Endpoint(layout)
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
valid = Signal()
|
||||||
|
sink_d = Endpoint(layout)
|
||||||
|
|
||||||
|
self.sync += [
|
||||||
|
If(sink.valid & ~source.ready,
|
||||||
|
valid.eq(1)
|
||||||
|
).Elif(source.ready,
|
||||||
|
valid.eq(0)
|
||||||
|
),
|
||||||
|
If(~source.ready & ~valid,
|
||||||
|
sink_d.eq(sink)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
self.comb += [
|
||||||
|
sink.ready.eq(~valid),
|
||||||
|
If(valid,
|
||||||
|
sink_d.connect(source, omit={"ready"})
|
||||||
|
).Else(
|
||||||
|
sink.connect(source, omit={"ready"})
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
# Cast ---------------------------------------------------------------------------------------------
|
# Cast ---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
class Cast(CombinatorialActor):
|
class Cast(CombinatorialActor):
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
# This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||||
|
# License: BSD
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import random
|
||||||
|
|
||||||
|
from migen import *
|
||||||
|
|
||||||
|
from litex.soc.interconnect.stream import *
|
||||||
|
|
||||||
|
|
||||||
|
class TestStream(unittest.TestCase):
|
||||||
|
def pipe_test(self, dut):
|
||||||
|
prng = random.Random(42)
|
||||||
|
def generator(dut, valid_rand=90):
|
||||||
|
for data in range(128):
|
||||||
|
yield dut.sink.valid.eq(1)
|
||||||
|
yield dut.sink.data.eq(data)
|
||||||
|
yield
|
||||||
|
while (yield dut.sink.ready) == 0:
|
||||||
|
yield
|
||||||
|
yield dut.sink.valid.eq(0)
|
||||||
|
while prng.randrange(100) < valid_rand:
|
||||||
|
yield
|
||||||
|
|
||||||
|
def checker(dut, ready_rand=90):
|
||||||
|
dut.errors = 0
|
||||||
|
for data in range(128):
|
||||||
|
yield dut.source.ready.eq(0)
|
||||||
|
yield
|
||||||
|
while (yield dut.source.valid) == 0:
|
||||||
|
yield
|
||||||
|
while prng.randrange(100) < ready_rand:
|
||||||
|
yield
|
||||||
|
yield dut.source.ready.eq(1)
|
||||||
|
yield
|
||||||
|
if ((yield dut.source.data) != data):
|
||||||
|
dut.errors += 1
|
||||||
|
yield
|
||||||
|
run_simulation(dut, [generator(dut), checker(dut)])
|
||||||
|
self.assertEqual(dut.errors, 0)
|
||||||
|
|
||||||
|
def test_pipe_valid(self):
|
||||||
|
dut = PipeValid([("data", 8)])
|
||||||
|
self.pipe_test(dut)
|
||||||
|
|
||||||
|
def test_pipe_ready(self):
|
||||||
|
dut = PipeReady([("data", 8)])
|
||||||
|
self.pipe_test(dut)
|
Loading…
Reference in New Issue