diff --git a/data/rtl-config-vhdl.json b/data/rtl-config-vhdl.json index c3b90adba6..74b6fe10b8 100644 --- a/data/rtl-config-vhdl.json +++ b/data/rtl-config-vhdl.json @@ -451,6 +451,16 @@ "name": "handshake.shrsi", "generator": "python $DYNAMATIC/tools/unit-generators/vhdl/vhdl-unit-generator.py -n $MODULE_NAME -o $OUTPUT_DIR/$MODULE_NAME.vhd -t shrsi -p bitwidth=$BITWIDTH extra_signals=$EXTRA_SIGNALS" }, + { + "name": "handshake.init", + "parameters": [ + { + "name": "INITIAL_VALUE", + "type": "unsigned" + } + ], + "generator": "python $DYNAMATIC/tools/unit-generators/vhdl/vhdl-unit-generator.py -n $MODULE_NAME -o $OUTPUT_DIR/$MODULE_NAME.vhd -t init -p bitwidth=$BITWIDTH extra_signals=$EXTRA_SIGNALS initial_value=$INITIAL_VALUE" + }, { "name": "handshake.shrui", "generator": "python $DYNAMATIC/tools/unit-generators/vhdl/vhdl-unit-generator.py -n $MODULE_NAME -o $OUTPUT_DIR/$MODULE_NAME.vhd -t shrui -p bitwidth=$BITWIDTH extra_signals=$EXTRA_SIGNALS" diff --git a/experimental/lib/Support/FtdImplementation.cpp b/experimental/lib/Support/FtdImplementation.cpp index 9ab2726c26..825151ae25 100644 --- a/experimental/lib/Support/FtdImplementation.cpp +++ b/experimental/lib/Support/FtdImplementation.cpp @@ -750,15 +750,22 @@ void ftd::addRegenOperandConsumer(PatternRewriter &rewriter, cstAttr, startValue); constOp->setAttr(FTD_INIT_MERGE, rewriter.getUnitAttr()); + Operation *initOp; + initOp = rewriter.create(consumerOp->getLoc(), + conditionValue); + + initOp->setAttr(FTD_INIT_MERGE, rewriter.getUnitAttr()); + // Create the `init` operation - SmallVector mergeOperands = {constOp.getResult(), conditionValue}; - auto initMergeOp = rewriter.create(consumerOp->getLoc(), - mergeOperands); - initMergeOp->setAttr(FTD_INIT_MERGE, rewriter.getUnitAttr()); + // SmallVector mergeOperands = {constOp.getResult(), conditionValue}; + // auto initMergeOp = + // rewriter.create(consumerOp->getLoc(), + // mergeOperands); + // initMergeOp->setAttr(FTD_INIT_MERGE, rewriter.getUnitAttr()); // The multiplexer is to be fed by the init block, and takes as inputs the // regenerated value and the result itself (to be set after) it was created. - auto selectSignal = initMergeOp.getResult(); + auto selectSignal = initOp->getResult(0); selectSignal.setType(channelifyType(selectSignal.getType())); SmallVector muxOperands = {regeneratedValue, regeneratedValue}; @@ -1269,28 +1276,31 @@ LogicalResult experimental::ftd::addGsaGates(Region ®ion, // The inputs of the merge are the condition value and a `false` // constant driven by the start value of the function. This will // created later on, so we use a dummy value. - SmallVector mergeOperands; - mergeOperands.push_back(conditionValue); - mergeOperands.push_back(conditionValue); + // SmallVector mergeOperands; + // mergeOperands.push_back(conditionValue); + // mergeOperands.push_back(conditionValue); + + // auto initMergeOp = + // rewriter.create(loc, mergeOperands); - auto initMergeOp = - rewriter.create(loc, mergeOperands); + Operation *initOp; + initOp = rewriter.create(loc, conditionValue); - initMergeOp->setAttr(FTD_INIT_MERGE, rewriter.getUnitAttr()); + initOp->setAttr(FTD_INIT_MERGE, rewriter.getUnitAttr()); // Replace the new condition value - conditionValue = initMergeOp->getResult(0); + conditionValue = initOp->getResult(0); conditionValue.setType(channelifyType(conditionValue.getType())); // Add the activation constant driven by the backedge value, which will // be then updated with the real start value, once available - auto cstType = rewriter.getIntegerType(1); - auto cstAttr = IntegerAttr::get(cstType, 0); - rewriter.setInsertionPointToStart(initMergeOp->getBlock()); - auto constOp = rewriter.create( - initMergeOp->getLoc(), cstAttr, startValue); - constOp->setAttr(FTD_INIT_MERGE, rewriter.getUnitAttr()); - initMergeOp->setOperand(0, constOp.getResult()); + // auto cstType = rewriter.getIntegerType(1); + // auto cstAttr = IntegerAttr::get(cstType, 0); + // rewriter.setInsertionPointToStart(initMergeOp->getBlock()); + // auto constOp = rewriter.create( + // initMergeOp->getLoc(), cstAttr, startValue); + // constOp->setAttr(FTD_INIT_MERGE, rewriter.getUnitAttr()); + // initMergeOp->setOperand(0, constOp.getResult()); } // When a single input gamma is encountered, a mux is inserted as a diff --git a/include/dynamatic/Dialect/Handshake/HandshakeOps.td b/include/dynamatic/Dialect/Handshake/HandshakeOps.td index 8a728fba01..3c086d58dc 100644 --- a/include/dynamatic/Dialect/Handshake/HandshakeOps.td +++ b/include/dynamatic/Dialect/Handshake/HandshakeOps.td @@ -299,10 +299,6 @@ def InitOp : Handshake_Op<"init", [ let arguments = (ins HandshakeType:$operand); let results = (outs HandshakeType:$result); - let extraClassDeclaration = [{ - static constexpr ::llvm::StringLiteral INIT_TOKEN_ATTR_NAME = "INIT_TOKEN", - TIMING_ATTR_NAME = "TIMING"; - }]; let assemblyFormat = [{ $operand attr-dict `:` custom(type($operand)) diff --git a/lib/Conversion/HandshakeToHW/HandshakeToHW.cpp b/lib/Conversion/HandshakeToHW/HandshakeToHW.cpp index 00fb5d03b2..e21e58a261 100644 --- a/lib/Conversion/HandshakeToHW/HandshakeToHW.cpp +++ b/lib/Conversion/HandshakeToHW/HandshakeToHW.cpp @@ -764,6 +764,18 @@ ModuleDiscriminator::ModuleDiscriminator(Operation *op) { addUnsigned("DATA_WIDTH", resType.getElementTypeBitWidth()); addUnsigned("SIZE", resType.getNumElements()); }) + .Case([&](handshake::InitOp initOp) { + auto paramsAttr = + initOp->getAttrOfType("hw.parameters"); + if (paramsAttr) { + auto initTokenAttr = + paramsAttr.get("INIT_TOKEN").dyn_cast_or_null(); + int initialValue = + (initTokenAttr && initTokenAttr.getValue()) ? 1 : 0; + addUnsigned("INITIAL_VALUE", initialValue); + } else + addUnsigned("INITIAL_VALUE", 0); + }) .Default([&](auto) { op->emitError() << "This operation cannot be lowered to RTL " "due to a lack of an RTL implementation for it."; @@ -2142,6 +2154,7 @@ class HandshakeToHWPass ConvertToHWInstance, ConvertToHWInstance, ConvertToHWInstance, + ConvertToHWInstance, ConvertToHWInstance, ConvertToHWInstance, ConvertToHWInstance, diff --git a/lib/Support/RTL/RTL.cpp b/lib/Support/RTL/RTL.cpp index b613155b7d..e2aa47a197 100644 --- a/lib/Support/RTL/RTL.cpp +++ b/lib/Support/RTL/RTL.cpp @@ -336,7 +336,8 @@ LogicalResult RTLMatch::registerBitwidthParameter(hw::HWModuleExternOp &modOp, handshakeOp == "handshake.spec_commit" || handshakeOp == "handshake.spec_save_commit" || handshakeOp == "handshake.sharing_wrapper" || - handshakeOp == "handshake.non_spec" + handshakeOp == "handshake.non_spec" || + handshakeOp == "handshake.init" // clang-format on ) { // Default @@ -491,7 +492,8 @@ RTLMatch::registerExtraSignalParameters(hw::HWModuleExternOp &modOp, handshakeOp == "handshake.load" || handshakeOp == "handshake.store" || handshakeOp == "handshake.spec_commit" || - handshakeOp == "handshake.speculating_branch" + handshakeOp == "handshake.speculating_branch" || + handshakeOp == "handshake.init" // clang-format on ) { diff --git a/tools/unit-generators/vhdl/generators/handshake/init.py b/tools/unit-generators/vhdl/generators/handshake/init.py new file mode 100644 index 0000000000..256c2e988c --- /dev/null +++ b/tools/unit-generators/vhdl/generators/handshake/init.py @@ -0,0 +1,157 @@ +from generators.support.signal_manager import generate_concat_signal_manager +from generators.support.signal_manager.utils.concat import get_concat_extra_signals_bitwidth + + +def generate_init(name, params): + bitwidth = params["bitwidth"] + extra_signals = params.get("extra_signals", None) + # The initial value to use for the buffer + initial_value = params.get("initial_value", 0) + + if extra_signals: + return _generate_init_signal_manager(name, bitwidth, extra_signals, initial_value) + elif bitwidth == 0: + return _generate_init_dataless(name) + else: + return _generate_init(name, bitwidth, initial_value) + + +def _generate_init_dataless(name): + + entity = f""" +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +-- Entity of init_dataless +entity {name} is + port ( + clk, rst : in std_logic; + -- input channel + ins_valid : in std_logic; + ins_ready : out std_logic; + -- output channel + outs_valid : out std_logic; + outs_ready : in std_logic + ); +end entity; +""" + + architecture = f""" +-- Architecture of init_dataless +architecture arch of {name} is + signal fullReg, outputValid : std_logic; +begin + outputValid <= ins_valid or fullReg; + + process (clk) is + begin + if (rising_edge(clk)) then + if (rst = '1') then + fullReg <= '1'; + else + fullReg <= outputValid and not outs_ready; + end if; + end if; + end process; + + ins_ready <= not fullReg; + outs_valid <= outputValid; +end architecture; +""" + + return entity + architecture + + +def _generate_init(name, bitwidth, initial_value): + init_dataless_name = f"{name}_dataless" + + dependencies = _generate_init_dataless( + init_dataless_name) + + dataReg_init = f"'{initial_value}'" + + entity = f""" +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +-- Entity of init +entity {name} is + port ( + clk, rst : in std_logic; + -- input channel + ins : in std_logic_vector({bitwidth} - 1 downto 0); + ins_valid : in std_logic; + ins_ready : out std_logic; + -- output channel + outs : out std_logic_vector({bitwidth} - 1 downto 0); + outs_valid : out std_logic; + outs_ready : in std_logic + ); +end entity; +""" + + architecture = f""" +-- Architecture of init +architecture arch of {name} is + signal regEnable, regNotFull : std_logic; + signal dataReg : std_logic_vector({bitwidth} - 1 downto 0); +begin + regEnable <= regNotFull and ins_valid and not outs_ready; + + control : entity work.{init_dataless_name} + port map( + clk => clk, + rst => rst, + ins_valid => ins_valid, + ins_ready => regNotFull, + outs_valid => outs_valid, + outs_ready => outs_ready + ); + + process (clk) is + begin + if (rising_edge(clk)) then + if (rst = '1') then + dataReg <= (others => {dataReg_init}); + elsif (regEnable) then + dataReg <= ins; + end if; + end if; + end process; + + process (regNotFull, dataReg, ins) is + begin + if (regNotFull) then + outs <= ins; + else + outs <= dataReg; + end if; + end process; + + ins_ready <= regNotFull; + +end architecture; +""" + + return dependencies + entity + architecture + + +def _generate_init_signal_manager(name, bitwidth, extra_signals, initial_value): + extra_signals_bitwidth = get_concat_extra_signals_bitwidth(extra_signals) + return generate_concat_signal_manager( + name, + [{ + "name": "ins", + "bitwidth": bitwidth, + "extra_signals": extra_signals + }], + [{ + "name": "outs", + "bitwidth": bitwidth, + "extra_signals": extra_signals + }], + extra_signals, + lambda name: _generate_init(name, bitwidth + extra_signals_bitwidth, initial_value)) + \ No newline at end of file diff --git a/tools/unit-generators/vhdl/vhdl-unit-generator.py b/tools/unit-generators/vhdl/vhdl-unit-generator.py index 0d1ee570f0..a7ad974e75 100644 --- a/tools/unit-generators/vhdl/vhdl-unit-generator.py +++ b/tools/unit-generators/vhdl/vhdl-unit-generator.py @@ -136,5 +136,6 @@ def main(generators): generators.add("handshake", "remsi") generators.add("handshake", "ram") generators.add("handshake", "sharing_wrapper") + generators.add("handshake", "init") main(generators)