-
Notifications
You must be signed in to change notification settings - Fork 311
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ESI] FIFO with ESI channels (#8004)
Adds an op which provides a FIFO with ESI channels (FIFO signaling semantics only for now) on both ends.
- Loading branch information
Showing
8 changed files
with
286 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// REQUIRES: iverilog,cocotb | ||
|
||
// Test the original HandshakeToHW flow. | ||
|
||
// RUN: circt-opt %s --lower-esi-to-physical --lower-esi-ports --lower-esi-to-hw --lower-seq-fifo --lower-seq-hlmem --lower-seq-to-sv --lower-verif-to-sv --sv-trace-iverilog --prettify-verilog --export-verilog -o %t.hw.mlir > %t.sv | ||
// RUN: circt-cocotb-driver.py --objdir=%T --topLevel=fifo1 --pythonModule=esi_widgets --pythonFolder="%S" %t.sv %esi_prims | ||
|
||
module attributes {circt.loweringOptions = "disallowLocalVariables"} { | ||
hw.module @fifo1(in %clk: !seq.clock, in %rst: i1, in %in: !esi.channel<i32, FIFO>, out out: !esi.channel<i32, FIFO(2)>) { | ||
%fifo = esi.fifo in %in clk %clk rst %rst depth 12 : !esi.channel<i32, FIFO> -> !esi.channel<i32, FIFO(2)> | ||
hw.output %fifo : !esi.channel<i32, FIFO(2)> | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
from typing import List, Optional | ||
import cocotb | ||
from cocotb.clock import Clock | ||
from cocotb.triggers import RisingEdge | ||
|
||
|
||
async def init(dut, timeout: Optional[int] = None): | ||
# Create a 10ns period (100MHz) clock on port clock | ||
clk = Clock(dut.clk, 10, units="ns") | ||
cocotb.start_soon(clk.start()) # Start the clock | ||
|
||
# Reset | ||
dut.rst.value = 1 | ||
for i in range(10): | ||
await RisingEdge(dut.clk) | ||
dut.rst.value = 0 | ||
await RisingEdge(dut.clk) | ||
|
||
if timeout is None: | ||
return | ||
|
||
async def timeout_fn(): | ||
for i in range(timeout): | ||
await RisingEdge(dut.clk) | ||
assert False, "Timeout" | ||
|
||
cocotb.start_soon(timeout_fn()) | ||
|
||
|
||
class ESIInputPort: | ||
|
||
async def write(self, data): | ||
raise RuntimeError("Must be implemented by subclass") | ||
|
||
|
||
class ESIFifoInputPort(ESIInputPort): | ||
|
||
def __init__(self, dut, name): | ||
self.dut = dut | ||
self.name = name | ||
self.data = getattr(dut, name) | ||
self.rden = getattr(dut, f"{name}_rden") | ||
self.empty = getattr(dut, f"{name}_empty") | ||
# Configure initial state | ||
self.empty.value = 1 | ||
|
||
async def write(self, data: int): | ||
self.data.value = data | ||
self.empty.value = 0 | ||
await RisingEdge(self.dut.clk) | ||
while self.rden.value == 0: | ||
await RisingEdge(self.dut.clk) | ||
self.empty.value = 1 | ||
|
||
|
||
class ESIOutputPort: | ||
|
||
async def read(self) -> Optional[int]: | ||
raise RuntimeError("Must be implemented by subclass") | ||
|
||
async def cmd_read(self): | ||
raise RuntimeError("Must be implemented by subclass") | ||
|
||
|
||
class ESIFifoOutputPort(ESIOutputPort): | ||
|
||
def __init__(self, dut, name: str, latency: int = 0): | ||
self.dut = dut | ||
self.name = name | ||
self.data = getattr(dut, name) | ||
self.rden = getattr(dut, f"{name}_rden") | ||
self.empty = getattr(dut, f"{name}_empty") | ||
self.latency = latency | ||
# Configure initial state | ||
self.rden.value = 0 | ||
self.running = 0 | ||
self.q: List[int] = [] | ||
|
||
async def init_read(self): | ||
|
||
async def read_after_latency(): | ||
for i in range(self.latency): | ||
await RisingEdge(self.dut.clk) | ||
self.q.append(self.data.value) | ||
|
||
self.running = 1 | ||
self.empty.value = 0 | ||
while await RisingEdge(self.dut.clk): | ||
if self.rden.value == 1: | ||
cocotb.start_soon(read_after_latency()) | ||
|
||
async def read(self) -> Optional[int]: | ||
if len(self.q) == 0: | ||
await RisingEdge(self.dut.clk) | ||
return self.q.pop(0) | ||
|
||
async def cmd_read(self): | ||
if self.running == 0: | ||
cocotb.start_soon(self.init_read()) | ||
|
||
while self.empty.value == 1: | ||
await RisingEdge(self.dut.clk) | ||
self.rden.value = 1 | ||
await RisingEdge(self.dut.clk) | ||
self.rden.value = 0 | ||
|
||
|
||
@cocotb.test() | ||
async def fillAndDrain(dut): | ||
in_port = ESIFifoInputPort(dut, "in") | ||
out_port = ESIFifoOutputPort(dut, "out", 2) | ||
await init(dut, timeout=10000) | ||
|
||
for i in range(10): | ||
for i in range(12): | ||
await in_port.write(i) | ||
for i in range(12): | ||
await out_port.cmd_read() | ||
for i in range(12): | ||
data = await out_port.read() | ||
# print(f"{i:2}: 0x{int(data):016x}") | ||
assert data == i | ||
|
||
for i in range(4): | ||
await RisingEdge(dut.clk) | ||
|
||
|
||
@cocotb.test() | ||
async def backToBack(dut): | ||
in_port = ESIFifoInputPort(dut, "in") | ||
out_port = ESIFifoOutputPort(dut, "out", 2) | ||
await init(dut) | ||
|
||
NUM_ITERS = 500 | ||
|
||
async def write(): | ||
for i in range(NUM_ITERS): | ||
await in_port.write(i) | ||
|
||
cocotb.start_soon(write()) | ||
|
||
for i in range(NUM_ITERS): | ||
await out_port.cmd_read() | ||
|
||
for i in range(NUM_ITERS): | ||
data = await out_port.read() | ||
# print(f"{i:2}: 0x{int(data):016x}") | ||
assert data == i | ||
|
||
for i in range(4): | ||
await RisingEdge(dut.clk) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters