diff --git a/data/rtl-config-vhdl.json b/data/rtl-config-vhdl.json index 3d278943c..69d5fca62 100644 --- a/data/rtl-config-vhdl.json +++ b/data/rtl-config-vhdl.json @@ -458,6 +458,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/include/dynamatic/Dialect/Handshake/HandshakeOps.td b/include/dynamatic/Dialect/Handshake/HandshakeOps.td index e36441571..564b4b40c 100644 --- a/include/dynamatic/Dialect/Handshake/HandshakeOps.td +++ b/include/dynamatic/Dialect/Handshake/HandshakeOps.td @@ -367,10 +367,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 7d51f52ba..036a37a18 100644 --- a/lib/Conversion/HandshakeToHW/HandshakeToHW.cpp +++ b/lib/Conversion/HandshakeToHW/HandshakeToHW.cpp @@ -763,6 +763,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."; @@ -2176,6 +2188,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 47a4ae33b..7b8d80d21 100644 --- a/lib/Support/RTL/RTL.cpp +++ b/lib/Support/RTL/RTL.cpp @@ -337,7 +337,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 @@ -493,7 +494,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 000000000..256c2e988 --- /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 0d1ee570f..a7ad974e7 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)