Skip to content

Commit

Permalink
[Pipeline] Add preliminary stall lowering
Browse files Browse the repository at this point in the history
This commit adds preliminary stall lowering.
Given the presence of a stall signal, every stage registers' clock enable value is now &'ed with the (pipeline) global stall signal.
  • Loading branch information
mortbopet committed Jun 26, 2023
1 parent e290fcd commit 08d3e64
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 40 deletions.
38 changes: 38 additions & 0 deletions integration_test/Dialect/Pipeline/stall/stallTest.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// REQUIRES: iverilog,cocotb

// Test 1: default lowering (input muxing)

// RUN: circt-opt %s -pass-pipeline='builtin.module(hw.module(pipeline.scheduled(pipeline-explicit-regs), lower-pipeline-to-hw{outline-stages}), lower-seq-to-sv, sv-trace-iverilog, export-verilog)' \
// RUN: -o %t.mlir > %t.sv

// RUN: circt-cocotb-driver.py --objdir=%T --topLevel=stallTest \
// RUN: --pythonModule=stallTest --pythonFolder="%S,%S/.." %t.sv 2>&1 | FileCheck %s

// Test 2: Clock-gate implementation

// RUN: circt-opt %s -pass-pipeline='builtin.module(hw.module(pipeline.scheduled(pipeline-explicit-regs), lower-pipeline-to-hw{outline-stages clock-gate-regs}), lower-seq-to-sv, sv-trace-iverilog, export-verilog)' \
// RUN: -o %t_clockgated.mlir > %t.sv

// RUN: circt-cocotb-driver.py --objdir=%T --topLevel=stallTest \
// RUN: --pythonModule=stallTest --pythonFolder="%S,%S/.." %t.sv 2>&1 | FileCheck %s


// CHECK: ** TEST
// CHECK: ** TESTS=[[N:.*]] PASS=[[N]] FAIL=0 SKIP=0

hw.module @stallTest(%arg0 : i32, %arg1 : i32, %go : i1, %stall : i1, %clock : i1, %reset : i1) -> (out: i32, done : i1) {
%out, %done = pipeline.scheduled(%arg0, %arg1) stall %stall clock %clock reset %reset go %go : (i32, i32) -> (i32) {
^bb0(%a0 : i32, %a1: i32, %s0_valid : i1):
%add0 = comb.add %a0, %a1 : i32
pipeline.stage ^bb1

^bb1(%s1_valid : i1):
%add1 = comb.add %add0, %a0 : i32
pipeline.stage ^bb2

^bb2(%s2_valid : i1):
%add2 = comb.add %add1, %add0 : i32
pipeline.return %add2 : i32
}
hw.output %out, %done : i32, i1
}
65 changes: 65 additions & 0 deletions integration_test/Dialect/Pipeline/stall/stallTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import cocotb
from cocotb.triggers import Timer
import cocotb.clock


async def clock(dut):
dut.clock.value = 0
await Timer(1, units='ns')
dut.clock.value = 1
await Timer(1, units='ns')


async def initDut(dut):
"""
Initializes a dut by adding a clock, setting initial valid and ready flags,
and performing a reset.
"""
# Reset
dut.reset.value = 1
await clock(dut)
dut.reset.value = 0
await clock(dut)


def ref(v1, v2):
x1 = v1 + v2
x2 = x1 + v1
return x1 + x2


@cocotb.test()
async def test1(dut):
dut.go.value = 0
dut.stall.value = 0
await initDut(dut)

v1 = 42
v2 = 24
resref = ref(v1, v2)

# Get values into the first stage
dut.arg0.value = v1
dut.arg1.value = v2
dut.go.value = 1
await clock(dut)

# Stall for 2 cycles. Done should not be asserted nor the output correct.
dut.go.value = 0
dut.arg0.value = 0
dut.arg1.value = 0
dut.stall.value = 1
for i in range(2):
await clock(dut)
assert dut.done != 1, "DUT should not be done when stalling"

# Unstall and wait for 1 clock cycles - this should propagate the values through
# the remaining stage.
dut.stall.value = 0
await clock(dut)
assert dut.done == 1, "DUT should be done after unstalling"
assert dut.out == resref, f"Expected {resref}, got {dut.out}"

# Clock once more, done should be deasserted.
await clock(dut)
assert dut.done == 0, "DUT should not be done after pipeline has finished"
Loading

0 comments on commit 08d3e64

Please sign in to comment.