Skip to content

Commit

Permalink
[HandshakeToFIRRTL] Implement lowering of StoreOp. (#441)
Browse files Browse the repository at this point in the history
* [HandshakeToFIRRTL] Implement lowering of StoreOp.

The implementation is a simple combinational circuit that waits for
all inputs to be valid and all outputs to be ready. It uses the
buildJoinLogic helper to implement the logic.
  • Loading branch information
mikeurbach committed Jan 18, 2021
1 parent 57a5e72 commit b08e3af
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 0 deletions.
51 changes: 51 additions & 0 deletions lib/Conversion/HandshakeToFIRRTL/HandshakeToFIRRTL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,7 @@ class HandshakeBuilder : public HandshakeVisitor<HandshakeBuilder, bool> {
bool visitHandshake(MergeOp op);
bool visitHandshake(MuxOp op);
bool visitHandshake(SinkOp op);
bool visitHandshake(handshake::StoreOp op);

bool buildJoinLogic(SmallVector<ValueVector *, 4> inputs,
ValueVector *output);
Expand Down Expand Up @@ -1638,6 +1639,56 @@ bool HandshakeBuilder::visitHandshake(MemoryOp op) {
return true;
}

bool HandshakeBuilder::visitHandshake(handshake::StoreOp op) {
// Input data accepted from the predecessor.
ValueVector inputData = portList[0];
Value inputDataData = inputData[2];

// Input address accepted from the predecessor.
ValueVector inputAddr = portList[1];
Value inputAddrData = inputAddr[2];

// Control channel.
ValueVector control = portList[2];

// Data sending to the MemoryOp.
ValueVector outputData = portList[3];
Value outputDataValid = outputData[0];
Value outputDataReady = outputData[1];
Value outputDataData = outputData[2];

// Address sending to the MemoryOp.
ValueVector outputAddr = portList[4];
Value outputAddrValid = outputAddr[0];
Value outputAddrReady = outputAddr[1];
Value outputAddrData = outputAddr[2];

auto bitType = UIntType::get(rewriter.getContext(), 1);

// Create a wire that will be asserted when all inputs are valid.
auto inputsValid = rewriter.create<WireOp>(
insertLoc, bitType, rewriter.getStringAttr("inputsValid"));

// Create a gate that will be asserted when all outputs are ready.
auto outputsReady = rewriter.create<AndPrimOp>(
insertLoc, bitType, outputDataReady, outputAddrReady);

// Build the standard join logic from the inputs to the inputsValid and
// outputsReady signals.
ValueVector joinLogicOutput({inputsValid, outputsReady});
buildJoinLogic({&inputData, &inputAddr, &control}, &joinLogicOutput);

// Output address and data signals are connected directly.
rewriter.create<ConnectOp>(insertLoc, outputAddrData, inputAddrData);
rewriter.create<ConnectOp>(insertLoc, outputDataData, inputDataData);

// Output valid signals are connected from the inputsValid wire.
rewriter.create<ConnectOp>(insertLoc, outputDataValid, inputsValid);
rewriter.create<ConnectOp>(insertLoc, outputAddrValid, inputsValid);

return true;
}

//===----------------------------------------------------------------------===//
// Old Operation Conversion Functions
//===----------------------------------------------------------------------===//
Expand Down
46 changes: 46 additions & 0 deletions test/Conversion/HandshakeToFIRRTL/test_store.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// RUN: circt-opt -lower-handshake-to-firrtl -split-input-file %s | FileCheck %s

// CHECK-LABEL: firrtl.module @handshake_store_3ins_2outs
// CHECK: %[[IN_DATA_VALID:.+]] = firrtl.subfield %arg0("valid")
// CHECK: %[[IN_DATA_READY:.+]] = firrtl.subfield %arg0("ready")
// CHECK: %[[IN_DATA_DATA:.+]] = firrtl.subfield %arg0("data")
// CHECK: %[[IN_ADDR_VALID:.+]] = firrtl.subfield %arg1("valid")
// CHECK: %[[IN_ADDR_READY:.+]] = firrtl.subfield %arg1("ready")
// CHECK: %[[IN_ADDR_DATA:.+]] = firrtl.subfield %arg1("data")
// CHECK: %[[IN_CONTROL_VALID:.+]] = firrtl.subfield %arg2("valid")
// CHECK: %[[IN_CONTROL_READY:.+]] = firrtl.subfield %arg2("ready")
// CHECK: %[[OUT_DATA_VALID:.+]] = firrtl.subfield %arg3("valid")
// CHECK: %[[OUT_DATA_READY:.+]] = firrtl.subfield %arg3("ready")
// CHECK: %[[OUT_DATA_DATA:.+]] = firrtl.subfield %arg3("data")
// CHECK: %[[OUT_ADDR_VALID:.+]] = firrtl.subfield %arg4("valid")
// CHECK: %[[OUT_ADDR_READY:.+]] = firrtl.subfield %arg4("ready")
// CHECK: %[[OUT_ADDR_DATA:.+]] = firrtl.subfield %arg4("data")

// CHECK: %[[ALL_VALID_WIRE:inputsValid]] = firrtl.wire : !firrtl.uint<1>

// CHECK: %[[ALL_READY:.+]] = firrtl.and %[[OUT_DATA_READY]], %[[OUT_ADDR_READY]]

// CHECK: %[[ALL_VALID0:.+]] = firrtl.and %[[IN_ADDR_VALID]], %[[IN_DATA_VALID]]
// CHECK: %[[ALL_VALID:.+]] = firrtl.and %[[IN_CONTROL_VALID]], %[[ALL_VALID0]]

// CHECK: firrtl.connect %[[ALL_VALID_WIRE]], %[[ALL_VALID]]

// CHECK: %[[ALL_DONE:.+]] = firrtl.and %[[ALL_READY]], %[[ALL_VALID]]

// CHECK: firrtl.connect %[[IN_DATA_READY]], %[[ALL_DONE]]
// CHECK: firrtl.connect %[[IN_ADDR_READY]], %[[ALL_DONE]]
// CHECK: firrtl.connect %[[IN_CONTROL_READY]], %[[ALL_DONE]]

// CHECK: firrtl.connect %[[OUT_ADDR_DATA]], %[[IN_ADDR_DATA]]
// CHECK: firrtl.connect %[[OUT_DATA_DATA]], %[[IN_DATA_DATA]]

// CHECK: firrtl.connect %[[OUT_DATA_VALID]], %[[ALL_VALID_WIRE]]
// CHECK: firrtl.connect %[[OUT_ADDR_VALID]], %[[ALL_VALID_WIRE]]

// CHECK-LABEL: firrtl.module @main
handshake.func @main(%arg0: i8, %arg1: index, %arg2: none, ...) -> (i8, index, none) {
// CHECK: {{.+}} = firrtl.instance @handshake_store_3ins_2outs
%0:2 = "handshake.store"(%arg0, %arg1, %arg2) : (i8, index, none) -> (i8, index)

handshake.return %0#0, %0#1, %arg2 : i8, index, none
}

0 comments on commit b08e3af

Please sign in to comment.