From b08e3af36a7f67b0dcef2e0473ff373f79ee94b0 Mon Sep 17 00:00:00 2001 From: mikeurbach Date: Mon, 18 Jan 2021 13:41:43 -0700 Subject: [PATCH] [HandshakeToFIRRTL] Implement lowering of StoreOp. (#441) * [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. --- .../HandshakeToFIRRTL/HandshakeToFIRRTL.cpp | 51 +++++++++++++++++++ .../HandshakeToFIRRTL/test_store.mlir | 46 +++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 test/Conversion/HandshakeToFIRRTL/test_store.mlir diff --git a/lib/Conversion/HandshakeToFIRRTL/HandshakeToFIRRTL.cpp b/lib/Conversion/HandshakeToFIRRTL/HandshakeToFIRRTL.cpp index 4ab9809836a4..44a6c5345426 100644 --- a/lib/Conversion/HandshakeToFIRRTL/HandshakeToFIRRTL.cpp +++ b/lib/Conversion/HandshakeToFIRRTL/HandshakeToFIRRTL.cpp @@ -646,6 +646,7 @@ class HandshakeBuilder : public HandshakeVisitor { bool visitHandshake(MergeOp op); bool visitHandshake(MuxOp op); bool visitHandshake(SinkOp op); + bool visitHandshake(handshake::StoreOp op); bool buildJoinLogic(SmallVector inputs, ValueVector *output); @@ -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( + insertLoc, bitType, rewriter.getStringAttr("inputsValid")); + + // Create a gate that will be asserted when all outputs are ready. + auto outputsReady = rewriter.create( + 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(insertLoc, outputAddrData, inputAddrData); + rewriter.create(insertLoc, outputDataData, inputDataData); + + // Output valid signals are connected from the inputsValid wire. + rewriter.create(insertLoc, outputDataValid, inputsValid); + rewriter.create(insertLoc, outputAddrValid, inputsValid); + + return true; +} + //===----------------------------------------------------------------------===// // Old Operation Conversion Functions //===----------------------------------------------------------------------===// diff --git a/test/Conversion/HandshakeToFIRRTL/test_store.mlir b/test/Conversion/HandshakeToFIRRTL/test_store.mlir new file mode 100644 index 000000000000..311d9bb81261 --- /dev/null +++ b/test/Conversion/HandshakeToFIRRTL/test_store.mlir @@ -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 +}