From ddcd1d3fcb2c33e272580ad3abebcf3daa73aab1 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Fri, 10 Jul 2026 16:20:52 -0700 Subject: [PATCH] Port splitting part 2: Support methods with multiple output ports This is a squash merge of GitHub PR 849. Introduce ATuple and ATupleSel into ASyntax. The ActionValue_ constructor now takes a star type, rather than numeric type, so that it can either be a "Bit n" or a tuple of bit types. In the printing of ASyntax, method types now have a List of return types rather than a Maybe of a single type. Method outputs are resolved in AConv now, instead of earlier in the evaluator. Therefore some signal names now have `__d` suffix rather than `__h` suffix. Verilog: Wires connected to submodule results ports have the form $_RES_, except for backwards compatibility, when there is only one result port, it retains the form $. Input ports are $_. Bluesim: Tuples (split ports) are not yet visible; the Bluesim backend converts them to wide bit vectors. Bluetcl: The "module ports" and "submodule full" output syntax has changed. A results field is always included, which may be empty if there is no result; otherwise it includes a lists of ports, with their name and bit width. Documentation is updated. Introduce and use type functions for TupleSize and AppendTuple. Introduce and use type functions PortsOf, ShallowPortsOf, DeepPortsOf. Add path analysis tests for split method inputs/outputs. Cover per-port combinational paths through split method results: value methods, submodule split outputs, ActionValue split results, and loop detection through a split output port. Adds tests for port splitting, including path analysis and bluetcl port reporting. Add 49 bsc.scheduler/paths tests for combinational path analysis through split method inputs/outputs (the per-port tracking from port splitting): - deep/shallow split, nested structs, vectors, Maybe/union payloads - value and ActionValue methods; split inputs, outputs, and both - input<->output isolation: crossing, combining, fan-out, dead ports - per-port combinational loop detection and confinement (G0032) - packed<->split boundaries, data-dependent selector muxes, EN/RDY - paths through a submodule's split ports Add if-split tests for ActionValue methods with split output ports Cover iSplitIface handling of a port-split (ShallowSplit) ActionValue result, whose value stays a tuple rather than Bit#(n), both with the action unsplit and split via the splitIf pragma. --- doc/user_guide/bluetcl.tex | 11 +- src/Libraries/Base1/Prelude.bs | 246 ++++--- src/Libraries/Base1/SplitPorts.bs | 16 +- src/Libraries/Base1/Vector.bs | 8 +- src/bluesim/bs_prim_ops.h | 2 +- src/bluesim/bs_wide_data.h | 2 +- src/bluesim/wide_data.cxx | 2 +- src/comp/AAddScheduleDefs.hs | 12 +- src/comp/ACheck.hs | 2 + src/comp/AConv.hs | 214 ++++-- src/comp/ADropUndet.hs | 2 + src/comp/ADumpSchedule.hs | 2 +- src/comp/AExpand.hs | 9 + src/comp/AExpr2STP.hs | 30 +- src/comp/AExpr2Util.hs | 34 +- src/comp/AExpr2Yices.hs | 29 +- src/comp/ANoInline.hs | 2 +- src/comp/APaths.hs | 134 ++-- src/comp/ARankMethCalls.hs | 8 +- src/comp/ARenameIO.hs | 4 +- src/comp/ASchedule.hs | 10 +- src/comp/AState.hs | 99 ++- src/comp/ASyntax.hs | 142 ++-- src/comp/ASyntaxUtil.hs | 41 ++ src/comp/ATaskSplice.hs | 7 +- src/comp/AUses.hs | 2 + src/comp/AVeriQuirks.hs | 7 + src/comp/AVerilog.hs | 8 +- src/comp/AVerilogUtil.hs | 11 +- src/comp/BackendNamingConventions.hs | 54 +- src/comp/BinData.hs | 8 + src/comp/CSyntax.hs | 6 +- src/comp/CType.hs | 10 +- src/comp/CVPrint.hs | 7 +- src/comp/DisjointTest.hs | 30 +- src/comp/GenABin.hs | 2 +- src/comp/GenBin.hs | 2 +- src/comp/GenWrap.hs | 34 +- src/comp/IExpand.hs | 85 ++- src/comp/IExpandUtils.hs | 15 +- src/comp/IInlineFmt.hs | 22 +- src/comp/ISplitIf.hs | 6 +- src/comp/ISyntax.hs | 10 +- src/comp/ISyntaxUtil.hs | 50 +- src/comp/ITransform.hs | 4 +- src/comp/IfcBetterInfo.hs | 8 +- src/comp/LambdaCalc.hs | 12 +- src/comp/LambdaCalcUtil.hs | 13 +- src/comp/Parser/BSV/CVParser.lhs | 8 +- src/comp/Parser/BSV/CVParserImperative.lhs | 16 +- src/comp/Parser/Classic/CParser.hs | 2 +- src/comp/PreStrings.hs | 2 + src/comp/SAL.hs | 13 +- src/comp/SignalNaming.hs | 7 + src/comp/SimCCBlock.hs | 36 +- src/comp/SimCOpt.hs | 1 + src/comp/SimExpand.hs | 11 +- src/comp/SimMakeCBlocks.hs | 20 +- src/comp/SimPackage.hs | 13 +- src/comp/SimPackageOpt.hs | 13 +- src/comp/SystemCWrapper.hs | 6 +- src/comp/TCheck.hs | 51 +- src/comp/TopUtils.hs | 4 +- src/comp/Type.hs | 23 +- src/comp/VIOProps.hs | 18 +- src/comp/VModInfo.hs | 22 +- src/comp/bluetcl.hs | 167 ++--- src/comp/showrules.hs | 2 +- .../module.tcl.bluetcl-bh-out.expected | 6 +- .../commands/module.tcl.bluetcl-out.expected | 6 +- .../submodule.tcl.bluetcl-bh-out.expected | 68 +- .../submodule.tcl.bluetcl-out.expected | 68 +- .../targeted/port_types/SplitPortTypes.bs | 60 ++ .../inhigh.tcl.bluetcl-bh-out.expected | 4 +- .../inhigh.tcl.bluetcl-out.expected | 4 +- .../targeted/port_types/port_types.exp | 8 + .../prims.tcl.bluetcl-bh-out.expected | 46 +- .../port_types/prims.tcl.bluetcl-out.expected | 46 +- .../targeted/port_types/split_port_types.tcl | 16 + ...lit_port_types.tcl.bluetcl-bh-out.expected | 55 ++ .../split_port_types.tcl.bluetcl-out.expected | 55 ++ .../zero_size.tcl.bluetcl-bh-out.expected | 4 +- .../zero_size.tcl.bluetcl-out.expected | 4 +- .../bsc.bugs/bluespec_inc/b1610/Test2.bs | 2 +- .../bsc.bugs/bluespec_inc/b1758/b1758.exp | 12 +- .../bsc.codegen/foreign/BDPIActionValue_.bsv | 2 +- .../bsc.evaluator/mkTest.atsexpand.expected | 8 +- .../mkTest.atsexpand.nolift.expandif.expected | 8 +- ...ormConstantAcrossEquals.atsexpand.expected | 8 +- .../bsc.evaluator/sysShiftMult.ats.expected | 4 +- testsuite/bsc.if/split/MultiPortAVNoSplit.bs | 24 + testsuite/bsc.if/split/MultiPortAVSplit.bs | 25 + testsuite/bsc.if/split/splitIf.exp | 5 + .../EResources.bs.bsc-vcomp-out.expected | 4 +- testsuite/bsc.lib/Prelude/TupleSize.bs | 2 +- .../lambda_calculus/lc-sysTb.out.expected | 24 +- testsuite/bsc.misc/sal/CTX_sysTb.sal.expected | 24 +- ...alNum_ENotation.bsv.bsc-vcomp-out.expected | 2 +- .../Method.bsv.bsc-vcomp-out.expected | 6 +- ...thodActionValue.bsv.bsc-vcomp-out.expected | 2 +- .../MethodRead.bsv.bsc-vcomp-out.expected | 2 +- .../SplitIf.bsv.bsc-sched-out.expected | 2 +- .../SplitIf2.bsv.bsc-sched-out.expected | 2 +- .../AVArgUse_C.bsv.bsc-sched-out.expected | 2 +- .../AVArgUse_SBR.bsv.bsc-sched-out.expected | 2 +- .../bsc.scheduler/paths/AVEnArgMuxPath.bs | 48 ++ .../bsc.scheduler/paths/AVSplitInPath.bs | 26 + .../bsc.scheduler/paths/AVSubmodInPath.bs | 42 ++ .../bsc.scheduler/paths/ArgSelectorPath.bs | 31 + .../bsc.scheduler/paths/DeepLeafBasic.bs | 28 + .../bsc.scheduler/paths/DeepLeafConst.bs | 35 + .../bsc.scheduler/paths/DeepLeafCross.bs | 34 + testsuite/bsc.scheduler/paths/DeepLeafLoop.bs | 45 ++ .../bsc.scheduler/paths/DeepLeafTwoLevels.bs | 41 ++ .../bsc.scheduler/paths/DeepWireFanout.bs | 37 + .../bsc.scheduler/paths/EnRdyAVEnResult.bs | 28 + .../bsc.scheduler/paths/EnRdyDeepEnOut.bs | 32 + .../bsc.scheduler/paths/EnRdyEnToSplitOut.bs | 23 + testsuite/bsc.scheduler/paths/EnRdyInToRdy.bs | 25 + .../bsc.scheduler/paths/EnRdyTwoEnSplit.bs | 29 + .../bsc.scheduler/paths/GranDeepNested.bs | 31 + testsuite/bsc.scheduler/paths/GranNoSplit.bs | 30 + .../bsc.scheduler/paths/GranShallowNested.bs | 30 + testsuite/bsc.scheduler/paths/GranTwoArgs.bs | 27 + testsuite/bsc.scheduler/paths/GranVec.bs | 22 + .../bsc.scheduler/paths/IOMatrixCombine.bs | 23 + .../bsc.scheduler/paths/IOMatrixCross.bs | 22 + .../paths/IOMatrixDeepCombine.bs | 31 + .../bsc.scheduler/paths/IOMatrixDeepCross.bs | 30 + .../bsc.scheduler/paths/IOMatrixFanout.bs | 22 + .../bsc.scheduler/paths/LoopAVPortLoop.bs | 41 ++ .../bsc.scheduler/paths/LoopConfinedArg2.bs | 47 ++ .../bsc.scheduler/paths/LoopConfinedP1.bs | 44 ++ .../bsc.scheduler/paths/LoopConfinedP2.bs | 43 ++ .../bsc.scheduler/paths/LoopInputArgLoop.bs | 37 + .../bsc.scheduler/paths/LoopNoFalseLoop.bs | 46 ++ .../bsc.scheduler/paths/LoopSwapNoLoop.bs | 40 ++ testsuite/bsc.scheduler/paths/MaybeDeep.bs | 30 + testsuite/bsc.scheduler/paths/MaybeShallow.bs | 25 + .../bsc.scheduler/paths/PackedInSplitOut.bs | 23 + testsuite/bsc.scheduler/paths/RWireFanout.bs | 32 + .../bsc.scheduler/paths/SelectorMuxPath.bs | 55 ++ .../paths/SelectorSplitOutPath.bs | 64 ++ .../paths/SiblingDisjointFanout.bs | 41 ++ testsuite/bsc.scheduler/paths/SplitAVPath.bs | 24 + .../paths/SplitInPackedCombine.bs | 22 + .../paths/SplitInPackedOneField.bs | 24 + .../bsc.scheduler/paths/SplitOutputLoop.bs | 34 + .../bsc.scheduler/paths/SplitOutputPath.bs | 23 + .../bsc.scheduler/paths/SplitSubmodPath.bs | 47 ++ .../bsc.scheduler/paths/SubmodCrossbarPath.bs | 50 ++ .../bsc.scheduler/paths/SubmodDeepLeafPath.bs | 49 ++ .../bsc.scheduler/paths/SubmodInputArgPath.bs | 41 ++ .../paths/SubmodSelectOutPath.bs | 43 ++ testsuite/bsc.scheduler/paths/UnionPayload.bs | 37 + .../bsc.scheduler/paths/VecNestedDeep.bs | 49 ++ .../bsc.scheduler/paths/VecStructDeepMulti.bs | 35 + .../bsc.scheduler/paths/VecStructShallow.bs | 36 + testsuite/bsc.scheduler/paths/paths.exp | 680 ++++++++++++++++++ .../sysStateNameTest.atsexpand.expected | 2 +- .../sysStateNameTest2.atsexpand.expected | 2 +- .../statename/sysUseMod2.atsexpand.expected | 2 +- .../sysUseMod2Arrow.atsexpand.expected | 2 +- .../DummyInRuleQual.bs.bsc-vcomp-out.expected | 2 +- ...ne_ResNotInBits.bsv.bsc-vcomp-out.expected | 6 - testsuite/bsc.verilog/splitports/DeepSplit.bs | 26 +- .../bsc.verilog/splitports/InstanceSplit.bs | 27 +- .../splitports/PortNameConflict.bs | 4 +- .../bsc.verilog/splitports/ShallowSplit.bs | 23 +- .../bsc.verilog/splitports/SomeArgNames.bs | 4 +- .../bsc.verilog/splitports/TooManyArgNames.bs | 4 +- .../bsc.verilog/splitports/splitports.exp | 42 ++ .../splitports/sysDeepSplit.out.expected | 5 + .../splitports/sysInstanceSplit.out.expected | 4 + .../splitports/sysShallowSplit.out.expected | 4 + 175 files changed, 4336 insertions(+), 888 deletions(-) create mode 100644 testsuite/bsc.bluetcl/targeted/port_types/SplitPortTypes.bs create mode 100644 testsuite/bsc.bluetcl/targeted/port_types/split_port_types.tcl create mode 100644 testsuite/bsc.bluetcl/targeted/port_types/split_port_types.tcl.bluetcl-bh-out.expected create mode 100644 testsuite/bsc.bluetcl/targeted/port_types/split_port_types.tcl.bluetcl-out.expected create mode 100644 testsuite/bsc.if/split/MultiPortAVNoSplit.bs create mode 100644 testsuite/bsc.if/split/MultiPortAVSplit.bs create mode 100644 testsuite/bsc.scheduler/paths/AVEnArgMuxPath.bs create mode 100644 testsuite/bsc.scheduler/paths/AVSplitInPath.bs create mode 100644 testsuite/bsc.scheduler/paths/AVSubmodInPath.bs create mode 100644 testsuite/bsc.scheduler/paths/ArgSelectorPath.bs create mode 100644 testsuite/bsc.scheduler/paths/DeepLeafBasic.bs create mode 100644 testsuite/bsc.scheduler/paths/DeepLeafConst.bs create mode 100644 testsuite/bsc.scheduler/paths/DeepLeafCross.bs create mode 100644 testsuite/bsc.scheduler/paths/DeepLeafLoop.bs create mode 100644 testsuite/bsc.scheduler/paths/DeepLeafTwoLevels.bs create mode 100644 testsuite/bsc.scheduler/paths/DeepWireFanout.bs create mode 100644 testsuite/bsc.scheduler/paths/EnRdyAVEnResult.bs create mode 100644 testsuite/bsc.scheduler/paths/EnRdyDeepEnOut.bs create mode 100644 testsuite/bsc.scheduler/paths/EnRdyEnToSplitOut.bs create mode 100644 testsuite/bsc.scheduler/paths/EnRdyInToRdy.bs create mode 100644 testsuite/bsc.scheduler/paths/EnRdyTwoEnSplit.bs create mode 100644 testsuite/bsc.scheduler/paths/GranDeepNested.bs create mode 100644 testsuite/bsc.scheduler/paths/GranNoSplit.bs create mode 100644 testsuite/bsc.scheduler/paths/GranShallowNested.bs create mode 100644 testsuite/bsc.scheduler/paths/GranTwoArgs.bs create mode 100644 testsuite/bsc.scheduler/paths/GranVec.bs create mode 100644 testsuite/bsc.scheduler/paths/IOMatrixCombine.bs create mode 100644 testsuite/bsc.scheduler/paths/IOMatrixCross.bs create mode 100644 testsuite/bsc.scheduler/paths/IOMatrixDeepCombine.bs create mode 100644 testsuite/bsc.scheduler/paths/IOMatrixDeepCross.bs create mode 100644 testsuite/bsc.scheduler/paths/IOMatrixFanout.bs create mode 100644 testsuite/bsc.scheduler/paths/LoopAVPortLoop.bs create mode 100644 testsuite/bsc.scheduler/paths/LoopConfinedArg2.bs create mode 100644 testsuite/bsc.scheduler/paths/LoopConfinedP1.bs create mode 100644 testsuite/bsc.scheduler/paths/LoopConfinedP2.bs create mode 100644 testsuite/bsc.scheduler/paths/LoopInputArgLoop.bs create mode 100644 testsuite/bsc.scheduler/paths/LoopNoFalseLoop.bs create mode 100644 testsuite/bsc.scheduler/paths/LoopSwapNoLoop.bs create mode 100644 testsuite/bsc.scheduler/paths/MaybeDeep.bs create mode 100644 testsuite/bsc.scheduler/paths/MaybeShallow.bs create mode 100644 testsuite/bsc.scheduler/paths/PackedInSplitOut.bs create mode 100644 testsuite/bsc.scheduler/paths/RWireFanout.bs create mode 100644 testsuite/bsc.scheduler/paths/SelectorMuxPath.bs create mode 100644 testsuite/bsc.scheduler/paths/SelectorSplitOutPath.bs create mode 100644 testsuite/bsc.scheduler/paths/SiblingDisjointFanout.bs create mode 100644 testsuite/bsc.scheduler/paths/SplitAVPath.bs create mode 100644 testsuite/bsc.scheduler/paths/SplitInPackedCombine.bs create mode 100644 testsuite/bsc.scheduler/paths/SplitInPackedOneField.bs create mode 100644 testsuite/bsc.scheduler/paths/SplitOutputLoop.bs create mode 100644 testsuite/bsc.scheduler/paths/SplitOutputPath.bs create mode 100644 testsuite/bsc.scheduler/paths/SplitSubmodPath.bs create mode 100644 testsuite/bsc.scheduler/paths/SubmodCrossbarPath.bs create mode 100644 testsuite/bsc.scheduler/paths/SubmodDeepLeafPath.bs create mode 100644 testsuite/bsc.scheduler/paths/SubmodInputArgPath.bs create mode 100644 testsuite/bsc.scheduler/paths/SubmodSelectOutPath.bs create mode 100644 testsuite/bsc.scheduler/paths/UnionPayload.bs create mode 100644 testsuite/bsc.scheduler/paths/VecNestedDeep.bs create mode 100644 testsuite/bsc.scheduler/paths/VecStructDeepMulti.bs create mode 100644 testsuite/bsc.scheduler/paths/VecStructShallow.bs diff --git a/doc/user_guide/bluetcl.tex b/doc/user_guide/bluetcl.tex index 96baa7bb5..9ef3e72fd 100644 --- a/doc/user_guide/bluetcl.tex +++ b/doc/user_guide/bluetcl.tex @@ -337,7 +337,13 @@ \subsubsubsection{Bluetcl::module} {\bf module} {\bf methods} {\em modname}& Returns a list of the flattened methods in the module. \\ \hline -{\bf module} {\bf ports} {\em modname}& Returns a list of the ports in the module. \\ +{\bf module} {\bf ports} {\em modname}& Returns a list of the ports in the +module, organized by interface element. For each method, the entry includes +its argument ports (\te{args}) and a \te{results} field listing the method's +output ports, each given as a \te{port} name and bit \te{size}. The +\te{results} list may be empty (for an action method with no return value) or +contain more than one port (when a method's result is split across several +output ports). \\ \hline {\bf module} {\bf porttypes} {\em modname}& Returns a list of the types of the ports in the module. \\ @@ -430,7 +436,8 @@ \subsubsubsection{Bluetcl::submodule} \hline {\bf submodule} {\bf full} {\em modname}& Returns information about each submodule in the specified module and the rules which use the methods -of the submodule. \\ +of the submodule. The per-method port information uses the same format as +{\bf module ports}, including the \te{results} field of output ports. \\ \hline \hline \end{tabular} diff --git a/src/Libraries/Base1/Prelude.bs b/src/Libraries/Base1/Prelude.bs index 1758af0ad..55fa7d573 100644 --- a/src/Libraries/Base1/Prelude.bs +++ b/src/Libraries/Base1/Prelude.bs @@ -173,7 +173,7 @@ package Prelude( Tuple6, tuple6, Has_tpl_6(..), Tuple7, tuple7, Has_tpl_7(..), Tuple8, tuple8, Has_tpl_8(..), - AppendTuple(..), AppendTuple', AppendTuple'', TupleSize, TupleSize', + AppendTuple(..), AppendTuple', AppendTuple'', TupleSize(..), TupleSize', -- lists required for desugaring List(..), @@ -259,8 +259,8 @@ package Prelude( NumConArg(..), StarConArg(..), OtherConArg(..), MetaConsNamed(..), MetaConsAnon(..), MetaField(..), - WrapField(..), WrapMethod(..), WrapPorts(..), - Port(..), unPort, SplitPorts(..) + WrapField(..), WrapMethod(..), WrapPorts(..), NonEmptyBits(..), + Port(..), unPort, SplitPorts(..), PrimSeqTupleBits(..) ) where infixr 0 $ @@ -993,9 +993,9 @@ fromPrimAction a = ActionValue (\aw -> AVStruct { avValue = _; avAction = a; avW type Action = ActionValue () --X@ \begin{verbatim} ---X@ typedef ActionValue_#(0) Action_; +--X@ typedef ActionValue_#(void) Action_; --X@ \end{verbatim} -type Action_ = ActionValue_ 0 +type Action_ = ActionValue_ () --@ An empty \te{Action}. --@ \index{noAction@\te{noAction} (empty action)} @@ -1012,23 +1012,36 @@ noAction = fromPrimAction primNoActions (:<-) :: Reg a -> ActionValue a -> Action (:<-) r av = av `bind` r._write ---X@ A primitive \te{ActionValue} of bits +--X@ A primitive \te{ActionValue} of bits. +--X@ The type parameter should be either (), Bit n, or a tuple of Bit n. --X@ \begin{verbatim} ---X@ struct ActionValue_ #(type n); +--X@ struct ActionValue_ #(type a; --X@ \end{verbatim} -struct ActionValue_ n +struct ActionValue_ a = - avValue_ :: Bit n + avValue_ :: a avAction_ :: PrimAction -toActionValue_ :: (Bits a n) => ActionValue a -> ActionValue_ n -toActionValue_ (ActionValue av) = +toActionValue_ :: (Bits a n) => ActionValue a -> ActionValue_ (Bit n) +toActionValue_ = bitsToActionValue_ ∘ fmap pack + +fromActionValue_ :: (Bits a n) => ActionValue_ (Bit n) -> ActionValue a +fromActionValue_ = fmap unpack ∘ bitsFromActionValue_ + +toAction_ :: Action -> Action_ +toAction_ = bitsToActionValue_ + +fromAction_ :: Action_ -> Action +fromAction_ = bitsFromActionValue_ + +bitsToActionValue_ :: ActionValue a -> ActionValue_ a +bitsToActionValue_ (ActionValue av) = letseq av' = av ActionWorld - in ActionValue_ { avValue_ = pack av'.avValue; avAction_ = av'.avAction} + in ActionValue_ { avValue_ = av'.avValue; avAction_ = av'.avAction} -fromActionValue_ :: (Bits a n) => ActionValue_ n -> ActionValue a -fromActionValue_ av_ = ActionValue (\aw -> - AVStruct { avValue = unpack av_.avValue_; avAction = av_.avAction_; avWorld = aw}) +bitsFromActionValue_ :: ActionValue_ a -> ActionValue a +bitsFromActionValue_ av_ = ActionValue (\ aw -> + AVStruct { avValue = av_.avValue_; avAction = av_.avAction_; avWorld = aw}) -- ---------------------------------------------------------------- @@ -3344,9 +3357,9 @@ $time = fromActionValue_ (__time__) $stime :: ActionValue (Bit 32) $stime = fromActionValue_ (__stime__) -foreign __time__ :: ActionValue_ 64 = "$time" +foreign __time__ :: ActionValue_ (Bit 64) = "$time" -foreign __stime__ :: ActionValue_ 32 = "$stime" +foreign __stime__ :: ActionValue_ (Bit 32) = "$stime" -- File type and system tasks which use it data File = InvalidFile | @@ -3400,7 +3413,7 @@ foreign $fflush :: PrimAction = "$fflush" -- Type checking is done by bsc -- $fopen :: String -> ActionValue#(File) -- $fopen :: String -> String -> ActionValue#(File) -foreign $fopen :: ActionValue_ 32 = "$fopen" +foreign $fopen :: ActionValue_ (Bit 32) = "$fopen" -- The arguments for these are handled internally @@ -3409,16 +3422,16 @@ foreign $fwriteb :: PrimAction = "$fwriteb" foreign $fwriteo :: PrimAction = "$fwriteo" foreign $fwriteh :: PrimAction = "$fwriteh" -foreign $swriteAV :: ActionValue_ n = "$swriteAV" +foreign $swriteAV :: ActionValue_ (Bit n) = "$swriteAV" foreign $swrite :: PrimAction = "$swrite" -foreign $swritebAV :: ActionValue_ n = "$swritebAV" +foreign $swritebAV :: ActionValue_ (Bit n) = "$swritebAV" foreign $swriteb :: PrimAction = "$swriteb" -foreign $swriteoAV :: ActionValue_ n = "$swriteoAV" +foreign $swriteoAV :: ActionValue_ (Bit n) = "$swriteoAV" foreign $swriteo :: PrimAction = "$swriteo" -foreign $swritehAV :: ActionValue_ n = "$swritehAV" +foreign $swritehAV :: ActionValue_ (Bit n) = "$swritehAV" foreign $swriteh :: PrimAction = "$swriteh" -foreign $sformatAV :: ActionValue_ n = "$sformatAV" +foreign $sformatAV :: ActionValue_ (Bit n) = "$sformatAV" foreign $sformat :: PrimAction = "$sformat" foreign $fdisplay :: PrimAction = "$fdisplay" @@ -3426,20 +3439,19 @@ foreign $fdisplayb :: PrimAction = "$fdisplayb" foreign $fdisplayo :: PrimAction = "$fdisplayo" foreign $fdisplayh :: PrimAction = "$fdisplayh" -foreign $random :: ActionValue_ 32 = "$random" +foreign $random :: ActionValue_ (Bit 32) = "$random" $fgetc :: File -> ActionValue (Int 32) -- to allow space for -1 $fgetc f = fromActionValue_ (__fgetc__ (pack f)) -foreign __fgetc__ :: Bit 32 -> ActionValue_ 32 = "$fgetc" +foreign __fgetc__ :: Bit 32 -> ActionValue_ (Bit 32) = "$fgetc" $fclose :: File -> Action -$fclose f = fromActionValue_ (__fclose__ (pack f)) +$fclose f = fromAction_ (__fclose__ (pack f)) foreign __fclose__ :: Bit 32 -> Action_ = "$fclose" $ungetc :: Bit 8 -> File -> ActionValue (Int 32) $ungetc c f = fromActionValue_ ( __fungetc__ c (pack f)) -foreign __fungetc__ :: Bit 8 -> Bit 32 -> ActionValue_ 32 = "$ungetc" - +foreign __fungetc__ :: Bit 8 -> Bit 32 -> ActionValue_ (Bit 32) = "$ungetc" -- "standard" file descriptors stdin :: File @@ -3454,7 +3466,7 @@ stdout_mcd = MCD 1 $test$plusargs :: String -> ActionValue Bool $test$plusargs x = fromActionValue_ (__testplusargs__ x) -foreign __testplusargs__ :: String -> ActionValue_ 1 = "$test$plusargs" +foreign __testplusargs__ :: String -> ActionValue_ (Bit 1) = "$test$plusargs" ------------------ @@ -3536,6 +3548,7 @@ tuple8 :: a -> b -> c -> d -> e -> f -> g -> h -> Tuple8 a b c d e f g h tuple8 a b c d e f g h = (a,b,c,d,e,f,g,h) class AppendTuple a b c | a b -> c where + type TAppendTuple a b = c appendTuple :: a -> b -> c splitTuple :: c -> (a, b) @@ -3575,7 +3588,8 @@ instance (AppendTuple'' a b c) => AppendTuple'' (h, a) b (h, c) where splitTuple'' (x, y) = case splitTuple'' y of (w, z) -> ((x, w), z) -class TupleSize a n | a -> n where {} +class TupleSize a n | a -> n where + type TTupleSize a = n instance TupleSize () 0 where {} instance (TupleSize' a n) => TupleSize a n where {} @@ -4608,18 +4622,16 @@ data (MetaField :: $ -> # -> *) name idx = MetaField deriving (FShow) --- Tag a method with metadata. --- Currently just the list of input port names. --- Should eventually include the output port names, when we support multiple output ports. -primitive primMethod :: List String -> a -> a +-- Tag a method with metadata: the input and output port names. +primitive primMethod :: List String -> List String -> a -> a -- Convert bewtween a field in an interface that is being synthesized, -- and a field in the corresponding field in the generated wrapper interface. -- Also takes the name of the field for error reporting purposes. class (WrapField :: $ -> * -> * -> *) name f w | name f -> w where - -- Given a proxy value for the field name, and the values of the prefix and arg_names pragmas, + -- Given a proxy value for the field name, and the values of the prefix, arg_names and result pragmas, -- converts a synthesized interface field value to its wrapper interface field. - toWrapField :: StrArg name -> String -> List String -> f -> w + toWrapField :: StrArg name -> String -> List String -> String -> f -> w -- Given a proxy value for the field name, converts a wrapper interface field value -- to its synthesized interface field. @@ -4630,35 +4642,39 @@ class (WrapField :: $ -> * -> * -> *) name f w | name f -> w where saveFieldPortTypes :: StrArg name -> f -> Maybe Name__ -> String -> List String -> String -> Module () instance (WrapMethod m w) => (WrapField name m w) where - toWrapField _ prefix names = - let baseNames = methodArgBaseNames (_ :: m) prefix names 1 - in primMethod (inputPortNames (_ :: m) baseNames) ∘ toWrapMethod + toWrapField _ prefix argNames resultName = + let argBaseNames = methodArgBaseNames (_ :: m) prefix argNames 1 + in primMethod + (inputPortNames (_ :: m) argBaseNames) + (outputPortNames (_ :: m) resultName) + ∘ toWrapMethod fromWrapField _ = fromWrapMethod - saveFieldPortTypes _ _ modName prefix names = - let baseNames = methodArgBaseNames (_ :: m) prefix names 1 - in saveMethodPortTypes (_ :: m) modName baseNames + saveFieldPortTypes _ _ modName prefix argNames resultName = + let baseNames = methodArgBaseNames (_ :: m) prefix argNames 1 + in saveMethodPortTypes (_ :: m) modName baseNames resultName -- TODO: It doesn't seem possible to have a PrimAction field in a synthesized interface, -- but this case was being handled in GenWrap. instance WrapField name PrimAction PrimAction where - toWrapField _ _ _ = id + toWrapField _ _ _ _ = id fromWrapField _ = id saveFieldPortTypes _ _ _ _ _ _ = return () instance WrapField name Clock Clock where - toWrapField _ _ _ = id + toWrapField _ _ _ _ = id fromWrapField _ = id saveFieldPortTypes _ _ _ _ _ _ = return () instance WrapField name Reset Reset where - toWrapField _ _ _ = id + toWrapField _ _ _ _ = id fromWrapField _ = id saveFieldPortTypes _ _ _ _ _ _ = return () instance (Bits a n) => WrapField name (Inout a) (Inout_ n) where - toWrapField _ _ _ = primInoutCast0 + toWrapField _ _ _ _ = primInoutCast0 fromWrapField _ = primInoutUncast0 - saveFieldPortTypes _ _ modName _ _ result = primSavePortType modName result $ typeOf (_ :: (Inout a)) + saveFieldPortTypes _ _ modName _ _ result = + primSavePortType modName result $ typeOf (_ :: (Inout a)) class WrapMethod m w | m -> w where -- Convert a synthesized interface method to its wrapper interface method. @@ -4673,10 +4689,13 @@ class WrapMethod m w | m -> w where -- Compute the list of input port names for a method, from the argument base names. inputPortNames :: m -> List String -> List String + -- Compute the list of input port names for a method, from the result base name. + outputPortNames :: m -> String -> List String + -- Save the port types for a method, given the module name, argument base names and result name. saveMethodPortTypes :: m -> Maybe Name__ -> List String -> String -> Module () -instance (SplitPorts a p, TupleSize p n, WrapPorts p pb, WrapMethod b v, Curry (pb -> v) w) => +instance (WrapPorts (PortsOf a) pb, WrapMethod b v, Curry (pb -> v) w) => WrapMethod (a -> b) w where toWrapMethod f = curryN $ toWrapMethod ∘ f ∘ unsplitPorts ∘ unpackPorts fromWrapMethod f = fromWrapMethod ∘ uncurryN f ∘ packPorts ∘ splitPorts @@ -4691,94 +4710,135 @@ instance (SplitPorts a p, TupleSize p n, WrapPorts p pb, WrapMethod b v, Curry ( (prefix +++ "_" +++ integerToString i) (methodArgBaseNames (_ :: b) prefix Nil $ i + 1) - inputPortNames _ (Cons h t) = checkPortNames (_ :: a) h `listPrimAppend` inputPortNames (_ :: b) t + inputPortNames _ (Cons h t) = + filterZeroWidthPorts (_ :: PortsOf a) (checkPortNames (_ :: a) h) + `listPrimAppend` inputPortNames (_ :: b) t inputPortNames _ Nil = error "inputPortNames: empty arg names list" + outputPortNames _ = outputPortNames (_ :: b) + saveMethodPortTypes _ modName (Cons h t) result = do - savePortTypes (_ :: p) modName $ checkPortNames (_ :: a) h + savePortTypes (_ :: PortsOf a) modName $ checkPortNames (_ :: a) h saveMethodPortTypes (_ :: b) modName t result saveMethodPortTypes _ _ Nil _ = error "saveMethodPortTypes: empty arg names list" -instance (Bits a n) => WrapMethod (ActionValue a) (ActionValue_ n) where - toWrapMethod = toActionValue_ - fromWrapMethod = fromActionValue_ +instance (WrapPorts (PortsOf a) pb, PrimSeqTupleBits pb) => + WrapMethod (ActionValue a) (ActionValue_ pb) where + toWrapMethod = bitsToActionValue_ ∘ fmap (primDeepSeqTupleBits ∘ packPorts ∘ splitPorts) + fromWrapMethod = fmap (unsplitPorts ∘ unpackPorts) ∘ bitsFromActionValue_ methodArgBaseNames _ _ Nil _ = Nil methodArgBaseNames prx prefix argNames _ = primError (getEvalPosition prx) $ integerToString (listLength argNames) +++ " excess arg_names provided for method " +++ prefix inputPortNames _ Nil = Nil inputPortNames _ (Cons _ _) = error "inputPortNames: uncaught excess arg names" - saveMethodPortTypes _ modName _ result = primSavePortType modName result $ typeOf (_ :: a) + outputPortNames _ base = filterZeroWidthPorts (_ :: PortsOf a) $ checkPortNames (_ :: a) base + saveMethodPortTypes _ modName _ result = + savePortTypes (_ :: PortsOf a) modName $ checkPortNames (_ :: a) result -instance (Bits a n) => WrapMethod a (Bit n) where - toWrapMethod = pack - fromWrapMethod = unpack +instance (WrapPorts (PortsOf a) pb, PrimSeqTupleBits pb) => + WrapMethod a pb where + toWrapMethod = primDeepSeqTupleBits ∘ packPorts ∘ splitPorts + fromWrapMethod = unsplitPorts ∘ unpackPorts methodArgBaseNames _ _ Nil _ = Nil methodArgBaseNames prx prefix argNames _ = primError (getEvalPosition prx) $ integerToString (listLength argNames) +++ " excess arg_names provided for method " +++ prefix inputPortNames _ Nil = Nil inputPortNames _ (Cons _ _) = error "inputPortNames: uncaught excess arg names" - saveMethodPortTypes _ modName _ result = primSavePortType modName result $ typeOf (_ :: a) - -{- -Eventually, we should support splitting multiple output ports. -instance (SplitPorts a p, TupleSize p n, WrapPorts p pb) => WrapMethod (ActionValue a) (ActionValue pb) where - toWrapMethod = fmap packPorts - fromWrapMethod = fmap unpackPorts - outputPortNames _ base = checkPortNames (_ :: a) base - saveMethodPortTypes _ modName _ result = - savePortTypes (_ :: p) modName $ checkPortNames (_ :: a) result - -instance (SplitPorts a p, TupleSize p n, WrapPorts p pb) => WrapMethod a pb where - toWrapMethod a = packPorts a - fromWrapMethod a = unpackPorts a - outputPortNames _ base = checkPortNames (_ :: a) base + outputPortNames _ base = filterZeroWidthPorts (_ :: PortsOf a) $ checkPortNames (_ :: a) base saveMethodPortTypes _ modName _ result = - savePortTypes (_ :: p) modName $ checkPortNames (_ :: a) result --} + savePortTypes (_ :: PortsOf a) modName $ checkPortNames (_ :: a) result class WrapPorts p pb | p -> pb where - -- Convert from a tuple of values to a tuple of bits. + -- Convert from a tuple of Port values to a tuple of bits. packPorts :: p -> pb - -- Convert from a tuple of bits to a tuple of values. + -- Convert from a tuple of bits to a tuple of Port values. unpackPorts :: pb -> p -- Save the port types, given their names. savePortTypes :: p -> Maybe Name__ -> List String -> Module () - -instance (Bits a n, WrapPorts b bb) => WrapPorts (Port a, b) (Bit n, bb) where - packPorts (Port a, b) = (pack a, packPorts b) - unpackPorts (a, b) = (Port $ unpack a, unpackPorts b) + -- Filter the port names to only those that have non-zero width. + filterZeroWidthPorts :: p -> List String -> List String + +instance (Bits a n, NonEmptyBits n ab, WrapPorts b bb) => + WrapPorts (Port a, b) (TAppendTuple ab bb) where + packPorts (Port a, b) = toNonEmptyBits (pack a) `appendTuple` packPorts b + unpackPorts p = case splitTuple p of + (ab, bb) -> (Port (unpack (fromNonEmptyBits ab)), unpackPorts bb) savePortTypes _ modName (Cons h t) = do - primSavePortType modName h $ typeOf (_ :: a) + if valueOf n > 0 + then primSavePortType modName h $ typeOf (_ :: a) + else return () savePortTypes (_ :: b) modName t savePortTypes _ _ Nil = error "savePortTypes: empty port names list" - -instance (Bits a n) => WrapPorts (Port a) (Bit n) where - packPorts (Port a) = pack a - unpackPorts = Port ∘ unpack - savePortTypes _ modName (Cons h _) = primSavePortType modName h $ typeOf (_ :: a) - savePortTypes _ _ Nil = error "savePortTypes: empty port names list" + filterZeroWidthPorts _ (Cons h t) = + if valueOf n > 0 + then Cons h (filterZeroWidthPorts (_ :: b) t) + else filterZeroWidthPorts (_ :: b) t + filterZeroWidthPorts _ Nil = error "filterZeroWidthPorts: empty port names list" + +instance (Bits a n, NonEmptyBits n pb) => WrapPorts (Port a) pb where + packPorts (Port a) = toNonEmptyBits (pack a) + unpackPorts = Port ∘ unpack ∘ fromNonEmptyBits + savePortTypes _ modName (Cons h Nil) = primSavePortType modName h $ typeOf (_ :: a) + savePortTypes _ _ _ = error "savePortTypes: expected one port name" + filterZeroWidthPorts _ (Cons h Nil) = + if valueOf n > 0 then Cons h Nil else Nil + filterZeroWidthPorts _ _ = error "filterZeroWidthPorts: expected one port name" instance WrapPorts () () where packPorts _ = () unpackPorts _ = () - savePortTypes _ _ _ = return () + savePortTypes _ _ Nil = return () + savePortTypes _ _ _ = error "savePortTypes: non-empty port names list" + filterZeroWidthPorts _ Nil = Nil + filterZeroWidthPorts _ _ = error "filterZeroWidthPorts: non-empty port names list" + +-- Helper class to conditionally convert Bit 0 to () +class NonEmptyBits n pb | n -> pb where + toNonEmptyBits :: Bit n -> pb + fromNonEmptyBits :: pb -> Bit n + +instance NonEmptyBits 0 () where + toNonEmptyBits _ = () + fromNonEmptyBits _ = 0 + +instance NonEmptyBits n (Bit n) where + toNonEmptyBits = id + fromNonEmptyBits = id + +-- Force a tuple of bit values to be fully expanded by the evaluator. +primDeepSeqTupleBits :: (PrimSeqTupleBits a) => a -> a +primDeepSeqTupleBits a = primSeqTupleBits a a + +class PrimSeqTupleBits a where + primSeqTupleBits :: a -> b -> b + +instance (PrimSeqTupleBits b) => PrimSeqTupleBits (Bit n, b) where + primSeqTupleBits (a, b) c = primSeq a (primSeqTupleBits b c) + +instance PrimSeqTupleBits (Bit n) where + primSeqTupleBits = primSeq + +instance PrimSeqTupleBits () where + primSeqTupleBits () = id -- Compute the list port names for type 'a' given a base name. -- Check that the number of port names matches the number of ports. --- This error should only occur if there is an error in a WrapPorts instance. -checkPortNames :: (SplitPorts a p, TupleSize p n) => a -> String -> List String +-- This error should only occur if there is an error in a SplitPorts instance. +checkPortNames :: (SplitPorts a p) => a -> String -> List String checkPortNames proxy base = let pn = portNames proxy base + n = valueOf (TTupleSize p) in - if listLength pn /= valueOf n + if listLength pn /= n then primError (getEvalPosition proxy) $ - "SplitPorts: " +++ base +++ " has " +++ integerToString (valueOf n) +++ + "SplitPorts: " +++ base +++ " has " +++ integerToString n +++ " ports, but " +++ integerToString (listLength pn) +++ " port names were given" else pn class SplitPorts a p | a -> p where + type PortsOf a = p -- Convert a value to a tuple of values corresponding to ports. splitPorts :: a -> p -- Combine a tuple of values corresponding to ports into a value. @@ -4822,7 +4882,7 @@ class SplitTuplePorts a p | a -> p where unsplitTuplePorts :: p -> a splitTuplePortNames :: Integer -> a -> String -> List String -instance (SplitPorts a p, SplitTuplePorts b q, AppendTuple p q r) => SplitTuplePorts (a, b) r where +instance (SplitPorts a p, SplitTuplePorts b q) => SplitTuplePorts (a, b) (TAppendTuple p q) where splitTuplePorts (a, b) = splitPorts a `appendTuple` splitTuplePorts b unsplitTuplePorts x = case splitTuple x of (a, b) -> (unsplitPorts a, unsplitTuplePorts b) diff --git a/src/Libraries/Base1/SplitPorts.bs b/src/Libraries/Base1/SplitPorts.bs index 01c82f1ae..265257f9b 100644 --- a/src/Libraries/Base1/SplitPorts.bs +++ b/src/Libraries/Base1/SplitPorts.bs @@ -12,12 +12,12 @@ data DeepSplit a = DeepSplit a -- Tag to indicate that the DeepSplitPorts recursion should terminate data NoSplit a = NoSplit a -instance (ShallowSplitPorts a p) => SplitPorts (ShallowSplit a) p where +instance SplitPorts (ShallowSplit a) (ShallowPortsOf a) where splitPorts (ShallowSplit x) = shallowSplitPorts x unsplitPorts = ShallowSplit ∘ shallowUnsplitPorts portNames _ = shallowSplitPortNames (_ :: a) -instance (DeepSplitPorts a p) => SplitPorts (DeepSplit a) p where +instance SplitPorts (DeepSplit a) (DeepPortsOf a) where splitPorts (DeepSplit x) = deepSplitPorts x unsplitPorts = DeepSplit ∘ deepUnsplitPorts portNames _ = deepSplitPortNames (_ :: a) @@ -30,6 +30,7 @@ instance DeepSplitPorts (NoSplit a) (Port a) where -- Helper class using generics, to split a struct or vector into a tuple of ports. class ShallowSplitPorts a p | a -> p where + type ShallowPortsOf a = p shallowSplitPorts :: a -> p shallowUnsplitPorts :: p -> a shallowSplitPortNames :: a -> String -> List String @@ -44,7 +45,8 @@ class ShallowSplitPorts' r p | r -> p where shallowUnsplitPorts' :: p -> r shallowSplitPortNames' :: r -> String -> List String -instance (ShallowSplitPorts' a p, ShallowSplitPorts' b q, AppendTuple p q r) => ShallowSplitPorts' (a, b) r where +instance (ShallowSplitPorts' a p, ShallowSplitPorts' b q) => + ShallowSplitPorts' (a, b) (TAppendTuple p q) where shallowSplitPorts' (a, b) = shallowSplitPorts' a `appendTuple` shallowSplitPorts' b shallowUnsplitPorts' x = case splitTuple x of (a, b) -> (shallowUnsplitPorts' a, shallowUnsplitPorts' b) @@ -77,7 +79,7 @@ instance (ShallowSplitPorts' r p) => ShallowSplitPorts' (Meta m r) p where shallowUnsplitPorts' = Meta ∘ shallowUnsplitPorts' shallowSplitPortNames' _ = shallowSplitPortNames' (_ :: r) -instance (SplitPorts a p) => ShallowSplitPorts' (Conc a) p where +instance ShallowSplitPorts' (Conc a) (PortsOf a) where shallowSplitPorts' (Conc x) = splitPorts x shallowUnsplitPorts' = Conc ∘ unsplitPorts shallowSplitPortNames' _ = portNames (_ :: a) @@ -85,6 +87,7 @@ instance (SplitPorts a p) => ShallowSplitPorts' (Conc a) p where -- Helper class using generics, to recursively split structs and vectors into a tuple of ports. class DeepSplitPorts a p | a -> p where + type DeepPortsOf a = p deepSplitPorts :: a -> p deepUnsplitPorts :: p -> a deepSplitPortNames :: a -> String -> List String @@ -142,7 +145,7 @@ class DeepSplitPorts' r a p | r a -> p where deepSplitPortNames' :: r -> a -> String -> List String -- Terminate recursion for n /= 1 constructors -instance (SplitPorts a p) => DeepSplitPorts' r a p where +instance DeepSplitPorts' r a (PortsOf a) where deepSplitPorts' _ = splitPorts deepUnsplitPorts' _ = unsplitPorts deepSplitPortNames' _ = portNames @@ -158,7 +161,8 @@ class DeepSplitPorts'' r p | r -> p where deepUnsplitPorts'' :: p -> r deepSplitPortNames'' :: r -> String -> List String -instance (DeepSplitPorts'' a p, DeepSplitPorts'' b q, AppendTuple p q r) => DeepSplitPorts'' (a, b) r where +instance (DeepSplitPorts'' a p, DeepSplitPorts'' b q) => + DeepSplitPorts'' (a, b) (TAppendTuple p q) where deepSplitPorts'' (a, b) = deepSplitPorts'' a `appendTuple` deepSplitPorts'' b deepUnsplitPorts'' x = case splitTuple x of (a, b) -> (deepUnsplitPorts'' a, deepUnsplitPorts'' b) diff --git a/src/Libraries/Base1/Vector.bs b/src/Libraries/Base1/Vector.bs index f514a205e..ba577fe20 100644 --- a/src/Libraries/Base1/Vector.bs +++ b/src/Libraries/Base1/Vector.bs @@ -1293,14 +1293,14 @@ instance ConcatTuple 1 a a where unconcatTuple x = cons x nil -- Linear recursive implementation: O(n^2) --- instance (Add n1 1 n, ConcatTuple n1 a b, AppendTuple a b c) => ConcatTuple n a c where +-- instance (Add n1 1 n, ConcatTuple n1 a b) => ConcatTuple n a (TAppendTuple a b) where -- concatTuple v = appendTuple (head v) $ concatTuple (tail v) -- unconcatTuple x = case splitTuple x of -- (y, z) -> cons y $ unconcatTuple z -- O(n lg n) optimization: split into chunks that are powers of 2 -instance (Add lgn 1 (TLog (TAdd n 1)), Add (TExp lgn) n1 n, ConcatTuple n1 a b, ConcatTuple' lgn a c, AppendTuple b c d) => - ConcatTuple n a d where +instance (Add lgn 1 (TLog (TAdd n 1)), Add (TExp lgn) n1 n, ConcatTuple n1 a b, ConcatTuple' lgn a c) => + ConcatTuple n a (TAppendTuple b c) where concatTuple v = let v1 :: Vector n1 a = take v v2 :: Vector (TExp lgn) a = drop v @@ -1320,7 +1320,7 @@ instance ConcatTuple' 0 a a where concatTuple' v = head v unconcatTuple' x = cons x nil -instance (Add n1 1 n, ConcatTuple' n1 a b, AppendTuple b b c) => ConcatTuple' n a c where +instance (Add n1 1 n, ConcatTuple' n1 a b) => ConcatTuple' n a (TAppendTuple b b) where concatTuple' v = let v1 :: Vector (TExp n1) a = take v v2 :: Vector (TExp n1) a = drop v diff --git a/src/bluesim/bs_prim_ops.h b/src/bluesim/bs_prim_ops.h index 08e3d1fd7..2ed2ea9d4 100644 --- a/src/bluesim/bs_prim_ops.h +++ b/src/bluesim/bs_prim_ops.h @@ -1654,7 +1654,7 @@ static inline void wop_primExtractWide(unsigned int dst_sz, static inline void wop_primExtractWide(unsigned int dst_sz, unsigned int src_sz, - tUWide & src, + const tUWide & src, unsigned int high_sz, unsigned int high, unsigned int low_sz, unsigned int low, tUWide &dst) diff --git a/src/bluesim/bs_wide_data.h b/src/bluesim/bs_wide_data.h index 2c056b3f7..dd4496fa8 100644 --- a/src/bluesim/bs_wide_data.h +++ b/src/bluesim/bs_wide_data.h @@ -102,7 +102,7 @@ class WideData unsigned int extract32(unsigned int hi, unsigned int lo) const; unsigned long long extract64(unsigned int hi, unsigned int lo) const; WideData extractWide(unsigned int hi, unsigned int lo) const; - void wop_extractWide(unsigned int hi, unsigned int lo, WideData& result); + void wop_extractWide(unsigned int hi, unsigned int lo, WideData& result) const; void clear(unsigned int from = 0); void clear(unsigned int from, unsigned int to); void set(unsigned int from = 0); diff --git a/src/bluesim/wide_data.cxx b/src/bluesim/wide_data.cxx index f718ce233..f30f1169c 100644 --- a/src/bluesim/wide_data.cxx +++ b/src/bluesim/wide_data.cxx @@ -1755,7 +1755,7 @@ void wop_rem(const WideData& v1, const WideData& v2, WideData &result) /*** function calls ***/ /* maybe useful */ -void WideData::wop_extractWide(uint hi, uint lo, WideData& result) +void WideData::wop_extractWide(uint hi, uint lo, WideData& result) const { copy_bits_to_0(result.data, data, lo, (hi-lo+1)); clear_bits(result.data, (hi-lo+1), (result.numWords() * WORD_SIZE) - 1); diff --git a/src/comp/AAddScheduleDefs.hs b/src/comp/AAddScheduleDefs.hs index 44449a2ed..d90ae6e8a 100644 --- a/src/comp/AAddScheduleDefs.hs +++ b/src/comp/AAddScheduleDefs.hs @@ -105,12 +105,12 @@ aAddScheduleDefs flags pps pkg aschedinfo = -- The ExprMaps map from a method name (not RDY) to the expression -- for that method's ready or enable condition. let pre_rdy_map = M.fromList $ - [ (dropReadyPrefixId (aIfaceName m), adef_expr (aif_value m)) + [ (dropReadyPrefixId (aif_name m), adef_expr $ aif_value m) | m <- ifc0 - , isRdyId (aIfaceName m) + , isRdyId (aif_name m) ] pre_en_map = M.fromList $ - [ (aIfaceName m, e) + [ (aif_name m, e) | m <- ifc0 , (Just e) <- [getMethodEnExpr m] ] @@ -280,11 +280,11 @@ mkIfcWFs _ _ _ = [] -- ignore RDY methods, clocks, resets, inouts -- Get the map from a method to its rule names (or def name, for value method) buildRuleMap :: AIFace -> Maybe (Id, [Id]) buildRuleMap m@(AIAction {}) = - Just (aIfaceName m, map aRuleName (aIfaceRules m)) + Just (aif_name m, map aRuleName (aIfaceRules m)) buildRuleMap m@(AIActionValue {}) = - Just (aIfaceName m, map aRuleName (aIfaceRules m)) + Just (aif_name m, map aRuleName (aIfaceRules m)) buildRuleMap m@(AIDef { aif_name = mid }) | not (isRdyId mid) = - Just (mid, [aIfaceName m]) + Just (mid, [aif_name m]) buildRuleMap _ = Nothing -- Replace the value in a RDY method diff --git a/src/comp/ACheck.hs b/src/comp/ACheck.hs index f42553812..cc044f850 100644 --- a/src/comp/ACheck.hs +++ b/src/comp/ACheck.hs @@ -422,6 +422,8 @@ checkUse :: S.Set AId -> S.Set AId -> S.Set AId -> AExpr -> [AId] checkUse ds is ps (APrim _ _ _ es) = checkUses ds is ps es checkUse ds is ps (AMethCall _ i m es) = checkUses ds is ps es -- XXX check i and m ? checkUse ds is ps (AMethValue _ i m) = [] -- XXX check i and m ? +checkUse ds is ps (ATuple _ es) = checkUses ds is ps es +checkUse ds is ps (ATupleSel _ e _) = checkUse ds is ps e checkUse ds is ps (ANoInlineFunCall _ _ _ es) = checkUses ds is ps es checkUse ds is ps (AFunCall { ae_args = es }) = checkUses ds is ps es -- because all of the expressions used are used by the ATaskAction diff --git a/src/comp/AConv.hs b/src/comp/AConv.hs index 2ea42a585..9259beccd 100644 --- a/src/comp/AConv.hs +++ b/src/comp/AConv.hs @@ -13,8 +13,8 @@ import Id import FStringCompat import Flags(Flags) import PreStrings(sSigned) -import PreIds(idBit, idAVAction_, idAVValue_, idClockOsc, idClockGate, - idInout_, idPrimArray) +import PreIds(idBit, idActionValue_, idAVAction_, idAVValue_, idClockOsc, idClockGate, + idInout_, idPrimArray, idPrimPair, idPrimFst, idPrimSnd, idPrimUnit) import Pragma import Error(internalError, EMsg, WMsg, ErrMsg(..), ErrorHandle, bsError, bsWarning) @@ -28,7 +28,6 @@ import GenWrapUtils(isGenId, dropGenSuffixId) import Prim import Data.List(genericLength, nub) import Data.Maybe(fromMaybe) -import CType(TISort(..), StructSubType(..)) import VModInfo(lookupOutputClockWires, lookupOutputResetWire, lookupIfcInoutWire, vArgs, VArgInfo(..)) import SignalNaming @@ -187,18 +186,18 @@ aDo imod@(IModule mi fmod be wi ps iks its clks rsts itvs pts idefs rs ifc ffcal flags <- getFlags -- AVInst keeps the types of method ports - let tsConv :: Id -> [IType] -> ([AType], Maybe AType, Maybe AType) + let tsConv :: Id -> [IType] -> ([AType], Maybe AType, [AType]) tsConv i ts = let inputs = initOrErr "tsConv" ts res = lastOrErr "tsConv" ts in_types = map (aTypeConv i) inputs (en_type, val_type) - | isitActionValue_ res && getAV_Size res > 0 - = (Just (ATBit 1), Just (ATBit (getAV_Size res))) + | isitActionValue_ res + = (Just (ATBit 1), aTupleTypesConv i (getAV_Type res)) | isActionType res - = (Just (ATBit 1), Nothing) + = (Just (ATBit 1), []) | otherwise - = (Nothing, Just (aTypeConv i res)) + = (Nothing, aTupleTypesConv i res) in (in_types, en_type, val_type) let (IRules sps irule_list) = rs @@ -366,9 +365,7 @@ aIface flags iface@(IEFace i its maybe_e maybe_rs wp fi) = do ++ ppReadable iface) | otherwise -> do - -- internal error if type actionvalue XXX ae <- aExpr e - --trace ("exit v " ++ ppReadable i) $ return () return (AIDef i its' wp g (ADef i (aTypeConv i t) ae []) fi []) (Nothing, Just rs) -> do @@ -507,69 +504,22 @@ aExpr (IAps (ICon i (ICSel { })) ts (e:es)) = internalError ("aExpr: too many arguments to avValue_: " ++ ppReadable es) --- value part of ActionValue task without arguments -aExpr e@(IAps (ICon m (ICSel { })) _ - [(ICon i (ICForeign {fName = name, - isC = isC, - foports = Nothing, - fcallNo = mn}))]) - | m == idAVValue_ = - let n = case (mn) of - Nothing -> internalError - ("aExpr: avValue_ on ICForeign without fcallNo") - Just val -> val - t = aTypeConvE e (iGetType e) - in - return (ATaskValue t i name isC n) +aExpr e@(IAps (ICon _ (ICSel {})) _ _) = aSelExpr sels selExpr + where + (sels, selExpr) = unfoldICSel e + + unfoldICSel :: IExpr a -> ([(Id, AType)], [IExpr a]) + unfoldICSel e@(IAps (ICon i (ICSel {})) _ [e']) = + let (sels, a) = unfoldICSel e' + in ((i, aTypeConvE e $ iGetType e) : sels, a) + unfoldICSel e@(IAps (ICon i (ICSel {})) _ a@(_:_)) = + ([(i, aTypeConvE e $ iGetType e)], a) + -- a selector is always applied to at least its object operand + unfoldICSel e@(IAps (ICon _ (ICSel {})) _ []) = + internalError ("AConv.unfoldICSel: ICSel applied to no arguments:\n" ++ + ppReadable e) + unfoldICSel e = ([], [e]) --- value part of ActionValue task with arguments -aExpr e@(IAps (ICon m (ICSel { })) _ - [(IAps (ICon i (ICForeign {fName = name, - isC = isC, - foports = Nothing, - fcallNo = mn})) fts fes)]) - | m == idAVValue_ = - let n = case (mn) of - Nothing -> internalError - ("aExpr: avValue_ on ICForeign without fcallNo") - Just val -> val - t = aTypeConvE e (iGetType e) - in - -- the value side carries no arguments - -- the cookie "n" will connect it back up to the action side - return (ATaskValue t i name isC n) - --- value part of ActionValue method -aExpr e@(IAps (ICon sel_id (ICSel { })) ts - [(IAps (ICon m (ICSel { })) _ (ICon i (ICStateVar { }) : es))]) - | (sel_id == idAVValue_) = do - i' <- transId i - let atype = aTypeConvE e (iGetType e) - -- arguments should have been dropped in IExpand - when (not (null es)) $ - internalError ("AConv.aExpr actionvalue value with args " ++ - ppReadable e) - -- IExpand is failing to optimize away bit-zero results from methods - -- and foreign functions, so catch that here for ActionValue methods - return $ if (atype == aTZero) - then ASInt i (ATBit 0) (ilDec 0) - else AMethValue atype i' m - --- value method -aExpr e@(IAps (ICon m (ICSel { })) _ (ICon i (ICStateVar { }) : es)) = do - i' <- transId i - let atype = aTypeConvE e (iGetType e) - es' <- mapM aSExpr es - return $ AMethCall atype i' m es' - -aExpr e@(IAps (ICon m (ICSel { })) _ [(ICon i (ICClock { iClock = c }))]) | m == idClockGate = do - ac <- aClock c - return (aclock_gate ac) --- XXX This is here because aClock calls aSExpr on the oscillator. However, --- XXX that should be the only place where an osc ever appears in an expr. -aExpr e@(IAps (ICon m (ICSel { })) _ [(ICon i (ICClock { iClock = c }))]) | m == idClockOsc = do - ac <- aClock c - return (aclock_osc ac) aExpr (IAps (ICon _ (ICCon { iConType = ITAp _ t, conTagInfo = cti })) _ _) | t == itBit1 = return $ aSBool (conNo cti /= 0) aExpr e@(IAps (ICon i (ICForeign { fName = name, isC = isC, foports = Nothing})) ts es) = do @@ -593,6 +543,11 @@ aExpr e@(IAps (ICon i (ICForeign { fName = name, isC = False, foports = (Just op return $ ANoInlineFunCall t i' (ANoInlineFun name ns ops Nothing) es' +aExpr e@(IAps (ICon i _) _ _) | i == idPrimPair = do + let at = aTypeConvE e (iGetType e) + aes <- aTupleExpr e + return (ATuple at aes) + aExpr e@(ICon v (ICModPort { iConType = t })) = return (ASPort (aTypeConvE e t) v) aExpr e@(ICon v (ICModParam { iConType = t })) = return (ASParam (aTypeConvE e t) v) aExpr e@(ICon v (ICMethArg { iConType = t })) = return (ASPort (aTypeConvE e t) v) @@ -638,11 +593,110 @@ aExpr e@(ICon _ (ICInout { iConType = it, iInout = i})) | (isitInout_ it) = do ai <- aInout i return (ASInout at ai) +aExpr (ICon i _) | i == idPrimUnit = return $ ASInt i (ATBit 0) (ilDec 0) + aExpr e = internalError ("AConv.aExpr at " ++ ppString p ++ ":" ++ ppReadable e ++ "\n" ++ (show p) ++ ":" ++ (showTypeless e)) where p = getIExprPosition e +aTupleExpr :: IExpr a -> M [AExpr] +aTupleExpr (IAps (ICon i _) [t1, t2] [e1, e2]) | i == idPrimPair = do + ae1 <- aSExpr e1 + ae2 <- aTupleExpr e2 + return (ae1:ae2) +aTupleExpr e = fmap (:[]) (aSExpr e) + +-- the PrimFst/PrimSnd selectors that project an element out of a +-- tuple-returning method's result +isTupleSelector :: Id -> Bool +isTupleSelector s = s == idPrimFst || s == idPrimSnd + +aSelExpr :: [(Id, AType)] -> [IExpr a] -> M AExpr + +-- value part of ActionValue task without arguments +aSelExpr [(m, t)] [(ICon i (ICForeign {fName = name, + isC = isC, + foports = Nothing, + fcallNo = mn}))] + | m == idAVValue_ = + let n = case (mn) of + Nothing -> internalError + ("aExpr: avValue_ on ICForeign without fcallNo") + Just val -> val + in + return (ATaskValue t i name isC n) + +-- value part of ActionValue task with arguments +aSelExpr [(m, t)] [(IAps (ICon i (ICForeign {fName = name, + isC = isC, + foports = Nothing, + fcallNo = mn})) fts fes)] + | m == idAVValue_ = + let n = case (mn) of + Nothing -> internalError + ("aExpr: avValue_ on ICForeign without fcallNo") + Just val -> val + in + -- the value side carries no arguments + -- the cookie "n" will connect it back up to the action side + return (ATaskValue t i name isC n) + +-- A port selected (via PrimFst/PrimSnd) from a value method that returns a +-- tuple. The value method still carries its arguments. The number of PrimSnd +-- selectors skipped to reach the method is the 0-based output port index. +aSelExpr sels (ICon i (ICStateVar { }) : es) + | (pfx@((_, atype) : _), [(m, atypeTup)]) <- span (isTupleSelector . fst) sels = do + i' <- transId i + es' <- mapM aSExpr es + let idx = toInteger $ length (filter ((== idPrimSnd) . fst) pfx) + return $ ATupleSel atype (AMethCall atypeTup i' m es') (idx + 1) + +-- The value part of an ActionValue method, either bare or with a port selected +-- (via PrimFst/PrimSnd) from a tuple-returning method. The arguments were +-- dropped in IExpand, so none should remain. When there are leading +-- PrimFst/PrimSnd selectors, the number of PrimSnd selectors is the 0-based +-- output port index. +aSelExpr sels base@(ICon i (ICStateVar { }) : es) + | (pfx, [(iav, atypeTup), (m, _)]) <- span (isTupleSelector . fst) sels + , iav == idAVValue_ = do + i' <- transId i + when (not (null es)) $ + internalError ("AConv.aExpr actionvalue value with args " ++ + ppReadable sels ++ "\n" ++ ppReadable base) + let meth = AMethValue atypeTup i' m + case pfx of + -- bare ActionValue output. + -- IExpand is failing to optimize away bit-zero results from methods + -- and foreign functions, so catch that here for ActionValue methods. + [] -> return $ if (atypeTup == aTZero) + then ASInt i (ATBit 0) (ilDec 0) + else meth + -- a port selected from a tuple-returning ActionValue method + ((_, atype) : _) -> do + let idx = toInteger $ length (filter ((== idPrimSnd) . fst) pfx) + return $ ATupleSel atype meth (idx + 1) + +-- value method +aSelExpr [(m, atype)] (ICon i (ICStateVar { }) : es) = do + i' <- transId i + es' <- mapM aSExpr es + return $ AMethCall atype i' m es' + +aSelExpr [(m, _)] [ICon i (ICClock { iClock = c })] | m == idClockGate = do + ac <- aClock c + return (aclock_gate ac) +-- XXX This is here because aClock calls aSExpr on the oscillator. However, +-- XXX that should be the only place where an osc ever appears in an expr. +aSelExpr [(m, _)] [ICon i (ICClock { iClock = c })] | m == idClockOsc = do + ac <- aClock c + return (aclock_osc ac) + +aSelExpr sels base = internalError + ("AConv.aSelExpr:" ++ + ppReadable sels ++ "\n" ++ ppReadable base) + + aEDef :: Id -> IExpr a -> [DefProp] -> M AExpr aEDef i e ps = do da <- getDA @@ -662,12 +716,14 @@ aTypeConv _ (ITAp (ITCon i _ _) (ITNum n)) | i == idInout_ = ATAbstract idInout_ aTypeConv a (ITAp (ITCon r _ _) elem_ty) | r == idPrimArray = -- no way to get the size internalError("aTypeConv: array: " ++ ppReadable a) +aTypeConv a t@(ITAp (ITAp (ITCon p _ _) _) _) | p == idPrimPair = + ATTuple (aTupleTypesConv a t) aTypeConv _ t | t == itReal = ATReal aTypeConv _ t | t == itString = ATString Nothing -- Deal with AVs -aTypeConv _ (ITAp (ITCon i t (TIstruct SStruct fs@(val:_))) (ITNum n)) = - ATBit n - -- internalError ("Yes\n\n" ++ (show a) ++"\n\n" ++ (show n)) +aTypeConv a (ITAp (ITCon i _ _) t) | i == idActionValue_ = + aTypeConv a t +aTypeConv a (ITCon i _ _) | i == idPrimUnit = ATBit 0 aTypeConv _ t = abs t [] where abs (ITCon i _ _) ns = ATAbstract i (reverse ns) abs (ITAp t _) ns = abs t ns @@ -684,17 +740,25 @@ aTypeConvE a (ITAp (ITCon r _ _) elem_ty) | r == idPrimArray = -- XXX we could examine the expression and find the type -- XXX but this func isn't used to get the type of PrimBuildArray internalError ("aTypeConv: array: " ++ ppReadable a) +aTypeConvE _ t@(ITAp (ITAp (ITCon p _ _) _) _) | p == idPrimPair = + ATTuple (aTupleTypesConv p t) aTypeConvE a t | t == itReal = ATReal aTypeConvE a t | t == itString = case a of (ICon _ (ICString _ s)) -> ATString (Just (genericLength s)) otherwise -> ATString Nothing +aTypeConvE a (ITCon i _ _) | i == idPrimUnit = ATBit 0 aTypeConvE a t = abs t [] where abs (ITCon i _ _) ns = ATAbstract i (reverse ns) abs (ITAp t _) ns = abs t ns abs _ _ = -- ATAbstract idBit [] -- XXX what's this internalError ("aTypeConvE|" ++ show t) +aTupleTypesConv :: Id -> IType -> [AType] +aTupleTypesConv a (ITAp (ITAp (ITCon p _ _) t1) t2) | p == idPrimPair = + aTypeConv a t1 : aTupleTypesConv a t2 +aTupleTypesConv a t = [aTypeConv a t] + realPrim :: PrimOp -> Bool realPrim p = p `elem` [ diff --git a/src/comp/ADropUndet.hs b/src/comp/ADropUndet.hs index 2e9a0fb9f..fd764c4e1 100644 --- a/src/comp/ADropUndet.hs +++ b/src/comp/ADropUndet.hs @@ -100,6 +100,8 @@ hasNoActionValue :: M.Map AId Bool -> AExpr -> Bool hasNoActionValue avm (APrim { ae_args = es }) = all (hasNoActionValue avm) es hasNoActionValue avm (AMethCall { ae_args = es }) = all (hasNoActionValue avm) es hasNoActionValue avm (AMethValue {}) = False +hasNoActionValue avm (ATuple _ es) = all (hasNoActionValue avm) es +hasNoActionValue avm (ATupleSel { ae_exp = e }) = hasNoActionValue avm e hasNoActionValue avm (ANoInlineFunCall { ae_args = es }) = all (hasNoActionValue avm) es hasNoActionValue avm (AFunCall { ae_args = es }) = all (hasNoActionValue avm) es hasNoActionValue avm (ATaskValue {}) = False diff --git a/src/comp/ADumpSchedule.hs b/src/comp/ADumpSchedule.hs index ab6ecd630..5f0c59dda 100644 --- a/src/comp/ADumpSchedule.hs +++ b/src/comp/ADumpSchedule.hs @@ -322,7 +322,7 @@ genMethodDumpMap vSchedInfo ifc = methodDumpMap -- don't include output clocks and resets -- don't include ready Ids methodList = filter (not . isRdyId) $ - map aIfaceName (aIfaceMethods ifc) + map aif_name (aIfaceMethods ifc) methodRdys = [(mn, p) | (AIDef { aif_name = mn, aif_value = (ADef _ _ p _) }) <- ifc, isRdyId mn] methodDumpMap = [ (mid, p, clist) diff --git a/src/comp/AExpand.hs b/src/comp/AExpand.hs index 7f3227c5d..8b00f678d 100644 --- a/src/comp/AExpand.hs +++ b/src/comp/AExpand.hs @@ -458,6 +458,8 @@ isSimple c (APrim i t PrimConcat es) = c && all (is isSimple c e@(APrim _ _ p es) = c && isSmall e && cheap p es -- && all (isSimple c) es isSimple c (AMethCall _ _ _ es) = null es isSimple c (AMethValue _ _ _) = True +isSimple c (ATupleSel _ e _) = isSimple c e +isSimple c (ATuple _ es) = all (isSimple c) es -- foreign function calls cannot be inlined -- (except for $signed and $unsigned - handled by mustInline) isSimple c e@(AFunCall { }) = False @@ -537,6 +539,13 @@ getExprSize (APrim _ _ _ es) = (nub $ concat vars, sum terms, 1 + maximum depths getExprSize (AMethCall t i mid args) = ([mid],1,1) getExprSize (AMethValue t i mid) = ([mid],1,1) +-- Tuple construction and selection only appear at port boundaries, where they +-- pack/unpack a method's output port values. They are pure wiring and generate +-- no logic, so (like PrimBNot/PrimInv above) they add no terms or depth: the +-- size is just that of the underlying expression(s). +getExprSize (ATupleSel t e i) = getExprSize e +getExprSize (ATuple t es) = (nub $ concat vars, sum terms, maximum depths) + where (vars,terms,depths) = unzip3 $ map getExprSize es getExprSize (ATaskValue { }) = ([], 1,1) getExprSize (ASPort t i) = ([i], 1,1) getExprSize (ASParam t i) = ([i], 1,1) diff --git a/src/comp/AExpr2STP.hs b/src/comp/AExpr2STP.hs index ce45f26cd..ef9309577 100644 --- a/src/comp/AExpr2STP.hs +++ b/src/comp/AExpr2STP.hs @@ -32,7 +32,7 @@ import PFPrint import Util(itos, map_insertMany, makePairs) import TopUtils(withElapsed) -import AExpr2Util(getMethodOutputPort) +import AExpr2Util(getSingleMethodOutputPort, getMethodOutputPortAt) import Debug.Trace(traceM) import IOUtil(progArgs) @@ -579,21 +579,29 @@ convAExpr2SExpr mty (APrim i (ATBit width) p args) = do -- Method calls create independent variables, with given width -- XXX Passing the current context is just a heuristic -- XXX TODO: some methods calls may be mutex, such as FIFO.full and FIFO.empty +-- A bare AMethCall/AMethValue (with no ATupleSel applied) refers to a method +-- with a single output port; a method with multiple output ports is always +-- wrapped in an ATupleSel selecting one of them (handled in the arms below). +-- Reaching the internalError here would mean a multi-output method was used +-- without selecting a port. +-- the port helpers canonicalize to the actual port name, so that methods which +-- share the same output port appear logically equivalent +-- XXX These could be unevaluated functions, applied to converted arguments convAExpr2SExpr mty (AMethCall ty@(ATBit width) modId methId args) = do - -- get the actual port name, so that methods which share the same output port - -- will appear logically equivalent smap <- gets stateMap - let portId = getMethodOutputPort smap modId methId - e = (AMethCall ty modId portId args) - -- XXX This could be an unevaluated function, applied to converted arguments + let e = AMethCall ty modId (getSingleMethodOutputPort smap modId methId) args addUnknownExpr mty e width convAExpr2SExpr mty (AMethValue ty@(ATBit width) modId methId) = do - -- get the actual port name, so that methods which share the same output port - -- will appear logically equivalent smap <- gets stateMap - let portId = getMethodOutputPort smap modId methId - e = (AMethValue ty modId portId) - -- XXX This could be an unevaluated function, applied to converted arguments + let e = AMethValue ty modId (getSingleMethodOutputPort smap modId methId) + addUnknownExpr mty e width +convAExpr2SExpr mty (ATupleSel ty@(ATBit width) (AMethCall _ modId methId args) selIdx) = do + smap <- gets stateMap + let e = AMethCall ty modId (getMethodOutputPortAt smap modId methId selIdx) args + addUnknownExpr mty e width +convAExpr2SExpr mty (ATupleSel ty@(ATBit width) (AMethValue _ modId methId) selIdx) = do + smap <- gets stateMap + let e = AMethValue ty modId (getMethodOutputPortAt smap modId methId selIdx) addUnknownExpr mty e width convAExpr2SExpr mty e@(AMGate (ATBit 1) _ _) = diff --git a/src/comp/AExpr2Util.hs b/src/comp/AExpr2Util.hs index 104a25735..3f8111775 100644 --- a/src/comp/AExpr2Util.hs +++ b/src/comp/AExpr2Util.hs @@ -1,11 +1,13 @@ -- Common code used by various converters module AExpr2Util( - getMethodOutputPort + getMethodOutputPorts, + getSingleMethodOutputPort, + getMethodOutputPortAt ) where import qualified Data.Map as M -import Data.List(find) +import Data.List(find, genericIndex) import ErrorUtil(internalError) import PPrint @@ -32,8 +34,8 @@ import VModInfo(VModInfo(..), VFieldInfo(..), vName_to_id) -- XXX we can replace them with an unevaluated function applied to its arguments! -- XXX That way, the SMT solver will handle any equivalence of the arguments. -getMethodOutputPort :: (M.Map AId VModInfo) -> AId -> AId -> AId -getMethodOutputPort stateMap modId methId = +getMethodOutputPorts :: (M.Map AId VModInfo) -> AId -> AId -> [AId] +getMethodOutputPorts stateMap modId methId = let mod_err = internalError("canonMethCalls: module not found: " ++ ppReadable modId) fields = vFields $ M.findWithDefault mod_err modId stateMap @@ -41,14 +43,28 @@ getMethodOutputPort stateMap modId methId = ppReadable (modId, methId)) findFn (Method { vf_name = i }) = qualEq i methId findFn _ = False - mport = case (find findFn fields) of - Just (Method { vf_output = mo }) -> mo + ports = case (find findFn fields) of + Just (Method { vf_outputs = os }) -> os _ -> meth_err out_err = internalError("canonMethCalls: method has no output: " ++ ppReadable (modId, methId)) - in case mport of - Just (vn,_) -> vName_to_id vn - _ -> out_err + in if null ports then out_err else map (vName_to_id . fst) ports + +-- A bare method reference (with no tuple selection) refers to a method with a +-- single output port. Return that (canonical) port, failing if the method has +-- multiple output ports (those must be reached through a tuple selector). +getSingleMethodOutputPort :: (M.Map AId VModInfo) -> AId -> AId -> AId +getSingleMethodOutputPort stateMap modId methId = + case getMethodOutputPorts stateMap modId methId of + [portId] -> portId + ports -> internalError ("getSingleMethodOutputPort: unexpected output ports: " ++ + ppReadable (modId, methId, ports)) + +-- The output port at the given tuple-selector index, for a method whose result +-- is split across multiple output ports. +getMethodOutputPortAt :: (M.Map AId VModInfo) -> AId -> AId -> Integer -> AId +getMethodOutputPortAt stateMap modId methId selIdx = + getMethodOutputPorts stateMap modId methId `genericIndex` selIdx -- ------------------------- diff --git a/src/comp/AExpr2Yices.hs b/src/comp/AExpr2Yices.hs index b621930e0..2a8f8700e 100644 --- a/src/comp/AExpr2Yices.hs +++ b/src/comp/AExpr2Yices.hs @@ -30,7 +30,7 @@ import VModInfo(VModInfo) import PFPrint import Util(itos, map_insertMany, makePairs) import TopUtils(withElapsed) -import AExpr2Util(getMethodOutputPort) +import AExpr2Util(getSingleMethodOutputPort, getMethodOutputPortAt) import Debug.Trace(traceM) import IOUtil(progArgs) @@ -583,20 +583,29 @@ convAExpr2YExpr mty (APrim i (ATBit width) p args) = do -- Method calls create independent variables, with given width -- XXX Passing the current context is just a heuristic -- XXX TODO: some methods calls may be mutex, such as FIFO.full and FIFO.empty +-- A bare AMethCall/AMethValue (with no ATupleSel applied) refers to a method +-- with a single output port; a method with multiple output ports is always +-- wrapped in an ATupleSel selecting one of them (handled in the arms below). +-- Reaching the internalError here would mean a multi-output method was used +-- without selecting a port. +-- the port helpers canonicalize to the actual port name, so that methods which +-- share the same output port appear logically equivalent +-- XXX These could be unevaluated functions, applied to converted arguments convAExpr2YExpr mty (AMethCall ty@(ATBit width) modId methId args) = do - -- get the actual port name, so that methods which share the same output port - -- will appear logically equivalent smap <- gets stateMap - let portId = getMethodOutputPort smap modId methId - e = (AMethCall ty modId portId args) - -- XXX This could be an unevaluated function, applied to converted arguments + let e = AMethCall ty modId (getSingleMethodOutputPort smap modId methId) args addUnknownExpr mty e width convAExpr2YExpr mty (AMethValue ty@(ATBit width) modId methId) = do - -- get the actual port name, so that methods which share the same output port - -- will appear logically equivalent smap <- gets stateMap - let portId = getMethodOutputPort smap modId methId - e = (AMethValue ty modId portId) + let e = AMethValue ty modId (getSingleMethodOutputPort smap modId methId) + addUnknownExpr mty e width +convAExpr2YExpr mty (ATupleSel ty@(ATBit width) (AMethCall _ modId methId args) selIdx) = do + smap <- gets stateMap + let e = AMethCall ty modId (getMethodOutputPortAt smap modId methId selIdx) args + addUnknownExpr mty e width +convAExpr2YExpr mty (ATupleSel ty@(ATBit width) (AMethValue _ modId methId) selIdx) = do + smap <- gets stateMap + let e = AMethValue ty modId (getMethodOutputPortAt smap modId methId selIdx) addUnknownExpr mty e width convAExpr2YExpr mty e@(AMGate (ATBit 1) _ _) = diff --git a/src/comp/ANoInline.hs b/src/comp/ANoInline.hs index 4cee039c9..8b5449fed 100644 --- a/src/comp/ANoInline.hs +++ b/src/comp/ANoInline.hs @@ -157,7 +157,7 @@ liftAExpr True (ANoInlineFunCall t i f es) = do liftAExpr _ (APrim aid ty op es) = do es' <- mapM (liftAExpr False) es return $ APrim aid ty op es' -liftAExpr _ (AMethCall ty aid mid es) = do +liftAExpr _ (AMethCall ty aid mid es) = do es' <- mapM (liftAExpr False) es return $ AMethCall ty aid mid es' liftAExpr _ (AFunCall ty aid fun isC es) = do diff --git a/src/comp/APaths.hs b/src/comp/APaths.hs index 4b6e9bc64..5b761890e 100644 --- a/src/comp/APaths.hs +++ b/src/comp/APaths.hs @@ -116,7 +116,7 @@ import VModInfo(vPath, vFields, vArgs, import Pragma import Control.Monad(when) import Data.Maybe(isJust, isNothing, fromJust) -import Data.List(partition) +import Data.List(partition, genericIndex) import Id(unQualId, getIdBaseString) import Eval import Position(getPosition) @@ -170,8 +170,8 @@ data PathNode = PNDef AId | -- arguments to methods of submodules (Ids: instance, method, arg #) PNStateMethodArg AId AId Integer | - -- return values of methods of submodules (Ids: instance, method) - PNStateMethodRes AId AId | + -- return values of methods of submodules (Ids: instance, method, result #) + PNStateMethodRes AId AId Integer | -- enable signal of action methods of submodules (Ids: instance, method) PNStateMethodEnable AId AId | -- imported state has no ready signal @@ -190,8 +190,8 @@ data PathNode = PNWillFire AId | -- arguments to methods of current module (Ids: method, argument) PNTopMethodArg AId AId | - -- return values of methods of current module (Id: method) - PNTopMethodRes AId | + -- return values of methods of current module (Ids: method, result #) + PNTopMethodRes AId Integer | -- this is an internal graph node for the method's ready signal, -- the real output port is handled by a separate read method -- (Id: method) @@ -228,8 +228,8 @@ printPathNode use_pvprint d p node = fsep [text "Argument", pp port_id, s2par "of method", quotes (pp meth_id), s2par "of submodule", quotes (pp inst_id)] - (PNStateMethodRes inst_id meth_id) -> - fsep [s2par "Return value", + (PNStateMethodRes inst_id meth_id port_id) -> + fsep [s2par "Return value", pp port_id, s2par "of method", quotes (pp meth_id), s2par "of submodule", quotes (pp inst_id)] (PNStateMethodEnable inst_id meth_id) -> @@ -255,8 +255,8 @@ printPathNode use_pvprint d p node = (PNTopMethodArg meth_id arg_id) -> fsep [text "Argument", pp arg_id, s2par "of top-level method", quotes (pp meth_id)] - (PNTopMethodRes meth_id) -> - fsep [text "Output", + (PNTopMethodRes meth_id res_num) -> + fsep [text "Output", pp res_num, s2par "of top-level method", quotes (pp meth_id)] (PNTopMethodReady meth_id) -> fsep [s2par "Ready condition", @@ -290,14 +290,14 @@ instance PVPrint PathNode where instance NFData PathNode where rnf (PNDef aid) = rnf aid rnf (PNStateMethodArg a1 a2 n) = rnf3 a1 a2 n - rnf (PNStateMethodRes a1 a2) = rnf2 a1 a2 + rnf (PNStateMethodRes a1 a2 n) = rnf3 a1 a2 n rnf (PNStateMethodEnable a1 a2) = rnf2 a1 a2 rnf (PNStateArgument aid vn n) = rnf3 aid vn n rnf (PNStateMethodArgMux a1 a2) = rnf2 a1 a2 rnf (PNCanFire aid) = rnf aid rnf (PNWillFire aid) = rnf aid rnf (PNTopMethodArg a1 a2) = rnf2 a1 a2 - rnf (PNTopMethodRes aid) = rnf aid + rnf (PNTopMethodRes aid n) = rnf2 aid n rnf (PNTopMethodReady aid) = rnf aid rnf (PNTopMethodEnable aid) = rnf aid rnf (PNTopArgument aid n) = rnf2 aid n @@ -314,7 +314,7 @@ filterPNDefs pns = filter (not . isPNDef) pns isPNDef _ = False alwaysRdyNode :: [PProp] -> PathNode -> Bool -alwaysRdyNode pps (PNTopMethodRes m) = isAlwaysRdy pps m +alwaysRdyNode pps (PNTopMethodRes m _) = isAlwaysRdy pps m alwaysRdyNode pps _ = False enWhenRdyNode :: [PProp] -> PathNode -> Bool @@ -475,13 +475,13 @@ aPathsPreSched errh flags apkg = do -- 1) method name -- 2) input argument list zipped with [1..] -- 3) (Maybe VName) if method has an enable signal (action method) - -- 4) (Maybe VName) if method has a result (now only value methods) + -- 4) result list zipped with [1..] (value methods only) -- 5) (Maybe Id) if method has an associated clock -- Note: the VPort's are stripped of VeriPortProp to be just VName -- XXX is the VeriPortProp info worth keeping? state_instances :: [ ( AId, [(VName, VName)], [(VName, Integer, AExpr)], - [(AId, [(VName,Integer)], Maybe VName, Maybe VName, Maybe AId)] ) ] + [(AId, [(VName,Integer)], Maybe VName, [(VName, Integer)], Maybe AId)] ) ] state_instances = [(inst_id, nns, args, meth_info) | avi <- vs, @@ -498,12 +498,13 @@ aPathsPreSched errh flags apkg = do -- method info let meth_info = - [(meth_id, numbered_args, maybe_EN, maybe_res, maybe_clk) | + [(meth_id, numbered_args, maybe_EN, numbered_res, maybe_clk) | vfieldinfo@(Method { vf_name = meth_id }) <- vFields vmi, let args = map fst (vf_inputs vfieldinfo), let numbered_args = zip args [1..], let maybe_EN = (vf_enable vfieldinfo) >>= return . fst, - let maybe_res = (vf_output vfieldinfo) >>= return . fst, + let res = (vf_outputs vfieldinfo) >>= return . fst, + let numbered_res = zip res [1..], let maybe_clk = vf_clock vfieldinfo ] ] @@ -511,13 +512,14 @@ aPathsPreSched errh flags apkg = do state_input_nodes = [ PNStateMethodArg inst_id meth_id arg_num | (inst_id, _, _, methods) <- state_instances, - (meth_id, numbered_args, maybe_EN, maybe_res, _) <- methods, + (meth_id, numbered_args, maybe_EN, _, _) <- methods, arg_num <- map snd numbered_args ] state_output_nodes = - [ PNStateMethodRes inst_id meth_id | + [ PNStateMethodRes inst_id meth_id res_num | (inst_id, _, _, methods) <- state_instances, - (meth_id, _, _, Just res_name, _) <- methods + (meth_id, _, _, numbered_res, _) <- methods, + res_num <- map snd numbered_res ] state_enable_nodes = [ PNStateMethodEnable inst_id meth_id | @@ -558,7 +560,7 @@ aPathsPreSched errh flags apkg = do let method_inputs = [(arg, PNTopMethodArg m arg) | (AIDef { aif_inputs = args, - aif_value = (ADef m _ _ _) }) <- ifc, + aif_name = m }) <- ifc, (arg,_) <- args] ++ [(arg, PNTopMethodArg m arg) | (AIAction { aif_inputs = args, aif_name = m }) <- ifc, @@ -567,9 +569,14 @@ aPathsPreSched errh flags apkg = do aif_name = m }) <- ifc, (arg,_) <- args] + num_outputs (ADef {adef_type = ATTuple ts}) = fromIntegral (length ts) + num_outputs _ = 1 + method_outputs = - [(m, PNTopMethodRes m) | (AIDef { aif_value = (ADef m _ _ _) }) <- ifc] ++ - [(m, PNTopMethodRes m) | (AIActionValue { aif_name = m, aif_value = (ADef m' _ _ _) }) <- ifc] + [(m, PNTopMethodRes m res) | (AIDef { aif_name = m, aif_value = v }) <- ifc, + res <- [1..(num_outputs v)] ] ++ + [(m, PNTopMethodRes m res) | (AIActionValue { aif_name = m, aif_value = v }) <- ifc, + res <- [1..(num_outputs v)] ] method_enables = -- Name creation is safe, since it is based on VFieldInfo @@ -620,7 +627,7 @@ aPathsPreSched errh flags apkg = do -- These are internal graph nodes, not part of the interface. -- There are separate read methods which become the Verilog ports. - method_ready_nodes = map (PNTopMethodReady . aIfaceName) ifc + method_ready_nodes = map (PNTopMethodReady . aif_name) ifc -- ---------- @@ -683,17 +690,24 @@ aPathsPreSched errh flags apkg = do -- methods (ifc) let mkMethodEdges :: AIFace -> [(PathNode,PathNode)] - mkMethodEdges (AIDef mid inputs wp rdy (ADef m _ e _) _ _) = + mkMethodEdges (AIDef mid inputs wp rdy def@(ADef _ t e _) _ _) = -- connect the rdy expression (likely just an ASDef reference) -- to the internal graph node for the method ready - (mkEdges (PNTopMethodReady m) rdy env) ++ + (mkEdges (PNTopMethodReady mid) rdy env) ++ -- make faux connections from the rdy to the arguments, so that -- dependencies in the other direction are caught as loops - [(PNTopMethodReady m, PNTopMethodArg m arg) | (arg,_) <- inputs] ++ + [(PNTopMethodReady mid, PNTopMethodArg mid arg) | (arg,_) <- inputs] ++ + if length result_types /= length results + then internalError + ("APaths.aPathsPreSched: unexpected method results: " ++ ppReadable def) -- connect the definition to the method result -- (this method has no enable, so it cannot contribute to any -- methcall argument muxes, so just use "mkEdges") - (mkEdges (PNTopMethodRes m) e env) + else [edge | (res, e') <- zip [1..] results, edge <- mkEdges (PNTopMethodRes mid res) e' env] + where result_types | ATTuple ts <- t = ts + | otherwise = [t] + results | ATuple { ae_elems = elems } <- e = elems + | otherwise = [e] mkMethodEdges (AIAction inputs wp rdy m rs fi) = let rdy_node = PNTopMethodReady m en_node = PNTopMethodEnable m @@ -726,7 +740,7 @@ aPathsPreSched errh flags apkg = do -- connect the rules concatMap mkMRuleEdges rs - mkMethodEdges (AIActionValue inputs wp rdy m rs (ADef m' _ e _) fi) = + mkMethodEdges (AIActionValue inputs wp rdy m rs def@(ADef _ t e _) fi) = let rdy_node = PNTopMethodReady m en_node = PNTopMethodEnable m mkMRuleEdges (ARule ri _ _ _ rpred actions _ _) = @@ -748,6 +762,10 @@ aPathsPreSched errh flags apkg = do [(en_node, wf_node)] ++ -- add edges from rule WillFire to ENs in each action (concatMap (mkActionEdges env wf_node) actions) + result_types | ATTuple ts <- t = ts + | otherwise = [t] + results | ATuple { ae_elems = elems } <- e = elems + | otherwise = [e] in -- make faux connections from the rdy to the arguments and the -- enable, so that dependencies in the other direction are caught @@ -755,10 +773,14 @@ aPathsPreSched errh flags apkg = do [(rdy_node, en_node)] ++ [(rdy_node, PNTopMethodArg m arg) | (arg,_) <- inputs] ++ - -- connect the definition to the method result + (if length result_types /= length results + then internalError + ("APaths.aPathsPreSched: unexpected method results: " ++ ppReadable def) + -- connect the definitions to the method results -- (this method's Enable could contribute to methcall argument -- muxes, so use "mkEdgesWithMux") - (mkEdgesWithMux en_node (PNTopMethodRes m) e env) ++ + else [edge | (res, e') <- zip [1..] results, + edge <- (mkEdgesWithMux en_node (PNTopMethodRes m res) e' env)]) ++ -- connect the rules concatMap mkMRuleEdges rs @@ -788,9 +810,10 @@ aPathsPreSched errh flags apkg = do -- (but there are paths for instantiation arguments which become ports) let findOutputPathNodes inst_id vname methods = - [ (clk, PNStateMethodRes inst_id meth_id) | - (meth_id, _, _, Just res, clk) <- methods, - res == vname + [ (clk, PNStateMethodRes inst_id meth_id res_num) | + (meth_id, _, _, numbered_res, clk) <- methods, + (res_name, res_num) <- numbered_res, + res_name == vname ] findInputPathNodes inst_id vname methods argpairs = [ (Nothing, PNStateArgument inst_id arg_id arg_num) | @@ -885,7 +908,7 @@ aPathsPreSched errh flags apkg = do n <- filter (\x -> not (S.member x pathnodeset)) [n1,n2] ] when (not (null unknown_nodes)) $ internalError ("APath.aPaths': nodes not in graph: " ++ - show unknown_nodes) + ppReadable unknown_nodes ++ "\npathnodes = " ++ ppReadable pathnodes) -- ==================== -- Construct the graph @@ -905,10 +928,10 @@ aPathsPreSched errh flags apkg = do -- For urgency to be computed by paths, we must assume a path from -- a method's ready signal to its enable signal. - let rdy_to_en_edges = [(PNTopMethodRes rdy_id, PNTopMethodEnable m_id) | + let rdy_to_en_edges = [(PNTopMethodRes rdy_id 1, PNTopMethodEnable m_id) | (AIAction { aif_pred = (ASDef _ rdy_id), aif_name = m_id, aif_fieldinfo = m_fi }) <- ifc ] ++ - [(PNTopMethodRes rdy_id, PNTopMethodEnable m_id) | + [(PNTopMethodRes rdy_id 1, PNTopMethodEnable m_id) | (AIActionValue { aif_pred = (ASDef _ rdy_id), aif_name = m_id, aif_fieldinfo = m_fi }) <- ifc ] @@ -928,7 +951,7 @@ aPathsPreSched errh flags apkg = do -- edges from WF to RDY of value method [ (wf_rule_id, meth_id, filtered_path) | (PNWillFire wf_rule_id, rs) <- zip will_fire_nodes reachables, - (AIDef { aif_value = (ADef meth_id _ _ _) }) <- ifc, + (AIDef { aif_name = meth_id }) <- ifc, let meth_node = (PNTopMethodReady meth_id), let mpath = lookup meth_node rs, isJust mpath, @@ -1066,14 +1089,14 @@ aPathsPostSched flags pps apkg pathGraphInfo (ASchedule scheds _) = do -- We don't currently need the argument conversion info, because -- the node already contains the converted name (and not the number) let meth_info_map = M.fromList $ - [ (meth_id, ({-numbered_args,-} maybe_EN, maybe_res)) | + [ (meth_id, ({-numbered_args,-} maybe_EN, res)) | meth <- apkg_interface apkg, let vfieldinfo = aif_fieldinfo meth, let meth_id = vf_name vfieldinfo, --let args = map fst (vf_inputs vfieldinfo), --let numbered_args = zip args [1..], let maybe_EN = (vf_enable vfieldinfo) >>= return . fst, - let maybe_res = (vf_output vfieldinfo) >>= return . fst + let res = (vf_outputs vfieldinfo) >>= return . fst ] let findMethod m = @@ -1084,10 +1107,9 @@ aPathsPostSched flags pps apkg pathGraphInfo (ASchedule scheds _) = do -- the "arg" is already the VName and not a number let convertArg m arg = aidToVName arg - let convertRes m = + let convertRes m res_num = case (findMethod m) of - (_, Just res) -> res - _ -> internalError ("APaths convertRes: " ++ ppReadable m) + (_, res) -> res `genericIndex` (res_num - 1) let convertEnable m = case (findMethod m) of @@ -1096,7 +1118,7 @@ aPathsPostSched flags pps apkg pathGraphInfo (ASchedule scheds _) = do -- convert PathNode back to VName let pnToVName (PNTopMethodArg m arg) = convertArg m arg - pnToVName (PNTopMethodRes m) = convertRes m + pnToVName (PNTopMethodRes m res) = convertRes m res pnToVName (PNTopMethodEnable m) = convertEnable m pnToVName (PNTopArgument a _) = aidToVName a pnToVName (PNTopClkGate a) = aidToVName a @@ -1219,9 +1241,31 @@ findEdges env (AMethCall t i qmi exprs) = (edges, ms) = concatUnzip (map f (zip [1..] exprs)) meth_arg_mux = PNStateMethodArgMux i mi muxes = if null exprs then ms else meth_arg_mux:ms - in ([PNStateMethodRes i mi], edges, muxes) + in ([PNStateMethodRes i mi 1], edges, muxes) findEdges env (AMethValue t i qmi) = - ([PNStateMethodRes i (unQualId qmi)], [], []) + ([PNStateMethodRes i (unQualId qmi) 1], [], []) +findEdges env (ATupleSel _ (AMethCall t i qmi exprs) oi) = + -- make edges between exprs and meth input + -- return the output connection + let mi = unQualId qmi + -- like mkEdgesWithMux, but want to return the muxes, not connect them + f (n,exp) = let (is, edges, muxes) = findEdges env exp + pn = PNStateMethodArg i mi n + es = edges ++ (connectEdge pn is) + in (es, muxes) + (edges, ms) = concatUnzip (map f (zip [1..] exprs)) + meth_arg_mux = PNStateMethodArgMux i mi + muxes = if null exprs then ms else meth_arg_mux:ms + in ([PNStateMethodRes i mi oi], edges, muxes) +findEdges env (ATupleSel _ (AMethValue t i qmi) oi) = + ([PNStateMethodRes i (unQualId qmi) oi], [], []) +findEdges env (ATupleSel _ e _) = + internalError + ("APaths.findEdges: unexpected ATupleSel expression: " ++ ppReadable e) + +findEdges env (ATuple _ es) = + -- return any connections found in the element expressions + concatUnzip3 (map (findEdges env) es) findEdges env (ANoInlineFunCall { ae_args = es }) = -- return the function call inputs -- and return any connections found in the argument expressions diff --git a/src/comp/ARankMethCalls.hs b/src/comp/ARankMethCalls.hs index 9826b41b9..6efc07bdb 100644 --- a/src/comp/ARankMethCalls.hs +++ b/src/comp/ARankMethCalls.hs @@ -42,7 +42,7 @@ aRankMethCalls errh pprops orig_pkg = aRankMethCallsInternal :: ErrorHandle -> [[Id]] -> APackage -> IO APackage aRankMethCallsInternal _ [] orig_pkg = return orig_pkg aRankMethCallsInternal errh orig_ranks orig_pkg = - do let method_map = [(aIfaceName m, m) | m <- apkg_interface orig_pkg] + do let method_map = [(aif_name m, m) | m <- apkg_interface orig_pkg] rule_map = [(dropRulePrefixId (arule_id r), r) | r <- apkg_rules orig_pkg] def_map = [(adef_objid d, d) | d <- apkg_local_defs orig_pkg] -- add method ready signals foreach method in (* perf_spec *) @@ -127,6 +127,12 @@ instance RankMethCalls AExpr where defs_to_rewrite) rankMethCalls ver expr@(AMethValue { ameth_id = name }) = (expr { ameth_id = rankId ver name }, []) + rankMethCalls ver expr@(ATuple { ae_elems = elems }) = + let (ranked_elems, defs_to_rewrite) = rankMethCalls ver elems + in (expr { ae_elems = ranked_elems }, defs_to_rewrite) + rankMethCalls ver expr@(ATupleSel { ae_exp = e }) = + let (ranked_e, defs_to_rewrite) = rankMethCalls ver e + in (expr { ae_exp = ranked_e }, defs_to_rewrite) rankMethCalls ver expr@(ANoInlineFunCall { ae_args = args }) = let (ranked_args, defs_to_rewrite) = rankMethCalls ver args in (expr { ae_args = ranked_args }, defs_to_rewrite) diff --git a/src/comp/ARenameIO.hs b/src/comp/ARenameIO.hs index deb852f21..9403b7b44 100644 --- a/src/comp/ARenameIO.hs +++ b/src/comp/ARenameIO.hs @@ -134,11 +134,11 @@ trSI mp si = trM (Nothing) = Nothing trM (Just x) = Just (tr mp x) - trMeth ami@(ASPMethodInfo i ty mr me mv args rs) = + trMeth ami@(ASPMethodInfo i ty mr me vs args rs) = ami { aspm_name = tr mp i, aspm_mrdyid = trM mr, aspm_menableid = trM me, - aspm_mresultid = trM mv, + aspm_resultids = map (tr mp) vs, aspm_inputs = map (tr mp) args } in ASPSignalInfo { diff --git a/src/comp/ASchedule.hs b/src/comp/ASchedule.hs index a6ddbfcb0..de940b265 100644 --- a/src/comp/ASchedule.hs +++ b/src/comp/ASchedule.hs @@ -4139,11 +4139,11 @@ cvtIfc (AIActionValue _ _ ifPred ifId ifRs (ADef dId t _ _) _) = -- rule, dId and rId will be the same) [(Rule rId rOrig [ifPred, rPred] [ifPred, rPred, dExpr] rActs) | (ARule rId rps rDesc rWireProps rPred rActs _ rOrig) <- ifRs] - where dExpr = ASDef t dId -cvtIfc (AIDef _ _ _ ifPred (ADef dId t _ _) _ _) - | isRdyId dId = [] - | otherwise = [(Rule dId Nothing [ifPred] [ifPred,dExpr] [])] - where dExpr = ASDef t dId + where dExpr = ASDef t dId +cvtIfc (AIDef mId _ _ _ _ _ _) | isRdyId mId = [] +cvtIfc (AIDef mId _ _ ifPred (ADef dId t _ _) _ _) = + [(Rule mId Nothing [ifPred] [ifPred, dExpr] [])] + where dExpr = ASDef t dId cvtIfc (AIClock {}) = [] cvtIfc (AIReset {}) = [] cvtIfc (AIInout {}) = [] diff --git a/src/comp/AState.hs b/src/comp/AState.hs index dda4ded85..fbfc648d4 100644 --- a/src/comp/AState.hs +++ b/src/comp/AState.hs @@ -37,6 +37,7 @@ import AUses(useDropCond) import AVerilogUtil(vNameToTask) import RSchedule(RAT, ratToNestedLists) import Wires(WireProps(..)) +import Data.Maybe (listToMaybe) --import Debug.Trace --import Util(traces) @@ -209,12 +210,12 @@ aState' flags pps schedule_info apkg = do -- We separate out the RDY defs for always_ready methods from others, -- because we want the defs (they feed into enables) but do want the -- RDY ports. - isAlwaysReadyMethod m = (isRdyId (aIfaceName m)) && (isAlwaysRdy pps (aIfaceName m)) + isAlwaysReadyMethod m = (isRdyId (aif_name m)) && (isAlwaysRdy pps (aif_name m)) (always_rdy_ifc,other_ifc) = partition isAlwaysReadyMethod ifc outs :: [ADef] - outs = concatMap (outputDefToADef fmod pps) other_ifc + outs = concatMap (outputDefToADefs fmod pps) other_ifc always_ready_defs :: [ADef] - always_ready_defs = concatMap (outputDefToADef fmod pps) always_rdy_ifc + always_ready_defs = concatMap (outputDefToADefs fmod pps) always_rdy_ifc --traceM( "ifc are: " ++ ppReadable ifc ) ; --traceM( "outs are: " ++ ppReadable outs ) ; @@ -413,7 +414,7 @@ aState' flags pps schedule_info apkg = do -- mkEmuxxs needs to know which are the value methods, because -- selectors for muxes are RDY for value methods (instead of WILLFIRE) - value_method_ids = [ i | (AIDef { aif_value = (ADef i _ _ _) }) <- ifc ] + value_method_ids = [ i | (AIDef { aif_name = i }) <- ifc ] -- muxes for values (definitions) (emux_selss, emux_valss, emux_outss, esss) = @@ -444,7 +445,9 @@ aState' flags pps schedule_info apkg = do -- actionvalue method value references can be unconditionally converted subst :: AExpr -> Maybe AExpr subst (AMethValue vt modId methId) = - Just (ASPort vt (mkMethId modId methId Nothing MethodResult)) + Just (ASPort vt (mkMethId modId methId Nothing (MethodResult Nothing))) + subst (ATupleSel vt (AMethValue _ modId methId) idx) = + Just (ASPort vt (mkMethId modId methId Nothing (MethodResult (Just idx)))) -- substitute AMOsc, AMGate, AMReset references with their port subst (AMGate gt modId clkId) = Just (mkOutputGatePort vmi_map modId clkId) @@ -455,7 +458,15 @@ aState' flags pps schedule_info apkg = do let ino = do mult <- M.lookup (modId, methId) omMultMap -- send unused calls of multi-ported methods to port 0 toMaybe (mult > 1) 0 - in Just (ASPort vt (mkMethId modId methId ino MethodResult)) + in Just (ASPort vt (mkMethId modId methId ino (MethodResult Nothing))) + me' -> me' + subst e@(ATupleSel vt (AMethCall _ modId methId es) idx) = + case (M.lookup e substs) of + Nothing -> + let ino = do mult <- M.lookup (modId, methId) omMultMap + -- send unused calls of multi-ported methods to port 0 + toMaybe (mult > 1) 0 + in Just (ASPort vt (mkMethId modId methId ino (MethodResult (Just idx)))) me' -> me' -- AMethValue, AMGate and AMethCall should cover it subst e = Nothing @@ -658,7 +669,7 @@ genModVars vs omMultMap = allmvars -- and whether it's an action method) -- ( m@(Method { vf_name = methId, vf_inputs = argIds, vf_mult = mult }), - (argTypes, en_type, val_type) ) + (argTypes, en_type, val_types) ) <- zip (vFields vmodinfo) methType, -- -- for each part of the method, produce a triple of @@ -674,9 +685,8 @@ genModVars vs omMultMap = allmvars Nothing -> [] (Just t) -> [(MethodEnable, t, True)]) ++ -- value triple - (case (val_type) of - Nothing -> [] - (Just t) -> [(MethodResult, t, False)]), + [(MethodResult mn, t, False) + | (mn, t) <- zip (methResultNums val_types) val_types ], -- uniquifiers for multiple ports -- (if only one copy, then the list just contains 0) ino <- map (toMaybe (mult > 1)) [ 0 .. (getMultUse (modId, methId) - 1) `max` 0 ], @@ -709,25 +719,38 @@ isForeign (ATaskAction { }) = True isForeign _ = False --- Create an output ADef from the Interface method +-- Create output ADefs from the Interface method -- consider only value method returns and outputs of ActionValue methods -- note that expressions are named according to the information on -- the VFieldInfo -outputDefToADef :: Bool -> [PProp] -> AIFace -> [ADef] -outputDefToADef fmod pps ai@(AIDef{}) = if convert then [newdef] else [] - where def = aif_value ai - resName = mkNamedOutput (aif_fieldinfo ai) - newdef = def{ adef_objid = resName } - convert = not (fmod && isRdyId (aif_name ai)) -outputDefToADef _ pps ai@(AIActionValue{}) = [newdef] - where def = aif_value ai - resName = mkNamedOutput (aif_fieldinfo ai) - newdef = def{ adef_objid = resName } -outputDefToADef _ _ a@(AIAction{}) = [] -outputDefToADef _ _ a@(AIClock{}) = [] -outputDefToADef _ _ a@(AIReset{}) = [] -outputDefToADef _ _ a@(AIInout{}) = [] - +outputDefToADefs :: Bool -> [PProp] -> AIFace -> [ADef] +outputDefToADefs fmod pps (AIDef{aif_name=name, aif_value=def, aif_fieldinfo=fi}) = if convert then newdefs else [] + where resNames= mkNamedOutputs fi + newdefs = outputADefToADefs def resNames + convert = not (fmod && isRdyId name) +outputDefToADefs _ pps (AIActionValue{aif_name=name, aif_value=def, aif_fieldinfo=fi}) = newdefs + where resNames= mkNamedOutputs fi + newdefs = outputADefToADefs def resNames +outputDefToADefs _ _ a@(AIAction{}) = [] +outputDefToADefs _ _ a@(AIClock{}) = [] +outputDefToADefs _ _ a@(AIReset{}) = [] +outputDefToADefs _ _ a@(AIInout{}) = [] + +outputADefToADefs :: ADef -> [Id] -> [ADef] +outputADefToADefs (ADef { adef_type = ATTuple ts, adef_expr = ATuple _ es }) resNames = + zipWith3 (\t e resName -> ADef { adef_objid = resName, + adef_type = t, + adef_expr = e, + adef_props = [] }) + ts es resNames +outputADefToADefs (ADef { adef_type = t, adef_expr = e }) [resName] = + [ADef { adef_objid = resName, + adef_type = t, + adef_expr = e, + adef_props = [] }] +outputADefToADefs (ADef { adef_type = ATBit 0}) [] = [] +outputADefToADefs def resNames = + internalError $ "outputADefToADefs: unexpected ADef resNames: " ++ ppReadable (def, resNames) getVInst :: AId -> [AVInst] -> AVInst getVInst i as = head ( [ a | a <- as, i == (avi_vname a) ] ++ @@ -756,7 +779,7 @@ mkSIMethodTuple (AIDef name args _ pred _ vfi _) = aspm_type = "value", aspm_mrdyid = Just rdy, aspm_menableid = Nothing, - aspm_mresultid = Just res, + aspm_resultids = res, aspm_inputs = map fst args, aspm_assocrules = [] } ] @@ -767,7 +790,7 @@ mkSIMethodTuple (AIAction args _ pred name rs vfi) = aspm_type = "action", aspm_mrdyid = Just rdy, aspm_menableid = Just ena, - aspm_mresultid = Nothing, + aspm_resultids = [], aspm_inputs = map fst args, aspm_assocrules = map aRuleName rs } ] @@ -778,7 +801,7 @@ mkSIMethodTuple (AIActionValue args _ pred name rs _ vfi) = aspm_type = "actionvalue", aspm_mrdyid = Just rdy, aspm_menableid = Just ena, - aspm_mresultid = Just res, + aspm_resultids = res, aspm_inputs = map fst args, aspm_assocrules = map aRuleName rs } ] @@ -808,8 +831,8 @@ mkSignalInfoMethod aifaces = merged mergePorts [a] = [a] mergePorts [a, b] = [res] where res = case (isRdyId (aspm_name a), isRdyId (aspm_name b)) of - (True, False) -> b { aspm_mrdyid = (aspm_mresultid a) } - (False, True) -> a { aspm_mrdyid = (aspm_mresultid b) } + (True, False) -> b { aspm_mrdyid = listToMaybe (aspm_resultids a) } + (False, True) -> a { aspm_mrdyid = listToMaybe (aspm_resultids b) } _ -> internalError( "mergePorts" ++ ppReadable (a,b) ) mergePorts x = internalError( "mergePorts2:" ++ ppReadable x ) @@ -830,6 +853,7 @@ ratToBlobs mMap omMultMap rat = let -- True if there are 2 or more uses of the method, -- which means we need to do some sort of muxing + nonTrivial :: MethBlob -> Bool nonTrivial (_, (((AMethCall _ _ _ _, _) : _) : _)) = True nonTrivial _ = False @@ -1014,8 +1038,7 @@ mkEmuxs :: ([AExpr] -> [AExpr]) -> ([AExpr] -> AExpr) -> AId -> AId -> Maybe Integer -> MethPortBlob -> ([ADef], [ADef], [ADef], AExprSubst) mkEmuxs tl cnd rdb value_method_ids om o m ino emrs = - let meth_id = mkMethId o m ino MethodResult - + let -- Break each MethPortBlob into a list of the expressions for -- each argument, and then transpose the entire structure to -- make a list of, for each argument, a list of the different @@ -1031,8 +1054,16 @@ mkEmuxs tl cnd rdb value_method_ids om o m ino emrs = [1..] arg_blobs (sel_defs, val_defs, out_defs) = concatUnzip3 def_tuples + mkPortSubsts (e, _) = + case aType e of + ATTuple ats -> + [ (ATupleSel at e idx, + ASPort at $ mkMethId o m ino $ MethodResult (Just idx)) + | (idx, at) <- zip [1..] ats ] + at -> [ (e, ASPort at $ mkMethId o m ino $ MethodResult Nothing) ] + -- Replace the method call with the output port of the method - subst = [(e, ASPort (aType e) meth_id) | (e, _) <- emrs] + subst = concatMap mkPortSubsts emrs in -- traces ("mkEmuxs " ++ ppReadable emrs ++ ppReadable xs) $ (sel_defs, val_defs, out_defs, subst) diff --git a/src/comp/ASyntax.hs b/src/comp/ASyntax.hs index c60a6c0a0..b0bd445ad 100644 --- a/src/comp/ASyntax.hs +++ b/src/comp/ASyntax.hs @@ -61,14 +61,12 @@ module ASyntax( isUnsizedString, dropSize, unifyStringTypes, + isTupleType, getArrayElemType, getArraySize, - aIfaceName, - aIfaceNameString, aIfaceProps, - aIfaceResSize, aIfaceResType, - aIfaceResId, + aIfaceResIds, aIfaceArgs, aIfaceArgSize, aIfaceRules, @@ -97,6 +95,9 @@ module ASyntax( ppeAPackage, mkMethId, mkMethStr, + mkMethArgStr, + mkMethResStr, + methResultNums, isMethId, MethodPart(..), getParams, @@ -127,12 +128,12 @@ import Prim import ErrorUtil(internalError) import Backend import Pragma -import PreStrings(fsDollar, fsUnderscore, fsEnable) +import PreStrings(fsDollar, fsUnderscore, fsEnable, fs_res) import FStringCompat -- import Position(noPosition) import Position import Data.Maybe -import Util(itos, fromJustOrErr) +import Util(itos) import VModInfo import Wires import ProofObligation(ProofObligation, MsgFn) @@ -340,7 +341,7 @@ data ASPMethodInfo = ASPMethodInfo { aspm_type :: String, aspm_mrdyid :: Maybe AId, aspm_menableid :: Maybe AId, - aspm_mresultid :: Maybe AId, + aspm_resultids :: [AId], aspm_inputs :: [AId], aspm_assocrules :: [AId] } @@ -351,7 +352,7 @@ instance PPrint ASPMethodInfo where <+> text (aspm_type aspmi) <> equals <> braces ( pPrint d 0 (aspm_mrdyid aspmi) <+> pPrint d 0 (aspm_menableid aspmi) <+> - pPrint d 0 (aspm_mresultid aspmi) <+> + pPrint d 0 (aspm_resultids aspmi) $+$ pPrint d 0 (aspm_inputs aspmi) $+$ pPrint d 0 (aspm_assocrules aspmi) ) @@ -446,6 +447,10 @@ data AType = atr_length :: ASize, atr_elem_type :: AType } + -- Tuple type, for methods with multiple return values + | ATTuple { + att_elem_types :: [AType] + } -- abstract type, PrimAction, Interface, Clock, .. -- (can take size parameters as arguments) | ATAbstract { @@ -459,6 +464,7 @@ instance NFData AType where rnf (ATString msz) = rnf msz rnf ATReal = () rnf (ATArray len typ) = rnf2 len typ + rnf (ATTuple typs) = rnf typs rnf (ATAbstract aid args) = rnf2 aid args instance HasPosition AType where @@ -505,6 +511,10 @@ unifyStringTypes (t:ts) | isUnsizedString t = t helper t (t1:ts) | t /= t1 = dropSize t | otherwise = helper t ts +isTupleType :: AType -> Bool +isTupleType (ATTuple _) = True +isTupleType _ = False + type ASize = Integer getArrayElemType :: AType -> AType @@ -571,10 +581,10 @@ data AVInst = AVInst { -- XXX This list corresponds to vFields in the VModInfo, but cannot be -- XXX stored there, because VModInfo is created before types are known. -- There is a triple for each method in vFields of VModInfo. - -- The triple contains the types of each argument (in order) and maybe - -- the types of the EN and return value. + -- The triple contains the types of each argument (in order), maybe + -- the type of the EN, and the return values. -- NOTE: These are the output language types (i.e. ATBit n) - avi_meth_types :: [([AType], Maybe AType, Maybe AType)], + avi_meth_types :: [([AType], Maybe AType, [AType])], -- This field maps source-language types to their corresponding ports avi_port_types :: M.Map VName IType, avi_vmi :: VModInfo, -- Verilog names, conflict info, etc. @@ -672,11 +682,12 @@ getIfcInoutPorts :: AVInst -> [(AId, (AId, AType, VPort))] getIfcInoutPorts avi = let vmi = avi_vmi avi - res_types = map (\ (_,_,mr) -> mr) (avi_meth_types avi) + res_types = map (\ (_,_,rs) -> rs) (avi_meth_types avi) ifc_inouts = [(id,vn,ty) - | (Inout id vn _ _, mr) <- zip (vFields vmi) res_types, - let ty = fromJustOrErr ("ASyntax.unknown inout " ++ - ppReadable id) mr] + | (Inout id vn _ _, rs) <- zip (vFields vmi) res_types, + let ty = case rs of + [r] -> r + _ -> error ("ASyntax.unknown inout " ++ ppReadable id)] mkInoutPort ty vname = (mkOutputWireId (avi_vname avi) vname, @@ -817,17 +828,6 @@ instance NFData AIFace where rnf (AIReset name rst finfo) = rnf3 name rst finfo rnf (AIInout name inout finfo) = rnf3 name inout finfo -aIfaceName :: AIFace -> AId -aIfaceName (AIDef { aif_value = (ADef i _ _ _)}) = i -- XXX use aif_name -aIfaceName (AIAction { aif_name = i}) = i -aIfaceName (AIActionValue { aif_name = i}) = i -aIfaceName (AIClock { aif_name = i}) = i -aIfaceName (AIReset { aif_name = i}) = i -aIfaceName (AIInout { aif_name = i}) = i - -aIfaceNameString :: AIFace -> String -aIfaceNameString i = getIdString (aIfaceName i) - aiface_vname :: AIFace -> String aiface_vname i = getIdString (vf_name (aif_fieldinfo i)) @@ -838,13 +838,7 @@ aIfaceProps (AIAction { aif_props = p }) = p aIfaceProps (AIActionValue { aif_props = p }) = p aIfaceProps _ = emptyWireProps --- result size -aIfaceResSize :: AIFace -> Integer -aIfaceResSize (AIAction { }) = 0 -aIfaceResSize (AIDef {aif_value = (ADef _ (ATBit n) _ _) }) = n -aIfaceResSize (AIActionValue {aif_value = (ADef _ (ATBit n) _ _) }) = n -aIfaceResSize x = internalError ("aIfaceResSize: " ++ show x) - +-- The result type of an interface method, which may be a tuple for multiple output ports. aIfaceResType :: AIFace -> AType -- XXX should be ATAction? aIfaceResType (AIAction { }) = ATBit 0 @@ -853,10 +847,10 @@ aIfaceResType (AIActionValue { aif_value = (ADef _ t _ _)}) = t -- should not need type of clock or reset aIfaceResType x = internalError ("aIfaceResType: " ++ show x) -aIfaceResId :: AIFace -> [AId] -aIfaceResId (AIDef {aif_value = (ADef i _ _ _) }) = [i] -aIfaceResId (AIActionValue {aif_value = (ADef i _ _ _) }) = [i] -aIfaceResId _ = [] +aIfaceResIds :: AIFace -> [AId] +aIfaceResIds (AIDef {aif_name=id}) = [id] +aIfaceResIds (AIActionValue {aif_name=id}) = [id] +aIfaceResIds _ = [] aIfaceArgs :: AIFace -> [AInput] aIfaceArgs (AIClock {}) = [] @@ -904,7 +898,7 @@ addRdyToARule rdyId r0@(ARule { arule_id = ri, arule_pred = e }) = (d, r) aIfaceSchedNames :: AIFace -> [ARuleId] aIfaceSchedNames (AIAction { aif_body = rs}) = map arule_id rs aIfaceSchedNames (AIActionValue { aif_body = rs}) = map arule_id rs -aIfaceSchedNames (AIDef { aif_value = d }) = [adef_objid d] +aIfaceSchedNames (AIDef { aif_name = i }) = [i] aIfaceSchedNames _ = [] aIfacePred :: AIFace -> APred @@ -1054,6 +1048,16 @@ data AExpr ae_objid :: AId, ameth_id :: AMethodId } + | ATuple { + ae_type :: AType, + ae_elems :: [AExpr] + } + -- selection from an ATTuple + | ATupleSel { + ae_type :: AType, + ae_exp :: AExpr, + ae_index :: Integer + } -- calls a combinatorial function expressed via module instantiation -- XXX this can be created not only via "noinline" in BSV, -- XXX but also "foreign" in Classic syntax; consider renaming? @@ -1152,6 +1156,8 @@ instance NFData AExpr where rnf (APrim oid typ prim args) = rnf4 oid typ prim args rnf (AMethCall typ oid mid args) = rnf4 typ oid mid args rnf (AMethValue typ oid mid) = rnf3 typ oid mid + rnf (ATuple typ elems) = rnf2 typ elems + rnf (ATupleSel typ expr index) = rnf3 typ expr index rnf (ANoInlineFunCall typ oid fun args) = rnf4 typ oid fun args rnf (AFunCall typ oid fname isC args) = rnf5 typ oid fname isC args rnf (ATaskValue typ oid fname isC cookie) = rnf5 typ oid fname isC cookie @@ -1177,6 +1183,12 @@ instance Eq AExpr where AMethValue t aid mid == AMethValue t' aid' mid' = (t == t') && (mid == mid') && (aid == aid') + ATuple t aexprs == ATuple t' aexprs' = + (t == t') && (aexprs == aexprs') + + ATupleSel t aexpr index == ATupleSel t' aexpr' index' = + (t == t') && (index == index') && (aexpr == aexpr') + ANoInlineFunCall t aid af aexprs == ANoInlineFunCall t' aid' af' aexprs' = (t == t') && (af == af') && (aexprs == aexprs') && (aid == aid') @@ -1222,6 +1234,9 @@ instance HasPosition AExpr where getPosition APrim{ ae_objid = p } = getPosition p getPosition AMethCall{ ae_objid = p } = getPosition p getPosition AMethValue{ ae_objid = p } = getPosition p + getPosition ATuple{ ae_elems = e : _ } = getPosition e + getPosition ATuple{ ae_elems = [] } = noPosition -- Is there something better? + getPosition ATupleSel{ ae_exp = e } = getPosition e getPosition ANoInlineFunCall{ ae_objid = p } = getPosition p getPosition AFunCall{ ae_objid = p } = getPosition p getPosition ATaskValue{ ae_objid = p } = getPosition p @@ -1434,7 +1449,7 @@ instance PPrint AIFace where pPrint d p ai@(AIDef {} ) = (text "--AIDef" <+> pPrint d p (aif_name ai)) $+$ foldr (($+$) . ppV d) empty (aif_inputs ai) $+$ - pPrint d 0 (aif_value ai) $+$ + pPrint d p (aif_value ai) $+$ pPred d p (aif_pred ai) $+$ pPrint d 0 (aif_props ai) $+$ pPrint d 0 (aif_fieldinfo ai) $+$ @@ -1563,6 +1578,8 @@ instance PPrint AExpr where pPrint d 1 i <> sep (text "." <> ppMethId d m : map (pPrint d 1) es) pPrint d p (AMethValue _ i m) = pparen (p>0) $ pPrint d 1 i <> text "." <> ppMethId d m + pPrint d p (ATuple _ es) = parens (commaSep (map (pPrint d 0) es)) + pPrint d p (ATupleSel _ e idx) = pPrint d 1 e <> text "[" <> pPrint d 0 idx <> text "]" pPrint d p (ASPort _ i) = pPrint d p i pPrint d p (ASParam _ i) = pPrint d p i pPrint d p (ASDef _ i) = pPrint d p i @@ -1592,6 +1609,8 @@ instance PPrint AType where pPrint d p (ATString (Just n)) = text ("String (" ++ (itos n) ++ " chars)") pPrint d p (ATArray sz ty) = text "Array" <+> text (itos sz) <+> pPrint d 0 ty + pPrint d p (ATTuple ts) = + text "Tuple" <+> parens (commaSep (map (pPrint d 0) ts)) pPrint d p (ATAbstract i ns) = sep (text "ABSTRACT: " : pPrint d 0 i : map (pPrint d 0) ns) binOp :: PrimOp -> Bool @@ -1855,6 +1874,8 @@ instance PPrintExpand AExpr where where docArgs = map (pPrintExpand m d defContext) es pPrintExpand m d ec (AMethValue _ i meth) = pPrint d 1 i <> text "." <> ppMethId d meth + pPrintExpand m d ec (ATuple _ es) = parens (commaSep (map (pPrintExpand m d defContext) es)) + pPrintExpand m d ec (ATupleSel _ e idx) = (pparen (useParen ec) $ pPrintExpand m d defContext e) <> text ("[" ++ itos idx ++ "]") pPrintExpand m d ec (ASPort _ i) = pPrint d (getP ec) i pPrintExpand m d ec (ASParam _ i) = pPrint d (getP ec) i pPrintExpand m d ec (ASDef _ i) | isIdWillFire i && (lookupLevel m) > 0 || @@ -1885,19 +1906,24 @@ defLookup d ped = M.findWithDefault err d (defmap ped) -- # Some standardized methods for making (default) method strings -- ############################################################################# data MethodPart = - MethodArg Integer | -- argument 1, 2, ... input - MethodResult | -- return value output - MethodEnable -- enable signal input + MethodArg Integer | -- argument 1, 2, ... input + MethodResult (Maybe Integer) | -- return value: Nothing for a single result, + -- Just 1, 2, ... when split across ports + MethodEnable -- enable signal input deriving (Eq) -- The method syntax is as follows: -- Arguments are $_ starting from 1 -- (e.g. the_fifo$enq_1) --- Return values are $ (e.g. the_fifo$first) +-- Return values are $_RES_ when the result is split across +-- multiple output ports (e.g. the_fifo$first_RES_1), or just $ +-- when the method has a single result (e.g. the_fifo$first) -- Enable signals are $EN_ (e.g. the_fifo$EN_enq) -- Multi-ported methods are $__ +-- or $__RES_ -- The portnum is only omitted if the method has one or -- and infinite number of ports (like a register) +-- XXX these should probably just be a data type rather than Ids mkMethId :: Id -> Id -> Maybe Integer -> MethodPart -> Id mkMethId o m ino mp = -- trace ("POS O: " ++ (show (getIdPosition o)) ++ " " ++ @@ -1922,13 +1948,8 @@ mkMethStr obj m m_port mp = fsUnderscore, mkNumFString port] base = case mp of - MethodArg n -> - if (n == 0) - then internalError "mkMethStr" - else concatFString [meth_port, - fsUnderscore, - mkNumFString n] - MethodResult -> meth_port + MethodArg n -> mkMethArgStr meth_port n + MethodResult mn -> mkMethResStr meth_port mn MethodEnable -> -- XXX are we overloading fsEnable? concatFString [fsEnable, meth_port] @@ -1937,6 +1958,27 @@ mkMethStr obj m m_port mp = fsDollar, base] +mkMethArgStr :: FString -> Integer -> FString +mkMethArgStr meth_port n = + if (n == 0) + then internalError "mkMethArgStr" + else concatFString [meth_port, fsUnderscore, mkNumFString n] + +mkMethResStr :: FString -> Maybe Integer -> FString +-- a single result gets no _RES_ suffix +mkMethResStr meth_port Nothing = meth_port +mkMethResStr meth_port (Just n) = + if (n == 0) + then internalError "mkMethResStr" + else concatFString [meth_port, fsUnderscore, fs_res, mkNumFString n] + +-- The result numbers for a method with the given list of results: Nothing +-- (no _RES_ suffix) for a single result, Just 1, Just 2, ... when split across +-- multiple output ports. +methResultNums :: [a] -> [Maybe Integer] +methResultNums [_] = [Nothing] +methResultNums xs = zipWith (\ _ n -> Just n) xs [1..] + -- ############################################################################# -- # -- ############################################################################# diff --git a/src/comp/ASyntaxUtil.hs b/src/comp/ASyntaxUtil.hs index 561672e45..a12b6580d 100644 --- a/src/comp/ASyntaxUtil.hs +++ b/src/comp/ASyntaxUtil.hs @@ -72,6 +72,8 @@ instance AVars AExpr where aVars (ANoInlineFunCall _ _ _ es) = concatMap aVars es aVars (AFunCall _ _ _ _ es) = concatMap aVars es aVars (AMethCall _ _ _ es) = concatMap aVars es + aVars (ATuple _ es) = concatMap aVars es + aVars (ATupleSel _ e _) = aVars e -- aVars (ATaskValue ...) = [] -- because the variables are really "used" -- by the action which sets it -- same for AMethValue @@ -117,6 +119,8 @@ aMethValues :: AExpr -> [(AId, AId, AType)] aMethValues e@(APrim {}) = concatMap aMethValues (ae_args e) aMethValues e@(AMethCall {}) = concatMap aMethValues (ae_args e) aMethValues (AMethValue ty obj meth) = [(obj,meth,ty)] +aMethValues (ATuple _ es) = concatMap aMethValues es +aMethValues (ATupleSel _ e _) = aMethValues e aMethValues e@(ANoInlineFunCall {}) = concatMap aMethValues (ae_args e) aMethValues e@(AFunCall {}) = concatMap aMethValues (ae_args e) aMethValues (ATaskValue {}) = [] @@ -137,6 +141,8 @@ aMethCalls :: AExpr -> [(AId, AId)] aMethCalls e@(APrim {}) = concatMap aMethCalls (ae_args e) aMethCalls (AMethCall _ obj meth es) = ((obj,meth) : concatMap aMethCalls es) aMethCalls (AMethValue _ obj meth) = [] +aMethCalls (ATuple _ es) = concatMap aMethCalls es +aMethCalls (ATupleSel _ e _) = aMethCalls e aMethCalls e@(ANoInlineFunCall {}) = concatMap aMethCalls (ae_args e) aMethCalls e@(AFunCall {}) = concatMap aMethCalls (ae_args e) aMethCalls (ATaskValue {}) = [] @@ -157,6 +163,8 @@ aTaskValues :: AExpr -> [(AId, Integer, AType)] aTaskValues e@(APrim {}) = concatMap aTaskValues (ae_args e) aTaskValues e@(AMethCall {}) = concatMap aTaskValues (ae_args e) aTaskValues (AMethValue {}) = [] +aTaskValues (ATuple _ es) = concatMap aTaskValues es +aTaskValues (ATupleSel _ e _) = aTaskValues e aTaskValues e@(ANoInlineFunCall {}) = concatMap aTaskValues (ae_args e) aTaskValues e@(AFunCall {}) = concatMap aTaskValues (ae_args e) aTaskValues (ATaskValue ty f_id fun isC cookie) = [(f_id, cookie, ty)] @@ -180,6 +188,8 @@ exprForeignCalls e@(AFunCall {}) = else (concatMap exprForeignCalls (ae_args e)) exprForeignCalls e@(APrim {}) = concatMap exprForeignCalls (ae_args e) exprForeignCalls e@(AMethCall {}) = concatMap exprForeignCalls (ae_args e) +exprForeignCalls (ATuple _ es) = concatMap exprForeignCalls es +exprForeignCalls (ATupleSel _ e _) = exprForeignCalls e exprForeignCalls e@(ANoInlineFunCall {}) = concatMap exprForeignCalls (ae_args e) exprForeignCalls _ = [] @@ -227,6 +237,7 @@ instance ATypeC AType where aSize e = case aType e of ATBit s -> s + ATTuple ts -> sum (map aSize ts) ATString (Just s) -> 8*s -- 8 bits per character ATAbstract i [n] | i==idInout_ -> n ATArray sz t -> sz * (aSize t) @@ -455,6 +466,8 @@ aSubst m = mapAExprs xsub xsub x@(ASDef _ i) = M.findWithDefault x i m xsub (APrim aid t p es) = APrim aid t p (aSubst m es) xsub (AMethCall t i meth es) = AMethCall t i meth (aSubst m es) + xsub (ATuple t es) = ATuple t (aSubst m es) + xsub (ATupleSel t e n) = ATupleSel t (aSubst m e) n xsub (ANoInlineFunCall t i f es) = ANoInlineFunCall t i f (aSubst m es) xsub (AFunCall t i f isC es) = AFunCall t i f isC (aSubst m es) xsub (ASAny t me) = ASAny t (fmap (aSubst m) me) @@ -474,6 +487,12 @@ exprMap f e@(APrim i t o args) = exprMap f e@(AMethCall t i m args) = let e' = AMethCall t i m (map (exprMap f) args) in fromMaybe e' (f e) +exprMap f e@(ATuple t args) = + let e' = ATuple t (map (exprMap f) args) + in fromMaybe e' (f e) +exprMap f e@(ATupleSel t expr n) = + let e' = ATupleSel t (exprMap f expr) n + in fromMaybe e' (f e) exprMap f e@(ANoInlineFunCall t i fun args) = let e' = ANoInlineFunCall t i fun (map (exprMap f) args) in fromMaybe e' (f e) @@ -501,6 +520,18 @@ exprMapM f e@(AMethCall t i m args) = do Just e' -> return e' Nothing -> do args' <- mapM (exprMapM f) args return $ AMethCall t i m args' +exprMapM f e@(ATuple t elems) = do + me <- f e + case me of + Just e' -> return e' + Nothing -> do elems' <- mapM (exprMapM f) elems + return $ ATuple t elems' +exprMapM f e@(ATupleSel t expr n) = do + me <- f e + case me of + Just e' -> return e' + Nothing -> do expr' <- exprMapM f expr + return $ ATupleSel t expr' n exprMapM f e@(ANoInlineFunCall t i fun args) = do me <- f e case me of @@ -527,6 +558,12 @@ exprFold f v e@(APrim i t o args) = exprFold f v e@(AMethCall t i m args) = let v' = foldr (flip (exprFold f)) v args in f e v' +exprFold f v e@(ATuple t elems) = + let v' = foldr (flip (exprFold f)) v elems + in f e v' +exprFold f v e@(ATupleSel t expr n) = + let v' = exprFold f v expr + in f e v' exprFold f v e@(ANoInlineFunCall t i fun args) = let v' = foldr (flip (exprFold f)) v args in f e v' @@ -612,6 +649,10 @@ aIdFnToAExprFn fn (AMethCall ty aid mid args) = AMethCall ty (fn aid) mid (mapAExprs (aIdFnToAExprFn fn) args) aIdFnToAExprFn fn (AMethValue ty aid mid) = AMethValue ty (fn aid) mid +aIdFnToAExprFn fn (ATuple ty exprs) = + ATuple ty (mapAExprs (aIdFnToAExprFn fn) exprs) +aIdFnToAExprFn fn (ATupleSel ty expr n) = + ATupleSel ty (aIdFnToAExprFn fn expr) n aIdFnToAExprFn fn (ANoInlineFunCall ty aid fun args) = ANoInlineFunCall ty (fn aid) fun (mapAExprs (aIdFnToAExprFn fn) args) aIdFnToAExprFn fn (AFunCall ty aid fun isC args) = diff --git a/src/comp/ATaskSplice.hs b/src/comp/ATaskSplice.hs index 42d131c4d..8b821fcd0 100644 --- a/src/comp/ATaskSplice.hs +++ b/src/comp/ATaskSplice.hs @@ -1,7 +1,6 @@ module ATaskSplice(aTaskSplice) where import ASyntax import ASyntaxUtil -import Data.Maybe import Id import qualified Data.Map as M import ErrorUtil(internalError) @@ -14,9 +13,9 @@ aTaskSplice :: APackage -> APackage aTaskSplice apkg = mapAActions (spliceAction spliceMap) apkg where spliceMap = M.fromList [ (n, (id, t)) | ADef id t (ATaskValue { ae_cookie = n }) _ <- defs ] defs = (apkg_local_defs apkg) ++ - (mapMaybe av_ret_def (apkg_interface apkg)) - av_ret_def act@(AIActionValue {}) = Just (aif_value act) - av_ret_def _ = Nothing + (concatMap av_ret_def (apkg_interface apkg)) + av_ret_def act@(AIActionValue {}) = [aif_value act] + av_ret_def _ = [] spliceAction :: SpliceMap -> AAction -> AAction spliceAction spliceMap a@(ATaskAction { ataskact_temp = Nothing }) = diff --git a/src/comp/AUses.hs b/src/comp/AUses.hs index 557271206..cfe6961ba 100644 --- a/src/comp/AUses.hs +++ b/src/comp/AUses.hs @@ -846,6 +846,8 @@ eDomain e@(AMethCall _ i mi es) = do let this_use = singleMethodExprUse i (unQualId mi) e ucTrue es_uses <- mapM eDomain es mergeExprUsesM (this_use : es_uses) +eDomain (ATuple _ es) = mapM eDomain es >>= mergeExprUsesM +eDomain (ATupleSel _ e _) = eDomain e eDomain e@(AFunCall { ae_objid = i, ae_args = es }) = do let this_use = singleFFuncExprUse i e ucTrue es_uses <- mapM eDomain es diff --git a/src/comp/AVeriQuirks.hs b/src/comp/AVeriQuirks.hs index 72e843309..859bcc876 100644 --- a/src/comp/AVeriQuirks.hs +++ b/src/comp/AVeriQuirks.hs @@ -320,6 +320,12 @@ aQExp top (APrim aid t p es) = mapM (aQExp False) es >>= return . APrim ai aQExp top (AMethCall t i m es) = mapM (aQExp False) es >>= return . AMethCall t i m aQExp top (ANoInlineFunCall t i f es) = mapM (aQExp False) es >>= return . ANoInlineFunCall t i f aQExp top (AFunCall t i f isC es) = mapM (aQExp False) es >>= return . AFunCall t i f isC +aQExp top (ATuple t es) = do + es' <- mapM (aQExp False) es + return (ATuple t es') +aQExp top (ATupleSel t e n) = do + e' <- aQExp False e + return (ATupleSel t e' n) aQExp top e@(AMethValue {}) = return e aQExp top e@(ASInt _ _ _) = return e aQExp top e@(ASReal _ _ _) = return e @@ -408,6 +414,7 @@ aSInt t i = ASInt defaultAId t (ilHex i) mkDefS :: AExpr -> QQState AExpr mkDefS e@(AMethCall _ o m []) = return e -- XXX shouldn't exist mkDefS e@(AMethValue _ o m) = return e -- XXX shouldn't exist +mkDefS e@(ATupleSel _ _ _) = return e -- XXX shouldn't exist mkDefS e@(ASDef {}) = return e mkDefS e@(ASPort {}) = return e mkDefS e@(ASParam {}) = return e diff --git a/src/comp/AVerilog.hs b/src/comp/AVerilog.hs index 155495c48..438d735a8 100644 --- a/src/comp/AVerilog.hs +++ b/src/comp/AVerilog.hs @@ -474,8 +474,8 @@ groupPorts si as = -- (function to be folded over the method port info) findMethod :: ASPMethodInfo -> ([(AId,String,[VArg])],[(Id,VArg)]) -> ([(AId,String,[VArg])],[(Id,VArg)]) - findMethod (ASPMethodInfo i ty mr me mv args _) (ms, ports) = - let is = (catMaybes [mr, me, mv]) ++ args + findMethod (ASPMethodInfo i ty mr me vs args _) (ms, ports) = + let is = (catMaybes [mr, me]) ++ vs ++ args (ps, remaining) = findIds is ports in ((i,ty,ps):ms, remaining) @@ -574,10 +574,10 @@ groupMethodDefs vDef si ds = mkForMethod :: ASPMethodInfo -> ([VMItem], [VMItem], [VMItem], M.Map AId ADef) -> ([VMItem], [VMItem], [VMItem], M.Map AId ADef) - mkForMethod (ASPMethodInfo i ty mr _ mv _ rs) (odecls, idecls, gs, defs) = + mkForMethod (ASPMethodInfo i ty mr _ vs _ rs) (odecls, idecls, gs, defs) = let -- get the output defs - output_ids = catMaybes [mv, mr] + output_ids = vs ++ maybeToList mr (output_defs, other_defs) = findADefs output_ids defs -- get the rule defs rule_sched_ids = concatMap getRuleSignals rs diff --git a/src/comp/AVerilogUtil.hs b/src/comp/AVerilogUtil.hs index 36b06f395..c8f245233 100644 --- a/src/comp/AVerilogUtil.hs +++ b/src/comp/AVerilogUtil.hs @@ -862,7 +862,7 @@ vState flags rewire_map avinst = mkEnId m m_port = vMethId v_inst_name m m_port MethodEnable port_rename_table - mkResId m m_port = vMethId v_inst_name m m_port MethodResult port_rename_table + mkResId m k m_port = vMethId v_inst_name m m_port (MethodResult k) port_rename_table -- add the multiplicity to Verilog port names -- (if there are not multiple ports, no uniquifier is added) @@ -886,7 +886,7 @@ vState flags rewire_map avinst = inps = [ (mkVId (portid s ino), mkArgId m k ino, vSize argType) - | (meth@(Method m _ _ mult ps mo me), + | (meth@(Method m _ _ mult ps outs me), (argTypes,_,_)) <- zip (vFields vi) mts, -- let multu = getMethodMultUse m, @@ -908,7 +908,7 @@ vState flags rewire_map avinst = mkVId (portid s ino), mkEnId m ino, inhigh ) - | (Method m _ _ mult ss mo me@(Just (VName s,vps))) + | (Method m _ _ mult ss outs me@(Just (VName s,vps))) <- vFields vi, let inhigh = VPinhigh `elem` vps, -- let multu = getMethodMultUse m, @@ -922,9 +922,10 @@ vState flags rewire_map avinst = meth_return_vals = nub [ (mkVId (portid s ino), - mkResId m ino) - | ((Method m _ _ mult ss mo@(Just (VName s, vps)) me), (_,_,Just retType)) + mkResId m k ino) + | ((Method m _ _ mult ss outs me), (_,_,retTypes)) <- zip (vFields vi) mts, + ((VName s, vps), retType, k) <- zip3 outs retTypes (methResultNums outs), isNotZeroSized retType, -- let multu = getMethodMultUse m, ino <- if mult > 1 then map Just [0..mult-1] else [Nothing] diff --git a/src/comp/BackendNamingConventions.hs b/src/comp/BackendNamingConventions.hs index 7aec08133..ae1aae952 100644 --- a/src/comp/BackendNamingConventions.hs +++ b/src/comp/BackendNamingConventions.hs @@ -96,8 +96,8 @@ rwireHasId = mkId noPosition (mkFString rwireHasStr) rwireSetEnId, rwireSetArgId, rwireGetResId, rwireHasResId :: Id -> Id rwireSetEnId i = mkMethId i rwireSetId Nothing MethodEnable rwireSetArgId i = mkMethId i rwireSetId Nothing (MethodArg 1) -rwireGetResId i = mkMethId i rwireGetId Nothing MethodResult -rwireHasResId i = mkMethId i rwireHasId Nothing MethodResult +rwireGetResId i = mkMethId i rwireGetId Nothing (MethodResult Nothing) +rwireHasResId i = mkMethId i rwireHasId Nothing (MethodResult Nothing) -- ============================== -- Primitive CReg @@ -134,7 +134,7 @@ cregReadId n = mkId noPosition (mkFString (cregReadStr n)) cregWriteId n = mkId noPosition (mkFString (cregWriteStr n)) cregReadResId, cregWriteEnId, cregWriteArgId :: Id -> Int -> Id -cregReadResId i n = mkMethId i (cregReadId n) Nothing MethodResult +cregReadResId i n = mkMethId i (cregReadId n) Nothing (MethodResult Nothing) cregWriteEnId i n = mkMethId i (cregWriteId n) Nothing MethodEnable cregWriteArgId i n = mkMethId i (cregWriteId n) Nothing (MethodArg 1) @@ -351,7 +351,7 @@ regWriteId pos = mkId pos (mkFString regWriteStr) -- XXX no position? regReadResId, regWriteEnId, regWriteArgId :: Id -> Id -regReadResId i = mkMethId i (regReadId noPosition) Nothing MethodResult +regReadResId i = mkMethId i (regReadId noPosition) Nothing (MethodResult Nothing) regWriteEnId i = mkMethId i (regWriteId noPosition) Nothing MethodEnable regWriteArgId i = mkMethId i (regWriteId noPosition) Nothing (MethodArg 1) @@ -378,17 +378,17 @@ cregToReg old_avi = updVPort new_vn (_, ps) = (new_vn, ps) (new_vFields, new_meth_types) = - let convField (Method nm c r m [] (Just res) Nothing, ts) + let convField (Method nm c r m [] [res] Nothing, ts) | (nm == cregReadId 0) = let nm' = regReadId (getPosition nm) res' = updVPort qoutPortName res - in Just (Method nm' c r m [] (Just res') Nothing, ts) - convField (Method nm c r m [arg] Nothing (Just en), ts) + in Just (Method nm' c r m [] [res'] Nothing, ts) + convField (Method nm c r m [arg] [] (Just en), ts) | (nm == cregWriteId 0) = let nm' = regWriteId (getPosition nm) arg' = updVPort dinPortName arg en' = updVPort enPortName en - in Just (Method nm' c r m [arg'] Nothing (Just en'), ts) + in Just (Method nm' c r m [arg'] [] (Just en'), ts) convField _ = Nothing in unzip $ mapMaybe convField $ @@ -530,11 +530,11 @@ createMapForVMod :: AId -> VFieldInfo -> [(FString,FString)] createMapForVMod _ (Clock _) = [] createMapForVMod _ (Reset _) = [] createMapForVMod _ (Inout {}) = [] -createMapForVMod inst_id (Method meth_id _ _ mult ins mo me) = -- trace (ppReadable result) $ +createMapForVMod inst_id (Method meth_id _ _ mult ins outs me) = -- trace (ppReadable result) $ result where result = zip meths_fstr ports_fstr - (fmeths,fports) = createMapForOneMeth meth_id mult ins me mo + (fmeths,fports) = createMapForOneMeth meth_id mult ins outs me inst_fstr = getIdFString inst_id addInstId fs = concatFString [inst_fstr, fsDollar, fs] meths_fstr = map addInstId fmeths @@ -545,8 +545,8 @@ createMapForVMod inst_id (Method meth_id _ _ mult ins mo me) = -- trace (ppReada -- For a single method, create two lists: -- * The Bluespec names for the arguments and RDY/EN -- (for example, ["set_1","set"] or ["get"]) --- The first items in the list are the arguments, and the last is --- the return value or the enable (depending on the type of method). +-- The first items in the list are the arguments, followed by +-- the return value(s) and/or the enable (depending on the type of method). -- * The Verilog port names corresponding to the Bluespec names -- (for example, ["D_IN","EN"] or ["Q_OUT"]) -- If the method has multiplicity > 1, then the first list @@ -559,37 +559,35 @@ createMapForVMod inst_id (Method meth_id _ _ mult ins mo me) = -- trace (ppReada -- mkMethId in ASyntax -- the two lists should be the same length (this is checked) createMapForOneMeth :: Id -> Integer -> - [VPort] -> Maybe VPort -> Maybe VPort -> + [VPort] -> [VPort] -> Maybe VPort -> ([FString],[FString]) -createMapForOneMeth meth_id mult ins me mo = if check then +createMapForOneMeth meth_id mult ins outs me = if check then -- trace (ppReadable (method_names, verilog_names)) $ (method_names, verilog_names) else err where check = length method_names == length verilog_names err = internalError ("createMapForOneMeth " ++ - ppReadable (meth_id, mult, ins, me, mo)) + ppReadable (meth_id, mult, ins, me, outs)) meth_fstr = getIdFString meth_id meth_mult = if mult <= 1 then [meth_fstr] else [ concatFString [meth_fstr, fsUnderscore, mkNumFString n] | n <- [0 .. mult-1] ] - -- for method "x", make the names "x_1, x_2, .." for the ports - -- make the names x__n for multi-ported methods - method_input_names = [ addNum meth_n arg_n | + -- for method "x", make the names "x_ARG_1, x_ARG_2, .." for the ports + -- make the names x__ARG_n for multi-ported methods + method_input_names = [ mkMethArgStr meth_n (toInteger arg_n) | meth_n <- meth_mult, arg_n <- [1 .. length ins]] - addNum fs n = - concatFString [fs, fsUnderscore, (mkNumFString (toInteger n))] - -- the Verilog port names for the above verilog_input_names = map getFStringForVerilogPair ins - -- names for the output port - (method_output_names, verilog_output_name) = - case (mo) of - Nothing -> ([], []) - Just p -> (meth_mult, [getFStringForVerilogPair p]) + -- names for the output ports + method_output_names = [ mkMethResStr meth_n out_n | + meth_n <- meth_mult, out_n <- methResultNums outs] + + -- the Verilog port names for the above + verilog_output_names = map getFStringForVerilogPair outs -- names for the enable (method_enable_names, verilog_enable_name) = @@ -608,14 +606,14 @@ createMapForOneMeth meth_id mult ins me mo = if check then verilog_names_pre_mult = verilog_input_names ++ verilog_enable_name ++ - verilog_output_name + verilog_output_names -- handle the multiplicity for verilog names here -- note how we go from 1..mult instead of 0..mult-1 -- as the method side does verilog_names = if (mult <= 1) then verilog_names_pre_mult - else [addNum fs n | -- PORT_N + else [concatFString [fs, fsUnderscore, (mkNumFString (toInteger n))] | -- PORT_N fs <- verilog_names_pre_mult, n <- [1..mult]] diff --git a/src/comp/BinData.hs b/src/comp/BinData.hs index 357ff0682..81fcef9dc 100644 --- a/src/comp/BinData.hs +++ b/src/comp/BinData.hs @@ -999,6 +999,7 @@ instance Bin AType where writeBytes (ATReal) = do putI 2; writeBytes (ATArray sz t) = do putI 3; toBin sz; toBin t writeBytes (ATAbstract i szs) = do putI 4; toBin i; toBin szs + writeBytes (ATTuple ts) = do putI 5; toBin ts readBytes = do i <- getI case i of @@ -1007,6 +1008,7 @@ instance Bin AType where 2 -> do return ATReal 3 -> do sz <- fromBin; t <- fromBin; return (ATArray sz t) 4 -> do i <- fromBin; szs <- fromBin; return (ATAbstract i szs) + 5 -> do ts <- fromBin; return (ATTuple ts) n -> internalError $ "GenABin.Bin(AType).readBytes: " ++ show n -- ---------- @@ -1036,6 +1038,8 @@ instance Bin AExpr where writeBytes (AMGate t obj clk) = section "AExpr" $ do putI 14; toBin t; toBin obj; toBin clk writeBytes (ASInout t iot) = section "AExpr" $ do putI 15; toBin t; toBin iot writeBytes (ASReal i t val) = section "AExpr" $ do putI 16; toBin i; toBin t; toBin val + writeBytes (ATupleSel t e idx) = section "AExpr" $ do putI 17; toBin t; toBin e; toBin idx + writeBytes (ATuple t es) = section "AExpr" $ do putI 18; toBin t; toBin es readBytes = do i <- getI case i of @@ -1069,6 +1073,10 @@ instance Bin AExpr where 15 -> do t <- fromBin; iot <- fromBin; return (ASInout t iot) 16 -> do { i <- fromBin; t <- fromBin; val <- fromBin; return (ASReal i t val) } + 17 -> do { t <- fromBin; e <- fromBin; idx <- fromBin; + return (ATupleSel t e idx) } + 18 -> do { t <- fromBin; es <- fromBin; + return (ATuple t es) } n -> internalError $ "GenABin.Bin(IExpr).readBytes: " ++ show n -- toBin e = Out [AExp e] () -- fromBin = readShared diff --git a/src/comp/CSyntax.hs b/src/comp/CSyntax.hs index 91be040d4..9098c5a1b 100644 --- a/src/comp/CSyntax.hs +++ b/src/comp/CSyntax.hs @@ -1311,9 +1311,11 @@ instance PPrint CExpr where f (Inout i (VName p) mc mr) = t "inout_field " <> ppVarId d i <+> t p <+> mfi "clocked_by" mc <+> mfi "reset_by" mr - f (Method i mc mr n ps mo me) = + f (Method i mc mr n ps os me) = ppVarId d i <> g n <+> t "=" <+> t (unwords (map h ps)) <+> - mfi "clocked_by" mc <+> mfi "reset_by" mr <+> mfp "output" mo <+> mfp "enable" me + mfi "clocked_by" mc <+> mfi "reset_by" mr <+> + (if null os then empty else t"output" <+> t (unwords (map h os))) <+> + mfp "enable" me g 1 = t"" g n = t("[" ++ itos n ++ "]") h (s,[]) = show s diff --git a/src/comp/CType.hs b/src/comp/CType.hs index d914decbe..657fad091 100644 --- a/src/comp/CType.hs +++ b/src/comp/CType.hs @@ -457,14 +457,20 @@ getActionValueArg t = internalError ("getActionValueArg: " ++ ppReadable t) -- These are used during foreign function processing to determine if arguments -- and return values are polymorphic or of a known size. isTypePolyBit :: Type -> Bool +isTypePolyBit (TAp (TCon (TyCon i _ _)) (TAp (TCon (TyCon i' _ _)) arg)) + | (i == idActionValue) || (i == idActionValue_), (i' == idBit) = isTVar arg isTypePolyBit (TAp (TCon (TyCon i _ _)) arg) | (i == idBit) || (i == idActionValue) || (i == idActionValue_) = isTVar arg isTypePolyBit _ = False +-- Note that this is only used for foreign functions, so it does not currently handle tuples of Bits bitWidth :: Type -> Integer +bitWidth (TAp (TCon (TyCon i _ _)) (TAp (TCon (TyCon i' _ _)) arg)) + | ((i == idActionValue) || (i == idActionValue_)) && + (i' == idBit) && + (isTNum arg) = getTNum arg bitWidth (TAp (TCon (TyCon i _ _)) arg) - | ((i == idBit) || (i == idActionValue) || (i == idActionValue_)) && - (isTNum arg) = getTNum arg + | (i == idBit) && (isTNum arg) = getTNum arg bitWidth t = internalError $ "bitWidth: not a Bit type of known width -- " ++ (show t) diff --git a/src/comp/CVPrint.hs b/src/comp/CVPrint.hs index bd4aa74e5..3c7dc29ff 100644 --- a/src/comp/CVPrint.hs +++ b/src/comp/CVPrint.hs @@ -850,7 +850,7 @@ ppVeriMethod d _ (Inout i (VName s) mclk mrst) = (case mrst of Nothing -> empty Just i -> t"reset_by (" <> pvpId d i <> t")") -ppVeriMethod d mr (Method i mc mreset n pts mo me) = +ppVeriMethod d mr (Method i mc mreset n pts os me) = let f _ _ Nothing = empty f before after (Just (VName vn, prs)) = (case prs of @@ -859,7 +859,10 @@ ppVeriMethod d mr (Method i mc mreset n pts mo me) = (t (before ++ vn ++ after)) in t"method " <> - (f "" " " mo) <> + (case os of + [] -> empty + [o] -> f "" " " (Just o) + _ -> t"(" <> sepList (map (f "" " " . Just) os) (t",") <> t")") <> (pvpId d i <> (if n == 1 then empty else (t"[" <> (pp d n) <> t"]")) <> (t"(" <> sepList (map (f "" "" . Just) pts) (t",") <> t")") <> diff --git a/src/comp/DisjointTest.hs b/src/comp/DisjointTest.hs index 88d177c79..896c3ac11 100644 --- a/src/comp/DisjointTest.hs +++ b/src/comp/DisjointTest.hs @@ -11,12 +11,13 @@ module DisjointTest( import qualified Data.Set as S import qualified Data.Map as M import Control.Monad(foldM {- , when -}) +import Data.List (genericIndex) import Util(ordPair,uniquePairs) -import Error(ErrorHandle) +import Error(ErrorHandle, internalError) import Pretty -import PPrint(PPrint(..)) +import PPrint(PPrint(..), ppReadable) import Flags import ASyntax @@ -24,7 +25,7 @@ import ASyntaxUtil(AExprs(..), aAnd) import Pragma import VModInfo(VModInfo) -import AExpr2Util(getMethodOutputPort) +import AExpr2Util(getMethodOutputPorts) --import Debug.Trace(trace) import qualified AExpr2STP as STP @@ -270,9 +271,26 @@ buildSupportMap adefs avis rs = --trace ("XXX support map:" ++ ppReadable res) $ findSupport e@(ASDef _ i) = [DDef def i] where def = M.findWithDefault (err i) i idToDef findSupport e@(APrim { ae_args = es}) = findAExprs findSupport es - findSupport e@(AMethCall {ae_args = es}) = findAExprs findSupport es ++ [DMethod (ae_objid e) vlogport] - where vlogport = getMethodOutputPort portMap (ae_objid e) (ameth_id e) - findSupport e@(AMethValue {}) = [DMethod (ae_objid e) (ameth_id e)] + findSupport e@(AMethCall {ae_args = es}) = + case getMethodOutputPorts portMap (ae_objid e) (ameth_id e) of + [vlogport] -> findAExprs findSupport es ++ [DMethod (ae_objid e) vlogport] + ports -> internalError ("buildSupportMap: unexpected output ports: " + ++ ppReadable (ae_objid e, ameth_id e, ports)) + findSupport e@(AMethValue {}) = + case getMethodOutputPorts portMap (ae_objid e) (ameth_id e) of + [vlogport] -> [DMethod (ae_objid e) vlogport] + ports -> internalError ("buildSupportMap: unexpected output ports: " + ++ ppReadable (ae_objid e, ameth_id e, ports)) + findSupport (ATupleSel _ e@(AMethCall {ae_args = es}) idx) = + findAExprs findSupport es ++ [DMethod (ae_objid e) vlogport] + where + ports = getMethodOutputPorts portMap (ae_objid e) (ameth_id e) + vlogport = genericIndex ports (idx - 1) + findSupport (ATupleSel _ e@(AMethValue {}) idx) = + [DMethod (ae_objid e) vlogport] + where + ports = getMethodOutputPorts portMap (ae_objid e) (ameth_id e) + vlogport = genericIndex ports (idx - 1) findSupport e@(ANoInlineFunCall{ ae_args = es}) = findAExprs findSupport es findSupport e@(ATaskValue {ae_objid=id}) = [DTask id] findSupport e@(ASPort {ae_objid = id}) = [DLeaf id] diff --git a/src/comp/GenABin.hs b/src/comp/GenABin.hs index 6cc685e29..c2c855fd5 100644 --- a/src/comp/GenABin.hs +++ b/src/comp/GenABin.hs @@ -34,7 +34,7 @@ import qualified Data.ByteString as B -- .ba file tag -- change this whenever the .ba format changes -- See also GenBin.header header :: [Byte] -header = B.unpack $ TE.encodeUtf8 $ T.pack "bsc-ba-20260427-1" +header = B.unpack $ TE.encodeUtf8 $ T.pack "bsc-ba-20260616-1" genABinFile :: ErrorHandle -> String -> ABin -> IO () genABinFile errh fn abin = diff --git a/src/comp/GenBin.hs b/src/comp/GenBin.hs index 364cb599b..f2fc430e9 100644 --- a/src/comp/GenBin.hs +++ b/src/comp/GenBin.hs @@ -27,7 +27,7 @@ doTrace = elem "-trace-genbin" progArgs -- .bo file tag -- change this whenever the .bo format changes -- See also GenABin.header header :: [Byte] -header = B.unpack $ TE.encodeUtf8 $ T.pack "bsc-bo-20260427-1" +header = B.unpack $ TE.encodeUtf8 $ T.pack "bsc-bo-20260616-1" genBinFile :: ErrorHandle -> String -> CSignature -> CSignature -> IPackage a -> IO () diff --git a/src/comp/GenWrap.hs b/src/comp/GenWrap.hs index 997e962e5..42bf42d73 100644 --- a/src/comp/GenWrap.hs +++ b/src/comp/GenWrap.hs @@ -684,11 +684,11 @@ fixCModuleVerilog n (ss,ts,ps) in [mStmtSPTO vp e] saveArgTypes _ = [] let saveFieldTypes finf (Method { vf_inputs = inps, - vf_output = mo }) = do + vf_outputs = outs }) = do let rt = ret_type finf isAV <- isActionValue rt output_type <- if isAV then getAVType "fixCModVer" rt else return rt - let output_stmt = maybeToList (fmap ((flip mStmtSPT) rt) mo) + let output_stmt = map ((flip mStmtSPT) rt) outs -- we let the type-checker error on mismatches return (output_stmt ++ (zipWith mStmtSPT inps (arg_types finf))) saveFieldTypes finf (Inout { vf_inout = vn }) = do @@ -796,7 +796,7 @@ procType (n, ns, as, ts, ctx) ty = do if isAV then do av_t <- getAVType "procType" ty return (n+1, newId:ns, newSVar:as, - (ty, (TAp tActionValue_ (cTVarNum newId))):ts, + (ty, (TAp tActionValue_ (TAp tBit (cTVarNum newId)))):ts, (bitsCtx av_t newSVar):ctx) else do isInout <- isInoutType ty @@ -1112,10 +1112,13 @@ genTo pps ty mk = localPrefix = joinStrings_ currentPre localPrefix1 prefix = stringLiteralAt noPosition localPrefix arg_names = mkList (getPosition f) [stringLiteralAt (getPosition i) (getIdString i) | i <- aIds] - fnp = mkTypeProxyExpr $ TAp (cTCon idStrArg) $ cTStr (fieldPathName prefixes f)(getIdPosition f) + localResult1 = fromMaybe (getIdBaseString f) (lookupResultIfcPragma ciPrags) + localResult = joinStrings_ currentPre localResult1 + result = stringLiteralAt noPosition localResult + fnp = mkTypeProxyExpr $ TAp (cTCon idStrArg) $ cTStr (fieldPathName prefixes f) (getIdPosition f) -- XXX idEmpty is a horrible way to know no more selection is required let ec = if f == idEmpty then sel else CSelect sel (setInternal f) - let e = CApply (CVar idToWrapField) [fnp, prefix, arg_names, ec] + let e = CApply (CVar idToWrapField) [fnp, prefix, arg_names, result, ec] return [CLValue (binId prefixes f) [CClause [] [] e] []] -- -------------------- @@ -1637,10 +1640,10 @@ fixupVeriField _ _ f@(Reset { }) = f fixupVeriField _ _ f@(Inout { }) = f fixupVeriField pps vportprops m@(Method { }) = m { vf_inputs = inputs', - vf_output = output', + vf_outputs = outputs', vf_enable = enable'' } where inputs' = map fixup (vf_inputs m) - output' = fmap fixup (vf_output m) + outputs' = map fixup (vf_outputs m) enable' = fmap fixup (vf_enable m) fixup = fixupPort vportprops alwaysEnabled = isAlwaysEn pps (vf_name m) @@ -2044,10 +2047,8 @@ genNewMethodIfcPragmas ifcp pragmas fieldId newFieldId = ar = if (isAlwaysReadyIfc joinedPrags) then [PIAlwaysRdy ] else [] ae = if (isAlwaysEnabledIfc joinedPrags) then [PIAlwaysEnabled ] else [] -- The result names used the prefix plus the given of generated name - mResName = lookupResultIfcPragma pragmas - resultName = case mResName of - Just str -> joinStrings_ currentPre str - Nothing -> joinStrings_ currentPre methodStr + localResult1 = fromMaybe (getIdString fieldId) (lookupResultIfcPragma pragmas) + resultName = joinStrings_ currentPre localResult1 -- resName = (PIResultName resultName) -- The ready name @@ -2203,14 +2204,11 @@ mkFieldSavePortTypeStmts v ifcId = concatMapM $ meth noPrefixes ifcId _ -> do -- Compute the local prefix and result name for this field in the flattened interface -- from the current prefixes and pragmas from the field definition. - let methodStr = getIdBaseString f - currentPre = ifcp_renamePrefixes prefixes -- the current rename prefix + let currentPre = ifcp_renamePrefixes prefixes -- the current rename prefix localPrefix1 = fromMaybe (getIdBaseString f) (lookupPrefixIfcPragma ciPrags) localPrefix = joinStrings_ currentPre localPrefix1 - mResName = lookupResultIfcPragma ciPrags - resultName = case mResName of - Just str -> joinStrings_ currentPre str - Nothing -> joinStrings_ currentPre methodStr + localResult1 = fromMaybe (getIdBaseString f) (lookupResultIfcPragma ciPrags) + localResult = joinStrings_ currentPre localResult1 -- Arguments to saveFieldPortTypes: proxies for the field name as a type level string and the field type, -- and the values for the prefix, arg_names, and result pragmas. @@ -2218,7 +2216,7 @@ mkFieldSavePortTypeStmts v ifcId = concatMapM $ meth noPrefixes ifcId proxy = mkTypeProxyExpr $ foldr arrow r as prefix = stringLiteralAt noPosition localPrefix arg_names = mkList (getPosition f) [stringLiteralAt (getPosition i) (getIdString i) | i <- aIds] - result = stringLiteralAt noPosition resultName + result = stringLiteralAt noPosition localResult return [ CSExpr Nothing $ cVApply idLiftModule $ diff --git a/src/comp/IExpand.hs b/src/comp/IExpand.hs index 4e45159ed..807e5e352 100644 --- a/src/comp/IExpand.hs +++ b/src/comp/IExpand.hs @@ -318,7 +318,7 @@ iExpand errh flags symt alldefs is_noinlined_func pps def@(IDef mi _ _ _) = do in -- return the expression that should replace the heap pointer, -- and maybe a Def, if the expression is a def reference - if simple e || isActionType t then + if simple e || isActionType t || isPairType t then -- inline the expression, no def is created for this heap ptr (e', Nothing) else @@ -1043,11 +1043,11 @@ iExpandField modId implicitCond clkRst (i, bi, e, t) = do showTopProgress ("Elaborating method " ++ quote (pfpString i)) setIfcSchedNameScopeProgress (Just (IEP_Method i False)) (_, P p e') <- evalUH e - let (ins, eb) = case e' of - ICon _ (ICMethod _ ins eb) -> (ins, eb) + let (ins, outs, eb) = case e' of + ICon _ (ICMethod _ ins outs eb) -> (ins, outs, eb) _ -> internalError ("iExpandField: expected ICMethod: " ++ ppReadable e') (its, ((IDef i1 t1 e1 _), ws1, fi1), ((IDef wi wt we _), ws2, fi2)) - <- iExpandMethod modId 1 [] (pConj implicitCond p) clkRst (i, bi, ins, eb) + <- iExpandMethod modId 1 [] (pConj implicitCond p) clkRst (i, bi, ins, outs, eb) let wp1 = wsToProps ws1 -- default clock domain forced in by iExpandField let wp2 = wsToProps ws2 setIfcSchedNameScopeProgress Nothing @@ -1056,10 +1056,10 @@ iExpandField modId implicitCond clkRst (i, bi, e, t) = do -- expand a method iExpandMethod :: Id -> Integer -> [Id] -> HPred -> - (HClock, HReset) -> (Id, BetterInfo.BetterInfo, [String], HExpr) -> + (HClock, HReset) -> (Id, BetterInfo.BetterInfo, [String], [String], HExpr) -> G ([(Id, IType)], (HDef, HWireSet, VFieldInfo), (HDef, HWireSet, VFieldInfo)) -iExpandMethod modId n args implicitCond clkRst@(curClk, _) (i, bi, ins, e) = do +iExpandMethod modId n args implicitCond clkRst@(curClk, _) (i, bi, ins, outs, e) = do when doDebug $ traceM ("iExpandMethod " ++ ppString i ++ " " ++ ppReadable e) (_, P p e') <- evalUH e case e' of @@ -1069,23 +1069,24 @@ iExpandMethod modId n args implicitCond clkRst@(curClk, _) (i, bi, ins, e) = do -- a GenWrap-added context that wasn't satisfied, and GenWrap -- should only be adding Bits) errG (reportNonSynthTypeInMethod modId i e') - ILam li ty eb -> iExpandMethodLam modId n args implicitCond clkRst (i, bi, ins, eb) li ty p - _ -> iExpandMethod' implicitCond curClk (i, bi, e') p + ILam li ty eb -> iExpandMethodLam modId n args implicitCond clkRst (i, bi, ins, outs, eb) li ty p + _ -> iExpandMethod' implicitCond curClk (i, bi, outs, e') p iExpandMethodLam :: Id -> Integer -> [Id] -> HPred -> - (HClock, HReset) -> (Id, BetterInfo.BetterInfo, [String], HExpr) -> + (HClock, HReset) -> (Id, BetterInfo.BetterInfo, [String], [String], HExpr) -> Id -> IType -> Pred HeapData -> G ([(Id, IType)], (HDef, HWireSet, VFieldInfo), (HDef, HWireSet, VFieldInfo)) -iExpandMethodLam modId n args implicitCond clkRst (i, bi, ins, eb) li ty p = do - -- traceM ("iExpandMethodLam " ++ ppString i ++ " " ++ show ins) +iExpandMethodLam modId n args implicitCond clkRst (i, bi, ins, outs, eb) li ty p = do + --traceM ("iExpandMethodLam " ++ ppString i ++ " " ++ show (ins, outs)) + if null ins then internalError "iExpandMethodLam: no inputs" else return () let i' :: Id i' = mkId (getPosition i) $ mkFString $ head ins -- substitute argument with a modvar and replace with body eb' :: HExpr eb' = eSubst li (ICon i' (ICMethArg ty)) eb (its, (d, ws1, wf1), (wd, ws2, wf2)) <- - iExpandMethod modId (n+1) (i':args) (pConj implicitCond p) clkRst (i, bi, tail ins, eb') + iExpandMethod modId (n+1) (i':args) (pConj implicitCond p) clkRst (i, bi, tail ins, outs, eb') let inps :: [VPort] inps = vf_inputs wf1 let wf1' :: VFieldInfo @@ -1094,11 +1095,11 @@ iExpandMethodLam modId n args implicitCond clkRst (i, bi, ins, eb) li ty p = do _ -> internalError "iExpandMethodLam: unexpected wf1" return ((i', ty) : its, (d, ws1, wf1'), (wd, ws2, wf2)) -iExpandMethod' :: HPred -> HClock -> (Id, BetterInfo.BetterInfo, HExpr) -> +iExpandMethod' :: HPred -> HClock -> (Id, BetterInfo.BetterInfo, [String], HExpr) -> Pred HeapData -> G ([(Id, IType)], (HDef, HWireSet, VFieldInfo), (HDef, HWireSet, VFieldInfo)) -iExpandMethod' implicitCond curClk (i, bi, e0) p0 = do +iExpandMethod' implicitCond curClk (i, bi, outs, e0) p0 = do norm <- getTypeNormalizerC -- want the result type, not a type including arguments let methType :: IType @@ -1142,7 +1143,7 @@ iExpandMethod' implicitCond curClk (i, bi, e0) p0 = do IAps f@(ICon _ (ICTuple {})) ts [e1, e2] | isActionType methType -> let pos = getIdPosition i - vt = actionValue_BitN methType + vt = getAV_Type methType v = icUndetAt pos vt UNotUsed in (IAps f ts [v, icNoActions], ws) _ -> internalError "iExpandMethod: fixupActionWireSet" @@ -1158,8 +1159,8 @@ iExpandMethod' implicitCond curClk (i, bi, e0) p0 = do rdyId = mkRdyId i let enablePort :: Maybe VPort enablePort = toMaybe (isActionType methType) (BetterInfo.mi_enable bi) - let outputPort :: Maybe VPort - outputPort = toMaybe (isValueType methType) (BetterInfo.mi_result bi) + let outputPorts :: [VPort] + outputPorts = map (id_to_vPort . mkId (getPosition i) . mkFString) outs let rdyPort :: VPort rdyPort = BetterInfo.mi_ready bi @@ -1171,12 +1172,12 @@ iExpandMethod' implicitCond curClk (i, bi, e0) p0 = do Method { vf_name = i, vf_clock = methClock, vf_reset = methReset, vf_mult = 1, vf_inputs = [], - vf_output = outputPort, vf_enable = enablePort }), + vf_outputs = outputPorts, vf_enable = enablePort }), ((IDef rdyId itBit1 readySignal []), final_ws, Method { vf_name = rdyId, vf_clock = methClock, vf_reset = methReset, vf_mult = 1, vf_inputs = [], - vf_output = Just rdyPort, vf_enable = Nothing })) + vf_outputs = [rdyPort], vf_enable = Nothing })) -- deduce clock name for VFieldInfo -- type required to control ancestry-checking with action methods @@ -2561,20 +2562,16 @@ walkNF e = -- XXX is adding the clock to the wire set redundant? clk@(ICon i (ICClock { iClock = c })) : _ -> upd (pConj p0 p) (IAps f ts es') (wsAddClock c ws) - -- if the outer selector is avValue_ or avAction_ - -- and the inner is a method call - [(IAps sel@(ICon i_sel2 (ICSel { })) ts_2 es_2)] - | (i_sel == idAVValue_ || i_sel == idAVAction_) -> do - case es_2 of - st@(ICon i (ICStateVar { iVar = v })) : _ -> - handleMethod i_sel2 v - _ -> internalError ("walkNF: selector should be a method call") - - -- the inner selector can wind up on the heap - -- because of "move" in evalHeap - [e_ref@(IRefT t ptr ref)] | (isitActionValue_ t) || (isitAction t) - -> do (P p' e', ws) <- walkNF e_ref - upd (pConj p0 p') (IAps f ts [e']) ws + -- We can be selecting the avValue or avAction from an ActionValue method, + -- or a tuple member out of the result of calling a method with multiple outputs, + -- and need to recurse. + [e] | (i_sel == idAVValue_ || + i_sel == idAVAction_ || + i_sel == idPrimFst || + i_sel == idPrimSnd) -> do + do (P p' e', ws) <- walkNF e + upd (pConj p0 p') (IAps f ts [e']) ws + _ -> do when doDebug $ traceM "not stvar or foreign\n" when doDebug $ traceM (show u ++ "\n") when doDebug $ traceM (show es' ++ "\n") @@ -2589,6 +2586,11 @@ walkNF e = (P p' e', ws) <- walkNF e upd (pConjs [p0, p, p']) e' ws + IAps f@(ICon _ (ICTuple {})) ts [e1, e2] -> do + (P pe1 e1', ws1) <- walkNF e1 + (P pe2 e2', ws2) <- walkNF e2 + upd (pConj pe1 pe2) (IAps f ts [e1', e2']) (wsJoin ws1 ws2) + -- Any other application is not in NF (which is unexpected?) IAps f ts es -> do _ <- internalError ("walkNF fall-through: " ++ ppReadable (f,ts,es)) @@ -3167,10 +3169,16 @@ conAp' i (ICPrim _ PrimIsRawUndefined) _ (T t : E e : as) = do _ -> -- do traceM ("IsRawUndefined: False") return (P p iFalse) -conAp' i (ICPrim _ PrimMethod) _ [T t, E eInNames, E meth] = do +conAp' i (ICPrim _ PrimMethod) _ [T t, E eInNames, E eOutNames, E meth] = do (inNames, _) <- evalStringList eInNames + (outNames, _) <- evalStringList eOutNames P p meth' <- eval1 meth - return $ P p $ ICon (dummyId noPosition) $ ICMethod {iConType = t, iInputNames = inNames, iMethod = meth'} + return $ P p $ ICon (dummyId noPosition) $ ICMethod { + iConType = t, + iInputNames = inNames, + iOutputNames = outNames, + iMethod = meth' + } -- XXX is this still needed? conAp' i (ICUndet { iConType = t }) e as | t == itClock = @@ -3894,7 +3902,7 @@ conAp' _ (ICPrim _ op) fe@(ICon prim_id _) as | strictPrim op = do when doTrans $ traceM ("conAp: iTransform fallthrough: " ++ ppReadable (op, mkAp fe as')) errh <- getErrHandle case (iTransExpr errh (mkAp fe as')) of - (e', True) -> do + (e', True) | isBitType (iGetType e') -> do -- we used to evaluate further here, but that shouldn't -- be necessary (and probably indicates a bug elsewhere) when (doDebug || doTrans) $ traceM ("conAp: iTransform result: " ++ ppReadable e') @@ -4876,6 +4884,11 @@ doSel sel s tys ty n as ee (p, e) = -- canonical applications are strict (e.g. method call applications) _ | isCanon e -> bldApUH' "Sel" sel (map T tys ++ (E ee : as)) + -- tuple section from a multi-output method result + _ | s == idPrimFst || s == idPrimSnd -> do + (_, P p e') <- evalUH e + addPredG p $ bldApUH' "Sel PrimFst/Snd" sel (map T tys ++ (E e' : as)) + -- otherwise fail _ -> internalError ("doSel: " ++ ppReadable (sel, e, as)) diff --git a/src/comp/IExpandUtils.hs b/src/comp/IExpandUtils.hs index 79c9a1425..330b742ef 100644 --- a/src/comp/IExpandUtils.hs +++ b/src/comp/IExpandUtils.hs @@ -362,19 +362,24 @@ isPrimType (ITCon i _ _) = i == idPrimAction || -- i == idInteger i == idFmt || -- also not really a primitive i == idClock || - i == idReset + i == idReset || + i == idPrimUnit +-- ActionValue_ must be applied to (a tuple of) Bit +isPrimType (ITAp (ITCon i _ _) t) + | i == idActionValue_ = t == itPrimUnit || isBitTupleType t -- Primitive constructor applied to numeric type(s) -- We normalize types so no unresolved numeric types should escape elaboration. isPrimType (ITAp a (ITNum _)) = isPrimTAp a -- Primitive arrays isPrimType (ITAp (ITCon i _ _) elem_ty) | i == idPrimArray = isPrimType elem_ty +-- Tuples of bits +isPrimType t | isBitTupleType t = True isPrimType _ = False -- Primitive type applications isPrimTAp :: IType -> Bool isPrimTAp (ITCon _ _ (TIstruct SInterface{} _)) = True -isPrimTAp (ITCon i _ _) = i == idActionValue_ || - i == idBit || +isPrimTAp (ITCon i _ _) = i == idBit || i == idInout_ -- Again, no unresolved numeric types should escape elaboration. isPrimTAp (ITAp a (ITNum _)) = isPrimTAp a @@ -2069,8 +2074,8 @@ chkIfcPortNames errh args ifcs (ClockInfo ci co _ _) (ResetInfo ri ro) = ifc_port_names = [ (n, i) - | IEFace {ief_fieldinfo = Method i _ _ _ ins out en} <- ifcs, - (VName n, _) <- ins ++ maybeToList out ++ maybeToList en ] + | IEFace {ief_fieldinfo = Method i _ _ _ ins outs en} <- ifcs, + (VName n, _) <- ins ++ outs ++ maybeToList en ] ifc_inout_names = [ (n, i) | IEFace {ief_fieldinfo = Inout i (VName n) _ _} <- ifcs ] ifc_clock_names = diff --git a/src/comp/IInlineFmt.hs b/src/comp/IInlineFmt.hs index 54c117277..347e07a50 100644 --- a/src/comp/IInlineFmt.hs +++ b/src/comp/IInlineFmt.hs @@ -354,12 +354,13 @@ createValueExprs x = [createValueExpr x] -- ############################################################################# createValueExpr :: IExpr a -> IExpr a -createValueExpr (IAps (ICon c (ICSel {})) [ITNum s] [e@(IAps (ICon _ (ICForeign {})) _ _)]) | c == idAVAction_ +createValueExpr (IAps (ICon c (ICSel {})) [ITAp b (ITNum s)] [e@(IAps (ICon _ (ICForeign {})) _ _)]) + | c == idAVAction_, b == itBit = x - where x = (IAps (ICon idAVValue_ (ICSel {iConType = tt , selNo = 0, numSel = 2 })) [ITNum s] [e]) + where x = (IAps (ICon idAVValue_ (ICSel {iConType = tt , selNo = 0, numSel = 2 })) [ITAp itBit $ ITNum s] [e]) v0 = head tmpVarIds - tt = ITForAll v0 IKNum (ITAp (ITAp (ITCon (idArrow noPosition) (IKFun IKStar (IKFun IKStar IKStar)) TIabstract) (ITAp (ITCon idActionValue_ (IKFun IKNum IKStar) (TIstruct SStruct [idAVValue_,idAVAction_])) (ITVar v0))) - (ITAp itBit (ITVar v0)) ) + tt = ITForAll v0 IKStar (ITAp (ITAp (ITCon (idArrow noPosition) (IKFun IKStar (IKFun IKStar IKStar)) TIabstract) (ITAp (ITCon idActionValue_ (IKFun IKStar IKStar) (TIstruct SStruct [idAVValue_,idAVAction_])) (ITVar v0))) + (ITVar v0) ) createValueExpr (IAps cc@(ICon i (ICPrim _ PrimIf)) ts [cond, e0, e1]) = x where x = (IAps cc [rt] [cond, e0', e1']) @@ -370,11 +371,12 @@ createValueExpr x = internalError ("createValueExpr: " ++ ppReadable x) createActionExpr :: IExpr a -> IExpr a -createActionExpr (IAps (ICon c (ICSel {})) [ITNum s] [e@(IAps (ICon _ (ICForeign {})) _ _)]) | c == idAVValue_ +createActionExpr (IAps (ICon c (ICSel {})) [ITAp b (ITNum s)] [e@(IAps (ICon _ (ICForeign {})) _ _)]) + | c == idAVValue_, b == itBit = x - where x = (IAps (ICon idAVAction_ (ICSel {iConType = tt , selNo = 1, numSel = 2 })) [ITNum s] [e]) + where x = (IAps (ICon idAVAction_ (ICSel {iConType = tt , selNo = 1, numSel = 2 })) [ITAp itBit $ ITNum s] [e]) v0 = head tmpVarIds - tt = ITForAll v0 IKNum (ITAp (ITAp (ITCon (idArrow noPosition) (IKFun IKStar (IKFun IKStar IKStar)) TIabstract) (ITAp (ITCon idActionValue_ (IKFun IKNum IKStar) (TIstruct SStruct [idAVValue_,idAVAction_])) (ITVar v0))) + tt = ITForAll v0 IKStar (ITAp (ITAp (ITCon (idArrow noPosition) (IKFun IKStar (IKFun IKStar IKStar)) TIabstract) (ITAp (ITCon idActionValue_ (IKFun IKStar IKStar) (TIstruct SStruct [idAVValue_,idAVAction_])) (ITVar v0))) itAction ) createActionExpr (IAps cc@(ICon i (ICPrim _ PrimIf)) ts [cond, e0, e1]) = x @@ -386,14 +388,16 @@ createActionExpr x = joinActions [] allStrings :: IExpr a -> Bool -allStrings (IAps (ICon c (ICSel {})) [ITNum s] [(IAps (ICon _ (ICForeign {})) _ [e])]) | c == idAVAction_ && iGetType e == itString +allStrings (IAps (ICon c (ICSel {})) [ITAp b (ITNum s)] [(IAps (ICon _ (ICForeign {})) _ [e])]) + | c == idAVAction_ && b == itBit && iGetType e == itString = True allStrings (IAps (ICon i (ICPrim _ PrimIf)) _ [_, e0, e1]) = allStrings e0 && allStrings e1 allStrings _ = False createStringExpr :: IExpr a -> IExpr a -createStringExpr (IAps (ICon c (ICSel {})) [ITNum s] [(IAps (ICon _ (ICForeign {})) _ [e])]) | c == idAVAction_ +createStringExpr (IAps (ICon c (ICSel {})) [ITAp b (ITNum s)] [(IAps (ICon _ (ICForeign {})) _ [e])]) + | c == idAVAction_, b == itBit = e createStringExpr (IAps cc@(ICon i (ICPrim _ PrimIf)) ts [cond, e0, e1]) = x diff --git a/src/comp/ISplitIf.hs b/src/comp/ISplitIf.hs index 93fd3c942..07ef8351e 100644 --- a/src/comp/ISplitIf.hs +++ b/src/comp/ISplitIf.hs @@ -445,7 +445,7 @@ iSplitIface flags ieface@(IEFace i xargs (Just (e,t)) Nothing wp fi) in (smap, IEFace i xargs Nothing (Just irules_opt) wp fi) else case e of (IAps (ICon av (ICTuple {fieldIds = [_val_id,_act_id]})) - [ITNum _] [val_,act_]) + [_] [val_,act_]) | (av == idActionValue_) -> let irule = IRule i [] (getIdString i) wp iTrue act_ Nothing [] irules = IRules [] [irule] -- no sps @@ -457,9 +457,9 @@ iSplitIface flags ieface@(IEFace i xargs (Just (e,t)) Nothing wp fi) iSplitIface _ _ = internalError ("iSplitIface: no expression or unexpected rule") mkExpression :: IExpr a -> IType -> Maybe (IExpr a, IType) -mkExpression val_ ty = if (0==(getAV_Size ty)) +mkExpression val_ ty = if (isEmptyType (getAV_Type ty)) then Nothing - else (Just (val_,(actionValue_BitN ty))) + else (Just (val_,(getAV_Type ty))) check_meth_rules :: (PrimOp -> Bool) -> IEFace a -> Maybe (IExpr a) diff --git a/src/comp/ISyntax.hs b/src/comp/ISyntax.hs index 09ea35e2f..dd0260966 100644 --- a/src/comp/ISyntax.hs +++ b/src/comp/ISyntax.hs @@ -820,7 +820,7 @@ data IConInfo a = -- only exists before expansion | ICSchedPragmas { iConType :: IType, iPragmas :: [CSchedulePragma] } - | ICMethod { iConType :: IType, iInputNames :: [String], iMethod :: IExpr a } + | ICMethod { iConType :: IType, iInputNames :: [String], iOutputNames :: [String], iMethod :: IExpr a } | ICClock { iConType :: IType, iClock :: IClock a } | ICReset { iConType :: IType, iReset :: IReset a } -- iReset has effective type itBit1 | ICInout { iConType :: IType, iInout :: IInout a } @@ -915,8 +915,8 @@ cmpC c1 c2 = ICIFace { ifcTyId = ti1, ifcIds = is1 } -> compare (ti1, is1) (ifcTyId c2, ifcIds c2) ICRuleAssert { iAsserts = asserts } -> compare asserts (iAsserts c2) ICSchedPragmas { iPragmas = pragmas } -> compare pragmas (iPragmas c2) - ICMethod { iInputNames = inames1, iMethod = meth1 } -> - compare (inames1, meth1) (iInputNames c2, iMethod c2) + ICMethod { iInputNames = inames1, iOutputNames = outnames1, iMethod = meth1 } -> + compare (inames1, outnames1, meth1) (iInputNames c2, iOutputNames c2, iMethod c2) -- the ICon Id is not sufficient for equality comparison for Clk/Rst ICClock { iClock = clock1 } -> compare clock1 (iClock c2) ICReset { iReset = reset1 } -> compare reset1 (iReset c2) @@ -1241,7 +1241,7 @@ instance NFData (IConInfo a) where rnf (ICIFace x1 x2 x3) = rnf3 x1 x2 x3 rnf (ICRuleAssert x1 x2) = rnf2 x1 x2 rnf (ICSchedPragmas x1 x2) = rnf2 x1 x2 - rnf (ICMethod x1 x2 x3) = rnf3 x1 x2 x3 + rnf (ICMethod x1 x2 x3 x4) = rnf4 x1 x2 x3 x4 rnf (ICClock x1 x2) = rnf2 x1 x2 rnf (ICReset x1 x2) = rnf2 x1 x2 rnf (ICInout x1 x2) = rnf2 x1 x2 @@ -1463,7 +1463,7 @@ showTypelessCI (ICValue {iConType = t, iValDef = e}) = "(ICValue)" showTypelessCI (ICIFace {iConType = t, ifcTyId = i, ifcIds = ids}) = "(ICIFace _ " ++ (show i) ++ " " ++ (show ids) ++ ")" showTypelessCI (ICRuleAssert {iConType = t, iAsserts = rps}) = "(ICRuleAssert _ " ++ (show rps) ++ ")" showTypelessCI (ICSchedPragmas {iConType = t, iPragmas = sps}) = "(ICSchedPragmas _ " ++ (show sps) ++ ")" -showTypelessCI (ICMethod {iConType = t, iInputNames = ins, iMethod = m }) = "(ICMethod " ++ (show ins) ++ " " ++ (ppReadable m) ++ ")" +showTypelessCI (ICMethod {iConType = t, iInputNames = ins, iOutputNames = outs, iMethod = m }) = "(ICMethod " ++ (show ins) ++ " " ++ (show outs) ++ " " ++ (ppReadable m) ++ ")" showTypelessCI (ICClock {iConType = t, iClock = clock}) = "(ICClock)" showTypelessCI (ICReset {iConType = t, iReset = reset}) = "(ICReset)" showTypelessCI (ICInout {iConType = t, iInout = inout}) = "(ICInout)" diff --git a/src/comp/ISyntaxUtil.hs b/src/comp/ISyntaxUtil.hs index a8f5d3476..bbe73dd93 100644 --- a/src/comp/ISyntaxUtil.hs +++ b/src/comp/ISyntaxUtil.hs @@ -121,18 +121,16 @@ isSimpleType t = t == itInteger || t == itChar isitAction :: IType -> Bool -isitAction (ITAp (ITCon i (IKFun IKNum IKStar) - (TIstruct SStruct [_,_] ) ) (ITNum x)) - | (i == idActionValue_) = (x == 0) -isitAction (ITAp (ITCon i (IKFun IKStar IKStar) _) t) - | (i == idActionValue) = t == itPrimUnit +isitAction (ITAp (ITCon i (IKFun IKStar IKStar) _ ) t) + | (i == idActionValue_) || (i == idActionValue) = isEmptyType t isitAction x = (x == itAction) --- note this returns false for x == - because ActionValue_ 0 is really an Action +-- note this returns false for x == () because ActionValue_ () is really an Action +-- Also handle ActionValue_ (Bit 0), which can be introduced by foreign functions. isitActionValue_ :: IType -> Bool -isitActionValue_ (ITAp (ITCon i (IKFun IKNum IKStar) - (TIstruct SStruct [_,_] ) ) (ITNum x)) - | x > 0 = (i == idActionValue_) +isitActionValue_ (ITAp (ITCon i (IKFun IKStar IKStar) + (TIstruct SStruct [_,_] ) ) t) = + (i == idActionValue_) && not (isEmptyType t) isitActionValue_ _ = False isitActionValue :: IType -> Bool @@ -150,11 +148,11 @@ getInout_Size t = internalError ("getInout_Size: type is not Inout_: " ++ ppReadable t) -getAV_Size :: IType -> Integer -getAV_Size (ITAp (ITCon i (IKFun IKNum IKStar) - (TIstruct SStruct [_,_] ) ) (ITNum x)) | - (i == idActionValue_) = x -getAV_Size t = internalError ("getAV_Size: type is not AV_: " ++ ppReadable t) +getAV_Type :: IType -> IType +getAV_Type (ITAp (ITCon i (IKFun IKStar IKStar) + (TIstruct SStruct [_,_] ) ) t) | + (i == idActionValue_) = t +getAV_Type t = internalError ("getAV_Type: type is not AV_: " ++ ppReadable t) getAVType :: IType -> Maybe IType getAVType (ITAp (ITCon i (IKFun IKStar IKStar) _) t) | i == idActionValue = Just t @@ -176,20 +174,28 @@ itList, itMaybe :: IType -> IType itList t = ITAp (ITCon idList (IKFun IKStar IKStar) tiList) t itMaybe t = ITAp (ITCon idMaybe (IKFun IKStar IKStar) tiMaybe) t +isPairType :: IType -> Bool +isPairType (ITAp (ITAp (ITCon i _ _) _) _) = i == idPrimPair +isPairType _ = False + +isEmptyType :: IType -> Bool +isEmptyType (ITCon i _ _) = i == idPrimUnit +isEmptyType (ITAp c (ITNum 0)) = c == itBit +isEmptyType t = False + isBitType :: IType -> Bool isBitType (ITAp c n) = c == itBit isBitType _ = False +isBitTupleType :: IType -> Bool +isBitTupleType (ITAp (ITAp (ITCon i _ _) t1) t2) | i == idPrimPair = + isBitType t1 && isBitTupleType t2 +isBitTupleType t = isBitType t + -- extension point for ActionValue methods isActionType :: IType -> Bool isActionType x = (x == itAction) || (isitActionValue_ x) || (isitAction x) --- extension point for ActionValue methods -isValueType :: IType -> Bool -isValueType x | (isitActionValue_ x) && (getAV_Size x > 0) = True -isValueType (ITAp t n) | t == itBit = True -isValueType _ = False - -- Constructors iMkLit :: IType -> Integer -> IExpr a iMkLit t i = ICon idIntLit (ICInt { iConType = t, iVal = ilDec i }) @@ -1093,10 +1099,6 @@ joinActions [] = icNoActions joinActions as = foldr1 ja as where ja a1 a2 = IAps icJoinActions [] [a1, a2] --- perhaps the position information should be transferred over XXX -actionValue_BitN :: IType -> IType -actionValue_BitN t = itBitN (getAV_Size t) - iStrToInt :: String -> Position -> IExpr a iStrToInt s pos = iMkLitAt pos itInteger i where i = foldl sumString 0 s diff --git a/src/comp/ITransform.hs b/src/comp/ITransform.hs index 4b76fce44..28f15f0aa 100644 --- a/src/comp/ITransform.hs +++ b/src/comp/ITransform.hs @@ -249,8 +249,8 @@ runCSE e@(IAps _ _ _) = do -- because "runCSE" is called from iTrExpr, which already recurses on the -- arguments, so runCSE will already have been called on the arguments. let t = iGetType e - -- Only CSE applications that are not actions - if not (isActionType t) then + -- Only CSE applications that are not actions or tuple method values + if not (isActionType t || isPairType t) then newExprT t e else return e diff --git a/src/comp/IfcBetterInfo.hs b/src/comp/IfcBetterInfo.hs index 8baded88b..a519d8877 100644 --- a/src/comp/IfcBetterInfo.hs +++ b/src/comp/IfcBetterInfo.hs @@ -25,7 +25,6 @@ import VModInfo -- and for recording the types of external method ports data BetterInfo = BetterMethodInfo { mi_id :: Id, -- method Id - mi_result :: VPort, -- possible rename for method result mi_ready :: VPort, -- for ready signal mi_enable :: VPort, -- for enable signal mi_prefix :: Id -- default prefix for arguments (which are not found in classic) @@ -49,7 +48,6 @@ matchMethodName id mn = qualEq id (mi_id mn) -- creates a basic method remaing noMethodInfo :: Id -> BetterInfo noMethodInfo fieldId = BetterMethodInfo {mi_id = fieldId, - mi_result = id_to_vPort fieldId, mi_ready = id_to_vPort $ mkRdyId fieldId, mi_enable = id_to_vPort $ mkEnableId fieldId, mi_prefix = fieldId @@ -58,8 +56,7 @@ noMethodInfo fieldId = BetterMethodInfo {mi_id = fieldId, instance PPrint BetterInfo where pPrint d i info = (text "methodNames") <> ppId d (mi_id info) <> equals <> braces - ( printMaybe d i "Result:" (mi_result info) <> - printMaybe d i "Ready:" (mi_ready info) <> + ( printMaybe d i "Ready:" (mi_ready info) <> printMaybe d i "Enable:" (mi_enable info) <> text "Prefix:" <> pPrint d i (mi_prefix info) ) @@ -93,10 +90,9 @@ fieldInfoToBetterInfo :: Flags -> SymTab -> (Id,Maybe FieldInfo) -> BetterInfo fieldInfoToBetterInfo flags symTab (fieldId, Nothing) = noMethodInfo fieldId fieldInfoToBetterInfo flags symTab (fieldId, Just fi) = BetterMethodInfo {mi_id = fieldId, - mi_result = maybe (id_to_vPort fieldId) (str_to_vPort) mres, mi_ready = maybe (id_to_vPort $ mkRdyId fieldId) str_to_vPort mrdy, mi_enable = maybe (id_to_vPort $ mkEnableId fieldId) str_to_vPort men, mi_prefix = maybe fieldId (setIdBaseString fieldId) mprefix } where prags = fi_pragmas fi - (mprefix,mres,mrdy,men,_,_,_) = getMethodPragmaInfo prags + (mprefix,_,mrdy,men,_,_,_) = getMethodPragmaInfo prags diff --git a/src/comp/LambdaCalc.hs b/src/comp/LambdaCalc.hs index 8a62f0fa8..bc55c1db7 100644 --- a/src/comp/LambdaCalc.hs +++ b/src/comp/LambdaCalc.hs @@ -915,6 +915,7 @@ convAType (ATString (Just width)) = stringType -- XXX ? convAType (ATReal) = realType convAType (ATArray sz t) = arrType sz (convAType t) convAType t | (t == mkATBool) = boolType +convAType (ATTuple ts) = internalError ("convAType: multi-output methods are not yet supported") convAType t@(ATAbstract {}) = internalError ("convAType: " ++ ppReadable t) -- ----- @@ -1026,7 +1027,11 @@ convStmt modId avmap (AStmtAction cset (ACall obj meth as)) = do Nothing -> -- no name because the value is unused -- but we still need to declare the correct type case (M.lookup (unQualId meth) meth_ty_map) of - Just t -> (convAType t, Nothing) + Just [t] -> (convAType t, Nothing) + Just [] -> (voidType, Nothing) + -- TODO: support multiple return values + Just ts -> error ("convStmt: multiple return values for method " ++ + ppReadable (obj, meth, ts)) Nothing -> (voidType, Nothing) -- we'll create new defs "act#", "guard#", and "state#" with a unique number @@ -1187,6 +1192,11 @@ convAExpr e@(AMethValue t obj meth) = -- these are handled by convStmts and are not expected here internalError("convAExpr: AMethValue: " ++ ppReadable e) +convAExpr (ATupleSel _ _ _) = + internalError "convAExpr: multi-output methods are not yet supported" +convAExpr (ATuple {}) = + internalError "convAExpr: multi-output methods are not yet supported" + convAExpr (ANoInlineFunCall t i (ANoInlineFun name _ _ _) as) = do let func_id = noinlineId i a_exprs <- mapM convAExpr as diff --git a/src/comp/LambdaCalcUtil.hs b/src/comp/LambdaCalcUtil.hs index 1ed84f5a5..01876d349 100644 --- a/src/comp/LambdaCalcUtil.hs +++ b/src/comp/LambdaCalcUtil.hs @@ -159,11 +159,11 @@ lookupDef defmap i = -- Digested AVInst info for each submodule instance -- * The module name -- * The numeric type arguments for polymorphic modules --- * A map from AV method names to their return value +-- * A map from AV method names to their return values -- -type InstMap = M.Map Id (String, [Integer], M.Map Id AType) +type InstMap = M.Map Id (String, [Integer], M.Map Id [AType]) -lookupMod :: InstMap -> Id -> (String, [Integer], M.Map Id AType) +lookupMod :: InstMap -> Id -> (String, [Integer], M.Map Id [AType]) lookupMod instmap obj = case (M.lookup obj instmap) of Nothing -> internalError ("lookupMod: " ++ ppReadable obj) @@ -1037,6 +1037,9 @@ updateAExprTypes _ (AMethCall t obj meth as) = do -- method return values are Bit type updateAExprTypes _ e@(AMethValue t obj meth) = return e +updateAExprTypes _ (ATupleSel _ _ _) = error "updateAExprTypes: multi-output methods not yet supported" +updateAExprTypes _ (ATuple _ _) = error "updateAExprTypes: multi-output methods not yet supported" + -- noinline function arguments and return values are Bit type updateAExprTypes _ (ANoInlineFunCall t i f as) = do as' <- mapM updateAExprTypes_Bits as @@ -1224,13 +1227,13 @@ inlineUndet = mapAExprs g -- ------------------------- -getSubModAVMethReturnTypes :: AVInst -> M.Map Id AType +getSubModAVMethReturnTypes :: AVInst -> M.Map Id [AType] getSubModAVMethReturnTypes avi = let meth_types = avi_meth_types avi vfis = vFields (avi_vmi avi) - mkPair vfi (_, Just _, Just ret_ty) = Just (vf_name vfi, ret_ty) + mkPair vfi (_, Just _, ret_tys) = Just (vf_name vfi, ret_tys) mkPair _ _ = Nothing pairs = catMaybes $ zipWith mkPair vfis meth_types diff --git a/src/comp/Parser/BSV/CVParser.lhs b/src/comp/Parser/BSV/CVParser.lhs index 1a3969117..311fa20f3 100644 --- a/src/comp/Parser/BSV/CVParser.lhs +++ b/src/comp/Parser/BSV/CVParser.lhs @@ -1462,7 +1462,9 @@ returns a single identifier formed by joining the components with underscores. > -- Bool indicates whether there's a separate Ready method for this one > pMethodVeriProt prefix = > do pos <- getPos +> -- TODO: Add syntax for specifiying multiple output ports > (optOPort, name) <- pMethodNameOptOPort "method output port or name" +> let oPorts = maybeToList optOPort > multi <- option 1 (pInBrackets pDecimal) > args <- (option [] (pInParens (pCommaSep pMethodArgVeriPort)) > "method arguments") @@ -1507,7 +1509,7 @@ returns a single identifier formed by joining the components with underscores. > Just (VeriPt p) -> > [(mkRdyId name, > V.Method (mkRdyId fullname) -> clk rst 0 [] (Just p) Nothing, +> clk rst 0 [] [p] Nothing, > False)] > Just _ -> internalError "pMethodVeriProt(4)" > return ((name, @@ -1516,7 +1518,7 @@ returns a single identifier formed by joining the components with underscores. > rst > multi > args -> optOPort +> oPorts > en, > not(null nullOrReady)) > : nullOrReady) @@ -4600,7 +4602,7 @@ a "module verilog": > let g (s,Nothing) = [(s,[])] > g (s,Just g) = [(s,[]),(g,[])] > f (Nothing, _) = [] -> f (Just i , cmg) = [V.Method i Nothing Nothing 1 (concat(map g cmg)) Nothing Nothing] +> f (Just i , cmg) = [V.Method i Nothing Nothing 1 (concat(map g cmg)) [] Nothing] > in concat . (map f) > pImperativeForeignModuleAt :: Position -> Attributes -> ImperativeFlags diff --git a/src/comp/Parser/BSV/CVParserImperative.lhs b/src/comp/Parser/BSV/CVParserImperative.lhs index 224ba6ad9..11b4682af 100644 --- a/src/comp/Parser/BSV/CVParserImperative.lhs +++ b/src/comp/Parser/BSV/CVParserImperative.lhs @@ -1473,9 +1473,9 @@ some of these restrictions could be lifted if we made the compiler more clever > Port (name, _) _ _ -> addInput pos name ioerrs > _ -> ioerrs > chkBVIPorts (ISBVI pos (BVI_method (_,inf@(Method {}),_))) ioerrs = ioerrs3 -> where ioerrs1 = case (vf_output inf) of -> Just (name, _) -> addOutputPort pos name ioerrs -> _ -> ioerrs +> where ioerrs1 = foldr (\(name, _) iers -> addOutputPort pos name iers) +> ioerrs +> (vf_outputs inf) > ioerrs2 = case (vf_enable inf) of > Just (name, _) -> addInput pos name ioerrs1 > _ -> ioerrs1 @@ -1704,13 +1704,13 @@ Extract each type of statement, making sure to preserve the order > CLValue si [CClause [] [] > (cVApply idPrimInoutUncast0 [(CSelect (CVar bviMname) i)])] [] > -- the following case will generate an error in chkBSVMethod below: -> mkBSVMethod (sn, Method n _ _ _ is Nothing Nothing, b) = -- ... mo me needsReady +> mkBSVMethod (sn, Method n _ _ _ is [] Nothing, b) = -- ... mo me needsReady > mkBasicDef (\ e -> e) n sn is b -> mkBSVMethod (sn, Method n _ _ _ is (Just _) Nothing, b) = -- ... mo me needsReady +> mkBSVMethod (sn, Method n _ _ _ is (_ : _) Nothing, b) = -- ... mo me needsReady > mkBasicDef (\ e -> cVApply idUnpack [e]) n sn is b -> mkBSVMethod (sn, Method n _ _ _ is Nothing (Just _), b) = -- ... mo me needsReady +> mkBSVMethod (sn, Method n _ _ _ is [] (Just _), b) = -- ... mo me needsReady > mkBasicDef (\ e -> cVApply idFromActionValue_ [e]) n sn is b -> mkBSVMethod (sn, Method n _ _ _ is (Just _) (Just _), b) = -- ... mo me needsReady +> mkBSVMethod (sn, Method n _ _ _ is (_ : _) (Just _), b) = -- ... mo me needsReady > mkBasicDef (\ e -> cVApply idFromActionValue_ [e]) n sn is b > mkBSVIfc (name,constr,ss) = @@ -1728,7 +1728,7 @@ Extract each type of statement, making sure to preserve the order > lastPos = getPosition (last stmts) > bviMname = idM lastPos -> chkBSVMethod (Method n _ _ _ _ Nothing Nothing) = -- mo me +> chkBSVMethod (Method n _ _ _ _ [] Nothing) = -- os me > cvtErr (getPosition n) (EForeignModOutputOrEnable (pvpReadable n)) > chkBSVMethod m = return () > theFamilies cs as fs = do diff --git a/src/comp/Parser/Classic/CParser.hs b/src/comp/Parser/Classic/CParser.hs index 97aa4e0da..fd7b585ac 100644 --- a/src/comp/Parser/Classic/CParser.hs +++ b/src/comp/Parser/Classic/CParser.hs @@ -148,7 +148,7 @@ pModule = l L_module `into` \ pos -> ||! literal (mkFString "const") .> VPconst ||! literal (mkFString "unused") .> VPunused ||! literal (mkFString "inhigh") .> VPinhigh - mkMethod i n vps mo me = Method i Nothing Nothing n vps Nothing Nothing + mkMethod i n vps mo me = Method i Nothing Nothing n vps [] Nothing pMStmt :: CParser CMStmt pMStmt = pModuleInterface diff --git a/src/comp/PreStrings.hs b/src/comp/PreStrings.hs index c4e2efbcf..e7a246220 100644 --- a/src/comp/PreStrings.hs +++ b/src/comp/PreStrings.hs @@ -206,6 +206,8 @@ fsMuxVal = mkFString "VAL" fsEnable = mkFString "EN_" fs_rdy = mkFString "RDY_" fs_rl = mkFString "RL_" +fs_arg = mkFString "ARG_" +fs_res = mkFString "RES_" fs_unnamed = mkFString "unnamed" s_unnamed = "unnamed" fs_T = mkFString "_T" diff --git a/src/comp/SAL.hs b/src/comp/SAL.hs index 52b7d8951..ad58492ac 100644 --- a/src/comp/SAL.hs +++ b/src/comp/SAL.hs @@ -503,6 +503,7 @@ boolToBitVar = SVar $ primCtx (SId "boolToBit") anyVar :: AType -> SExpr anyVar (ATBit width) = SVar $ bitCtx width (SId "undef") anyVar t | (t == mkATBool) = SVar $ primCtx (SId "undefBool") +anyVar (ATTuple ts) = internalError ("anyVar: multi-output methods are not yet supported") anyVar (ATString _) = SVar $ stringCtx (SId "undef") anyVar (ATReal) = SVar $ primCtx (SId "undefReal") anyVar (ATArray sz t) = arrBuild sz $ @@ -891,6 +892,7 @@ convARule defmap instmap mmap r@(ARule rId _ _ _ p as _ _) = convAIFace :: DefMap -> InstMap -> MethodOrderMap -> AIFace -> [SDefn] +-- TODO: support multiple method output ports convAIFace defmap instmap mmap (AIDef methId args _ p (ADef _ ret_t ret_e _) _ _) = let @@ -927,6 +929,7 @@ convAIFace defmap instmap mmap sLam (arg_infos ++ [(stateId, modType)]) $ body] +-- TODO: support multiple method output ports convAIFace defmap instmap mmap (AIActionValue args _ p methId rs (ADef _ def_t def_e _) _) = let @@ -1042,6 +1045,7 @@ convAType (ATString (Just width)) = stringType -- XXX ? convAType (ATReal) = realType convAType (ATArray sz t) = arrType sz (convAType t) convAType t | (t == mkATBool) = boolType +convAType (ATTuple ts) = internalError ("convAType: multi-output methods are not yet supported") convAType t@(ATAbstract {}) = internalError ("convAType: " ++ ppReadable t) -- ----- @@ -1156,7 +1160,11 @@ convStmt avmap (AStmtAction cset (ACall obj meth as)) = do Nothing -> -- no name because the value is unused -- but we still need to declare the correct type case (M.lookup (unQualId meth) meth_ty_map) of - Just t -> (convAType t, Nothing) + Just [t] -> (convAType t, Nothing) + Just [] -> (voidType, Nothing) + Just _ -> error ("convStmt: multiple return values for method " + ++ ppReadable meth ++ " on instance " + ++ ppReadable obj) Nothing -> (voidType, Nothing) -- we'll create new defs "act#" and "state#" with a unique number @@ -1292,6 +1300,9 @@ convAExpr e@(AMethValue t obj meth) = -- these are handled by convStmts and are not expected here internalError("convAExpr: AMethValue: " ++ ppReadable e) +convAExpr (ATupleSel _ _ _) = internalError "convAExpr: multi-output methods are not yet supported" +convAExpr (ATuple {}) = internalError "convAExpr: multi-output methods are not yet supported" + convAExpr (ANoInlineFunCall t _ (ANoInlineFun name _ _ _) as) = do let func_id = noinlineQId name a_exprs <- mapM convAExpr as diff --git a/src/comp/SignalNaming.hs b/src/comp/SignalNaming.hs index 1f2c73004..3d93e326c 100644 --- a/src/comp/SignalNaming.hs +++ b/src/comp/SignalNaming.hs @@ -10,6 +10,7 @@ import ErrorUtil(internalError) import PPrint import Id import PreIds +import Util(itos) -- remember to allow a few characters for __d3222 etc suffix signal_length_limit :: Int @@ -67,6 +68,12 @@ signalNameFromAExpr' (expr@AMethCall { }) = connectWith "_" (map signalNameFromAExpr' (ae_args expr)) signalNameFromAExpr' (expr@AMethValue { }) = ppString (ae_objid expr) ++ "_" ++ ppString (unQualId (ameth_id expr)) +signalNameFromAExpr' (expr@ATuple { }) = + "TUPLE_" ++ + connectWith "_" (map signalNameFromAExpr' (ae_elems expr)) +signalNameFromAExpr' (expr@ATupleSel { }) = + signalNameFromAExpr' (ae_exp expr) ++ + "_SEL_" ++ itos (ae_index expr) signalNameFromAExpr' (expr@ANoInlineFunCall { }) = -- use the identifier name (it is the user-known function name); -- the string in ANoInlineFun is the module name diff --git a/src/comp/SimCCBlock.hs b/src/comp/SimCCBlock.hs index 78ff83fe0..9619232e8 100644 --- a/src/comp/SimCCBlock.hs +++ b/src/comp/SimCCBlock.hs @@ -66,7 +66,7 @@ import Eval import ErrorUtil(internalError) import Data.Maybe -import Data.List(partition, intersperse, intercalate, nub, sortBy) +import Data.List(partition, intersperse, intercalate, nub, sortBy, genericDrop) import Data.List.Split(wordsBy) import Numeric(showHex) import Control.Monad(when) @@ -367,6 +367,7 @@ aTypeToCType :: AType -> (CCFragment -> CCFragment) aTypeToCType (ATBit size) = (`ofType` (bitsType size CTunsigned)) aTypeToCType (ATString _) = (`ofType` (classType "std::string")) aTypeToCType (ATReal) = (`ofType` doubleType) +aTypeToCType (ATTuple _) = userType "WideData" aTypeToCType (ATArray _ _) = internalError "Unexpected array" aTypeToCType (ATAbstract _ _) = internalError "Unexpected abstract type" @@ -522,6 +523,8 @@ adjustInstQuals id = -- check if an aexpr is just a var id, or other situation not to deal by wop hasWop :: AExpr -> Bool hasWop (APrim { aprim_prim = p }) = (p /= PrimIf) +hasWop (ATuple _ _) = True +hasWop (ATupleSel _ _ _) = True hasWop _ = False -- --------------------- @@ -638,8 +641,7 @@ getWDataTest = do return f isWideDef :: (AType, AId) -> Bool -isWideDef x@(ATBit sz, aid) | sz > 64 = True -isWideDef x = False +isWideDef (t, _) = wideDataType t mkUndetVal :: AType -> State ConvState CCExpr mkUndetVal ty = do @@ -874,6 +876,7 @@ mkPrimCall ret sz name args = mkArg expr = if (isConst expr) || (isStringType (aType expr)) || ((aType expr) == ATReal) || + (isTupleType (aType expr)) || ((aSize expr) > 64) then aExprToCExpr noRet expr else do cexpr <- aExprToCExpr noRet expr @@ -1068,6 +1071,16 @@ aExprToCExpr _ p@(APrim _ _ _ _) = aExprToCExpr _ (AMethCall _ id mid args) = do arg_list <- mapM (aExprToCExpr noRet) args return $ (aInstMethIdToC id mid) `cCall` arg_list +-- a tuple is laid out in wide data as a concatenation of its elements, +-- with the first element in the most-significant bits (Verilog {e1,...,en}) +aExprToCExpr ret e@(ATuple _ exprs) = + wideConcatPrim ret (aSize e) exprs +-- NB: idx is 1-based (see AConv and AState), so 'genericDrop idx' yields the +-- elements strictly below the selected one; sizeAfter is therefore the low bit +-- of element idx, and [aSize t + sizeAfter - 1 : sizeAfter] is its bit range. +aExprToCExpr ret (ATupleSel t e idx) = + wideExtractPrim ret (aSize t) e (aSize t + sizeAfter - 1) sizeAfter + where sizeAfter = sum $ map aSize $ genericDrop idx $ att_elem_types $ ae_type e aExprToCExpr _ e@(AMGate _ id clkid) = do gmap <- gets gate_map case (M.lookup e gmap) of @@ -1145,7 +1158,7 @@ simFnStmtToCStmt (SFSDef isPort (ty,aid) Nothing) = let w = aSize ty dst = if isPort then aPortIdToCLval aid else aDefIdToCLval aid typed_id = (aTypeToCType ty) dst - in if w > 64 -- for wide data, use (bits,false) constructor to avoid initialization penalty + in if w > 64 || isTupleType ty -- for wide data, use (bits,false) constructor to avoid initialization penalty then return $ construct typed_id [mkUInt32 w, mkBool False] else return $ decl typed_id simFnStmtToCStmt (SFSDef isPort (ty@(ATString (Just sz)),aid) (Just expr)) = @@ -1422,6 +1435,11 @@ mkPortInit ((ATBit n),_,vn) | n > 32 = [ assign (aPortIdToCLval (vName_to_id vn)) (mkUInt64 0) ] mkPortInit ((ATBit n),_,vn) = [ assign (aPortIdToCLval (vName_to_id vn)) (mkUInt32 0) ] +mkPortInit (t@(ATTuple _),_,vn) = + let p = aPortIdToC (vName_to_id vn) + in [ stmt $ p `cDot` "setSize" `cCall` [ mkUInt32 $ aSize t ] + , stmt $ p `cDot` "clear" `cCall` [] + ] mkPortInit p = internalError ("SimCCBlock.mkPortInit: " ++ ppReadable p) -- Create a call to the "set_reset_fn" for submodules with output resets @@ -1708,6 +1726,8 @@ mkCtorInit task_id_set (aty@(ATBit sz),aid) = let val = ASInt defaultAId aty (ilHex (aaaa sz)) in Just (aid,[val]) | otherwise = Nothing +mkCtorInit _ (aty@(ATTuple _),aid) = + Just (aid, [ aNat (aSize aty) ]) -- system tasks shouldn't be returning other types (like String), -- so no need to consult the task_id_set mkCtorInit _ _ = Nothing @@ -2142,11 +2162,11 @@ wideLocalDef (SFSDef _ (ty, aid) _) = if wideDataType ty else [] wideLocalDef _ = [] --- return True if this type is wider than 64 bits +-- return True if this type is represented as wide data +-- (i.e. it is larger than 64 bits, or it is a tuple) wideDataType :: AType -> Bool -wideDataType (ATBit sz) - | sz > 64 = True - | otherwise = False +wideDataType (ATBit sz) = sz > 64 +wideDataType (ATTuple _) = True wideDataType _ = False diff --git a/src/comp/SimCOpt.hs b/src/comp/SimCOpt.hs index c5d3d0afb..024c53d28 100644 --- a/src/comp/SimCOpt.hs +++ b/src/comp/SimCOpt.hs @@ -157,6 +157,7 @@ moveDefsOntoStack flags instmodmap (blocks,scheds) = let sizeOkToMove = case (M.lookup (sbid,aid) btype_map) of (Just ty) -> (ty == ATReal) || ((not (isStringType ty)) && + (not (isTupleType ty)) && ((aSize ty) <= 64)) Nothing -> False -- don't move AV task defs diff --git a/src/comp/SimExpand.hs b/src/comp/SimExpand.hs index a23885156..501fc3c25 100644 --- a/src/comp/SimExpand.hs +++ b/src/comp/SimExpand.hs @@ -1040,7 +1040,7 @@ combineCombSchedInfo use_map domain_id_map parent_abi parent_csi -- schedule graph and conflicts (even the methods not used by -- any parent rules), so we need to know which are the method Ids child_apkg = abmi_apkg child_abi - child_meth_set = S.fromList $ map aIfaceName (apkg_interface child_apkg) + child_meth_set = S.fromList $ map aif_name (apkg_interface child_apkg) -- combine each part of the CSI comb_sched_map = combineSchedMap inst parent_uses @@ -1669,7 +1669,7 @@ mkRdyMap abi = mkPair (AIClock {}) = [] mkPair (AIReset {}) = [] mkPair ifc = - let name = aIfaceName ifc + let name = aif_name ifc pred_e = aIfacePred ifc in if (isRdyId name) then [] -- Rdy methods don't have Rdy methods @@ -1974,6 +1974,8 @@ eDomain m e@(AMethCall _ i mi es) = mergeUses ([(i, unQualId mi)] : map (eDomain m) es) -- don't count the return value uses of actionvalue, only the action part eDomain m (AMethValue _ _ _) = [] +eDomain m (ATupleSel _ e _) = eDomain m e +eDomain m (ATuple _ es) = mergeUses $ map (eDomain m) es eDomain m (ANoInlineFunCall _ _ _ es) = mergeUses $ map (eDomain m) es eDomain m (AFunCall _ _ _ _ es) = mergeUses $ map (eDomain m) es eDomain _ e@(ASPort _ i) = [] @@ -2210,10 +2212,11 @@ makeMethodTemps apkg = (AIDef {}) -> (True,False) (AIActionValue {}) -> (False,True) otherwise -> (False,False) + v = aif_value aif in if is_def || is_av - then case process is_av (aif_value aif) (aif_name aif) seqNo of + then case process is_av v (aif_name aif) seqNo of (Just t@(ADef tid ty e props)) -> - let aid = adef_objid (aif_value aif) + let aid = adef_objid v -- unclear if propagating the props is correct new_def = (ADef aid ty (ASDef ty tid) props) aif' = aif { aif_value = new_def } diff --git a/src/comp/SimMakeCBlocks.hs b/src/comp/SimMakeCBlocks.hs index 9ce858b5e..153873dbb 100644 --- a/src/comp/SimMakeCBlocks.hs +++ b/src/comp/SimMakeCBlocks.hs @@ -119,7 +119,7 @@ simMakeCBlocks flags sim_system = -- methods on the top-level module top_methods = sp_interface top_pkg (top_ameths, top_vmeths) = partition aIfaceHasAction top_methods - top_vmeth_set = S.fromList $ concatMap aIfaceResId top_vmeths + top_vmeth_set = S.fromList $ concatMap aIfaceResIds top_vmeths top_ameth_set = S.fromList $ map aRuleName $ concatMap aIfaceRules top_ameths -- input clocks to the top-level module @@ -132,7 +132,7 @@ simMakeCBlocks flags sim_system = , let p_name = getModuleName p , let ms = sp_interface p , m <- ms - , let m_name = aIfaceName m + , let m_name = aif_name m , let m_rules = aIfaceRules m , let sub_actions = concatMap arule_actions m_rules , let sub_names = [ (o,m) | (ACall o m _) <- sub_actions ] @@ -208,6 +208,10 @@ getExprIds in_sched def_map known ((APrim _ _ _ args):es) = getExprIds in_sched def_map known (args ++ es) getExprIds in_sched def_map known ((AMethCall _ _ _ args):es) = getExprIds in_sched def_map known (args ++ es) +getExprIds in_sched def_map known ((ATuple _ elems):es) = + getExprIds in_sched def_map known (elems ++ es) +getExprIds in_sched def_map known ((ATupleSel _ e _):es) = + getExprIds in_sched def_map known (e:es) getExprIds in_sched def_map known ((ANoInlineFunCall _ _ _ args):es) = getExprIds in_sched def_map known (args ++ es) getExprIds in_sched def_map known ((AFunCall _ _ _ _ args):es) = @@ -323,7 +327,7 @@ onePackageToBlock flags name_map full_meth_map ss pkg = dms = [ M.singleton clk [(aid, fromJust m')] | m <- iface - , let aid = aIfaceName m + , let aid = aif_name m , let m' = cvtIFace modId (sp_pps pkg) def_map meth_map method_order_map reset_list m , isJust m' @@ -517,7 +521,7 @@ cvtIFace :: Id -> [PProp] -> DefMap -> MethMap -> MethodOrderMap -> [(ResetId, AReset)] -> AIFace -> Maybe SimCCFn cvtIFace modId pps def_map meth_map method_order_map reset_list m = - do let name = aIfaceName m + do let name = aif_name m inputs = aIfaceArgs m args = [ (t,i) | (i,t) <- inputs ] -- always_enabled methods need to forcibly check their ready signal @@ -527,7 +531,7 @@ cvtIFace modId pps def_map meth_map method_order_map reset_list m = if ((isAlwaysEn pps name) && (aIfaceHasAction m)) then -- we have to find the name of the port associated -- with the RDY method - let rdy_id = mkRdyId (aIfaceName m) + let rdy_id = mkRdyId (aif_name m) mport = do (_,_,Just (_,vn),_,_) <- M.lookup rdy_id meth_map return $ ASPort aTBool (vName_to_id vn) in case mport of @@ -1443,6 +1447,8 @@ tsortActionsAndDefs modId rId mmap ds acts reset_ids = -- function to substitute ASDef for AMethValue substAV (AMethValue ty obj meth) = ASDef ty (mkAVMethTmpId obj meth) + substAV (ATuple ts es) = ATuple ts (map substAV es) + substAV (ATupleSel t e i) = ATupleSel t (substAV e) i substAV (APrim i t o es) = (APrim i t o (map substAV es)) substAV (AMethCall t o m es) = (AMethCall t o m (map substAV es)) substAV (AFunCall t o f isC es) = (AFunCall t o f isC (map substAV es)) @@ -1620,6 +1626,10 @@ substGateReferences smap stmts = e { ae_args = map substInAExpr es } substInAExpr e@(AMethCall { ae_args = es }) = e { ae_args = map substInAExpr es } + substInAExpr e@(ATuple { ae_elems = es }) = + e { ae_elems = map substInAExpr es } + substInAExpr e@(ATupleSel { ae_exp = e1 }) = + e { ae_exp = substInAExpr e1 } substInAExpr e@(ANoInlineFunCall { ae_args = es }) = e { ae_args = map substInAExpr es } substInAExpr e@(AFunCall { ae_args = es }) = diff --git a/src/comp/SimPackage.hs b/src/comp/SimPackage.hs index f17e688d8..e8626a520 100644 --- a/src/comp/SimPackage.hs +++ b/src/comp/SimPackage.hs @@ -375,7 +375,7 @@ getSimPackageInputs spkg = getPortInfo :: [PProp] -> AIFace -> Maybe (AId, (Maybe VName, [(AType,AId,VName)], Maybe (AType,VName), Bool, [AId])) getPortInfo pps aif = - let name = aIfaceName aif + let name = aif_name aif vfi = aif_fieldinfo aif en = do e <- vf_enable vfi -- always enabled implies enabled when ready @@ -385,9 +385,14 @@ getPortInfo pps aif = ps = map fst (vf_inputs vfi) ins = [ (t,i,vn) | ((i,t),vn) <- zip args ps ] rt = aIfaceResType aif - ret = case (vf_output vfi) of - (Just (vn,_)) -> Just (rt,vn) - Nothing -> Nothing + -- A value method has at most one result. In Bluesim that whole value + -- is returned directly, so when the Verilog output is split across + -- several ports (vf_outputs) we keep just the first port, which carries + -- the entire value; the remaining ports are Verilog-only slicing + -- metadata and are not needed here. + ret = case vf_outputs vfi of + ((vn,_) : _) -> Just (rt, vn) + [] -> Nothing isAction = case aif of (AIAction {}) -> True (AIActionValue {}) -> True diff --git a/src/comp/SimPackageOpt.hs b/src/comp/SimPackageOpt.hs index 82f966c88..cb00c867a 100644 --- a/src/comp/SimPackageOpt.hs +++ b/src/comp/SimPackageOpt.hs @@ -138,6 +138,7 @@ inlineDefs pkg = isNotOk d | isUnsized (adef_type d) = True | (aSize d > 64) = True + | isTupleType (adef_type d) = True | isTaskOrForeignFunc d = True | isCase d = True | otherwise = False @@ -230,6 +231,10 @@ optimizeConcats pkg = -- recurse for other optConcat (APrim i t o as) = APrim i t o (map optConcat as) optConcat (AMethCall t o m as) = AMethCall t o m (map optConcat as) + -- XXX There is maybe an opportunity to optimize tuple construction here, + -- since that basically turns into a concat as well. + optConcat (ATuple t as) = ATuple t (map optConcat as) + optConcat (ATupleSel t e idx) = ATupleSel t (optConcat e) idx optConcat (AFunCall t i f isC as) = AFunCall t i f isC (map optConcat as) optConcat e = e in mapAExprs optConcat pkg @@ -316,9 +321,15 @@ convertASAny errh flags apkg = do cvtASAnyExpr (APrim aid ty op args) = do args' <- mapM cvtASAnyExpr args return $ APrim aid ty op args' - cvtASAnyExpr (AMethCall ty aid mid args) = + cvtASAnyExpr (AMethCall ty aid mid args) = do args' <- mapM cvtASAnyExpr args return $ AMethCall ty aid mid args' + cvtASAnyExpr (ATuple ty elems) = + do elems' <- mapM cvtASAnyExpr elems + return $ ATuple ty elems' + cvtASAnyExpr (ATupleSel ty exp idx) = + do exp' <- cvtASAnyExpr exp + return $ ATupleSel ty exp' idx cvtASAnyExpr (ANoInlineFunCall ty aid fun args) = do args' <- mapM cvtASAnyExpr args return $ ANoInlineFunCall ty aid fun args' diff --git a/src/comp/SystemCWrapper.hs b/src/comp/SystemCWrapper.hs index b7fd88344..75d694b05 100644 --- a/src/comp/SystemCWrapper.hs +++ b/src/comp/SystemCWrapper.hs @@ -8,7 +8,7 @@ import Pragma(isAlwaysRdy, isEnWhenRdy) import FileNameUtil(mkCxxName, mkHName) import ASyntax(AAbstractInput(..), AIFace(..), AExpr(..), AClock(..), - aIfaceArgs, aIfaceName, aIfaceProps) + aIfaceArgs, aif_name, aIfaceProps) import ASyntaxUtil import VModInfo(vName_to_id, VPathInfo(..)) import Wires @@ -38,7 +38,7 @@ checkSystemCIfc errh flags sim_system = do isBad m@(AIActionValue {}) = -- we allow ActionValue methods only -- if they have no arguments and no enable not ((null (aIfaceArgs m)) && - (isEnWhenRdy pps (aIfaceName m))) + (isEnWhenRdy pps (aif_name m))) isBad _ = False bad_methods = [ getIdBaseString (aif_name m) | m <- sp_interface top_pkg @@ -157,7 +157,7 @@ wrapSystemC flags sim_system = do ] -- utility functions for grouping methods by domain - meth_domains = M.fromList [ (aIfaceName aif, dom) + meth_domains = M.fromList [ (aif_name aif, dom) | aif <- (sp_interface top_pkg) , let wp = aIfaceProps aif , let dom = wpClockDomain wp diff --git a/src/comp/TCheck.hs b/src/comp/TCheck.hs index e6d0cd09c..20c627f23 100644 --- a/src/comp/TCheck.hs +++ b/src/comp/TCheck.hs @@ -710,43 +710,42 @@ tiExpr as td exp@(CmoduleVerilog name ui clks rsts args fields sch ps) = do -- matches the types. let -- XXX These errors should give more info - chkResType :: [VPort] -> Maybe VPort -> Maybe VPort -> Type -> - TI ([VPort], Maybe VPort, Maybe VPort) - chkResType ps me@(Just _) mo@Nothing t = - if (isActionWithoutValue t) then return (ps, me, mo) + chkResType :: [VPort] -> Maybe VPort -> [VPort] -> Type -> + TI ([VPort], Maybe VPort, [VPort]) + chkResType ps me@(Just _) [] t = + if (isActionWithoutValue t) then return (ps, me, []) else if (isActionWithValue t) then errMissingValue "ActionValue" t - else if (isBit t) + else if (isBitTuple t) then errUnexpectedEnable "value" t else errBadResType t - chkResType ps me@Nothing mo@(Just _) t = - if (isBit t) then return (ps, me, mo) + chkResType ps me@Nothing outs@(_:_) t = + if (isBitTuple t) then return (ps, me, outs) else if (isActionWithValue t) then errMissingEnable "ActionValue" t else if (isActionWithoutValue t) then errUnexpectedValue "Action" t else errBadResType t - chkResType ps me@(Just _) mo@(Just _) t = - if (isActionWithValue t) then return (ps, me, mo) + chkResType ps me@(Just _) outs@(_:_) t = + if (isActionWithValue t) then return (ps, me, outs) else if (isActionWithoutValue t) then errUnexpectedValue "Action" t - else if (isBit t) + else if (isBitTuple t) then errUnexpectedEnable "value" t else errBadResType t - chkResType ps Nothing Nothing t = do - -- must have more than 0 ports - when (null ps) $ - err (getPosition f, - EForeignModTooFewPorts (pfpString f)) + chkResType ps Nothing [] t = do -- update the Classic fieldinfo to BSV format let inputs = initOrErr "chkResType" ps let final_port = lastOrErr "chkResType" ps -- XXX kill PrimAction once imports in Prelude are converted over if (isActionWithoutValue t) || (isPrimAction t) - then return (inputs, Just final_port, Nothing) - else if (isBit t) - then return (inputs, Nothing, Just final_port) - else errBadResType t + then return (inputs, Just final_port, []) + else if (isBit t) + -- The Classic fieldinfo format can only have a single result port. + then return (inputs, Nothing, [final_port]) + else if (t == tPrimUnit) + then return (ps, Nothing, []) + else errBadResType t errBadResType t = err (getPosition f, @@ -808,9 +807,9 @@ tiExpr as td exp@(CmoduleVerilog name ui clks rsts args fields sch ps) = do else if (null argTypes) then return vfi else errInoutHasArgs - Method { vf_inputs = inputs, vf_enable = me, vf_output = mo } -> + Method { vf_inputs = inputs, vf_enable = me, vf_outputs = outputs } -> do -- updates inputs, me and mo when processing Classic format - (inputs', me', mo') <- chkResType inputs me mo resType + (inputs', me', outputs') <- chkResType inputs me outputs resType -- check if any actions are SB with themselves when (((isActionWithValue resType) || (isActionWithoutValue resType) || @@ -818,7 +817,7 @@ tiExpr as td exp@(CmoduleVerilog name ui clks rsts args fields sch ps) = do (f `elem` self_sbs)) (errActionSelfSB f) chkArgs inputs' argTypes - return (vfi { vf_inputs = inputs', vf_enable = me', vf_output = mo' }) + return (vfi { vf_inputs = inputs', vf_enable = me', vf_outputs = outputs' }) -- paramResults <- mapM tiParam es qsses <- mapM tiArg args -- let (pses, tys) = unzip paramResults @@ -902,7 +901,7 @@ tiExpr as td exp@(CForeignFuncC link_id wrap_cqt) = do when (isTypeString av_arg) $ err (getPosition pos, EForeignFuncStringRes) (ctxs, prim_sz) <- findBitSize av_arg - let prim_t = TAp tActionValue_ prim_sz + let prim_t = TAp tActionValue_ $ TAp tBit prim_sz return (ctxs, prim_t, cexpr) -- anything else must be bitifiable else do let cexpr = \e -> cVApply idUnpack [e] @@ -1524,7 +1523,7 @@ finishSWriteAV as td v f es paramResults eq_ps = let (pss, es') = unzip pses -- v <- newTVar "XXX" KNum f - let tav = TAp tActionValue_ v + let tav = TAp tActionValue_ (TAp tBit v) let taskty = foldr fn tav tys -- XXX: quantifying in IConv instead so free type vars are caught correctly @@ -1586,7 +1585,7 @@ taskCheckFOpen as td f [filen] = (vp,filentc) <- tiExpr as tString filen -- let avfile = (TAp (tActionValueAt (getPosition f)) tFile) - tav32 = TAp (tActionValue_At (getPosition f)) t32 + tav32 = TAp (tActionValue_At (getPosition f)) bit32 fty = tString `fn` tav32 applied = (CTaskApplyT f fty [filentc]) let t = cVApply (setIdPosition (getPosition f) idFromActionValue_) [applied] @@ -1602,7 +1601,7 @@ taskCheckFOpen as td f [filen,mode] = -- -- let avfile = (TAp (tActionValueAt (getPosition f)) tFile) - tav32 = TAp (tActionValue_At (getPosition f)) t32 + tav32 = TAp (tActionValue_At (getPosition f)) bit32 fty = tString `fn` tString `fn` tav32 applied = (CTaskApplyT f fty [filentc,modetc]) let t = cVApply (setIdPosition (getPosition f) idFromActionValue_) [applied] diff --git a/src/comp/TopUtils.hs b/src/comp/TopUtils.hs index 0dcfe23b6..aa271cd9d 100644 --- a/src/comp/TopUtils.hs +++ b/src/comp/TopUtils.hs @@ -31,7 +31,7 @@ import IdPrint import ISyntax(IPackage(..), IModule(..), IStateVar(..), IRules(..)) import ASyntax(APackage(..), ASPackage(..), ARule(..), - aIfaceName) + aif_name) import SystemVerilogTokens(SV_Token(..)) import Version(bluespec, bscVersionStr) @@ -276,7 +276,7 @@ instance Stats APackage where (showLen (apkg_rules apkg) "rules" <> if v then text "" <+>pPrint PDReadable 0 [ i | ARule { arule_id = i } <- apkg_rules apkg ] else text "") $+$ (showLen (apkg_interface apkg) "interface methods" <> - if v then text "" <+> pPrint PDReadable 0 (map aIfaceName (apkg_interface apkg)) else text "") + if v then text "" <+> pPrint PDReadable 0 (map aif_name (apkg_interface apkg)) else text "") )) instance Stats ASPackage where diff --git a/src/comp/Type.hs b/src/comp/Type.hs index d526e6c75..70167ce01 100644 --- a/src/comp/Type.hs +++ b/src/comp/Type.hs @@ -60,13 +60,13 @@ tPrimPair = TCon (TyCon idPrimPair (Just (Kfun KStar (Kfun KStar KStar))) (TIstr tAction, tActionValue, tActionValue_, tAction_:: Type tAction = TCon (TyCon idAction (Just KStar) (TItype 0 (TAp tActionValue tPrimUnit))) tActionValue = TCon (TyCon idActionValue (Just (Kfun KStar KStar)) (TIstruct SStruct [id__value, id__action])) -tActionValue_ = TCon (TyCon idActionValue_ (Just (Kfun KNum KStar)) (TIstruct SStruct [id__value, id__action])) -tAction_ = TAp tActionValue_ (tOfSize 0 noPosition) +tActionValue_ = TCon (TyCon idActionValue_ (Just (Kfun KStar KStar)) (TIstruct SStruct [id__value, id__action])) +tAction_ = TAp tActionValue_ tPrimUnit tActionAt, tActionValueAt, tActionValue_At :: Position -> Type tActionAt pos = TCon (TyCon (idActionAt pos) (Just KStar) (TItype 0 (TAp (tActionValueAt pos) (tPrimUnitAt pos)))) tActionValueAt pos = TCon (TyCon (idActionValueAt pos) (Just (Kfun KStar KStar)) (TIstruct SStruct [id__value_at pos, id__action_at pos])) -tActionValue_At pos = TCon (TyCon (idActionValue_At pos) (Just (Kfun KNum KStar)) (TIstruct SStruct [id__value_at pos, id__action_at pos])) +tActionValue_At pos = TCon (TyCon (idActionValue_At pos) (Just (Kfun KStar KStar)) (TIstruct SStruct [id__value_at pos, id__action_at pos])) tPrimAction, tRules :: Type tPrimAction = TCon (TyCon idPrimAction (Just KStar) TIabstract) @@ -162,13 +162,21 @@ getAVType :: Type -> Type getAVType (TAp av t) | av == tActionValue = t getAVType t = internalError("getAVType not ActionValue: " ++ ppReadable t) +-- Note that we consider ActionValue_ (Bit 0) to be an action without a value, +-- as this is still created by foreign verilog module imports. +-- XXX should rework this to just yield ActionValue_ () for empty types. isActionWithoutValue :: Type -> Bool -isActionWithoutValue (TAp av (TCon (TyNum 0 _))) = av == tActionValue_ +isActionWithoutValue (TAp av (TAp (TCon (TyCon i _ _)) (TCon (TyNum 0 _)))) = + av == tActionValue_ && i == idBit +isActionWithoutValue (TAp av (TCon (TyCon i _ _))) = + av == tActionValue_ && i == idPrimUnit isActionWithoutValue _ = False isActionWithValue :: Type -> Bool -isActionWithValue (TAp av (TCon (TyNum n _))) = (av == tActionValue_) && (n > 0) isActionWithValue (TAp av (TVar _)) = av == tActionValue_ +isActionWithValue (TAp av (TAp (TCon (TyCon i _ _)) (TCon (TyNum 0 _)))) + | av == tActionValue_ && i == idBit = False +isActionWithValue (TAp av t) = (av == tActionValue_) && isBitTuple t isActionWithValue _ = False isClock, isReset, isInout, isInout_ :: Type -> Bool @@ -198,4 +206,9 @@ isChar t = t == tChar isReal t = t == tReal isFmt t = t == tFmt +isBitTuple :: Type -> Bool +isBitTuple (TAp (TAp (TCon (TyCon i _ _)) t1) t2) | i == idPrimPair = + isBit t1 && isBitTuple t2 +isBitTuple t = isBit t + -- ------------------------- diff --git a/src/comp/VIOProps.hs b/src/comp/VIOProps.hs index f9c88fdc5..8180646c3 100644 --- a/src/comp/VIOProps.hs +++ b/src/comp/VIOProps.hs @@ -10,7 +10,7 @@ import Flags import PPrint import ErrorUtil(internalError) import Id -import PreIds(idPrimAction, idInout_) +import PreIds(idPrimAction, idInout_, idPrimUnit) import VModInfo(vArgs, vFields, VName(..), VeriPortProp(..), VArgInfo(..), VFieldInfo(..), VPort) import Prim @@ -151,9 +151,13 @@ getIOProps flags ppp@(ASPackage _ _ _ os is ios vs _ ds io_ds fs _ _ _) = -- create the method name map let nmap = M.fromList $ createVerilogNameMapForAVInst flags v, - -- for each method that has an output port - vfi@(Method { vf_output = Just (vname,pprops) }) - <- vFields (avi_vmi v), + -- for each method (not clocks or resets) + vfi@(Method {}) <- vFields (avi_vmi v), + -- for each method output port + (methOutPart, (vname, pprops)) + <- zip (map MethodResult (methResultNums (vf_outputs vfi))) + (vf_outputs vfi), + -- for each port copy ino <- if (vf_mult vfi > 1) then map Just [0 .. vf_mult vfi] @@ -162,7 +166,7 @@ getIOProps flags ppp@(ASPackage _ _ _ os is ios vs _ ds io_ds fs _ _ _) = let meth_id = mkMethId (avi_vname v) (vf_name vfi) ino - MethodResult, + methOutPart, -- convert to Verilog signal name let veri_id = xLateIdUsingFStringMap nmap meth_id ] @@ -194,7 +198,8 @@ getIOProps flags ppp@(ASPackage _ _ _ os is ios vs _ ds io_ds fs _ _ _) = -- return empty-list here; but the internal check -- is nice to have (if it's not too expensive). internalError ("getOVProp: could not find method " ++ - ppString i) + ppString i ++ " in wireMap_out:\n" ++ + ppReadable wireMap_out) -- ---------- -- construct the VeriPortProp list for an input @@ -400,5 +405,6 @@ size :: AType -> Integer size (ATBit n) = n size (ATAbstract a _) | a == idPrimAction = 1 size (ATAbstract a [n]) | a == idInout_ = n +size (ATAbstract a _) | a == idPrimUnit = 0 size (ATString _ ) = 0 size t = internalError ("getIOProps.size: " ++ show t) diff --git a/src/comp/VModInfo.hs b/src/comp/VModInfo.hs index 6964602a1..ab96eb1b9 100644 --- a/src/comp/VModInfo.hs +++ b/src/comp/VModInfo.hs @@ -23,7 +23,7 @@ module VModInfo(VModInfo, mkVModInfo, getIfcIdPosition, str_to_vPort,getVPortString, mkNamedEnable, - mkNamedOutput, + mkNamedOutputs, mkNamedReady, mkNamedInout, extractNames @@ -274,7 +274,7 @@ data VFieldInfo = Method { vf_name :: Id, -- method name -- optional because the method may be independent of a reset signal vf_mult :: Integer, -- multiplicity vf_inputs :: [VPort], - vf_output :: Maybe VPort, + vf_outputs:: [VPort], vf_enable :: Maybe VPort } | Clock { vf_name :: Id } -- output clock name -- connection information is in the ClockInfo @@ -300,11 +300,12 @@ instance NFData VFieldInfo where instance PPrint VFieldInfo where pPrint d p (Method n c r m i o e) = - text "method " <> pout o <> pPrint d p n <> pmult m <> + text "method " <> pouts o <> pPrint d p n <> pmult m <> pins i <> pena e <+> ppMClk d c <+> ppMRst d r <> text ";" - where pout Nothing = empty - pout (Just po) = pPrint d p po + where pouts [] = empty + pouts [po] = pPrint d p po + pouts o = text "(" <> sepList (map (pPrint d p) o) (text ",") <> text ")" pmult 1 = empty pmult n = text "[" <> pPrint d p n <> text "]" pins [] = empty @@ -685,17 +686,16 @@ mkNamedEnable vfi = if (newStr == "") then baseid else setIdBaseString baseid ne where baseid = mkEnableId (vf_name vfi) newStr = maybe "" getVPortString (vf_enable vfi) -mkNamedOutput :: VFieldInfo -> Id -mkNamedOutput vfi = if (newStr == "") then baseid else setIdBaseString baseid newStr +mkNamedOutputs :: VFieldInfo -> [Id] +mkNamedOutputs vfi = map (setIdBaseString baseid) newStrs where baseid = (vf_name vfi) - newStr = maybe "" getVPortString (vf_output vfi) + newStrs = map getVPortString (vf_outputs vfi) -- VFieldInfo does not have a ready field, so we just use the default construction for the ready signal. -- in aState we merge method and RDY_method to do the right thing. mkNamedReady :: VFieldInfo -> Id mkNamedReady vfi = baseid -- if (newStr == "") then baseid else setIdBaseString baseid newStr where baseid = mkRdyId (vf_name vfi) - -- newStr = maybe "" getVPortString (vf_output vfi) mkNamedInout :: VFieldInfo -> Id mkNamedInout vfi = setIdBaseString baseid newStr @@ -705,8 +705,8 @@ mkNamedInout vfi = setIdBaseString baseid newStr --------------------------- Name extraction from VFieldInfo -- extract possible port Ids from a VField Info -- return value is result, ready, enable -extractNames :: VFieldInfo -> (Id, Id, Id ) +extractNames :: VFieldInfo -> ([Id], Id, Id ) extractNames vfi = (result, ready, enable) - where result = mkNamedOutput vfi + where result = mkNamedOutputs vfi ready = mkNamedReady vfi enable = mkNamedEnable vfi diff --git a/src/comp/bluetcl.hs b/src/comp/bluetcl.hs index b457ca703..93f745e55 100644 --- a/src/comp/bluetcl.hs +++ b/src/comp/bluetcl.hs @@ -1118,7 +1118,7 @@ tclModule ["methods",modname] = do let apkg = abemi_apkg abmi pps = abemi_pps abmi ifc = apkg_interface apkg - ifc_map = [ (aIfaceName aif, rawIfcFieldFromAIFace pps aif) + ifc_map = [ (aif_name aif, rawIfcFieldFromAIFace pps aif) | aif <- ifc ] let tifc = getModuleIfc abmi fs <- getIfcHierarchy Nothing ifc_map tifc @@ -1639,7 +1639,7 @@ tclRule ["full",modname,rule] = Nothing -> Nothing Just (ARule i ps _ _ rPred _ _ _) -> Just (ps, getPosition i, aAnds [ifPred, rPred]) - cvtIfc (AIDef _ _ _ ifPred (ADef dId _ _ _) _ _) = + cvtIfc (AIDef dId _ _ ifPred _ _ _) = if (dId == rId) then Just ([], getPosition dId, ifPred) else Nothing @@ -1960,7 +1960,7 @@ instance ExpandInfoHelper BModView where -- flattened ifc names let ifc_names = map pfpString $ filter (not . isRdyId) $ - map (aIfaceName) (apkg_interface apkg) + map (aif_name) (apkg_interface apkg) -- rules let rule_names = map (pfpString . arule_id) (apkg_rules apkg) -- schedule @@ -3283,7 +3283,7 @@ data RawIfcField = (Maybe Id) (Maybe Id) -- associated clk and rst [(Maybe Id, AType)] -- arguments [VPort] -- argument ports - (Maybe (VPort, AType)) -- return value + [(VPort, AType)] -- return values (Maybe VPort) -- enable signal -- Note: no ready signal at this stage | RawClock Id @@ -3301,26 +3301,32 @@ rawIfcFieldName (RawInout i _ _ _ _) = i rawIfcFieldFromAIFace :: [PProp] -> AIFace -> RawIfcField rawIfcFieldFromAIFace _ (AIDef i args _ _ def - (Method _ clk rst mult ins mo@(Just out) Nothing) _) = - let -- include the type in the "mo" - mo' = Just (out, adef_type def) - in RawMethod i mult clk rst (mapFst Just args) ins mo' Nothing + (Method _ clk rst mult ins outs Nothing) _) = + let -- include the type in the "outs" + outs' = zip outs $ + case adef_type def of + ATTuple ts -> ts + t -> [t] + in RawMethod i mult clk rst (mapFst Just args) ins outs' Nothing rawIfcFieldFromAIFace pps (AIAction args _ _ i _ - (Method _ clk rst mult ins Nothing me@(Just _))) = + (Method _ clk rst mult ins [] me@(Just _))) = let -- filter out inhigh enable ports -- XXX is there a better way to do this? me' = if (isAlwaysEn pps i) then Nothing else me - in RawMethod i mult clk rst (mapFst Just args) ins Nothing me' + in RawMethod i mult clk rst (mapFst Just args) ins [] me' rawIfcFieldFromAIFace pps (AIActionValue args _ _ i _ def - (Method _ clk rst mult ins mo@(Just out) me@(Just _))) = + (Method _ clk rst mult ins outs me@(Just _))) = let -- filter out inhigh enable ports -- XXX is there a better way to do this? me' = if (isAlwaysEn pps i) then Nothing else me - -- include the type in the "mo" - mo' = Just (out, adef_type def) - in RawMethod i mult clk rst (mapFst Just args) ins mo' me' + -- include the type in the "outs" + outs' = zip outs $ + case adef_type def of + ATTuple ts -> ts + t -> [t] + in RawMethod i mult clk rst (mapFst Just args) ins outs' me' rawIfcFieldFromAIFace _ (AIClock i _ (Clock _)) = RawClock i rawIfcFieldFromAIFace _ (AIReset i _ (Reset _)) = RawReset i rawIfcFieldFromAIFace _ (AIInout i (AInout e) (Inout _ vn mclk mrst)) = @@ -3329,23 +3335,20 @@ rawIfcFieldFromAIFace _ aif = internalError ("rawIfcFieldFromAIFace: unexpected AIFace combo: " ++ ppReadable aif) -rawIfcFieldFromAVInst :: ([AType], Maybe AType, Maybe AType) -> +rawIfcFieldFromAVInst :: ([AType], Maybe AType, [AType]) -> VFieldInfo -> RawIfcField -rawIfcFieldFromAVInst (arg_tys,_,mo_type) (Method i clk rst mult ins mo me) = +rawIfcFieldFromAVInst (arg_tys,_,out_tys) (Method i clk rst mult ins outs me) = let -- XXX AVInst doesn't record argument names args = zip (repeat Nothing) arg_tys - -- add the return bit-type to the mo - mo' = case (mo, mo_type) of - (Just o, Just o_type) -> Just (o, o_type) - (Nothing, Nothing) -> Nothing - _ -> internalError ("rawIfcFieldFromAVInst: unexpected mo: " ++ - ppReadable (mo, mo_type)) - in RawMethod i mult clk rst args ins mo' me + -- add the return bit-type to the outs + outs' = zip outs out_tys + in RawMethod i mult clk rst args ins outs' me rawIfcFieldFromAVInst _ (Clock i) = RawClock i rawIfcFieldFromAVInst _ (Reset i) = RawReset i -rawIfcFieldFromAVInst (_,_,mt) (Inout i vn mclk mrst) = - let t = fromJustOrErr ("getIfc: no type for Inout") mt - in RawInout i t vn mclk mrst +rawIfcFieldFromAVInst (_,_,[t]) (Inout i vn mclk mrst) = RawInout i t vn mclk mrst +rawIfcFieldFromAVInst _ vfi = + internalError ("rawIfcFieldFromAVInst: unexpected VFieldInfo: " ++ + ppReadable vfi) -- --------------- @@ -3495,7 +3498,7 @@ data PortIfcInfo = PIMethod Id Id (Maybe Id) (Maybe Id) -- associated clk and rst [(Maybe Id, AType, (String, IType))] -- arguments - (Maybe (String, AType, IType)) -- return value + [(String, AType, IType)] -- return values (Maybe (String, IType)) -- enable signal (Maybe (String, IType)) -- ready signal | PIClock Id Id (Maybe ((String, IType), Maybe (String, IType))) @@ -3528,7 +3531,7 @@ getModPortInfo apkg pps tifc = do -- interface hierarchy let -- map from flattened ifc name to its raw info - ifc_map = [ (aIfaceName aif, rawIfcFieldFromAIFace pps aif) + ifc_map = [ (aif_name aif, rawIfcFieldFromAIFace pps aif) | aif <- ifc ] ifc_hier <- getIfcHierarchy Nothing ifc_map tifc @@ -3642,8 +3645,8 @@ getSubmodPortInfo mtifc avi = do concatMap getIfcHier ifc_hier) adjustPrimFields :: Maybe Type -> AVInst -> - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) -> - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) + ([VFieldInfo], [([AType], Maybe AType, [AType])]) -> + ([VFieldInfo], [([AType], Maybe AType, [AType])]) adjustPrimFields Nothing _ vfts = vfts adjustPrimFields (Just tifc) avi vfts = if (leftCon tifc == Just idReg) @@ -3687,8 +3690,8 @@ adjustPrimFields (Just tifc) avi vfts = else vfts -- This is a no-op but it does add some error checking -adjustRegAlignedFields :: ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) -> - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) +adjustRegAlignedFields :: ([VFieldInfo], [([AType], Maybe AType, [AType])]) -> + ([VFieldInfo], [([AType], Maybe AType, [AType])]) adjustRegAlignedFields (vfi, fts) = let renameField vf@(Method {vf_name = i }) | (i `qualEq` id_read noPosition) = vf @@ -3698,8 +3701,8 @@ adjustRegAlignedFields (vfi, fts) = in (map renameField vfi, fts) -adjustRegFields :: ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) -> - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) +adjustRegFields :: ([VFieldInfo], [([AType], Maybe AType, [AType])]) -> + ([VFieldInfo], [([AType], Maybe AType, [AType])]) adjustRegFields (vfi, fts) = let renameField vf@(Method {vf_name = i }) | (i `qualEq` idPreludeRead) = vf { vf_name = id_read noPosition } @@ -3708,8 +3711,8 @@ adjustRegFields (vfi, fts) = ppReadable (vf_name vf)) in (map renameField vfi, fts) -adjustFIFOFields :: ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) -> - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) +adjustFIFOFields :: ([VFieldInfo], [([AType], Maybe AType, [AType])]) -> + ([VFieldInfo], [([AType], Maybe AType, [AType])]) adjustFIFOFields (vfi, fts) = let enq_rdy = mkRdyId idEnq deq_rdy = mkRdyId idDeq @@ -3721,8 +3724,8 @@ adjustFIFOFields (vfi, fts) = renameField vft = [vft] in unzip $ concatMap renameField $ zip vfi fts -adjustFIFO0Fields :: ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) -> - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) +adjustFIFO0Fields :: ([VFieldInfo], [([AType], Maybe AType, [AType])]) -> + ([VFieldInfo], [([AType], Maybe AType, [AType])]) adjustFIFO0Fields (vfi, fts) = let (clk, rst) = case vfi of @@ -3730,12 +3733,12 @@ adjustFIFO0Fields (vfi, fts) = (_:d@(Method _ c r _ _ _ _):_) -> (c, r) _ -> internalError ("adjustFIFO0Fields: vfi = " ++ ppReadable vfi) - first_vfi = Method idFirst clk rst 1 [] Nothing Nothing - first_fts = ([], Nothing, Nothing) + first_vfi = Method idFirst clk rst 1 [] [] Nothing + first_fts = ([], Nothing, []) in (first_vfi:vfi, first_fts:fts) -adjustSyncRegFields :: ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) -> - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) +adjustSyncRegFields :: ([VFieldInfo], [([AType], Maybe AType, [AType])]) -> + ([VFieldInfo], [([AType], Maybe AType, [AType])]) adjustSyncRegFields (vfi, fts) = let renameField vf@(Method {vf_name = i }) -- XXX these are qualified Clock, not Prelude @@ -3747,28 +3750,28 @@ adjustSyncRegFields (vfi, fts) = ppReadable (vf_name vf)) in (map renameField vfi, fts) -adjustRWireFields :: ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) -> - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) +adjustRWireFields :: ([VFieldInfo], [([AType], Maybe AType, [AType])]) -> + ([VFieldInfo], [([AType], Maybe AType, [AType])]) adjustRWireFields (vfi, fts) = let renameField vf@(Method {vf_name = i }) | (i `qualEq` idWHas) = vf { vf_name = unQualId $ mkRdyId idWGet } renameField vf = vf in (map renameField vfi, fts) -adjustRWire0Fields :: ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) -> - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) +adjustRWire0Fields :: ([VFieldInfo], [([AType], Maybe AType, [AType])]) -> + ([VFieldInfo], [([AType], Maybe AType, [AType])]) adjustRWire0Fields (vfi, fts) = let (clk, rst) = case vfi of ((Method _ c r _ _ _ _):_) -> (c, r) _ -> internalError ("adjustRWire0Fields: vfi = " ++ ppReadable vfi) - wget_vfi = Method (unQualId idWGet) clk rst 1 [] Nothing Nothing - wget_fts = ([], Nothing, Nothing) + wget_vfi = Method (unQualId idWGet) clk rst 1 [] [] Nothing + wget_fts = ([], Nothing, []) in (wget_vfi:vfi, wget_fts:fts) -adjustWireFields :: ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) -> - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) +adjustWireFields :: ([VFieldInfo], [([AType], Maybe AType, [AType])]) -> + ([VFieldInfo], [([AType], Maybe AType, [AType])]) adjustWireFields (vfi, fts) = let readId = id_read noPosition writeId = id_write noPosition @@ -3781,8 +3784,8 @@ adjustWireFields (vfi, fts) = in (map renameField vfi, fts) adjustPulseWireFields :: - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) -> - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) + ([VFieldInfo], [([AType], Maybe AType, [AType])]) -> + ([VFieldInfo], [([AType], Maybe AType, [AType])]) adjustPulseWireFields (vfi, fts) = let renameField vf@(Method {vf_name = i }) | (i `qualEq` idWSet) = vf { vf_name = unQualId idSend } @@ -3793,8 +3796,8 @@ adjustPulseWireFields (vfi, fts) = in (map renameField vfi, fts) adjustBypassWireFields :: - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) -> - ([VFieldInfo], [([AType], Maybe AType, Maybe AType)]) + ([VFieldInfo], [([AType], Maybe AType, [AType])]) -> + ([VFieldInfo], [([AType], Maybe AType, [AType])]) adjustBypassWireFields (vfi, fts) = let renameField vf@(Method {vf_name = i }) | (i `qualEq` idWGet) = vf { vf_name = id_read noPosition } @@ -3882,19 +3885,19 @@ getPortsIfc ptmap out_clkinfo out_rstinfo (SubIfc fId fs) = then [] else [PISubIfc fId fs'] getPortsIfc ptmap _ _ - (Field fId (RawMethod i mult mclk mrst args ins mo me) mrdy_inf) = - getPortsIfcMethod ptmap fId i mult mclk mrst args ins mo me mr + (Field fId (RawMethod i mult mclk mrst args ins outs me) mrdy_inf) = + getPortsIfcMethod ptmap fId i mult mclk mrst args ins outs me mr where mr = case (mrdy_inf) of Nothing -> Nothing - (Just (RawMethod ri m _ _ [] [] (Just (vp@(vn,_), t)) Nothing)) + (Just (RawMethod ri m _ _ [] [] [(vp@(vn,_), t)] Nothing)) | ((m == 0) || (m == 1)) -> if (t == aTBool) then Just vp else internalError ("getPortsIfc: Rdy wrong size: " ++ ppReadable (ri,t)) - (Just (RawMethod ri m _ _ as is mout men)) -> + (Just (RawMethod ri m _ _ as is os men)) -> internalError ("getPortsIfc: not Rdy: " ++ - ppReadable (ri, m, as, is, mout, men)) + ppReadable (ri, m, as, is, os, men)) (Just d) -> internalError ("getPortsIfc: not Rdy: " ++ ppReadable (rawIfcFieldName d)) getPortsIfc _ out_clkinfo _ (Field fId (RawClock i) Nothing) = @@ -3911,10 +3914,10 @@ getPortsIfc _ _ _ (Field fId rf (Just rdy_rf)) = getPortsIfcMethod :: M.Map VName IType -> Id -> Id -> Integer -> Maybe Id -> Maybe Id -> - [(Maybe Id, AType)] -> [VPort] -> Maybe (VPort, AType) -> + [(Maybe Id, AType)] -> [VPort] -> [(VPort, AType)] -> Maybe VPort -> Maybe VPort -> [PortIfcInfo] -getPortsIfcMethod ptmap fId methId mult mClk mRst args ins mOut mEn mRdy = +getPortsIfcMethod ptmap fId methId mult mClk mRst args ins outs mEn mRdy = let -- get the port-type pair for an argument getPortsArg (mi, bit_type) (vn, _) = @@ -3922,8 +3925,7 @@ getPortsIfcMethod ptmap fId methId mult mClk mRst args ins mOut mEn mRdy = then [] else [(mi, bit_type, getVNameType ptmap vn)] -- get the port-type pair for the output - getPortsOut Nothing = Nothing - getPortsOut (Just ((vn, _), bit_type)) = + getPortsOut ((vn, _), bit_type) = if (isSizeZero bit_type) then Nothing else @@ -3946,7 +3948,7 @@ getPortsIfcMethod ptmap fId methId mult mClk mRst args ins mOut mEn mRdy = -- the default result (multiplicity of 1) def_res = PIMethod fId methId mClk mRst (concat (zipWith getPortsArg args ins)) - (getPortsOut mOut) (getPortsEn mEn) (getPortsRdy mRdy) + (mapMaybe getPortsOut outs) (getPortsEn mEn) (getPortsRdy mRdy) -- the result if multiplicity > 1 mkMulRes n = @@ -3955,7 +3957,7 @@ getPortsIfcMethod ptmap fId methId mult mClk mRst args ins mOut mEn mRdy = in PIMethod (dupId s fId) -- XXX handle mults differently? (dupId s methId) mClk mRst (concat (zipWith getPortsArg args ins')) - (getPortsOut (dupMVPortType s mOut)) + (mapMaybe (getPortsOut . dupMVPortType s) outs) (getPortsEn (dupMVPort s mEn)) (getPortsRdy (dupMVPort s mRdy)) @@ -3964,9 +3966,8 @@ getPortsIfcMethod ptmap fId methId mult mClk mRst args ins mOut mEn mRdy = dupVPort suf (vn, ps) = (dupVName suf vn, ps) dupMVPort :: String -> Maybe VPort -> Maybe VPort dupMVPort suf mvp = mvp >>= Just . dupVPort suf - dupMVPortType :: String -> Maybe (VPort, AType) -> Maybe (VPort, AType) - dupMVPortType suf mvpt = - mvpt >>= (\ (vp, t) -> Just (dupVPort suf vp, t) ) + dupMVPortType :: String -> (VPort, AType) -> (VPort, AType) + dupMVPortType suf (vp, t) = (dupVPort suf vp, t) in if (mult == 1) || (mult == 0) then [def_res] @@ -4029,13 +4030,6 @@ dispMPortWithType s mport = Nothing -> [] Just (p, _) -> [tagStr s p] -dispMPortWithTypes :: String -> Maybe (String, AType, IType) -> [HTclObj] -dispMPortWithTypes s mport = - case mport of - Nothing -> [] - Just (p, _, _) -> -- XXX we have the opportunity to display the size - [tagStr s p] - -- display AType dispSize :: AType -> [HTclObj] dispSize (ATBit sz) = [tagInt "size" (fromInteger sz)] @@ -4085,16 +4079,23 @@ dispMethodArgs as = dispSize bit_type in TLst (map dispArg as) +dispMethodResults :: [(String, AType, IType)] -> HTclObj +dispMethodResults outs = + let dispOut (port, bit_type, _) = + TLst $ [tagStr "port" port] ++ + dispSize bit_type + in TLst (map dispOut outs) + dispIfc :: PortIfcInfo -> HTclObj -dispIfc (PIMethod fId i mClk mRst ins mOut mEn mRdy) = +dispIfc (PIMethod fId i mClk mRst ins outs mEn mRdy) = TLst $ [TStr "method", TStr (getIdBaseString fId), TStr (pfpString i), dispClockedBy mClk, dispResetBy mRst, - tag "args" [dispMethodArgs ins]] ++ - dispMPortWithTypes "result" mOut ++ + tag "args" [dispMethodArgs ins], + tag "results" [dispMethodResults outs]] ++ dispMPortWithType "enable" mEn ++ dispMPortWithType "ready" mRdy dispIfc (PIClock fId i Nothing) = @@ -4124,6 +4125,9 @@ dispIfc (PISubIfc fId fs) = dispPortType :: (String, IType) -> HTclObj dispPortType (p,t) = TLst [TStr p, TStr (pfpString t)] +dispPortTypes :: (String, AType, IType) -> HTclObj +dispPortTypes (p,at,t) = dispPortType (p,t) + dispMPortType :: Maybe (String, IType) -> [HTclObj] dispMPortType Nothing = [] dispMPortType (Just pt) = [dispPortType pt] @@ -4144,9 +4148,10 @@ dispPortsModArg (PAInout _ _ pt _ _) = [dispPortType pt] dispPortsIfc :: PortIfcInfo -> [HTclObj] -dispPortsIfc (PIMethod _ _ _ _ ins mOut mEn mRdy) = +dispPortsIfc (PIMethod _ _ _ _ ins outs mEn mRdy) = (map (dispPortType . thd) ins) ++ - dispMPortTypes mOut ++ dispMPortType mEn ++ dispMPortType mRdy + (map dispPortTypes outs) ++ + dispMPortType mEn ++ dispMPortType mRdy dispPortsIfc (PIClock _ _ Nothing) = [] dispPortsIfc (PIClock _ _ (Just (osc, mgate))) = [dispPortType osc] ++ dispMPortType mgate @@ -4217,7 +4222,7 @@ get_method_to_signal_map vmod = do case f of Method {} -> return () _ -> mzero -- failure, as in the guard function - port <- (vf_inputs f) ++ (maybeToList $ vf_output f) ++ (maybeToList $ vf_enable f) + port <- (vf_inputs f) ++ (vf_outputs f) ++ (maybeToList $ vf_enable f) count <- case (vf_mult f) of 1 -> return Nothing k -> map Just [1..k] diff --git a/src/comp/showrules.hs b/src/comp/showrules.hs index fbb92ebb7..531d94410 100644 --- a/src/comp/showrules.hs +++ b/src/comp/showrules.hs @@ -455,7 +455,7 @@ mkMorphState opts instmap hiermap abmis_by_name top_mod = let methmap = M.fromList [ ((inst,name),rules) | (inst,abmi) <- user_modules , aif <- apkg_interface (abmi_apkg abmi) - , let name = aIfaceName aif + , let name = aif_name aif , let rules = aIfaceRules aif , not (null rules) ] diff --git a/testsuite/bsc.bluetcl/commands/module.tcl.bluetcl-bh-out.expected b/testsuite/bsc.bluetcl/commands/module.tcl.bluetcl-bh-out.expected index b572a8ea5..784ac49b5 100644 --- a/testsuite/bsc.bluetcl/commands/module.tcl.bluetcl-bh-out.expected +++ b/testsuite/bsc.bluetcl/commands/module.tcl.bluetcl-bh-out.expected @@ -115,19 +115,19 @@ ios1_1 {Prelude.Inout Test.Bar} ---------- module ports mkT Command: module ports mkT -interface {{interface r {{method _write r__write {clock default_clock} {reset no_reset} {args {{{name r__write_1} {port r__write_1} {size 1}}}} {enable EN_r__write} {ready RDY_r__write}} {method _read r__read {clock no_clock} {reset no_reset} {args {}} {result r__read} {ready RDY_r__read}}}} {inout b b {port b} {clock default_clock} {reset default_reset}}} +interface {{interface r {{method _write r__write {clock default_clock} {reset no_reset} {args {{{name r__write_1} {port r__write_1} {size 1}}}} {results {}} {enable EN_r__write} {ready RDY_r__write}} {method _read r__read {clock no_clock} {reset no_reset} {args {}} {results {{{port r__read} {size 1}}}} {ready RDY_r__read}}}} {inout b b {port b} {clock default_clock} {reset default_reset}}} args {{inout i {port i} {clock default_clock} {reset default_reset} {size 2}} {clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}} --------- module ports mkM Command: module ports mkM -interface {{method _write _write {clock default_clock} {reset default_reset} {args {{{name _write_1} {port _write_1} {size 1}}}} {enable EN__write} {ready RDY__write}} {method _read _read {clock default_clock} {reset default_reset} {args {}} {result _read} {ready RDY__read}}} +interface {{method _write _write {clock default_clock} {reset default_reset} {args {{{name _write_1} {port _write_1} {size 1}}}} {results {}} {enable EN__write} {ready RDY__write}} {method _read _read {clock default_clock} {reset default_reset} {args {}} {results {{{port _read} {size 1}}}} {ready RDY__read}}} args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}} --------- module ports mkIfcWithVec Command: module ports mkIfcWithVec -interface {{interface vec1 {{interface 0 {{method _write vec1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec1_0__write_1} {port vec1_0__write_1} {size 1}}}} {enable EN_vec1_0__write} {ready RDY_vec1_0__write}} {method _read vec1_0__read {clock no_clock} {reset no_reset} {args {}} {result vec1_0__read} {ready RDY_vec1_0__read}}}} {interface 1 {{method _write vec1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec1_1__write_1} {port vec1_1__write_1} {size 1}}}} {enable EN_vec1_1__write} {ready RDY_vec1_1__write}} {method _read vec1_1__read {clock no_clock} {reset no_reset} {args {}} {result vec1_1__read} {ready RDY_vec1_1__read}}}}}} {interface vec2 {{interface 0 {{interface 0 {{method _write vec2_0_0__write {clock clks1_1} {reset no_reset} {args {{{name vec2_0_0__write_1} {port vec2_0_0__write_1} {size 1}}}} {enable EN_vec2_0_0__write} {ready RDY_vec2_0_0__write}} {method _read vec2_0_0__read {clock no_clock} {reset no_reset} {args {}} {result vec2_0_0__read} {ready RDY_vec2_0_0__read}}}} {interface 1 {{method _write vec2_0_1__write {clock clks1_1} {reset no_reset} {args {{{name vec2_0_1__write_1} {port vec2_0_1__write_1} {size 1}}}} {enable EN_vec2_0_1__write} {ready RDY_vec2_0_1__write}} {method _read vec2_0_1__read {clock no_clock} {reset no_reset} {args {}} {result vec2_0_1__read} {ready RDY_vec2_0_1__read}}}}}} {interface 1 {{interface 0 {{method _write vec2_1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec2_1_0__write_1} {port vec2_1_0__write_1} {size 1}}}} {enable EN_vec2_1_0__write} {ready RDY_vec2_1_0__write}} {method _read vec2_1_0__read {clock no_clock} {reset no_reset} {args {}} {result vec2_1_0__read} {ready RDY_vec2_1_0__read}}}} {interface 1 {{method _write vec2_1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec2_1_1__write_1} {port vec2_1_1__write_1} {size 1}}}} {enable EN_vec2_1_1__write} {ready RDY_vec2_1_1__write}} {method _read vec2_1_1__read {clock no_clock} {reset no_reset} {args {}} {result vec2_1_1__read} {ready RDY_vec2_1_1__read}}}}}}}} {interface vec3 {{interface 0 {{interface 0 {{interface 0 {{method _write vec3_0_0_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_0_0__write_1} {port vec3_0_0_0__write_1} {size 1}}}} {enable EN_vec3_0_0_0__write} {ready RDY_vec3_0_0_0__write}} {method _read vec3_0_0_0__read {clock no_clock} {reset no_reset} {args {}} {result vec3_0_0_0__read} {ready RDY_vec3_0_0_0__read}}}} {interface 1 {{method _write vec3_0_0_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_0_1__write_1} {port vec3_0_0_1__write_1} {size 1}}}} {enable EN_vec3_0_0_1__write} {ready RDY_vec3_0_0_1__write}} {method _read vec3_0_0_1__read {clock no_clock} {reset no_reset} {args {}} {result vec3_0_0_1__read} {ready RDY_vec3_0_0_1__read}}}}}} {interface 1 {{interface 0 {{method _write vec3_0_1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_1_0__write_1} {port vec3_0_1_0__write_1} {size 1}}}} {enable EN_vec3_0_1_0__write} {ready RDY_vec3_0_1_0__write}} {method _read vec3_0_1_0__read {clock no_clock} {reset no_reset} {args {}} {result vec3_0_1_0__read} {ready RDY_vec3_0_1_0__read}}}} {interface 1 {{method _write vec3_0_1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_1_1__write_1} {port vec3_0_1_1__write_1} {size 1}}}} {enable EN_vec3_0_1_1__write} {ready RDY_vec3_0_1_1__write}} {method _read vec3_0_1_1__read {clock no_clock} {reset no_reset} {args {}} {result vec3_0_1_1__read} {ready RDY_vec3_0_1_1__read}}}}}}}} {interface 1 {{interface 0 {{interface 0 {{method _write vec3_1_0_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_0_0__write_1} {port vec3_1_0_0__write_1} {size 1}}}} {enable EN_vec3_1_0_0__write} {ready RDY_vec3_1_0_0__write}} {method _read vec3_1_0_0__read {clock no_clock} {reset no_reset} {args {}} {result vec3_1_0_0__read} {ready RDY_vec3_1_0_0__read}}}} {interface 1 {{method _write vec3_1_0_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_0_1__write_1} {port vec3_1_0_1__write_1} {size 1}}}} {enable EN_vec3_1_0_1__write} {ready RDY_vec3_1_0_1__write}} {method _read vec3_1_0_1__read {clock no_clock} {reset no_reset} {args {}} {result vec3_1_0_1__read} {ready RDY_vec3_1_0_1__read}}}}}} {interface 1 {{interface 0 {{method _write vec3_1_1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_1_0__write_1} {port vec3_1_1_0__write_1} {size 1}}}} {enable EN_vec3_1_1_0__write} {ready RDY_vec3_1_1_0__write}} {method _read vec3_1_1_0__read {clock no_clock} {reset no_reset} {args {}} {result vec3_1_1_0__read} {ready RDY_vec3_1_1_0__read}}}} {interface 1 {{method _write vec3_1_1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_1_1__write_1} {port vec3_1_1_1__write_1} {size 1}}}} {enable EN_vec3_1_1_1__write} {ready RDY_vec3_1_1_1__write}} {method _read vec3_1_1_1__read {clock no_clock} {reset no_reset} {args {}} {result vec3_1_1_1__read} {ready RDY_vec3_1_1_1__read}}}}}}}}}} {method data1 data1 {clock no_clock} {reset no_reset} {args {}} {result data1} {ready RDY_data1}} {method data2 data2 {clock no_clock} {reset no_reset} {args {}} {result data2} {ready RDY_data2}} {method data3 data3 {clock no_clock} {reset no_reset} {args {}} {result data3} {ready RDY_data3}} {interface clks1 {{interface 0 {{clock {} clks1_0 {osc CLK_clks1_0} {gate CLK_GATE_clks1_0}}}} {interface 1 {{clock {} clks1_1 {osc CLK_clks1_1} {gate CLK_GATE_clks1_1}}}}}} {interface rsts1 {{interface 0 {{reset {} rsts1_0 {port RST_N_rsts1_0} {clock default_clock}}}} {interface 1 {{reset {} rsts1_1 {port RST_N_rsts1_1} {clock default_clock}}}}}} {interface ios1 {{interface 0 {{inout {} ios1_0 {port ios1_0} {clock clks1_1} {reset rsts1_1}}}} {interface 1 {{inout {} ios1_1 {port ios1_1} {clock clks1_1} {reset rsts1_1}}}}}}} +interface {{interface vec1 {{interface 0 {{method _write vec1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec1_0__write_1} {port vec1_0__write_1} {size 1}}}} {results {}} {enable EN_vec1_0__write} {ready RDY_vec1_0__write}} {method _read vec1_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec1_0__read} {size 1}}}} {ready RDY_vec1_0__read}}}} {interface 1 {{method _write vec1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec1_1__write_1} {port vec1_1__write_1} {size 1}}}} {results {}} {enable EN_vec1_1__write} {ready RDY_vec1_1__write}} {method _read vec1_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec1_1__read} {size 1}}}} {ready RDY_vec1_1__read}}}}}} {interface vec2 {{interface 0 {{interface 0 {{method _write vec2_0_0__write {clock clks1_1} {reset no_reset} {args {{{name vec2_0_0__write_1} {port vec2_0_0__write_1} {size 1}}}} {results {}} {enable EN_vec2_0_0__write} {ready RDY_vec2_0_0__write}} {method _read vec2_0_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec2_0_0__read} {size 1}}}} {ready RDY_vec2_0_0__read}}}} {interface 1 {{method _write vec2_0_1__write {clock clks1_1} {reset no_reset} {args {{{name vec2_0_1__write_1} {port vec2_0_1__write_1} {size 1}}}} {results {}} {enable EN_vec2_0_1__write} {ready RDY_vec2_0_1__write}} {method _read vec2_0_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec2_0_1__read} {size 1}}}} {ready RDY_vec2_0_1__read}}}}}} {interface 1 {{interface 0 {{method _write vec2_1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec2_1_0__write_1} {port vec2_1_0__write_1} {size 1}}}} {results {}} {enable EN_vec2_1_0__write} {ready RDY_vec2_1_0__write}} {method _read vec2_1_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec2_1_0__read} {size 1}}}} {ready RDY_vec2_1_0__read}}}} {interface 1 {{method _write vec2_1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec2_1_1__write_1} {port vec2_1_1__write_1} {size 1}}}} {results {}} {enable EN_vec2_1_1__write} {ready RDY_vec2_1_1__write}} {method _read vec2_1_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec2_1_1__read} {size 1}}}} {ready RDY_vec2_1_1__read}}}}}}}} {interface vec3 {{interface 0 {{interface 0 {{interface 0 {{method _write vec3_0_0_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_0_0__write_1} {port vec3_0_0_0__write_1} {size 1}}}} {results {}} {enable EN_vec3_0_0_0__write} {ready RDY_vec3_0_0_0__write}} {method _read vec3_0_0_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_0_0_0__read} {size 1}}}} {ready RDY_vec3_0_0_0__read}}}} {interface 1 {{method _write vec3_0_0_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_0_1__write_1} {port vec3_0_0_1__write_1} {size 1}}}} {results {}} {enable EN_vec3_0_0_1__write} {ready RDY_vec3_0_0_1__write}} {method _read vec3_0_0_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_0_0_1__read} {size 1}}}} {ready RDY_vec3_0_0_1__read}}}}}} {interface 1 {{interface 0 {{method _write vec3_0_1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_1_0__write_1} {port vec3_0_1_0__write_1} {size 1}}}} {results {}} {enable EN_vec3_0_1_0__write} {ready RDY_vec3_0_1_0__write}} {method _read vec3_0_1_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_0_1_0__read} {size 1}}}} {ready RDY_vec3_0_1_0__read}}}} {interface 1 {{method _write vec3_0_1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_1_1__write_1} {port vec3_0_1_1__write_1} {size 1}}}} {results {}} {enable EN_vec3_0_1_1__write} {ready RDY_vec3_0_1_1__write}} {method _read vec3_0_1_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_0_1_1__read} {size 1}}}} {ready RDY_vec3_0_1_1__read}}}}}}}} {interface 1 {{interface 0 {{interface 0 {{method _write vec3_1_0_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_0_0__write_1} {port vec3_1_0_0__write_1} {size 1}}}} {results {}} {enable EN_vec3_1_0_0__write} {ready RDY_vec3_1_0_0__write}} {method _read vec3_1_0_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_1_0_0__read} {size 1}}}} {ready RDY_vec3_1_0_0__read}}}} {interface 1 {{method _write vec3_1_0_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_0_1__write_1} {port vec3_1_0_1__write_1} {size 1}}}} {results {}} {enable EN_vec3_1_0_1__write} {ready RDY_vec3_1_0_1__write}} {method _read vec3_1_0_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_1_0_1__read} {size 1}}}} {ready RDY_vec3_1_0_1__read}}}}}} {interface 1 {{interface 0 {{method _write vec3_1_1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_1_0__write_1} {port vec3_1_1_0__write_1} {size 1}}}} {results {}} {enable EN_vec3_1_1_0__write} {ready RDY_vec3_1_1_0__write}} {method _read vec3_1_1_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_1_1_0__read} {size 1}}}} {ready RDY_vec3_1_1_0__read}}}} {interface 1 {{method _write vec3_1_1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_1_1__write_1} {port vec3_1_1_1__write_1} {size 1}}}} {results {}} {enable EN_vec3_1_1_1__write} {ready RDY_vec3_1_1_1__write}} {method _read vec3_1_1_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_1_1_1__read} {size 1}}}} {ready RDY_vec3_1_1_1__read}}}}}}}}}} {method data1 data1 {clock no_clock} {reset no_reset} {args {}} {results {{{port data1} {size 2}}}} {ready RDY_data1}} {method data2 data2 {clock no_clock} {reset no_reset} {args {}} {results {{{port data2} {size 4}}}} {ready RDY_data2}} {method data3 data3 {clock no_clock} {reset no_reset} {args {}} {results {{{port data3} {size 8}}}} {ready RDY_data3}} {interface clks1 {{interface 0 {{clock {} clks1_0 {osc CLK_clks1_0} {gate CLK_GATE_clks1_0}}}} {interface 1 {{clock {} clks1_1 {osc CLK_clks1_1} {gate CLK_GATE_clks1_1}}}}}} {interface rsts1 {{interface 0 {{reset {} rsts1_0 {port RST_N_rsts1_0} {clock default_clock}}}} {interface 1 {{reset {} rsts1_1 {port RST_N_rsts1_1} {clock default_clock}}}}}} {interface ios1 {{interface 0 {{inout {} ios1_0 {port ios1_0} {clock clks1_1} {reset rsts1_1}}}} {interface 1 {{inout {} ios1_1 {port ios1_1} {clock clks1_1} {reset rsts1_1}}}}}}} args {{inout io {port io} {clock default_clock} {reset default_reset} {size 2}} {clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}} --------- ---------- diff --git a/testsuite/bsc.bluetcl/commands/module.tcl.bluetcl-out.expected b/testsuite/bsc.bluetcl/commands/module.tcl.bluetcl-out.expected index d02606a21..32af9b611 100644 --- a/testsuite/bsc.bluetcl/commands/module.tcl.bluetcl-out.expected +++ b/testsuite/bsc.bluetcl/commands/module.tcl.bluetcl-out.expected @@ -115,19 +115,19 @@ ios1_1 Inout#(Test::Bar) ---------- module ports mkT Command: module ports mkT -interface {{interface r {{method _write r__write {clock default_clock} {reset no_reset} {args {{{name r__write_1} {port r__write_1} {size 1}}}} {enable EN_r__write} {ready RDY_r__write}} {method _read r__read {clock no_clock} {reset no_reset} {args {}} {result r__read} {ready RDY_r__read}}}} {inout b b {port b} {clock default_clock} {reset default_reset}}} +interface {{interface r {{method _write r__write {clock default_clock} {reset no_reset} {args {{{name r__write_1} {port r__write_1} {size 1}}}} {results {}} {enable EN_r__write} {ready RDY_r__write}} {method _read r__read {clock no_clock} {reset no_reset} {args {}} {results {{{port r__read} {size 1}}}} {ready RDY_r__read}}}} {inout b b {port b} {clock default_clock} {reset default_reset}}} args {{inout i {port i} {clock default_clock} {reset default_reset} {size 2}} {clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}} --------- module ports mkM Command: module ports mkM -interface {{method _write _write {clock default_clock} {reset default_reset} {args {{{name _write_1} {port _write_1} {size 1}}}} {enable EN__write} {ready RDY__write}} {method _read _read {clock default_clock} {reset default_reset} {args {}} {result _read} {ready RDY__read}}} +interface {{method _write _write {clock default_clock} {reset default_reset} {args {{{name _write_1} {port _write_1} {size 1}}}} {results {}} {enable EN__write} {ready RDY__write}} {method _read _read {clock default_clock} {reset default_reset} {args {}} {results {{{port _read} {size 1}}}} {ready RDY__read}}} args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}} --------- module ports mkIfcWithVec Command: module ports mkIfcWithVec -interface {{interface vec1 {{interface 0 {{method _write vec1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec1_0__write_1} {port vec1_0__write_1} {size 1}}}} {enable EN_vec1_0__write} {ready RDY_vec1_0__write}} {method _read vec1_0__read {clock no_clock} {reset no_reset} {args {}} {result vec1_0__read} {ready RDY_vec1_0__read}}}} {interface 1 {{method _write vec1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec1_1__write_1} {port vec1_1__write_1} {size 1}}}} {enable EN_vec1_1__write} {ready RDY_vec1_1__write}} {method _read vec1_1__read {clock no_clock} {reset no_reset} {args {}} {result vec1_1__read} {ready RDY_vec1_1__read}}}}}} {interface vec2 {{interface 0 {{interface 0 {{method _write vec2_0_0__write {clock clks1_1} {reset no_reset} {args {{{name vec2_0_0__write_1} {port vec2_0_0__write_1} {size 1}}}} {enable EN_vec2_0_0__write} {ready RDY_vec2_0_0__write}} {method _read vec2_0_0__read {clock no_clock} {reset no_reset} {args {}} {result vec2_0_0__read} {ready RDY_vec2_0_0__read}}}} {interface 1 {{method _write vec2_0_1__write {clock clks1_1} {reset no_reset} {args {{{name vec2_0_1__write_1} {port vec2_0_1__write_1} {size 1}}}} {enable EN_vec2_0_1__write} {ready RDY_vec2_0_1__write}} {method _read vec2_0_1__read {clock no_clock} {reset no_reset} {args {}} {result vec2_0_1__read} {ready RDY_vec2_0_1__read}}}}}} {interface 1 {{interface 0 {{method _write vec2_1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec2_1_0__write_1} {port vec2_1_0__write_1} {size 1}}}} {enable EN_vec2_1_0__write} {ready RDY_vec2_1_0__write}} {method _read vec2_1_0__read {clock no_clock} {reset no_reset} {args {}} {result vec2_1_0__read} {ready RDY_vec2_1_0__read}}}} {interface 1 {{method _write vec2_1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec2_1_1__write_1} {port vec2_1_1__write_1} {size 1}}}} {enable EN_vec2_1_1__write} {ready RDY_vec2_1_1__write}} {method _read vec2_1_1__read {clock no_clock} {reset no_reset} {args {}} {result vec2_1_1__read} {ready RDY_vec2_1_1__read}}}}}}}} {interface vec3 {{interface 0 {{interface 0 {{interface 0 {{method _write vec3_0_0_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_0_0__write_1} {port vec3_0_0_0__write_1} {size 1}}}} {enable EN_vec3_0_0_0__write} {ready RDY_vec3_0_0_0__write}} {method _read vec3_0_0_0__read {clock no_clock} {reset no_reset} {args {}} {result vec3_0_0_0__read} {ready RDY_vec3_0_0_0__read}}}} {interface 1 {{method _write vec3_0_0_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_0_1__write_1} {port vec3_0_0_1__write_1} {size 1}}}} {enable EN_vec3_0_0_1__write} {ready RDY_vec3_0_0_1__write}} {method _read vec3_0_0_1__read {clock no_clock} {reset no_reset} {args {}} {result vec3_0_0_1__read} {ready RDY_vec3_0_0_1__read}}}}}} {interface 1 {{interface 0 {{method _write vec3_0_1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_1_0__write_1} {port vec3_0_1_0__write_1} {size 1}}}} {enable EN_vec3_0_1_0__write} {ready RDY_vec3_0_1_0__write}} {method _read vec3_0_1_0__read {clock no_clock} {reset no_reset} {args {}} {result vec3_0_1_0__read} {ready RDY_vec3_0_1_0__read}}}} {interface 1 {{method _write vec3_0_1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_1_1__write_1} {port vec3_0_1_1__write_1} {size 1}}}} {enable EN_vec3_0_1_1__write} {ready RDY_vec3_0_1_1__write}} {method _read vec3_0_1_1__read {clock no_clock} {reset no_reset} {args {}} {result vec3_0_1_1__read} {ready RDY_vec3_0_1_1__read}}}}}}}} {interface 1 {{interface 0 {{interface 0 {{method _write vec3_1_0_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_0_0__write_1} {port vec3_1_0_0__write_1} {size 1}}}} {enable EN_vec3_1_0_0__write} {ready RDY_vec3_1_0_0__write}} {method _read vec3_1_0_0__read {clock no_clock} {reset no_reset} {args {}} {result vec3_1_0_0__read} {ready RDY_vec3_1_0_0__read}}}} {interface 1 {{method _write vec3_1_0_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_0_1__write_1} {port vec3_1_0_1__write_1} {size 1}}}} {enable EN_vec3_1_0_1__write} {ready RDY_vec3_1_0_1__write}} {method _read vec3_1_0_1__read {clock no_clock} {reset no_reset} {args {}} {result vec3_1_0_1__read} {ready RDY_vec3_1_0_1__read}}}}}} {interface 1 {{interface 0 {{method _write vec3_1_1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_1_0__write_1} {port vec3_1_1_0__write_1} {size 1}}}} {enable EN_vec3_1_1_0__write} {ready RDY_vec3_1_1_0__write}} {method _read vec3_1_1_0__read {clock no_clock} {reset no_reset} {args {}} {result vec3_1_1_0__read} {ready RDY_vec3_1_1_0__read}}}} {interface 1 {{method _write vec3_1_1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_1_1__write_1} {port vec3_1_1_1__write_1} {size 1}}}} {enable EN_vec3_1_1_1__write} {ready RDY_vec3_1_1_1__write}} {method _read vec3_1_1_1__read {clock no_clock} {reset no_reset} {args {}} {result vec3_1_1_1__read} {ready RDY_vec3_1_1_1__read}}}}}}}}}} {method data1 data1 {clock no_clock} {reset no_reset} {args {}} {result data1} {ready RDY_data1}} {method data2 data2 {clock no_clock} {reset no_reset} {args {}} {result data2} {ready RDY_data2}} {method data3 data3 {clock no_clock} {reset no_reset} {args {}} {result data3} {ready RDY_data3}} {interface clks1 {{interface 0 {{clock {} clks1_0 {osc CLK_clks1_0} {gate CLK_GATE_clks1_0}}}} {interface 1 {{clock {} clks1_1 {osc CLK_clks1_1} {gate CLK_GATE_clks1_1}}}}}} {interface rsts1 {{interface 0 {{reset {} rsts1_0 {port RST_N_rsts1_0} {clock default_clock}}}} {interface 1 {{reset {} rsts1_1 {port RST_N_rsts1_1} {clock default_clock}}}}}} {interface ios1 {{interface 0 {{inout {} ios1_0 {port ios1_0} {clock clks1_1} {reset rsts1_1}}}} {interface 1 {{inout {} ios1_1 {port ios1_1} {clock clks1_1} {reset rsts1_1}}}}}}} +interface {{interface vec1 {{interface 0 {{method _write vec1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec1_0__write_1} {port vec1_0__write_1} {size 1}}}} {results {}} {enable EN_vec1_0__write} {ready RDY_vec1_0__write}} {method _read vec1_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec1_0__read} {size 1}}}} {ready RDY_vec1_0__read}}}} {interface 1 {{method _write vec1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec1_1__write_1} {port vec1_1__write_1} {size 1}}}} {results {}} {enable EN_vec1_1__write} {ready RDY_vec1_1__write}} {method _read vec1_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec1_1__read} {size 1}}}} {ready RDY_vec1_1__read}}}}}} {interface vec2 {{interface 0 {{interface 0 {{method _write vec2_0_0__write {clock clks1_1} {reset no_reset} {args {{{name vec2_0_0__write_1} {port vec2_0_0__write_1} {size 1}}}} {results {}} {enable EN_vec2_0_0__write} {ready RDY_vec2_0_0__write}} {method _read vec2_0_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec2_0_0__read} {size 1}}}} {ready RDY_vec2_0_0__read}}}} {interface 1 {{method _write vec2_0_1__write {clock clks1_1} {reset no_reset} {args {{{name vec2_0_1__write_1} {port vec2_0_1__write_1} {size 1}}}} {results {}} {enable EN_vec2_0_1__write} {ready RDY_vec2_0_1__write}} {method _read vec2_0_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec2_0_1__read} {size 1}}}} {ready RDY_vec2_0_1__read}}}}}} {interface 1 {{interface 0 {{method _write vec2_1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec2_1_0__write_1} {port vec2_1_0__write_1} {size 1}}}} {results {}} {enable EN_vec2_1_0__write} {ready RDY_vec2_1_0__write}} {method _read vec2_1_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec2_1_0__read} {size 1}}}} {ready RDY_vec2_1_0__read}}}} {interface 1 {{method _write vec2_1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec2_1_1__write_1} {port vec2_1_1__write_1} {size 1}}}} {results {}} {enable EN_vec2_1_1__write} {ready RDY_vec2_1_1__write}} {method _read vec2_1_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec2_1_1__read} {size 1}}}} {ready RDY_vec2_1_1__read}}}}}}}} {interface vec3 {{interface 0 {{interface 0 {{interface 0 {{method _write vec3_0_0_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_0_0__write_1} {port vec3_0_0_0__write_1} {size 1}}}} {results {}} {enable EN_vec3_0_0_0__write} {ready RDY_vec3_0_0_0__write}} {method _read vec3_0_0_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_0_0_0__read} {size 1}}}} {ready RDY_vec3_0_0_0__read}}}} {interface 1 {{method _write vec3_0_0_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_0_1__write_1} {port vec3_0_0_1__write_1} {size 1}}}} {results {}} {enable EN_vec3_0_0_1__write} {ready RDY_vec3_0_0_1__write}} {method _read vec3_0_0_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_0_0_1__read} {size 1}}}} {ready RDY_vec3_0_0_1__read}}}}}} {interface 1 {{interface 0 {{method _write vec3_0_1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_1_0__write_1} {port vec3_0_1_0__write_1} {size 1}}}} {results {}} {enable EN_vec3_0_1_0__write} {ready RDY_vec3_0_1_0__write}} {method _read vec3_0_1_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_0_1_0__read} {size 1}}}} {ready RDY_vec3_0_1_0__read}}}} {interface 1 {{method _write vec3_0_1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_0_1_1__write_1} {port vec3_0_1_1__write_1} {size 1}}}} {results {}} {enable EN_vec3_0_1_1__write} {ready RDY_vec3_0_1_1__write}} {method _read vec3_0_1_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_0_1_1__read} {size 1}}}} {ready RDY_vec3_0_1_1__read}}}}}}}} {interface 1 {{interface 0 {{interface 0 {{method _write vec3_1_0_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_0_0__write_1} {port vec3_1_0_0__write_1} {size 1}}}} {results {}} {enable EN_vec3_1_0_0__write} {ready RDY_vec3_1_0_0__write}} {method _read vec3_1_0_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_1_0_0__read} {size 1}}}} {ready RDY_vec3_1_0_0__read}}}} {interface 1 {{method _write vec3_1_0_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_0_1__write_1} {port vec3_1_0_1__write_1} {size 1}}}} {results {}} {enable EN_vec3_1_0_1__write} {ready RDY_vec3_1_0_1__write}} {method _read vec3_1_0_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_1_0_1__read} {size 1}}}} {ready RDY_vec3_1_0_1__read}}}}}} {interface 1 {{interface 0 {{method _write vec3_1_1_0__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_1_0__write_1} {port vec3_1_1_0__write_1} {size 1}}}} {results {}} {enable EN_vec3_1_1_0__write} {ready RDY_vec3_1_1_0__write}} {method _read vec3_1_1_0__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_1_1_0__read} {size 1}}}} {ready RDY_vec3_1_1_0__read}}}} {interface 1 {{method _write vec3_1_1_1__write {clock clks1_1} {reset no_reset} {args {{{name vec3_1_1_1__write_1} {port vec3_1_1_1__write_1} {size 1}}}} {results {}} {enable EN_vec3_1_1_1__write} {ready RDY_vec3_1_1_1__write}} {method _read vec3_1_1_1__read {clock no_clock} {reset no_reset} {args {}} {results {{{port vec3_1_1_1__read} {size 1}}}} {ready RDY_vec3_1_1_1__read}}}}}}}}}} {method data1 data1 {clock no_clock} {reset no_reset} {args {}} {results {{{port data1} {size 2}}}} {ready RDY_data1}} {method data2 data2 {clock no_clock} {reset no_reset} {args {}} {results {{{port data2} {size 4}}}} {ready RDY_data2}} {method data3 data3 {clock no_clock} {reset no_reset} {args {}} {results {{{port data3} {size 8}}}} {ready RDY_data3}} {interface clks1 {{interface 0 {{clock {} clks1_0 {osc CLK_clks1_0} {gate CLK_GATE_clks1_0}}}} {interface 1 {{clock {} clks1_1 {osc CLK_clks1_1} {gate CLK_GATE_clks1_1}}}}}} {interface rsts1 {{interface 0 {{reset {} rsts1_0 {port RST_N_rsts1_0} {clock default_clock}}}} {interface 1 {{reset {} rsts1_1 {port RST_N_rsts1_1} {clock default_clock}}}}}} {interface ios1 {{interface 0 {{inout {} ios1_0 {port ios1_0} {clock clks1_1} {reset rsts1_1}}}} {interface 1 {{inout {} ios1_1 {port ios1_1} {clock clks1_1} {reset rsts1_1}}}}}}} args {{inout io {port io} {clock default_clock} {reset default_reset} {size 2}} {clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}} --------- ---------- diff --git a/testsuite/bsc.bluetcl/commands/submodule.tcl.bluetcl-bh-out.expected b/testsuite/bsc.bluetcl/commands/submodule.tcl.bluetcl-bh-out.expected index 6f89b6109..fb719aa49 100644 --- a/testsuite/bsc.bluetcl/commands/submodule.tcl.bluetcl-bh-out.expected +++ b/testsuite/bsc.bluetcl/commands/submodule.tcl.bluetcl-bh-out.expected @@ -11,6 +11,7 @@ Command: submodule ports mkT clock default_clock reset default_reset args {{{port _write_1} {size 1}}} + results {} enable EN__write ready RDY__write method @@ -19,7 +20,7 @@ Command: submodule ports mkT clock default_clock reset default_reset args {} - result _read + results {{{port _read} {size 1}}} ready RDY__read args clock default_clock {osc CLK} @@ -36,6 +37,7 @@ Command: submodule ports mkT clock default_clock reset default_reset args {{{port _write_1} {size 1}}} + results {} enable EN__write ready RDY__write method @@ -44,7 +46,7 @@ Command: submodule ports mkT clock default_clock reset default_reset args {} - result _read + results {{{port _read} {size 1}}} ready RDY__read args clock default_clock {osc CLK} @@ -77,6 +79,7 @@ Command: submodule ports mkT clock clk reset rst args {{{port WVAL} {size 4}}} + results {} enable WSET method wget @@ -84,14 +87,14 @@ Command: submodule ports mkT clock clk reset rst args {} - result WGET + results {{{port WGET} {size 4}}} method whas whas clock clk reset rst args {} - result WHAS + results {{{port WHAS} {size 1}}} inout io_out io_out @@ -122,6 +125,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec1_0__write_1} {size 1}}} + results {} enable EN_vec1_0__write ready RDY_vec1_0__write method @@ -130,7 +134,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec1_0__read + results {{{port vec1_0__read} {size 1}}} ready RDY_vec1_0__read interface 1 @@ -140,6 +144,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec1_1__write_1} {size 1}}} + results {} enable EN_vec1_1__write ready RDY_vec1_1__write method @@ -148,7 +153,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec1_1__read + results {{{port vec1_1__read} {size 1}}} ready RDY_vec1_1__read interface vec2 @@ -162,6 +167,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec2_0_0__write_1} {size 1}}} + results {} enable EN_vec2_0_0__write ready RDY_vec2_0_0__write method @@ -170,7 +176,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec2_0_0__read + results {{{port vec2_0_0__read} {size 1}}} ready RDY_vec2_0_0__read interface 1 @@ -180,6 +186,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec2_0_1__write_1} {size 1}}} + results {} enable EN_vec2_0_1__write ready RDY_vec2_0_1__write method @@ -188,7 +195,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec2_0_1__read + results {{{port vec2_0_1__read} {size 1}}} ready RDY_vec2_0_1__read interface 1 @@ -200,6 +207,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec2_1_0__write_1} {size 1}}} + results {} enable EN_vec2_1_0__write ready RDY_vec2_1_0__write method @@ -208,7 +216,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec2_1_0__read + results {{{port vec2_1_0__read} {size 1}}} ready RDY_vec2_1_0__read interface 1 @@ -218,6 +226,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec2_1_1__write_1} {size 1}}} + results {} enable EN_vec2_1_1__write ready RDY_vec2_1_1__write method @@ -226,7 +235,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec2_1_1__read + results {{{port vec2_1_1__read} {size 1}}} ready RDY_vec2_1_1__read interface vec3 @@ -242,6 +251,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_0_0_0__write_1} {size 1}}} + results {} enable EN_vec3_0_0_0__write ready RDY_vec3_0_0_0__write method @@ -250,7 +260,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_0_0_0__read + results {{{port vec3_0_0_0__read} {size 1}}} ready RDY_vec3_0_0_0__read interface 1 @@ -260,6 +270,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_0_0_1__write_1} {size 1}}} + results {} enable EN_vec3_0_0_1__write ready RDY_vec3_0_0_1__write method @@ -268,7 +279,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_0_0_1__read + results {{{port vec3_0_0_1__read} {size 1}}} ready RDY_vec3_0_0_1__read interface 1 @@ -280,6 +291,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_0_1_0__write_1} {size 1}}} + results {} enable EN_vec3_0_1_0__write ready RDY_vec3_0_1_0__write method @@ -288,7 +300,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_0_1_0__read + results {{{port vec3_0_1_0__read} {size 1}}} ready RDY_vec3_0_1_0__read interface 1 @@ -298,6 +310,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_0_1_1__write_1} {size 1}}} + results {} enable EN_vec3_0_1_1__write ready RDY_vec3_0_1_1__write method @@ -306,7 +319,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_0_1_1__read + results {{{port vec3_0_1_1__read} {size 1}}} ready RDY_vec3_0_1_1__read interface 1 @@ -320,6 +333,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_1_0_0__write_1} {size 1}}} + results {} enable EN_vec3_1_0_0__write ready RDY_vec3_1_0_0__write method @@ -328,7 +342,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_1_0_0__read + results {{{port vec3_1_0_0__read} {size 1}}} ready RDY_vec3_1_0_0__read interface 1 @@ -338,6 +352,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_1_0_1__write_1} {size 1}}} + results {} enable EN_vec3_1_0_1__write ready RDY_vec3_1_0_1__write method @@ -346,7 +361,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_1_0_1__read + results {{{port vec3_1_0_1__read} {size 1}}} ready RDY_vec3_1_0_1__read interface 1 @@ -358,6 +373,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_1_1_0__write_1} {size 1}}} + results {} enable EN_vec3_1_1_0__write ready RDY_vec3_1_1_0__write method @@ -366,7 +382,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_1_1_0__read + results {{{port vec3_1_1_0__read} {size 1}}} ready RDY_vec3_1_1_0__read interface 1 @@ -376,6 +392,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_1_1_1__write_1} {size 1}}} + results {} enable EN_vec3_1_1_1__write ready RDY_vec3_1_1_1__write method @@ -384,7 +401,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_1_1_1__read + results {{{port vec3_1_1_1__read} {size 1}}} ready RDY_vec3_1_1_1__read method data1 @@ -392,7 +409,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result data1 + results {{{port data1} {size 2}}} ready RDY_data1 method data2 @@ -400,7 +417,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result data2 + results {{{port data2} {size 4}}} ready RDY_data2 method data3 @@ -408,7 +425,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result data3 + results {{{port data3} {size 8}}} ready RDY_data3 interface clks1 @@ -458,6 +475,7 @@ Command: submodule ports mkM clock _clk__1 reset _rst__1 args {{{port D_IN} {size 1}}} + results {} enable EN method _read @@ -465,7 +483,7 @@ Command: submodule ports mkM clock _clk__1 reset _rst__1 args {} - result Q_OUT + results {{{port Q_OUT} {size 1}}} args clock _clk__1 {osc CLK} reset _rst__1 {port RST} {clock _clk__1} @@ -480,6 +498,7 @@ Command: submodule ports mkM clock _clk__1 reset _rst__1 args {{{port D_IN} {size 1}}} + results {} enable EN method _read @@ -487,7 +506,7 @@ Command: submodule ports mkM clock _clk__1 reset _rst__1 args {} - result Q_OUT + results {{{port Q_OUT} {size 1}}} args clock _clk__1 {osc CLK} reset _rst__1 {port RST} {clock _clk__1} @@ -502,6 +521,7 @@ Command: submodule ports mkM clock _clk__1 reset _rst__1 args {{{port D_IN} {size 1}}} + results {} enable EN method _read @@ -509,7 +529,7 @@ Command: submodule ports mkM clock _clk__1 reset _rst__1 args {} - result Q_OUT + results {{{port Q_OUT} {size 1}}} args clock _clk__1 {osc CLK} reset _rst__1 {port RST} {clock _clk__1} diff --git a/testsuite/bsc.bluetcl/commands/submodule.tcl.bluetcl-out.expected b/testsuite/bsc.bluetcl/commands/submodule.tcl.bluetcl-out.expected index aaf292aaf..926e03cde 100644 --- a/testsuite/bsc.bluetcl/commands/submodule.tcl.bluetcl-out.expected +++ b/testsuite/bsc.bluetcl/commands/submodule.tcl.bluetcl-out.expected @@ -11,6 +11,7 @@ Command: submodule ports mkT clock default_clock reset default_reset args {{{port _write_1} {size 1}}} + results {} enable EN__write ready RDY__write method @@ -19,7 +20,7 @@ Command: submodule ports mkT clock default_clock reset default_reset args {} - result _read + results {{{port _read} {size 1}}} ready RDY__read args clock default_clock {osc CLK} @@ -36,6 +37,7 @@ Command: submodule ports mkT clock default_clock reset default_reset args {{{port _write_1} {size 1}}} + results {} enable EN__write ready RDY__write method @@ -44,7 +46,7 @@ Command: submodule ports mkT clock default_clock reset default_reset args {} - result _read + results {{{port _read} {size 1}}} ready RDY__read args clock default_clock {osc CLK} @@ -77,6 +79,7 @@ Command: submodule ports mkT clock clk reset rst args {{{port WVAL} {size 4}}} + results {} enable WSET method wget @@ -84,14 +87,14 @@ Command: submodule ports mkT clock clk reset rst args {} - result WGET + results {{{port WGET} {size 4}}} method whas whas clock clk reset rst args {} - result WHAS + results {{{port WHAS} {size 1}}} inout io_out io_out @@ -122,6 +125,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec1_0__write_1} {size 1}}} + results {} enable EN_vec1_0__write ready RDY_vec1_0__write method @@ -130,7 +134,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec1_0__read + results {{{port vec1_0__read} {size 1}}} ready RDY_vec1_0__read interface 1 @@ -140,6 +144,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec1_1__write_1} {size 1}}} + results {} enable EN_vec1_1__write ready RDY_vec1_1__write method @@ -148,7 +153,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec1_1__read + results {{{port vec1_1__read} {size 1}}} ready RDY_vec1_1__read interface vec2 @@ -162,6 +167,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec2_0_0__write_1} {size 1}}} + results {} enable EN_vec2_0_0__write ready RDY_vec2_0_0__write method @@ -170,7 +176,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec2_0_0__read + results {{{port vec2_0_0__read} {size 1}}} ready RDY_vec2_0_0__read interface 1 @@ -180,6 +186,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec2_0_1__write_1} {size 1}}} + results {} enable EN_vec2_0_1__write ready RDY_vec2_0_1__write method @@ -188,7 +195,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec2_0_1__read + results {{{port vec2_0_1__read} {size 1}}} ready RDY_vec2_0_1__read interface 1 @@ -200,6 +207,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec2_1_0__write_1} {size 1}}} + results {} enable EN_vec2_1_0__write ready RDY_vec2_1_0__write method @@ -208,7 +216,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec2_1_0__read + results {{{port vec2_1_0__read} {size 1}}} ready RDY_vec2_1_0__read interface 1 @@ -218,6 +226,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec2_1_1__write_1} {size 1}}} + results {} enable EN_vec2_1_1__write ready RDY_vec2_1_1__write method @@ -226,7 +235,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec2_1_1__read + results {{{port vec2_1_1__read} {size 1}}} ready RDY_vec2_1_1__read interface vec3 @@ -242,6 +251,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_0_0_0__write_1} {size 1}}} + results {} enable EN_vec3_0_0_0__write ready RDY_vec3_0_0_0__write method @@ -250,7 +260,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_0_0_0__read + results {{{port vec3_0_0_0__read} {size 1}}} ready RDY_vec3_0_0_0__read interface 1 @@ -260,6 +270,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_0_0_1__write_1} {size 1}}} + results {} enable EN_vec3_0_0_1__write ready RDY_vec3_0_0_1__write method @@ -268,7 +279,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_0_0_1__read + results {{{port vec3_0_0_1__read} {size 1}}} ready RDY_vec3_0_0_1__read interface 1 @@ -280,6 +291,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_0_1_0__write_1} {size 1}}} + results {} enable EN_vec3_0_1_0__write ready RDY_vec3_0_1_0__write method @@ -288,7 +300,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_0_1_0__read + results {{{port vec3_0_1_0__read} {size 1}}} ready RDY_vec3_0_1_0__read interface 1 @@ -298,6 +310,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_0_1_1__write_1} {size 1}}} + results {} enable EN_vec3_0_1_1__write ready RDY_vec3_0_1_1__write method @@ -306,7 +319,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_0_1_1__read + results {{{port vec3_0_1_1__read} {size 1}}} ready RDY_vec3_0_1_1__read interface 1 @@ -320,6 +333,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_1_0_0__write_1} {size 1}}} + results {} enable EN_vec3_1_0_0__write ready RDY_vec3_1_0_0__write method @@ -328,7 +342,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_1_0_0__read + results {{{port vec3_1_0_0__read} {size 1}}} ready RDY_vec3_1_0_0__read interface 1 @@ -338,6 +352,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_1_0_1__write_1} {size 1}}} + results {} enable EN_vec3_1_0_1__write ready RDY_vec3_1_0_1__write method @@ -346,7 +361,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_1_0_1__read + results {{{port vec3_1_0_1__read} {size 1}}} ready RDY_vec3_1_0_1__read interface 1 @@ -358,6 +373,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_1_1_0__write_1} {size 1}}} + results {} enable EN_vec3_1_1_0__write ready RDY_vec3_1_1_0__write method @@ -366,7 +382,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_1_1_0__read + results {{{port vec3_1_1_0__read} {size 1}}} ready RDY_vec3_1_1_0__read interface 1 @@ -376,6 +392,7 @@ Command: submodule ports mkT clock clks1_1 reset no_reset args {{{port vec3_1_1_1__write_1} {size 1}}} + results {} enable EN_vec3_1_1_1__write ready RDY_vec3_1_1_1__write method @@ -384,7 +401,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result vec3_1_1_1__read + results {{{port vec3_1_1_1__read} {size 1}}} ready RDY_vec3_1_1_1__read method data1 @@ -392,7 +409,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result data1 + results {{{port data1} {size 2}}} ready RDY_data1 method data2 @@ -400,7 +417,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result data2 + results {{{port data2} {size 4}}} ready RDY_data2 method data3 @@ -408,7 +425,7 @@ Command: submodule ports mkT clock no_clock reset no_reset args {} - result data3 + results {{{port data3} {size 8}}} ready RDY_data3 interface clks1 @@ -458,6 +475,7 @@ Command: submodule ports mkM clock _clk__1 reset _rst__1 args {{{port D_IN} {size 1}}} + results {} enable EN method _read @@ -465,7 +483,7 @@ Command: submodule ports mkM clock _clk__1 reset _rst__1 args {} - result Q_OUT + results {{{port Q_OUT} {size 1}}} args clock _clk__1 {osc CLK} reset _rst__1 {port RST} {clock _clk__1} @@ -480,6 +498,7 @@ Command: submodule ports mkM clock _clk__1 reset _rst__1 args {{{port D_IN} {size 1}}} + results {} enable EN method _read @@ -487,7 +506,7 @@ Command: submodule ports mkM clock _clk__1 reset _rst__1 args {} - result Q_OUT + results {{{port Q_OUT} {size 1}}} args clock _clk__1 {osc CLK} reset _rst__1 {port RST} {clock _clk__1} @@ -502,6 +521,7 @@ Command: submodule ports mkM clock _clk__1 reset _rst__1 args {{{port D_IN} {size 1}}} + results {} enable EN method _read @@ -509,7 +529,7 @@ Command: submodule ports mkM clock _clk__1 reset _rst__1 args {} - result Q_OUT + results {{{port Q_OUT} {size 1}}} args clock _clk__1 {osc CLK} reset _rst__1 {port RST} {clock _clk__1} diff --git a/testsuite/bsc.bluetcl/targeted/port_types/SplitPortTypes.bs b/testsuite/bsc.bluetcl/targeted/port_types/SplitPortTypes.bs new file mode 100644 index 000000000..5fec7e02f --- /dev/null +++ b/testsuite/bsc.bluetcl/targeted/port_types/SplitPortTypes.bs @@ -0,0 +1,60 @@ +package SplitPortTypes where + +-- Test that port types are reported correctly all the way through to Bluetcl +-- ("module porttypes" / "module ports") when a method's arguments and/or +-- result are split into multiple input/output ports (deep and shallow). + +import SplitPorts + +struct Inner = + a :: Bool + b :: Int 16 + deriving (Bits) + +struct Outer = + x :: UInt 8 + y :: Inner + z :: Bit 4 + deriving (Bits) + +interface SplitPortTypes = + -- ---- split OUTPUT ports ---- + -- value method, result deep-split: one port per leaf field + -- (x :: UInt 8, y.a :: Bool, y.b :: Int 16, z :: Bit 4) + getDeep :: DeepSplit Outer + -- value method, result shallow-split: Inner stays packed + -- (x :: UInt 8, y :: Inner, z :: Bit 4) + getShallow :: ShallowSplit Outer + -- ActionValue method whose value is deep-split into multiple output ports + nextDeep :: ActionValue (DeepSplit Outer) + + -- ---- split INPUT ports ---- + -- one argument deep-split into multiple input ports + putDeep :: DeepSplit Outer -> Action + -- one argument shallow-split into input ports (Inner stays packed) + putShallow :: ShallowSplit Outer -> Action + -- two deep-split arguments, named via the arg_names pragma + combineDeep :: DeepSplit Outer -> DeepSplit Outer -> Action + {-# arg_names = ["lhs", "rhs"] #-} + + -- ---- split INPUT and OUTPUT together ---- + -- value method whose argument and result are both deep-split + transform :: DeepSplit Outer -> DeepSplit Outer + +{-# synthesize mkSplitPortTypes #-} +mkSplitPortTypes :: Module SplitPortTypes +mkSplitPortTypes = + module + r :: Reg (UInt 8) <- mkReg 0 + let mkOuter v = Outer { x = v; y = Inner { a = v == 0; b = 7 }; z = 3 } + interface + getDeep = DeepSplit (mkOuter r) + getShallow = ShallowSplit (mkOuter r) + nextDeep = do + r := r + 1 + return (DeepSplit (mkOuter r)) + putDeep (DeepSplit o) = r := o.x + putShallow (ShallowSplit o) = r := o.x + combineDeep (DeepSplit lhs) (DeepSplit rhs) = r := lhs.x + rhs.x + transform (DeepSplit o) = + DeepSplit (Outer { x = o.x + 1; y = o.y; z = o.z }) diff --git a/testsuite/bsc.bluetcl/targeted/port_types/inhigh.tcl.bluetcl-bh-out.expected b/testsuite/bsc.bluetcl/targeted/port_types/inhigh.tcl.bluetcl-bh-out.expected index f7972c0b8..dadadf149 100644 --- a/testsuite/bsc.bluetcl/targeted/port_types/inhigh.tcl.bluetcl-bh-out.expected +++ b/testsuite/bsc.bluetcl/targeted/port_types/inhigh.tcl.bluetcl-bh-out.expected @@ -1,11 +1,11 @@ -verilog mkInhighEnable_Sub sysInhighEnable ---------- -{rg1 MOD {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {{{port Q_IN} {size 1}}}}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {result D_OUT}}}} {args {{reset _rst__1 {port RST} {clock _clk__1}} {clock _clk__1 {osc CLK} {gate CLK_GATE}}}}} {rg2 mkInhighEnable_Sub {interface {{method _write _write {clock default_clock} {reset no_reset} {args {{{port _write_1} {size 1}}}}} {method _read _read {clock default_clock} {reset no_reset} {args {}} {result _read}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}}} +{rg1 MOD {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {{{port Q_IN} {size 1}}}} {results {}}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {results {{{port D_OUT} {size 1}}}}}}} {args {{reset _rst__1 {port RST} {clock _clk__1}} {clock _clk__1 {osc CLK} {gate CLK_GATE}}}}} {rg2 mkInhighEnable_Sub {interface {{method _write _write {clock default_clock} {reset no_reset} {args {{{port _write_1} {size 1}}}} {results {}}} {method _read _read {clock default_clock} {reset no_reset} {args {}} {results {{{port _read} {size 1}}}}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}}} {rg1 MOD {ports {{RST Prelude.Reset} {CLK Prelude.Clock} {CLK_GATE Prelude.Bool} {Q_IN Prelude.Bool} {D_OUT Prelude.Bool}}}} {rg2 mkInhighEnable_Sub {ports {{CLK Prelude.Clock} {RST_N Prelude.Reset} {_write_1 Prelude.Bool} {_read Prelude.Bool}}}} ---------- -{interface {{method _write _write {clock default_clock} {reset no_reset} {args {{{name _write_1} {port _write_1} {size 1}}}}} {method _read _read {clock default_clock} {reset no_reset} {args {}} {result _read}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}} +{interface {{method _write _write {clock default_clock} {reset no_reset} {args {{{name _write_1} {port _write_1} {size 1}}}} {results {}}} {method _read _read {clock default_clock} {reset no_reset} {args {}} {results {{{port _read} {size 1}}}}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}} {CLK Prelude.Clock} {RST_N Prelude.Reset} {_write_1 Prelude.Bool} {_read Prelude.Bool} ---------- diff --git a/testsuite/bsc.bluetcl/targeted/port_types/inhigh.tcl.bluetcl-out.expected b/testsuite/bsc.bluetcl/targeted/port_types/inhigh.tcl.bluetcl-out.expected index 1bf3c6e11..127dc8996 100644 --- a/testsuite/bsc.bluetcl/targeted/port_types/inhigh.tcl.bluetcl-out.expected +++ b/testsuite/bsc.bluetcl/targeted/port_types/inhigh.tcl.bluetcl-out.expected @@ -1,11 +1,11 @@ -verilog mkInhighEnable_Sub sysInhighEnable ---------- -{rg1 MOD {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {{{port Q_IN} {size 1}}}}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {result D_OUT}}}} {args {{reset _rst__1 {port RST} {clock _clk__1}} {clock _clk__1 {osc CLK} {gate CLK_GATE}}}}} {rg2 mkInhighEnable_Sub {interface {{method _write _write {clock default_clock} {reset no_reset} {args {{{port _write_1} {size 1}}}}} {method _read _read {clock default_clock} {reset no_reset} {args {}} {result _read}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}}} +{rg1 MOD {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {{{port Q_IN} {size 1}}}} {results {}}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {results {{{port D_OUT} {size 1}}}}}}} {args {{reset _rst__1 {port RST} {clock _clk__1}} {clock _clk__1 {osc CLK} {gate CLK_GATE}}}}} {rg2 mkInhighEnable_Sub {interface {{method _write _write {clock default_clock} {reset no_reset} {args {{{port _write_1} {size 1}}}} {results {}}} {method _read _read {clock default_clock} {reset no_reset} {args {}} {results {{{port _read} {size 1}}}}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}}} {rg1 MOD {ports {{RST Reset} {CLK Clock} {CLK_GATE Bool} {Q_IN Bool} {D_OUT Bool}}}} {rg2 mkInhighEnable_Sub {ports {{CLK Clock} {RST_N Reset} {_write_1 Bool} {_read Bool}}}} ---------- -{interface {{method _write _write {clock default_clock} {reset no_reset} {args {{{name _write_1} {port _write_1} {size 1}}}}} {method _read _read {clock default_clock} {reset no_reset} {args {}} {result _read}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}} +{interface {{method _write _write {clock default_clock} {reset no_reset} {args {{{name _write_1} {port _write_1} {size 1}}}} {results {}}} {method _read _read {clock default_clock} {reset no_reset} {args {}} {results {{{port _read} {size 1}}}}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}} {CLK Clock} {RST_N Reset} {_write_1 Bool} {_read Bool} ---------- diff --git a/testsuite/bsc.bluetcl/targeted/port_types/port_types.exp b/testsuite/bsc.bluetcl/targeted/port_types/port_types.exp index 2781faf0b..0b029117c 100644 --- a/testsuite/bsc.bluetcl/targeted/port_types/port_types.exp +++ b/testsuite/bsc.bluetcl/targeted/port_types/port_types.exp @@ -19,3 +19,11 @@ bsc_compile Prims.bsv {-verilog -elab} bluetcl_run_compare_pass prims.tcl "" "" # --------------- +# Test that port types are reported correctly for methods whose arguments +# and/or result are split into multiple input/output ports (deep/shallow, +# value and ActionValue) + +bsc_compile SplitPortTypes.bs {-verilog -elab} +bluetcl_run_compare_pass split_port_types.tcl + +# --------------- diff --git a/testsuite/bsc.bluetcl/targeted/port_types/prims.tcl.bluetcl-bh-out.expected b/testsuite/bsc.bluetcl/targeted/port_types/prims.tcl.bluetcl-bh-out.expected index 547da936a..59b75dd63 100644 --- a/testsuite/bsc.bluetcl/targeted/port_types/prims.tcl.bluetcl-bh-out.expected +++ b/testsuite/bsc.bluetcl/targeted/port_types/prims.tcl.bluetcl-bh-out.expected @@ -1,75 +1,75 @@ -verilog sysPrims ---------- -rg RegN {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable EN}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {result Q_OUT}}}} {args {{clock _clk__1 {osc CLK}} {reset _rst__1 {port RST} {clock _clk__1}} {parameter width {param width}} {parameter init {param init}}}} +rg RegN {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable EN}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {results {{{port Q_OUT} {size 32}}}}}}} {args {{clock _clk__1 {osc CLK}} {reset _rst__1 {port RST} {clock _clk__1}} {parameter width {param width}} {parameter init {param init}}}} rg RegN {ports {{CLK Prelude.Clock} {RST Prelude.Reset} {D_IN {Prelude.Int 32}} {EN Prelude.Bool} {Q_OUT {Prelude.Int 32}}}} ---------- -rgA RegA {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable EN}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {result Q_OUT}}}} {args {{clock _clk__1 {osc CLK}} {reset _rst__1 {port RST} {clock _clk__1}} {parameter width {param width}} {parameter init {param init}}}} +rgA RegA {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable EN}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {results {{{port Q_OUT} {size 32}}}}}}} {args {{clock _clk__1 {osc CLK}} {reset _rst__1 {port RST} {clock _clk__1}} {parameter width {param width}} {parameter init {param init}}}} rgA RegA {ports {{CLK Prelude.Clock} {RST Prelude.Reset} {D_IN {Prelude.Int 32}} {EN Prelude.Bool} {Q_OUT {Prelude.Int 32}}}} ---------- -rgU RegUN {interface {{method _write _write {clock _clk__1} {reset no_reset} {args {{{port D_IN} {size 32}}}} {enable EN}} {method _read _read {clock _clk__1} {reset no_reset} {args {}} {result Q_OUT}}}} {args {{clock _clk__1 {osc CLK}} {parameter width {param width}}}} +rgU RegUN {interface {{method _write _write {clock _clk__1} {reset no_reset} {args {{{port D_IN} {size 32}}}} {results {}} {enable EN}} {method _read _read {clock _clk__1} {reset no_reset} {args {}} {results {{{port Q_OUT} {size 32}}}}}}} {args {{clock _clk__1 {osc CLK}} {parameter width {param width}}}} rgU RegUN {ports {{CLK Prelude.Clock} {D_IN {Prelude.Int 32}} {EN Prelude.Bool} {Q_OUT {Prelude.Int 32}}}} ---------- -rw RWire {interface {{method wset wset {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {enable WSET}} {method wget wget {clock clk} {reset rst} {args {}} {result WGET} {ready WHAS}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} +rw RWire {interface {{method wset wset {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {results {}} {enable WSET}} {method wget wget {clock clk} {reset rst} {args {}} {results {{{port WGET} {size 32}}}} {ready WHAS}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} rw RWire {ports {{WVAL {Prelude.Int 32}} {WSET Prelude.Bool} {WGET {Prelude.Int 32}} {WHAS Prelude.Bool}}} ---------- -rw0 RWire0 {interface {{method wset wset {clock clk} {reset rst} {args {}} {enable WSET}} {method wget wget {clock clk} {reset rst} {args {}} {ready WHAS}}}} {args {{clock clk} {reset rst {clock clk}}}} +rw0 RWire0 {interface {{method wset wset {clock clk} {reset rst} {args {}} {results {}} {enable WSET}} {method wget wget {clock clk} {reset rst} {args {}} {results {}} {ready WHAS}}}} {args {{clock clk} {reset rst {clock clk}}}} rw0 RWire0 {ports {{WSET Prelude.Bool} {WHAS Prelude.Bool}}} ---------- -w RWire {interface {{method _write _write {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {result WGET} {ready WHAS}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} +w RWire {interface {{method _write _write {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {results {}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {results {{{port WGET} {size 32}}}} {ready WHAS}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} w RWire {ports {{WVAL {Prelude.Int 32}} {WSET Prelude.Bool} {WGET {Prelude.Int 32}} {WHAS Prelude.Bool}}} ---------- -dw RWire {interface {{method _write _write {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {result WGET} {ready WHAS}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} +dw RWire {interface {{method _write _write {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {results {}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {results {{{port WGET} {size 32}}}} {ready WHAS}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} dw RWire {ports {{WVAL {Prelude.Int 32}} {WSET Prelude.Bool} {WGET {Prelude.Int 32}} {WHAS Prelude.Bool}}} ---------- -bw BypassWire {interface {{method _write _write {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}}} {method _read _read {clock clk} {reset rst} {args {}} {result WGET}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} +bw BypassWire {interface {{method _write _write {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {results {}}} {method _read _read {clock clk} {reset rst} {args {}} {results {{{port WGET} {size 32}}}}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} bw BypassWire {ports {{WVAL {Prelude.Int 32}} {WGET {Prelude.Int 32}}}} ---------- -pw RWire0 {interface {{method send send {clock clk} {reset rst} {args {}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {result WHAS}}}} {args {{clock clk} {reset rst {clock clk}}}} +pw RWire0 {interface {{method send send {clock clk} {reset rst} {args {}} {results {}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {results {{{port WHAS} {size 1}}}}}}} {args {{clock clk} {reset rst {clock clk}}}} pw RWire0 {ports {{WSET Prelude.Bool} {WHAS Prelude.Bool}}} ---------- -pwo RWire0 {interface {{method send send {clock clk} {reset rst} {args {}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {result WHAS}}}} {args {{clock clk} {reset rst {clock clk}}}} +pwo RWire0 {interface {{method send send {clock clk} {reset rst} {args {}} {results {}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {results {{{port WHAS} {size 1}}}}}}} {args {{clock clk} {reset rst {clock clk}}}} pwo RWire0 {ports {{WSET Prelude.Bool} {WHAS Prelude.Bool}}} ---------- -rf RegFile {interface {{method upd upd {clock _clk__1} {reset no_reset} {args {{{port ADDR_IN} {size 2}} {{port D_IN} {size 32}}}} {enable WE}} {method sub_1 sub_1 {clock _clk__1} {reset no_reset} {args {{{port ADDR_1} {size 2}}}} {result D_OUT_1}} {method sub_2 sub_2 {clock _clk__1} {reset no_reset} {args {{{port ADDR_2} {size 2}}}} {result D_OUT_2}} {method sub_3 sub_3 {clock _clk__1} {reset no_reset} {args {{{port ADDR_3} {size 2}}}} {result D_OUT_3}} {method sub_4 sub_4 {clock _clk__1} {reset no_reset} {args {{{port ADDR_4} {size 2}}}} {result D_OUT_4}} {method sub_5 sub_5 {clock _clk__1} {reset no_reset} {args {{{port ADDR_5} {size 2}}}} {result D_OUT_5}}}} {args {{clock _clk__1 {osc CLK}} {parameter addr_width {param addr_width}} {parameter data_width {param data_width}} {parameter lo {param lo}} {parameter hi {param hi}}}} +rf RegFile {interface {{method upd upd {clock _clk__1} {reset no_reset} {args {{{port ADDR_IN} {size 2}} {{port D_IN} {size 32}}}} {results {}} {enable WE}} {method sub_1 sub_1 {clock _clk__1} {reset no_reset} {args {{{port ADDR_1} {size 2}}}} {results {{{port D_OUT_1} {size 32}}}}} {method sub_2 sub_2 {clock _clk__1} {reset no_reset} {args {{{port ADDR_2} {size 2}}}} {results {{{port D_OUT_2} {size 32}}}}} {method sub_3 sub_3 {clock _clk__1} {reset no_reset} {args {{{port ADDR_3} {size 2}}}} {results {{{port D_OUT_3} {size 32}}}}} {method sub_4 sub_4 {clock _clk__1} {reset no_reset} {args {{{port ADDR_4} {size 2}}}} {results {{{port D_OUT_4} {size 32}}}}} {method sub_5 sub_5 {clock _clk__1} {reset no_reset} {args {{{port ADDR_5} {size 2}}}} {results {{{port D_OUT_5} {size 32}}}}}}} {args {{clock _clk__1 {osc CLK}} {parameter addr_width {param addr_width}} {parameter data_width {param data_width}} {parameter lo {param lo}} {parameter hi {param hi}}}} rf RegFile {ports {{CLK Prelude.Clock} {ADDR_IN {Prelude.Bit 2}} {D_IN {Prelude.Int 32}} {WE Prelude.Bool} {ADDR_1 {Prelude.Bit 2}} {D_OUT_1 {Prelude.Int 32}} {ADDR_2 {Prelude.Bit 2}} {D_OUT_2 {Prelude.Int 32}} {ADDR_3 {Prelude.Bit 2}} {D_OUT_3 {Prelude.Int 32}} {ADDR_4 {Prelude.Bit 2}} {D_OUT_4 {Prelude.Int 32}} {ADDR_5 {Prelude.Bit 2}} {D_OUT_5 {Prelude.Int 32}}}} ---------- -ff1 FIFO2 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {result D_OUT} {ready EMPTY_N}} {method notFull notFull {clock clk} {reset _rst__1} {args {}} {result FULL_N}} {method notEmpty notEmpty {clock clk} {reset _rst__1} {args {}} {result EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}} {parameter guarded {param guarded}}}} +ff1 FIFO2 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {{{port D_OUT} {size 32}}}} {ready EMPTY_N}} {method notFull notFull {clock clk} {reset _rst__1} {args {}} {results {{{port FULL_N} {size 1}}}}} {method notEmpty notEmpty {clock clk} {reset _rst__1} {args {}} {results {{{port EMPTY_N} {size 1}}}}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}} {parameter guarded {param guarded}}}} ff1 FIFO2 {ports {{RST Prelude.Reset} {CLK Prelude.Clock} {D_IN {Prelude.Int 32}} {ENQ Prelude.Bool} {FULL_N Prelude.Bool} {DEQ Prelude.Bool} {EMPTY_N Prelude.Bool} {D_OUT {Prelude.Int 32}} {CLR Prelude.Bool}}} ---------- -f1 FIFO1 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {result D_OUT} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}} {parameter guarded {param guarded}}}} +f1 FIFO1 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {{{port D_OUT} {size 32}}}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}} {parameter guarded {param guarded}}}} f1 FIFO1 {ports {{RST Prelude.Reset} {CLK Prelude.Clock} {D_IN {Prelude.Int 32}} {ENQ Prelude.Bool} {FULL_N Prelude.Bool} {DEQ Prelude.Bool} {EMPTY_N Prelude.Bool} {D_OUT {Prelude.Int 32}} {CLR Prelude.Bool}}} ---------- -f10 FIFO10 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter guarded {param guarded}}}} +f10 FIFO10 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter guarded {param guarded}}}} f10 FIFO10 {ports {{RST Prelude.Reset} {CLK Prelude.Clock} {ENQ Prelude.Bool} {FULL_N Prelude.Bool} {DEQ Prelude.Bool} {EMPTY_N Prelude.Bool} {CLR Prelude.Bool}}} ---------- -f2 FIFO2 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {result D_OUT} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}} {parameter guarded {param guarded}}}} +f2 FIFO2 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {{{port D_OUT} {size 32}}}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}} {parameter guarded {param guarded}}}} f2 FIFO2 {ports {{RST Prelude.Reset} {CLK Prelude.Clock} {D_IN {Prelude.Int 32}} {ENQ Prelude.Bool} {FULL_N Prelude.Bool} {DEQ Prelude.Bool} {EMPTY_N Prelude.Bool} {D_OUT {Prelude.Int 32}} {CLR Prelude.Bool}}} ---------- -f20 FIFO20 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter guarded {param guarded}}}} +f20 FIFO20 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter guarded {param guarded}}}} f20 FIFO20 {ports {{RST Prelude.Reset} {CLK Prelude.Clock} {ENQ Prelude.Bool} {FULL_N Prelude.Bool} {DEQ Prelude.Bool} {EMPTY_N Prelude.Bool} {CLR Prelude.Bool}}} ---------- -fs SizedFIFO {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {result D_OUT} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter p1width {param p1width}} {parameter p2depth {param p2depth}} {parameter p3cntr_width {param p3cntr_width}} {parameter guarded {param guarded}}}} +fs SizedFIFO {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {{{port D_OUT} {size 32}}}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter p1width {param p1width}} {parameter p2depth {param p2depth}} {parameter p3cntr_width {param p3cntr_width}} {parameter guarded {param guarded}}}} fs SizedFIFO {ports {{RST Prelude.Reset} {CLK Prelude.Clock} {D_IN {Prelude.Int 32}} {ENQ Prelude.Bool} {FULL_N Prelude.Bool} {DEQ Prelude.Bool} {EMPTY_N Prelude.Bool} {D_OUT {Prelude.Int 32}} {CLR Prelude.Bool}}} ---------- -fs0 SizedFIFO0 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter p1depth {param p1depth}} {parameter p2cntr_width {param p2cntr_width}} {parameter guarded {param guarded}}}} +fs0 SizedFIFO0 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter p1depth {param p1depth}} {parameter p2cntr_width {param p2cntr_width}} {parameter guarded {param guarded}}}} fs0 SizedFIFO0 {ports {{RST Prelude.Reset} {CLK Prelude.Clock} {ENQ Prelude.Bool} {FULL_N Prelude.Bool} {DEQ Prelude.Bool} {EMPTY_N Prelude.Bool} {CLR Prelude.Bool}}} ---------- -fL1 FIFOL1 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {result D_OUT} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}}}} +fL1 FIFOL1 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {{{port D_OUT} {size 32}}}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}}}} fL1 FIFOL1 {ports {{RST Prelude.Reset} {CLK Prelude.Clock} {D_IN {Prelude.Int 32}} {ENQ Prelude.Bool} {FULL_N Prelude.Bool} {DEQ Prelude.Bool} {EMPTY_N Prelude.Bool} {D_OUT {Prelude.Int 32}} {CLR Prelude.Bool}}} ---------- -fL10 FIFO20 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter guarded {param guarded}}}} +fL10 FIFO20 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter guarded {param guarded}}}} fL10 FIFO20 {ports {{RST Prelude.Reset} {CLK Prelude.Clock} {ENQ Prelude.Bool} {FULL_N Prelude.Bool} {DEQ Prelude.Bool} {EMPTY_N Prelude.Bool} {CLR Prelude.Bool}}} ---------- dclk ClockGen {interface {{clock gen_clk gen_clk {osc CLK_OUT}}}} {args {{parameter v1Width {param v1Width}} {parameter v2Width {param v2Width}} {parameter initDelay {param initDelay}} {parameter initValue {param initValue}} {parameter otherValue {param otherValue}}}} dclk ClockGen {ports {{CLK_OUT Prelude.Clock}}} ---------- -sr SyncRegister {interface {{method _write _write {clock clk_src} {reset sRstIn} {args {{{port sD_IN} {size 32}}}} {enable sEN} {ready sRDY}} {method _read _read {clock clk_dst} {reset no_reset} {args {}} {result dD_OUT}}}} {args {{parameter width {param width}} {parameter init {param init}} {clock clk_src {osc sCLK}} {clock clk_dst {osc dCLK}} {reset sRstIn {port sRST} {clock clk_src}}}} +sr SyncRegister {interface {{method _write _write {clock clk_src} {reset sRstIn} {args {{{port sD_IN} {size 32}}}} {results {}} {enable sEN} {ready sRDY}} {method _read _read {clock clk_dst} {reset no_reset} {args {}} {results {{{port dD_OUT} {size 32}}}}}}} {args {{parameter width {param width}} {parameter init {param init}} {clock clk_src {osc sCLK}} {clock clk_dst {osc dCLK}} {reset sRstIn {port sRST} {clock clk_src}}}} sr SyncRegister {ports {{sCLK Prelude.Clock} {dCLK Prelude.Clock} {sRST Prelude.Reset} {sD_IN {Prelude.Int 32}} {sEN Prelude.Bool} {sRDY Prelude.Bool} {dD_OUT {Prelude.Int 32}}}} ---------- -bcw CrossingBypassWire {interface {{method wset wset {clock clk} {reset no_reset} {args {{{port WVAL} {size 32}}}}} {method wget wget {clock dstClk} {reset no_reset} {args {}} {result WGET}}}} {args {{parameter width {param width}} {clock clk {osc CLK}} {clock dstClk}}} +bcw CrossingBypassWire {interface {{method wset wset {clock clk} {reset no_reset} {args {{{port WVAL} {size 32}}}} {results {}}} {method wget wget {clock dstClk} {reset no_reset} {args {}} {results {{{port WGET} {size 32}}}}}}} {args {{parameter width {param width}} {clock clk {osc CLK}} {clock dstClk}}} bcw CrossingBypassWire {ports {{CLK Prelude.Clock} {WVAL {Prelude.Int 32}} {WGET {Prelude.Int 32}}}} ---------- -ncw CrossingBypassWire {interface {{method wset wset {clock clk} {reset no_reset} {args {{{port WVAL} {size 32}}}}} {method wget wget {clock dstClk} {reset no_reset} {args {}} {result WGET}}}} {args {{parameter width {param width}} {clock clk {osc CLK}} {clock dstClk}}} +ncw CrossingBypassWire {interface {{method wset wset {clock clk} {reset no_reset} {args {{{port WVAL} {size 32}}}} {results {}}} {method wget wget {clock dstClk} {reset no_reset} {args {}} {results {{{port WGET} {size 32}}}}}}} {args {{parameter width {param width}} {clock clk {osc CLK}} {clock dstClk}}} ncw CrossingBypassWire {ports {{CLK Prelude.Clock} {WVAL {Prelude.Int 32}} {WGET {Prelude.Int 32}}}} ---------- diff --git a/testsuite/bsc.bluetcl/targeted/port_types/prims.tcl.bluetcl-out.expected b/testsuite/bsc.bluetcl/targeted/port_types/prims.tcl.bluetcl-out.expected index 56f80bdcd..d1099dcef 100644 --- a/testsuite/bsc.bluetcl/targeted/port_types/prims.tcl.bluetcl-out.expected +++ b/testsuite/bsc.bluetcl/targeted/port_types/prims.tcl.bluetcl-out.expected @@ -1,75 +1,75 @@ -verilog sysPrims ---------- -rg RegN {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable EN}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {result Q_OUT}}}} {args {{clock _clk__1 {osc CLK}} {reset _rst__1 {port RST} {clock _clk__1}} {parameter width {param width}} {parameter init {param init}}}} +rg RegN {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable EN}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {results {{{port Q_OUT} {size 32}}}}}}} {args {{clock _clk__1 {osc CLK}} {reset _rst__1 {port RST} {clock _clk__1}} {parameter width {param width}} {parameter init {param init}}}} rg RegN {ports {{CLK Clock} {RST Reset} {D_IN Int#(32)} {EN Bool} {Q_OUT Int#(32)}}} ---------- -rgA RegA {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable EN}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {result Q_OUT}}}} {args {{clock _clk__1 {osc CLK}} {reset _rst__1 {port RST} {clock _clk__1}} {parameter width {param width}} {parameter init {param init}}}} +rgA RegA {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable EN}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {results {{{port Q_OUT} {size 32}}}}}}} {args {{clock _clk__1 {osc CLK}} {reset _rst__1 {port RST} {clock _clk__1}} {parameter width {param width}} {parameter init {param init}}}} rgA RegA {ports {{CLK Clock} {RST Reset} {D_IN Int#(32)} {EN Bool} {Q_OUT Int#(32)}}} ---------- -rgU RegUN {interface {{method _write _write {clock _clk__1} {reset no_reset} {args {{{port D_IN} {size 32}}}} {enable EN}} {method _read _read {clock _clk__1} {reset no_reset} {args {}} {result Q_OUT}}}} {args {{clock _clk__1 {osc CLK}} {parameter width {param width}}}} +rgU RegUN {interface {{method _write _write {clock _clk__1} {reset no_reset} {args {{{port D_IN} {size 32}}}} {results {}} {enable EN}} {method _read _read {clock _clk__1} {reset no_reset} {args {}} {results {{{port Q_OUT} {size 32}}}}}}} {args {{clock _clk__1 {osc CLK}} {parameter width {param width}}}} rgU RegUN {ports {{CLK Clock} {D_IN Int#(32)} {EN Bool} {Q_OUT Int#(32)}}} ---------- -rw RWire {interface {{method wset wset {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {enable WSET}} {method wget wget {clock clk} {reset rst} {args {}} {result WGET} {ready WHAS}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} +rw RWire {interface {{method wset wset {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {results {}} {enable WSET}} {method wget wget {clock clk} {reset rst} {args {}} {results {{{port WGET} {size 32}}}} {ready WHAS}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} rw RWire {ports {{WVAL Int#(32)} {WSET Bool} {WGET Int#(32)} {WHAS Bool}}} ---------- -rw0 RWire0 {interface {{method wset wset {clock clk} {reset rst} {args {}} {enable WSET}} {method wget wget {clock clk} {reset rst} {args {}} {ready WHAS}}}} {args {{clock clk} {reset rst {clock clk}}}} +rw0 RWire0 {interface {{method wset wset {clock clk} {reset rst} {args {}} {results {}} {enable WSET}} {method wget wget {clock clk} {reset rst} {args {}} {results {}} {ready WHAS}}}} {args {{clock clk} {reset rst {clock clk}}}} rw0 RWire0 {ports {{WSET Bool} {WHAS Bool}}} ---------- -w RWire {interface {{method _write _write {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {result WGET} {ready WHAS}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} +w RWire {interface {{method _write _write {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {results {}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {results {{{port WGET} {size 32}}}} {ready WHAS}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} w RWire {ports {{WVAL Int#(32)} {WSET Bool} {WGET Int#(32)} {WHAS Bool}}} ---------- -dw RWire {interface {{method _write _write {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {result WGET} {ready WHAS}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} +dw RWire {interface {{method _write _write {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {results {}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {results {{{port WGET} {size 32}}}} {ready WHAS}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} dw RWire {ports {{WVAL Int#(32)} {WSET Bool} {WGET Int#(32)} {WHAS Bool}}} ---------- -bw BypassWire {interface {{method _write _write {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}}} {method _read _read {clock clk} {reset rst} {args {}} {result WGET}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} +bw BypassWire {interface {{method _write _write {clock clk} {reset rst} {args {{{port WVAL} {size 32}}}} {results {}}} {method _read _read {clock clk} {reset rst} {args {}} {results {{{port WGET} {size 32}}}}}}} {args {{parameter width {param width}} {clock clk} {reset rst {clock clk}}}} bw BypassWire {ports {{WVAL Int#(32)} {WGET Int#(32)}}} ---------- -pw RWire0 {interface {{method send send {clock clk} {reset rst} {args {}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {result WHAS}}}} {args {{clock clk} {reset rst {clock clk}}}} +pw RWire0 {interface {{method send send {clock clk} {reset rst} {args {}} {results {}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {results {{{port WHAS} {size 1}}}}}}} {args {{clock clk} {reset rst {clock clk}}}} pw RWire0 {ports {{WSET Bool} {WHAS Bool}}} ---------- -pwo RWire0 {interface {{method send send {clock clk} {reset rst} {args {}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {result WHAS}}}} {args {{clock clk} {reset rst {clock clk}}}} +pwo RWire0 {interface {{method send send {clock clk} {reset rst} {args {}} {results {}} {enable WSET}} {method _read _read {clock clk} {reset rst} {args {}} {results {{{port WHAS} {size 1}}}}}}} {args {{clock clk} {reset rst {clock clk}}}} pwo RWire0 {ports {{WSET Bool} {WHAS Bool}}} ---------- -rf RegFile {interface {{method upd upd {clock _clk__1} {reset no_reset} {args {{{port ADDR_IN} {size 2}} {{port D_IN} {size 32}}}} {enable WE}} {method sub_1 sub_1 {clock _clk__1} {reset no_reset} {args {{{port ADDR_1} {size 2}}}} {result D_OUT_1}} {method sub_2 sub_2 {clock _clk__1} {reset no_reset} {args {{{port ADDR_2} {size 2}}}} {result D_OUT_2}} {method sub_3 sub_3 {clock _clk__1} {reset no_reset} {args {{{port ADDR_3} {size 2}}}} {result D_OUT_3}} {method sub_4 sub_4 {clock _clk__1} {reset no_reset} {args {{{port ADDR_4} {size 2}}}} {result D_OUT_4}} {method sub_5 sub_5 {clock _clk__1} {reset no_reset} {args {{{port ADDR_5} {size 2}}}} {result D_OUT_5}}}} {args {{clock _clk__1 {osc CLK}} {parameter addr_width {param addr_width}} {parameter data_width {param data_width}} {parameter lo {param lo}} {parameter hi {param hi}}}} +rf RegFile {interface {{method upd upd {clock _clk__1} {reset no_reset} {args {{{port ADDR_IN} {size 2}} {{port D_IN} {size 32}}}} {results {}} {enable WE}} {method sub_1 sub_1 {clock _clk__1} {reset no_reset} {args {{{port ADDR_1} {size 2}}}} {results {{{port D_OUT_1} {size 32}}}}} {method sub_2 sub_2 {clock _clk__1} {reset no_reset} {args {{{port ADDR_2} {size 2}}}} {results {{{port D_OUT_2} {size 32}}}}} {method sub_3 sub_3 {clock _clk__1} {reset no_reset} {args {{{port ADDR_3} {size 2}}}} {results {{{port D_OUT_3} {size 32}}}}} {method sub_4 sub_4 {clock _clk__1} {reset no_reset} {args {{{port ADDR_4} {size 2}}}} {results {{{port D_OUT_4} {size 32}}}}} {method sub_5 sub_5 {clock _clk__1} {reset no_reset} {args {{{port ADDR_5} {size 2}}}} {results {{{port D_OUT_5} {size 32}}}}}}} {args {{clock _clk__1 {osc CLK}} {parameter addr_width {param addr_width}} {parameter data_width {param data_width}} {parameter lo {param lo}} {parameter hi {param hi}}}} rf RegFile {ports {{CLK Clock} {ADDR_IN Bit#(2)} {D_IN Int#(32)} {WE Bool} {ADDR_1 Bit#(2)} {D_OUT_1 Int#(32)} {ADDR_2 Bit#(2)} {D_OUT_2 Int#(32)} {ADDR_3 Bit#(2)} {D_OUT_3 Int#(32)} {ADDR_4 Bit#(2)} {D_OUT_4 Int#(32)} {ADDR_5 Bit#(2)} {D_OUT_5 Int#(32)}}} ---------- -ff1 FIFO2 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {result D_OUT} {ready EMPTY_N}} {method notFull notFull {clock clk} {reset _rst__1} {args {}} {result FULL_N}} {method notEmpty notEmpty {clock clk} {reset _rst__1} {args {}} {result EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}} {parameter guarded {param guarded}}}} +ff1 FIFO2 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {{{port D_OUT} {size 32}}}} {ready EMPTY_N}} {method notFull notFull {clock clk} {reset _rst__1} {args {}} {results {{{port FULL_N} {size 1}}}}} {method notEmpty notEmpty {clock clk} {reset _rst__1} {args {}} {results {{{port EMPTY_N} {size 1}}}}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}} {parameter guarded {param guarded}}}} ff1 FIFO2 {ports {{RST Reset} {CLK Clock} {D_IN Int#(32)} {ENQ Bool} {FULL_N Bool} {DEQ Bool} {EMPTY_N Bool} {D_OUT Int#(32)} {CLR Bool}}} ---------- -f1 FIFO1 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {result D_OUT} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}} {parameter guarded {param guarded}}}} +f1 FIFO1 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {{{port D_OUT} {size 32}}}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}} {parameter guarded {param guarded}}}} f1 FIFO1 {ports {{RST Reset} {CLK Clock} {D_IN Int#(32)} {ENQ Bool} {FULL_N Bool} {DEQ Bool} {EMPTY_N Bool} {D_OUT Int#(32)} {CLR Bool}}} ---------- -f10 FIFO10 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter guarded {param guarded}}}} +f10 FIFO10 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter guarded {param guarded}}}} f10 FIFO10 {ports {{RST Reset} {CLK Clock} {ENQ Bool} {FULL_N Bool} {DEQ Bool} {EMPTY_N Bool} {CLR Bool}}} ---------- -f2 FIFO2 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {result D_OUT} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}} {parameter guarded {param guarded}}}} +f2 FIFO2 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {{{port D_OUT} {size 32}}}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}} {parameter guarded {param guarded}}}} f2 FIFO2 {ports {{RST Reset} {CLK Clock} {D_IN Int#(32)} {ENQ Bool} {FULL_N Bool} {DEQ Bool} {EMPTY_N Bool} {D_OUT Int#(32)} {CLR Bool}}} ---------- -f20 FIFO20 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter guarded {param guarded}}}} +f20 FIFO20 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter guarded {param guarded}}}} f20 FIFO20 {ports {{RST Reset} {CLK Clock} {ENQ Bool} {FULL_N Bool} {DEQ Bool} {EMPTY_N Bool} {CLR Bool}}} ---------- -fs SizedFIFO {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {result D_OUT} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter p1width {param p1width}} {parameter p2depth {param p2depth}} {parameter p3cntr_width {param p3cntr_width}} {parameter guarded {param guarded}}}} +fs SizedFIFO {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {{{port D_OUT} {size 32}}}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter p1width {param p1width}} {parameter p2depth {param p2depth}} {parameter p3cntr_width {param p3cntr_width}} {parameter guarded {param guarded}}}} fs SizedFIFO {ports {{RST Reset} {CLK Clock} {D_IN Int#(32)} {ENQ Bool} {FULL_N Bool} {DEQ Bool} {EMPTY_N Bool} {D_OUT Int#(32)} {CLR Bool}}} ---------- -fs0 SizedFIFO0 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter p1depth {param p1depth}} {parameter p2cntr_width {param p2cntr_width}} {parameter guarded {param guarded}}}} +fs0 SizedFIFO0 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter p1depth {param p1depth}} {parameter p2cntr_width {param p2cntr_width}} {parameter guarded {param guarded}}}} fs0 SizedFIFO0 {ports {{RST Reset} {CLK Clock} {ENQ Bool} {FULL_N Bool} {DEQ Bool} {EMPTY_N Bool} {CLR Bool}}} ---------- -fL1 FIFOL1 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {result D_OUT} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}}}} +fL1 FIFOL1 {interface {{method enq enq {clock clk} {reset _rst__1} {args {{{port D_IN} {size 32}}}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {{{port D_OUT} {size 32}}}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter width {param width}}}} fL1 FIFOL1 {ports {{RST Reset} {CLK Clock} {D_IN Int#(32)} {ENQ Bool} {FULL_N Bool} {DEQ Bool} {EMPTY_N Bool} {D_OUT Int#(32)} {CLR Bool}}} ---------- -fL10 FIFO20 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter guarded {param guarded}}}} +fL10 FIFO20 {interface {{method enq enq {clock clk} {reset _rst__1} {args {}} {results {}} {enable ENQ} {ready FULL_N}} {method deq deq {clock clk} {reset _rst__1} {args {}} {results {}} {enable DEQ} {ready EMPTY_N}} {method first first {clock clk} {reset _rst__1} {args {}} {results {}} {ready EMPTY_N}} {method clear clear {clock clk} {reset _rst__1} {args {}} {results {}} {enable CLR}}}} {args {{reset _rst__1 {port RST} {clock clk}} {clock clk {osc CLK}} {parameter guarded {param guarded}}}} fL10 FIFO20 {ports {{RST Reset} {CLK Clock} {ENQ Bool} {FULL_N Bool} {DEQ Bool} {EMPTY_N Bool} {CLR Bool}}} ---------- dclk ClockGen {interface {{clock gen_clk gen_clk {osc CLK_OUT}}}} {args {{parameter v1Width {param v1Width}} {parameter v2Width {param v2Width}} {parameter initDelay {param initDelay}} {parameter initValue {param initValue}} {parameter otherValue {param otherValue}}}} dclk ClockGen {ports {{CLK_OUT Clock}}} ---------- -sr SyncRegister {interface {{method _write _write {clock clk_src} {reset sRstIn} {args {{{port sD_IN} {size 32}}}} {enable sEN} {ready sRDY}} {method _read _read {clock clk_dst} {reset no_reset} {args {}} {result dD_OUT}}}} {args {{parameter width {param width}} {parameter init {param init}} {clock clk_src {osc sCLK}} {clock clk_dst {osc dCLK}} {reset sRstIn {port sRST} {clock clk_src}}}} +sr SyncRegister {interface {{method _write _write {clock clk_src} {reset sRstIn} {args {{{port sD_IN} {size 32}}}} {results {}} {enable sEN} {ready sRDY}} {method _read _read {clock clk_dst} {reset no_reset} {args {}} {results {{{port dD_OUT} {size 32}}}}}}} {args {{parameter width {param width}} {parameter init {param init}} {clock clk_src {osc sCLK}} {clock clk_dst {osc dCLK}} {reset sRstIn {port sRST} {clock clk_src}}}} sr SyncRegister {ports {{sCLK Clock} {dCLK Clock} {sRST Reset} {sD_IN Int#(32)} {sEN Bool} {sRDY Bool} {dD_OUT Int#(32)}}} ---------- -bcw CrossingBypassWire {interface {{method wset wset {clock clk} {reset no_reset} {args {{{port WVAL} {size 32}}}}} {method wget wget {clock dstClk} {reset no_reset} {args {}} {result WGET}}}} {args {{parameter width {param width}} {clock clk {osc CLK}} {clock dstClk}}} +bcw CrossingBypassWire {interface {{method wset wset {clock clk} {reset no_reset} {args {{{port WVAL} {size 32}}}} {results {}}} {method wget wget {clock dstClk} {reset no_reset} {args {}} {results {{{port WGET} {size 32}}}}}}} {args {{parameter width {param width}} {clock clk {osc CLK}} {clock dstClk}}} bcw CrossingBypassWire {ports {{CLK Clock} {WVAL Int#(32)} {WGET Int#(32)}}} ---------- -ncw CrossingBypassWire {interface {{method wset wset {clock clk} {reset no_reset} {args {{{port WVAL} {size 32}}}}} {method wget wget {clock dstClk} {reset no_reset} {args {}} {result WGET}}}} {args {{parameter width {param width}} {clock clk {osc CLK}} {clock dstClk}}} +ncw CrossingBypassWire {interface {{method wset wset {clock clk} {reset no_reset} {args {{{port WVAL} {size 32}}}} {results {}}} {method wget wget {clock dstClk} {reset no_reset} {args {}} {results {{{port WGET} {size 32}}}}}}} {args {{parameter width {param width}} {clock clk {osc CLK}} {clock dstClk}}} ncw CrossingBypassWire {ports {{CLK Clock} {WVAL Int#(32)} {WGET Int#(32)}}} ---------- diff --git a/testsuite/bsc.bluetcl/targeted/port_types/split_port_types.tcl b/testsuite/bsc.bluetcl/targeted/port_types/split_port_types.tcl new file mode 100644 index 000000000..cfc785205 --- /dev/null +++ b/testsuite/bsc.bluetcl/targeted/port_types/split_port_types.tcl @@ -0,0 +1,16 @@ +namespace import ::Bluetcl::* + +puts [flags set {-verilog}] +puts [module load mkSplitPortTypes] + +puts {----------} +puts "module porttypes mkSplitPortTypes" +foreach e [module porttypes mkSplitPortTypes] { + puts $e +} + +puts {----------} +puts "module ports mkSplitPortTypes" +foreach e [module ports mkSplitPortTypes] { + puts $e +} diff --git a/testsuite/bsc.bluetcl/targeted/port_types/split_port_types.tcl.bluetcl-bh-out.expected b/testsuite/bsc.bluetcl/targeted/port_types/split_port_types.tcl.bluetcl-bh-out.expected new file mode 100644 index 000000000..6abf20c92 --- /dev/null +++ b/testsuite/bsc.bluetcl/targeted/port_types/split_port_types.tcl.bluetcl-bh-out.expected @@ -0,0 +1,55 @@ +-verilog +mkSplitPortTypes +---------- +module porttypes mkSplitPortTypes +CLK Prelude.Clock +RST_N Prelude.Reset +getDeep_x {Prelude.UInt 8} +getDeep_y_a Prelude.Bool +getDeep_y_b {Prelude.Int 16} +getDeep_z {Prelude.Bit 4} +RDY_getDeep Prelude.Bool +getShallow_x {Prelude.UInt 8} +getShallow_y SplitPortTypes.Inner +getShallow_z {Prelude.Bit 4} +RDY_getShallow Prelude.Bool +nextDeep_x {Prelude.UInt 8} +nextDeep_y_a Prelude.Bool +nextDeep_y_b {Prelude.Int 16} +nextDeep_z {Prelude.Bit 4} +EN_nextDeep Prelude.Bool +RDY_nextDeep Prelude.Bool +putDeep_1_x {Prelude.UInt 8} +putDeep_1_y_a Prelude.Bool +putDeep_1_y_b {Prelude.Int 16} +putDeep_1_z {Prelude.Bit 4} +EN_putDeep Prelude.Bool +RDY_putDeep Prelude.Bool +putShallow_1_x {Prelude.UInt 8} +putShallow_1_y SplitPortTypes.Inner +putShallow_1_z {Prelude.Bit 4} +EN_putShallow Prelude.Bool +RDY_putShallow Prelude.Bool +combineDeep_lhs_x {Prelude.UInt 8} +combineDeep_lhs_y_a Prelude.Bool +combineDeep_lhs_y_b {Prelude.Int 16} +combineDeep_lhs_z {Prelude.Bit 4} +combineDeep_rhs_x {Prelude.UInt 8} +combineDeep_rhs_y_a Prelude.Bool +combineDeep_rhs_y_b {Prelude.Int 16} +combineDeep_rhs_z {Prelude.Bit 4} +EN_combineDeep Prelude.Bool +RDY_combineDeep Prelude.Bool +transform_1_x {Prelude.UInt 8} +transform_1_y_a Prelude.Bool +transform_1_y_b {Prelude.Int 16} +transform_1_z {Prelude.Bit 4} +transform_x {Prelude.UInt 8} +transform_y_a Prelude.Bool +transform_y_b {Prelude.Int 16} +transform_z {Prelude.Bit 4} +RDY_transform Prelude.Bool +---------- +module ports mkSplitPortTypes +interface {{method getDeep getDeep {clock default_clock} {reset default_reset} {args {}} {results {{{port getDeep_x} {size 8}} {{port getDeep_y_a} {size 1}} {{port getDeep_y_b} {size 16}} {{port getDeep_z} {size 4}}}} {ready RDY_getDeep}} {method getShallow getShallow {clock default_clock} {reset default_reset} {args {}} {results {{{port getShallow_x} {size 8}} {{port getShallow_y} {size 17}} {{port getShallow_z} {size 4}}}} {ready RDY_getShallow}} {method nextDeep nextDeep {clock default_clock} {reset default_reset} {args {}} {results {{{port nextDeep_x} {size 8}} {{port nextDeep_y_a} {size 1}} {{port nextDeep_y_b} {size 16}} {{port nextDeep_z} {size 4}}}} {enable EN_nextDeep} {ready RDY_nextDeep}} {method putDeep putDeep {clock default_clock} {reset default_reset} {args {{{name putDeep_1_x} {port putDeep_1_x} {size 8}} {{name putDeep_1_y_a} {port putDeep_1_y_a} {size 1}} {{name putDeep_1_y_b} {port putDeep_1_y_b} {size 16}} {{name putDeep_1_z} {port putDeep_1_z} {size 4}}}} {results {}} {enable EN_putDeep} {ready RDY_putDeep}} {method putShallow putShallow {clock default_clock} {reset default_reset} {args {{{name putShallow_1_x} {port putShallow_1_x} {size 8}} {{name putShallow_1_y} {port putShallow_1_y} {size 17}} {{name putShallow_1_z} {port putShallow_1_z} {size 4}}}} {results {}} {enable EN_putShallow} {ready RDY_putShallow}} {method combineDeep combineDeep {clock default_clock} {reset default_reset} {args {{{name combineDeep_lhs_x} {port combineDeep_lhs_x} {size 8}} {{name combineDeep_lhs_y_a} {port combineDeep_lhs_y_a} {size 1}} {{name combineDeep_lhs_y_b} {port combineDeep_lhs_y_b} {size 16}} {{name combineDeep_lhs_z} {port combineDeep_lhs_z} {size 4}} {{name combineDeep_rhs_x} {port combineDeep_rhs_x} {size 8}} {{name combineDeep_rhs_y_a} {port combineDeep_rhs_y_a} {size 1}} {{name combineDeep_rhs_y_b} {port combineDeep_rhs_y_b} {size 16}} {{name combineDeep_rhs_z} {port combineDeep_rhs_z} {size 4}}}} {results {}} {enable EN_combineDeep} {ready RDY_combineDeep}} {method transform transform {clock no_clock} {reset no_reset} {args {{{name transform_1_x} {port transform_1_x} {size 8}} {{name transform_1_y_a} {port transform_1_y_a} {size 1}} {{name transform_1_y_b} {port transform_1_y_b} {size 16}} {{name transform_1_z} {port transform_1_z} {size 4}}}} {results {{{port transform_x} {size 8}} {{port transform_y_a} {size 1}} {{port transform_y_b} {size 16}} {{port transform_z} {size 4}}}} {ready RDY_transform}}} +args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}} diff --git a/testsuite/bsc.bluetcl/targeted/port_types/split_port_types.tcl.bluetcl-out.expected b/testsuite/bsc.bluetcl/targeted/port_types/split_port_types.tcl.bluetcl-out.expected new file mode 100644 index 000000000..83b846b70 --- /dev/null +++ b/testsuite/bsc.bluetcl/targeted/port_types/split_port_types.tcl.bluetcl-out.expected @@ -0,0 +1,55 @@ +-verilog +mkSplitPortTypes +---------- +module porttypes mkSplitPortTypes +CLK Clock +RST_N Reset +getDeep_x UInt#(8) +getDeep_y_a Bool +getDeep_y_b Int#(16) +getDeep_z Bit#(4) +RDY_getDeep Bool +getShallow_x UInt#(8) +getShallow_y SplitPortTypes::Inner +getShallow_z Bit#(4) +RDY_getShallow Bool +nextDeep_x UInt#(8) +nextDeep_y_a Bool +nextDeep_y_b Int#(16) +nextDeep_z Bit#(4) +EN_nextDeep Bool +RDY_nextDeep Bool +putDeep_1_x UInt#(8) +putDeep_1_y_a Bool +putDeep_1_y_b Int#(16) +putDeep_1_z Bit#(4) +EN_putDeep Bool +RDY_putDeep Bool +putShallow_1_x UInt#(8) +putShallow_1_y SplitPortTypes::Inner +putShallow_1_z Bit#(4) +EN_putShallow Bool +RDY_putShallow Bool +combineDeep_lhs_x UInt#(8) +combineDeep_lhs_y_a Bool +combineDeep_lhs_y_b Int#(16) +combineDeep_lhs_z Bit#(4) +combineDeep_rhs_x UInt#(8) +combineDeep_rhs_y_a Bool +combineDeep_rhs_y_b Int#(16) +combineDeep_rhs_z Bit#(4) +EN_combineDeep Bool +RDY_combineDeep Bool +transform_1_x UInt#(8) +transform_1_y_a Bool +transform_1_y_b Int#(16) +transform_1_z Bit#(4) +transform_x UInt#(8) +transform_y_a Bool +transform_y_b Int#(16) +transform_z Bit#(4) +RDY_transform Bool +---------- +module ports mkSplitPortTypes +interface {{method getDeep getDeep {clock default_clock} {reset default_reset} {args {}} {results {{{port getDeep_x} {size 8}} {{port getDeep_y_a} {size 1}} {{port getDeep_y_b} {size 16}} {{port getDeep_z} {size 4}}}} {ready RDY_getDeep}} {method getShallow getShallow {clock default_clock} {reset default_reset} {args {}} {results {{{port getShallow_x} {size 8}} {{port getShallow_y} {size 17}} {{port getShallow_z} {size 4}}}} {ready RDY_getShallow}} {method nextDeep nextDeep {clock default_clock} {reset default_reset} {args {}} {results {{{port nextDeep_x} {size 8}} {{port nextDeep_y_a} {size 1}} {{port nextDeep_y_b} {size 16}} {{port nextDeep_z} {size 4}}}} {enable EN_nextDeep} {ready RDY_nextDeep}} {method putDeep putDeep {clock default_clock} {reset default_reset} {args {{{name putDeep_1_x} {port putDeep_1_x} {size 8}} {{name putDeep_1_y_a} {port putDeep_1_y_a} {size 1}} {{name putDeep_1_y_b} {port putDeep_1_y_b} {size 16}} {{name putDeep_1_z} {port putDeep_1_z} {size 4}}}} {results {}} {enable EN_putDeep} {ready RDY_putDeep}} {method putShallow putShallow {clock default_clock} {reset default_reset} {args {{{name putShallow_1_x} {port putShallow_1_x} {size 8}} {{name putShallow_1_y} {port putShallow_1_y} {size 17}} {{name putShallow_1_z} {port putShallow_1_z} {size 4}}}} {results {}} {enable EN_putShallow} {ready RDY_putShallow}} {method combineDeep combineDeep {clock default_clock} {reset default_reset} {args {{{name combineDeep_lhs_x} {port combineDeep_lhs_x} {size 8}} {{name combineDeep_lhs_y_a} {port combineDeep_lhs_y_a} {size 1}} {{name combineDeep_lhs_y_b} {port combineDeep_lhs_y_b} {size 16}} {{name combineDeep_lhs_z} {port combineDeep_lhs_z} {size 4}} {{name combineDeep_rhs_x} {port combineDeep_rhs_x} {size 8}} {{name combineDeep_rhs_y_a} {port combineDeep_rhs_y_a} {size 1}} {{name combineDeep_rhs_y_b} {port combineDeep_rhs_y_b} {size 16}} {{name combineDeep_rhs_z} {port combineDeep_rhs_z} {size 4}}}} {results {}} {enable EN_combineDeep} {ready RDY_combineDeep}} {method transform transform {clock no_clock} {reset no_reset} {args {{{name transform_1_x} {port transform_1_x} {size 8}} {{name transform_1_y_a} {port transform_1_y_a} {size 1}} {{name transform_1_y_b} {port transform_1_y_b} {size 16}} {{name transform_1_z} {port transform_1_z} {size 4}}}} {results {{{port transform_x} {size 8}} {{port transform_y_a} {size 1}} {{port transform_y_b} {size 16}} {{port transform_z} {size 4}}}} {ready RDY_transform}}} +args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}} diff --git a/testsuite/bsc.bluetcl/targeted/port_types/zero_size.tcl.bluetcl-bh-out.expected b/testsuite/bsc.bluetcl/targeted/port_types/zero_size.tcl.bluetcl-bh-out.expected index e3facb44e..bb0527ecb 100644 --- a/testsuite/bsc.bluetcl/targeted/port_types/zero_size.tcl.bluetcl-bh-out.expected +++ b/testsuite/bsc.bluetcl/targeted/port_types/zero_size.tcl.bluetcl-bh-out.expected @@ -1,11 +1,11 @@ -verilog mkZeroSize_Sub sysZeroSize ---------- -{rg1 MOD {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {}} {enable EN}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}}}}} {args {{reset _rst__1 {port RST} {clock _clk__1}} {clock _clk__1 {osc CLK} {gate CLK_GATE}}}}} {rg2 mkZeroSize_Sub {interface {{method m1 m1 {clock no_clock} {reset no_reset} {args {}} {ready RDY_m1}} {method m2 m2 {clock default_clock} {reset no_reset} {args {{{port m2_y} {size 1}}}} {enable EN_m2} {ready RDY_m2}} {method m3 m3 {clock default_clock} {reset no_reset} {args {}} {enable EN_m3} {ready RDY_m3}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}}} +{rg1 MOD {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {}} {results {}} {enable EN}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {results {}}}}} {args {{reset _rst__1 {port RST} {clock _clk__1}} {clock _clk__1 {osc CLK} {gate CLK_GATE}}}}} {rg2 mkZeroSize_Sub {interface {{method m1 m1 {clock no_clock} {reset no_reset} {args {}} {results {}} {ready RDY_m1}} {method m2 m2 {clock default_clock} {reset no_reset} {args {{{port m2_y} {size 1}}}} {results {}} {enable EN_m2} {ready RDY_m2}} {method m3 m3 {clock default_clock} {reset no_reset} {args {}} {results {}} {enable EN_m3} {ready RDY_m3}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}}} {rg1 MOD {ports {{RST Prelude.Reset} {CLK Prelude.Clock} {CLK_GATE Prelude.Bool} {EN Prelude.Bool}}}} {rg2 mkZeroSize_Sub {ports {{CLK Prelude.Clock} {RST_N Prelude.Reset} {RDY_m1 Prelude.Bool} {m2_y Prelude.Bool} {EN_m2 Prelude.Bool} {RDY_m2 Prelude.Bool} {EN_m3 Prelude.Bool} {RDY_m3 Prelude.Bool}}}} ---------- -{interface {{method m1 m1 {clock no_clock} {reset no_reset} {args {}} {ready RDY_m1}} {method m2 m2 {clock default_clock} {reset no_reset} {args {{{name m2_y} {port m2_y} {size 1}}}} {enable EN_m2} {ready RDY_m2}} {method m3 m3 {clock default_clock} {reset no_reset} {args {}} {enable EN_m3} {ready RDY_m3}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}} +{interface {{method m1 m1 {clock no_clock} {reset no_reset} {args {}} {results {}} {ready RDY_m1}} {method m2 m2 {clock default_clock} {reset no_reset} {args {{{name m2_y} {port m2_y} {size 1}}}} {results {}} {enable EN_m2} {ready RDY_m2}} {method m3 m3 {clock default_clock} {reset no_reset} {args {}} {results {}} {enable EN_m3} {ready RDY_m3}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}} {CLK Prelude.Clock} {RST_N Prelude.Reset} {RDY_m1 Prelude.Bool} {m2_y Prelude.Bool} {EN_m2 Prelude.Bool} {RDY_m2 Prelude.Bool} {EN_m3 Prelude.Bool} {RDY_m3 Prelude.Bool} ---------- diff --git a/testsuite/bsc.bluetcl/targeted/port_types/zero_size.tcl.bluetcl-out.expected b/testsuite/bsc.bluetcl/targeted/port_types/zero_size.tcl.bluetcl-out.expected index 4d5264b9d..e62ad7fa7 100644 --- a/testsuite/bsc.bluetcl/targeted/port_types/zero_size.tcl.bluetcl-out.expected +++ b/testsuite/bsc.bluetcl/targeted/port_types/zero_size.tcl.bluetcl-out.expected @@ -1,11 +1,11 @@ -verilog mkZeroSize_Sub sysZeroSize ---------- -{rg1 MOD {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {}} {enable EN}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}}}}} {args {{reset _rst__1 {port RST} {clock _clk__1}} {clock _clk__1 {osc CLK} {gate CLK_GATE}}}}} {rg2 mkZeroSize_Sub {interface {{method m1 m1 {clock no_clock} {reset no_reset} {args {}} {ready RDY_m1}} {method m2 m2 {clock default_clock} {reset no_reset} {args {{{port m2_y} {size 1}}}} {enable EN_m2} {ready RDY_m2}} {method m3 m3 {clock default_clock} {reset no_reset} {args {}} {enable EN_m3} {ready RDY_m3}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}}} +{rg1 MOD {interface {{method _write _write {clock _clk__1} {reset _rst__1} {args {}} {results {}} {enable EN}} {method _read _read {clock _clk__1} {reset _rst__1} {args {}} {results {}}}}} {args {{reset _rst__1 {port RST} {clock _clk__1}} {clock _clk__1 {osc CLK} {gate CLK_GATE}}}}} {rg2 mkZeroSize_Sub {interface {{method m1 m1 {clock no_clock} {reset no_reset} {args {}} {results {}} {ready RDY_m1}} {method m2 m2 {clock default_clock} {reset no_reset} {args {{{port m2_y} {size 1}}}} {results {}} {enable EN_m2} {ready RDY_m2}} {method m3 m3 {clock default_clock} {reset no_reset} {args {}} {results {}} {enable EN_m3} {ready RDY_m3}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}}} {rg1 MOD {ports {{RST Reset} {CLK Clock} {CLK_GATE Bool} {EN Bool}}}} {rg2 mkZeroSize_Sub {ports {{CLK Clock} {RST_N Reset} {RDY_m1 Bool} {m2_y Bool} {EN_m2 Bool} {RDY_m2 Bool} {EN_m3 Bool} {RDY_m3 Bool}}}} ---------- -{interface {{method m1 m1 {clock no_clock} {reset no_reset} {args {}} {ready RDY_m1}} {method m2 m2 {clock default_clock} {reset no_reset} {args {{{name m2_y} {port m2_y} {size 1}}}} {enable EN_m2} {ready RDY_m2}} {method m3 m3 {clock default_clock} {reset no_reset} {args {}} {enable EN_m3} {ready RDY_m3}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}} +{interface {{method m1 m1 {clock no_clock} {reset no_reset} {args {}} {results {}} {ready RDY_m1}} {method m2 m2 {clock default_clock} {reset no_reset} {args {{{name m2_y} {port m2_y} {size 1}}}} {results {}} {enable EN_m2} {ready RDY_m2}} {method m3 m3 {clock default_clock} {reset no_reset} {args {}} {results {}} {enable EN_m3} {ready RDY_m3}}}} {args {{clock default_clock {osc CLK}} {reset default_reset {port RST_N} {clock default_clock}}}} {CLK Clock} {RST_N Reset} {RDY_m1 Bool} {m2_y Bool} {EN_m2 Bool} {RDY_m2 Bool} {EN_m3 Bool} {RDY_m3 Bool} ---------- diff --git a/testsuite/bsc.bugs/bluespec_inc/b1610/Test2.bs b/testsuite/bsc.bugs/bluespec_inc/b1610/Test2.bs index 20b45d091..9eb201aa5 100644 --- a/testsuite/bsc.bugs/bluespec_inc/b1610/Test2.bs +++ b/testsuite/bsc.bugs/bluespec_inc/b1610/Test2.bs @@ -1,7 +1,7 @@ package Test2 where interface RegPrimPairBoolMaybeBitSizeOfBit32_ = - _write :: Bit 34 -> ActionValue_ 0 + _write :: Bit 34 -> ActionValue_ (Bit 0) fromRegPrimPairBoolMaybeBitSizeOfBit32_ :: (Bits (Bool, Maybe (Bit (SizeOf (Bit 32)))) 34) => diff --git a/testsuite/bsc.bugs/bluespec_inc/b1758/b1758.exp b/testsuite/bsc.bugs/bluespec_inc/b1758/b1758.exp index e9dcc3bca..5a00dd66b 100644 --- a/testsuite/bsc.bugs/bluespec_inc/b1758/b1758.exp +++ b/testsuite/bsc.bugs/bluespec_inc/b1758/b1758.exp @@ -8,12 +8,10 @@ compile_verilog_pass ZeroBitValueMethod.bsv {} {-dexpanded -dATS} # Test that the method reference has been replaced by 0 in the evaluator if { $vtest == 1 } { - # XXX This still need to be fixed - find_regexp ZeroBitValueMethod.bsv.bsc-vcomp-out \ + find_regexp_fail ZeroBitValueMethod.bsv.bsc-vcomp-out \ {\= \.ZeroBitValueMethod\.getVal g} - # XXX AConv doesn't replace it either find_regexp ZeroBitValueMethod.bsv.bsc-vcomp-out \ - {\= g\.getVal} + {\=\=> Prelude\.\$display#0 "v \= %b" 0} } # ----- @@ -23,12 +21,10 @@ compile_verilog_pass ZeroBitActionValueMethod.bsv {} {-dexpanded -dATS} # Test that the method reference has been replaced by 0 in the evaluator if { $vtest == 1 } { - # XXX This still need to be fixed - find_regexp ZeroBitActionValueMethod.bsv.bsc-vcomp-out \ + find_regexp_fail ZeroBitActionValueMethod.bsv.bsc-vcomp-out \ {\= \.Prelude\.avValue_ ·0 \(\.ZeroBitActionValueMethod\.get g\)} - # At least AConv replaces it find_regexp ZeroBitActionValueMethod.bsv.bsc-vcomp-out \ - {g\.get\; p\.put 0\'d0\;} + {g\.get\; p\.put\;} } # ----- diff --git a/testsuite/bsc.codegen/foreign/BDPIActionValue_.bsv b/testsuite/bsc.codegen/foreign/BDPIActionValue_.bsv index 6c4fba560..681ab00ad 100644 --- a/testsuite/bsc.codegen/foreign/BDPIActionValue_.bsv +++ b/testsuite/bsc.codegen/foreign/BDPIActionValue_.bsv @@ -1,4 +1,4 @@ -import "BDPI" function ActionValue_#(32) my_time (Bit#(8) x); +import "BDPI" function ActionValue_#(Bit#(32)) my_time (Bit#(8) x); function ActionValue#(Bit#(32)) my_time2(Bit#(8) x); let y = my_time(x); diff --git a/testsuite/bsc.evaluator/mkTest.atsexpand.expected b/testsuite/bsc.evaluator/mkTest.atsexpand.expected index 63e14d11e..1dff74ee0 100644 --- a/testsuite/bsc.evaluator/mkTest.atsexpand.expected +++ b/testsuite/bsc.evaluator/mkTest.atsexpand.expected @@ -26,7 +26,7 @@ slots :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd1] [] - meth types=[([], Nothing, Just (Bit 1)), ([Bit 1], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 1]), ([Bit 1], Just (Bit 1), [])] port types=D_IN -> Prelude.Bool Q_OUT -> Prelude.Bool slots_1 :: ABSTRACT: Prelude.VReg = RegUN @@ -41,7 +41,7 @@ slots_1 :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd1] [] - meth types=[([], Nothing, Just (Bit 1)), ([Bit 1], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 1]), ([Bit 1], Just (Bit 1), [])] port types=D_IN -> Prelude.Bool Q_OUT -> Prelude.Bool ptr :: ABSTRACT: Prelude.VReg = RegUN @@ -56,7 +56,7 @@ ptr :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd5] [] - meth types=[([], Nothing, Just (Bit 5)), ([Bit 5], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 5]), ([Bit 5], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 5 Q_OUT -> Prelude.Bit 5 pred :: ABSTRACT: Prelude.VReg = RegUN @@ -71,7 +71,7 @@ pred :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd1] [] - meth types=[([], Nothing, Just (Bit 1)), ([Bit 1], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 1]), ([Bit 1], Just (Bit 1), [])] port types=D_IN -> Prelude.Bool Q_OUT -> Prelude.Bool -- AP rules diff --git a/testsuite/bsc.evaluator/mkTest.atsexpand.nolift.expandif.expected b/testsuite/bsc.evaluator/mkTest.atsexpand.nolift.expandif.expected index 342befbad..2c1fcb19f 100644 --- a/testsuite/bsc.evaluator/mkTest.atsexpand.nolift.expandif.expected +++ b/testsuite/bsc.evaluator/mkTest.atsexpand.nolift.expandif.expected @@ -26,7 +26,7 @@ slots :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd1] [] - meth types=[([], Nothing, Just (Bit 1)), ([Bit 1], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 1]), ([Bit 1], Just (Bit 1), [])] port types=D_IN -> Prelude.Bool Q_OUT -> Prelude.Bool slots_1 :: ABSTRACT: Prelude.VReg = RegUN @@ -41,7 +41,7 @@ slots_1 :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd1] [] - meth types=[([], Nothing, Just (Bit 1)), ([Bit 1], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 1]), ([Bit 1], Just (Bit 1), [])] port types=D_IN -> Prelude.Bool Q_OUT -> Prelude.Bool ptr :: ABSTRACT: Prelude.VReg = RegUN @@ -56,7 +56,7 @@ ptr :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd5] [] - meth types=[([], Nothing, Just (Bit 5)), ([Bit 5], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 5]), ([Bit 5], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 5 Q_OUT -> Prelude.Bit 5 pred :: ABSTRACT: Prelude.VReg = RegUN @@ -71,7 +71,7 @@ pred :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd1] [] - meth types=[([], Nothing, Just (Bit 1)), ([Bit 1], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 1]), ([Bit 1], Just (Bit 1), [])] port types=D_IN -> Prelude.Bool Q_OUT -> Prelude.Bool -- AP rules diff --git a/testsuite/bsc.evaluator/sysITransformConstantAcrossEquals.atsexpand.expected b/testsuite/bsc.evaluator/sysITransformConstantAcrossEquals.atsexpand.expected index e9b7f4719..bdff286a1 100644 --- a/testsuite/bsc.evaluator/sysITransformConstantAcrossEquals.atsexpand.expected +++ b/testsuite/bsc.evaluator/sysITransformConstantAcrossEquals.atsexpand.expected @@ -26,7 +26,7 @@ r :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd3] [] - meth types=[([], Nothing, Just (Bit 3)), ([Bit 3], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 3]), ([Bit 3], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 3 Q_OUT -> Prelude.Bit 3 x :: ABSTRACT: Prelude.VReg = RegUN @@ -41,7 +41,7 @@ x :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd2] [] - meth types=[([], Nothing, Just (Bit 2)), ([Bit 2], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 2]), ([Bit 2], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 2 Q_OUT -> Prelude.Bit 2 y :: ABSTRACT: Prelude.VReg = RegUN @@ -56,7 +56,7 @@ y :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd2] [] - meth types=[([], Nothing, Just (Bit 2)), ([Bit 2], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 2]), ([Bit 2], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 2 Q_OUT -> Prelude.Bit 2 z :: ABSTRACT: Prelude.VReg = RegUN @@ -71,7 +71,7 @@ z :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd2] [] - meth types=[([], Nothing, Just (Bit 2)), ([Bit 2], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 2]), ([Bit 2], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 2 Q_OUT -> Prelude.Bit 2 -- AP rules diff --git a/testsuite/bsc.evaluator/sysShiftMult.ats.expected b/testsuite/bsc.evaluator/sysShiftMult.ats.expected index 82f846b43..c2250b423 100644 --- a/testsuite/bsc.evaluator/sysShiftMult.ats.expected +++ b/testsuite/bsc.evaluator/sysShiftMult.ats.expected @@ -26,7 +26,7 @@ x :: ABSTRACT: Prelude.VReg = RegN []) [clock { osc: CLK gate: 1'd1 }, reset { wire: RST_N }, 32'd32, 32'd17] [] - meth types=[([], Nothing, Just (Bit 32)), ([Bit 32], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 32]), ([Bit 32], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 32 Q_OUT -> Prelude.Bit 32 y :: ABSTRACT: Prelude.VReg = RegN @@ -41,7 +41,7 @@ y :: ABSTRACT: Prelude.VReg = RegN []) [clock { osc: CLK gate: 1'd1 }, reset { wire: RST_N }, 32'd32, 32'd24] [] - meth types=[([], Nothing, Just (Bit 32)), ([Bit 32], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 32]), ([Bit 32], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 32 Q_OUT -> Prelude.Bit 32 -- AP local definitions diff --git a/testsuite/bsc.if/split/MultiPortAVNoSplit.bs b/testsuite/bsc.if/split/MultiPortAVNoSplit.bs new file mode 100644 index 000000000..d2608e670 --- /dev/null +++ b/testsuite/bsc.if/split/MultiPortAVNoSplit.bs @@ -0,0 +1,24 @@ +package MultiPortAVNoSplit where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- Port-split ActionValue result in iSplitIface (ShallowSplit value stays a +-- tuple, not Bit#(n)), action left unsplit (one rule). +interface Ifc = + avmeth :: ActionValue (ShallowSplit Pair) + +{-# synthesize sysMultiPortAVNoSplit #-} +sysMultiPortAVNoSplit :: Module Ifc +sysMultiPortAVNoSplit = + module + cond :: Reg Bool <- mkRegU + x :: Reg Bool <- mkRegU + interface + avmeth = + do nosplitIf cond (x := True) (x := False) + return (ShallowSplit (Pair { p1 = cond; p2 = x })) diff --git a/testsuite/bsc.if/split/MultiPortAVSplit.bs b/testsuite/bsc.if/split/MultiPortAVSplit.bs new file mode 100644 index 000000000..47d8ddd5a --- /dev/null +++ b/testsuite/bsc.if/split/MultiPortAVSplit.bs @@ -0,0 +1,25 @@ +package MultiPortAVSplit where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- Port-split ActionValue result in iSplitIface: ShallowSplit keeps the value a +-- tuple, not Bit#(n). splitIf also splits the action into two rules (the value +-- is shared). See MultiPortAVNoSplit for the unsplit case. +interface Ifc = + avmeth :: ActionValue (ShallowSplit Pair) + +{-# synthesize sysMultiPortAVSplit #-} +sysMultiPortAVSplit :: Module Ifc +sysMultiPortAVSplit = + module + cond :: Reg Bool <- mkRegU + x :: Reg Bool <- mkRegU + interface + avmeth = + do splitIf cond (x := True) (x := False) + return (ShallowSplit (Pair { p1 = cond; p2 = x })) diff --git a/testsuite/bsc.if/split/splitIf.exp b/testsuite/bsc.if/split/splitIf.exp index 36c6a9671..73758685f 100644 --- a/testsuite/bsc.if/split/splitIf.exp +++ b/testsuite/bsc.if/split/splitIf.exp @@ -119,3 +119,8 @@ count_rules_after_splitIf Cond_AV_NoSplit.bsv 3 {sysCond_AV_NoSplit} {-split-if} count_rules_after_splitIf Cond_MethodArg_Split.bsv 1 {sysCond_MethodArg_Split} count_rules_after_splitIf Cond_MethodArg_NoSplit.bsv 3 {sysCond_MethodArg_NoSplit} {-split-if} +# Port-split ActionValue result in iSplitIface (ShallowSplit value stays a tuple, +# not Bit#(n)). NoSplit: action unsplit; Split: splitIf also splits the action. +count_rules_after_splitIf MultiPortAVNoSplit.bs 1 {sysMultiPortAVNoSplit} +count_rules_after_splitIf MultiPortAVSplit.bs 2 {sysMultiPortAVSplit} + diff --git a/testsuite/bsc.interra/messages/EResources/EResources.bs.bsc-vcomp-out.expected b/testsuite/bsc.interra/messages/EResources/EResources.bs.bsc-vcomp-out.expected index c2834ce68..6b022d6a2 100755 --- a/testsuite/bsc.interra/messages/EResources/EResources.bs.bsc-vcomp-out.expected +++ b/testsuite/bsc.interra/messages/EResources/EResources.bs.bsc-vcomp-out.expected @@ -5,5 +5,5 @@ Verilog file created: subtractor.v code generation for mkDifference starts Error: "EResources.bs", line 43, column 13: (G0002) `m.minus' needs more than 1 ports for the following uses: - `m.minus x__h369 y__h370' at "EResources.bs", line 43, column 13 - `m.minus y__h370 x__h369' at "EResources.bs", line 43, column 13 + `m.minus x___d1 y___d2' at "EResources.bs", line 43, column 13 + `m.minus y___d2 x___d1' at "EResources.bs", line 43, column 13 diff --git a/testsuite/bsc.lib/Prelude/TupleSize.bs b/testsuite/bsc.lib/Prelude/TupleSize.bs index 8596eb9e6..2f05acc21 100644 --- a/testsuite/bsc.lib/Prelude/TupleSize.bs +++ b/testsuite/bsc.lib/Prelude/TupleSize.bs @@ -4,7 +4,7 @@ package TupleSize where -- Helper function that requires TupleSize constraint tupleSize :: (TupleSize t n) => t -> Integer -tupleSize _ = valueOf n +tupleSize _ = valueOf (TTupleSize t) {-# verilog sysTupleSize #-} sysTupleSize :: Module Empty diff --git a/testsuite/bsc.misc/lambda_calculus/lc-sysTb.out.expected b/testsuite/bsc.misc/lambda_calculus/lc-sysTb.out.expected index b8f66649d..d7eb40301 100644 --- a/testsuite/bsc.misc/lambda_calculus/lc-sysTb.out.expected +++ b/testsuite/bsc.misc/lambda_calculus/lc-sysTb.out.expected @@ -31,16 +31,16 @@ dim_sysTb = rule_RL_r0_sysTb :: MOD_sysTb -> (Bool, MOD_sysTb, ()); rule_RL_r0_sysTb = (\ (state0 :: MOD_sysTb) -> - let { (def_c1__h532 :: Bit #51) = meth_read_RegN (inst_c1__sysTb state0) - ; (def_c2__h543 :: Bit #51) = meth_read_RegN (inst_c2__sysTb state0) + let { (def_c2___d6 :: Bit #51) = meth_read_RegN (inst_c2__sysTb state0) + ; (def_c1___d5 :: Bit #51) = meth_read_RegN (inst_c1__sysTb state0) ; (def_state___d2 :: Bit #2) = meth_read_RegN (inst_state__sysTb state0) ; (def_gcd_RDY_start____d1 :: Bool) = meth_RDY_start_sysMethods (inst_gcd__sysTb state0) - ; (def_add___d7 :: Bit #51) = noinline_add def_c1__h532 (3 :: Bit #51) - ; (def_add___d8 :: Bit #51) = noinline_add def_c2__h543 (2 :: Bit #51) + ; (def_add___d7 :: Bit #51) = noinline_add def_c1___d5 (3 :: Bit #51) + ; (def_add___d8 :: Bit #51) = noinline_add def_c2___d6 (2 :: Bit #51) ; (def_state_EQ_0___d3 :: Bool) = primEQ def_state___d2 (0 :: Bit #2) ; (def_gcd_RDY_start_AND_state_EQ_0___d4 :: Bool) = def_gcd_RDY_start____d1 && def_state_EQ_0___d3 ; (act1 :: (Bool, MOD_sysMethods, ())) = - meth_start_sysMethods def_c1__h532 def_c2__h543 (inst_gcd__sysTb state0) + meth_start_sysMethods def_c1___d5 def_c2___d6 (inst_gcd__sysTb state0) ; (guard1 :: Bool) = fst3 act1 ; (state1 :: MOD_sysTb) = state0 { inst_gcd__sysTb = snd3 act1 } ; (act2 :: (Bool, MOD_RegN #51, ())) = meth_write_RegN def_add___d7 (inst_c1__sysTb state1) @@ -58,14 +58,14 @@ rule_RL_r0_sysTb = rule_RL_r1_sysTb :: MOD_sysTb -> (Bool, MOD_sysTb, ()); rule_RL_r1_sysTb = (\ (state0 :: MOD_sysTb) -> - let { (def_c1__h532 :: Bit #51) = meth_read_RegN (inst_c1__sysTb state0) - ; (def_c2__h543 :: Bit #51) = meth_read_RegN (inst_c2__sysTb state0) + let { (def_c2___d6 :: Bit #51) = meth_read_RegN (inst_c2__sysTb state0) + ; (def_c1___d5 :: Bit #51) = meth_read_RegN (inst_c1__sysTb state0) ; (def_state___d2 :: Bit #2) = meth_read_RegN (inst_state__sysTb state0) - ; (def_add___d7 :: Bit #51) = noinline_add def_c1__h532 (3 :: Bit #51) - ; (def_add___d8 :: Bit #51) = noinline_add def_c2__h543 (2 :: Bit #51) + ; (def_add___d7 :: Bit #51) = noinline_add def_c1___d5 (3 :: Bit #51) + ; (def_add___d8 :: Bit #51) = noinline_add def_c2___d6 (2 :: Bit #51) ; (def_state_EQ_1___d9 :: Bool) = primEQ def_state___d2 (1 :: Bit #2) ; (act1 :: (Bool, MOD_sysMethods, Bit #51)) = - meth_start_and_result_sysMethods def_c1__h532 def_c2__h543 (inst_gcd__sysTb state0) + meth_start_and_result_sysMethods def_c1___d5 def_c2___d6 (inst_gcd__sysTb state0) ; (guard1 :: Bool) = fst3 act1 ; (state1 :: MOD_sysTb) = state0 { inst_gcd__sysTb = snd3 act1 } ; (def_gcd_start_and_result___d10 :: Bit #51) = thd act1 @@ -121,8 +121,8 @@ rule_RL_r2_sysTb = rule_RL_exit_sysTb :: MOD_sysTb -> (Bool, MOD_sysTb, ()); rule_RL_exit_sysTb = (\ (state0 :: MOD_sysTb) -> - let { (def_c1__h532 :: Bit #51) = meth_read_RegN (inst_c1__sysTb state0) - ; (def_c1_ULE_100___d21 :: Bool) = primULE def_c1__h532 (100 :: Bit #51) + let { (def_c1___d5 :: Bit #51) = meth_read_RegN (inst_c1__sysTb state0) + ; (def_c1_ULE_100___d21 :: Bool) = primULE def_c1___d5 (100 :: Bit #51) ; (def_TASK_time___d23 :: Bit #64) = (primAny :: Bit #64) } in mktuple (not def_c1_ULE_100___d21) state0 ()); diff --git a/testsuite/bsc.misc/sal/CTX_sysTb.sal.expected b/testsuite/bsc.misc/sal/CTX_sysTb.sal.expected index a2f5775ea..cb4b6d151 100644 --- a/testsuite/bsc.misc/sal/CTX_sysTb.sal.expected +++ b/testsuite/bsc.misc/sal/CTX_sysTb.sal.expected @@ -19,17 +19,17 @@ BEGIN #) ; rule_RL_r0 (state0 : STATE) : [ BOOLEAN, STATE ] = - LET def_c1__h532 : Bit{51}!T = CTX_RegN{51}!meth_read(state0.inst_c1) - IN LET def_c2__h543 : Bit{51}!T = CTX_RegN{51}!meth_read(state0.inst_c2) + LET def_c2___d6 : Bit{51}!T = CTX_RegN{51}!meth_read(state0.inst_c2) + IN LET def_c1___d5 : Bit{51}!T = CTX_RegN{51}!meth_read(state0.inst_c1) IN LET def_state___d2 : Bit{2}!T = CTX_RegN{2}!meth_read(state0.inst_state) IN LET def_gcd_RDY_start____d1 : BOOLEAN = CTX_sysMethods!meth_RDY_start(state0.inst_gcd) - IN LET def_add___d7 : Bit{51}!T = CTX_module_add!fn(def_c1__h532, Bit{51}!mkConst(3)) - IN LET def_add___d8 : Bit{51}!T = CTX_module_add!fn(def_c2__h543, Bit{51}!mkConst(2)) + IN LET def_add___d7 : Bit{51}!T = CTX_module_add!fn(def_c1___d5, Bit{51}!mkConst(3)) + IN LET def_add___d8 : Bit{51}!T = CTX_module_add!fn(def_c2___d6, Bit{51}!mkConst(2)) IN LET def_state_EQ_0___d3 : BOOLEAN = Prim1{2}!primEQ(def_state___d2, Bit{2}!mkConst(0)) IN LET def_gcd_RDY_start_AND_state_EQ_0___d4 : BOOLEAN = def_gcd_RDY_start____d1 AND def_state_EQ_0___d3 IN LET act1 : [ CTX_sysMethods!STATE, Unit!T ] = - CTX_sysMethods!meth_start(def_c1__h532, def_c2__h543, state0.inst_gcd) + CTX_sysMethods!meth_start(def_c1___d5, def_c2___d6, state0.inst_gcd) IN LET state1 : STATE = state0 WITH .inst_gcd := act1.1 IN LET act2 : [ CTX_RegN{51}!STATE, Unit!T ] = CTX_RegN{51}!meth_write(def_add___d7, state1.inst_c1) IN LET state2 : STATE = state1 WITH .inst_c1 := act2.1 @@ -41,14 +41,14 @@ BEGIN IN ( def_gcd_RDY_start_AND_state_EQ_0___d4, state4 ) ; rule_RL_r1 (state0 : STATE) : [ BOOLEAN, STATE ] = - LET def_c1__h532 : Bit{51}!T = CTX_RegN{51}!meth_read(state0.inst_c1) - IN LET def_c2__h543 : Bit{51}!T = CTX_RegN{51}!meth_read(state0.inst_c2) + LET def_c2___d6 : Bit{51}!T = CTX_RegN{51}!meth_read(state0.inst_c2) + IN LET def_c1___d5 : Bit{51}!T = CTX_RegN{51}!meth_read(state0.inst_c1) IN LET def_state___d2 : Bit{2}!T = CTX_RegN{2}!meth_read(state0.inst_state) - IN LET def_add___d7 : Bit{51}!T = CTX_module_add!fn(def_c1__h532, Bit{51}!mkConst(3)) - IN LET def_add___d8 : Bit{51}!T = CTX_module_add!fn(def_c2__h543, Bit{51}!mkConst(2)) + IN LET def_add___d7 : Bit{51}!T = CTX_module_add!fn(def_c1___d5, Bit{51}!mkConst(3)) + IN LET def_add___d8 : Bit{51}!T = CTX_module_add!fn(def_c2___d6, Bit{51}!mkConst(2)) IN LET def_state_EQ_1___d9 : BOOLEAN = Prim1{2}!primEQ(def_state___d2, Bit{2}!mkConst(1)) IN LET act1 : [ CTX_sysMethods!STATE, Bit{51}!T ] = - CTX_sysMethods!meth_start_and_result(def_c1__h532, def_c2__h543, state0.inst_gcd) + CTX_sysMethods!meth_start_and_result(def_c1___d5, def_c2___d6, state0.inst_gcd) IN LET state1 : STATE = state0 WITH .inst_gcd := act1.1 IN LET def_gcd_start_and_result___d10 : Bit{51}!T = act1.2 IN LET def_gcd_start_and_result_0_PLUS_1___d11 : Bit{51}!T = @@ -87,8 +87,8 @@ BEGIN IN ( def_gcd_RDY_result__4_AND_state_EQ_2_5___d16, state2 ) ; rule_RL_exit (state0 : STATE) : [ BOOLEAN, STATE ] = - LET def_c1__h532 : Bit{51}!T = CTX_RegN{51}!meth_read(state0.inst_c1) - IN LET def_c1_ULE_100___d21 : BOOLEAN = Prim1{51}!primULE(def_c1__h532, Bit{51}!mkConst(100)) + LET def_c1___d5 : Bit{51}!T = CTX_RegN{51}!meth_read(state0.inst_c1) + IN LET def_c1_ULE_100___d21 : BOOLEAN = Prim1{51}!primULE(def_c1___d5, Bit{51}!mkConst(100)) IN LET def_TASK_time___d23 : Bit{64}!T = Bit{64}!undef IN ( NOT def_c1_ULE_100___d21, state0 ) ; diff --git a/testsuite/bsc.names/signal_names/LiteralNum_ENotation.bsv.bsc-vcomp-out.expected b/testsuite/bsc.names/signal_names/LiteralNum_ENotation.bsv.bsc-vcomp-out.expected index 4fbc93c46..9e7784b8a 100644 --- a/testsuite/bsc.names/signal_names/LiteralNum_ENotation.bsv.bsc-vcomp-out.expected +++ b/testsuite/bsc.names/signal_names/LiteralNum_ENotation.bsv.bsc-vcomp-out.expected @@ -30,7 +30,7 @@ rg_start :: ABSTRACT: Prelude.VReg = RegN []) [clock { osc: CLK gate: 1'd1 }, reset { wire: RST_N }, 32'd1, 1'd1] [] - meth types=[([], Nothing, Just (Bit 1)), ([Bit 1], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 1]), ([Bit 1], Just (Bit 1), [])] port types=D_IN -> Prelude.Bool Q_OUT -> Prelude.Bool -- AP local definitions diff --git a/testsuite/bsc.names/signal_names/Method.bsv.bsc-vcomp-out.expected b/testsuite/bsc.names/signal_names/Method.bsv.bsc-vcomp-out.expected index 3c77e5980..e7a70d288 100644 --- a/testsuite/bsc.names/signal_names/Method.bsv.bsc-vcomp-out.expected +++ b/testsuite/bsc.names/signal_names/Method.bsv.bsc-vcomp-out.expected @@ -35,9 +35,9 @@ rg :: ABSTRACT: PreludeBSV._PreludeBSV.VRWire103 = RWire [(WSET, WHAS), (WVAL, WGET)]) [32'd8, clock { osc: CLK gate: 1'd1 }, reset { wire: RST_N }] [] - meth types=[([Bit 8], Just (Bit 1), Nothing), - ([], Nothing, Just (Bit 1)), - ([], Nothing, Just (Bit 8))] + meth types=[([Bit 8], Just (Bit 1), []), + ([], Nothing, [Bit 1]), + ([], Nothing, [Bit 8])] port types=WGET -> Prelude.Bit 8 WHAS -> Prelude.Bool WVAL -> Prelude.Bit 8 diff --git a/testsuite/bsc.names/signal_names/MethodActionValue.bsv.bsc-vcomp-out.expected b/testsuite/bsc.names/signal_names/MethodActionValue.bsv.bsc-vcomp-out.expected index 5d88c8eb0..4b22211c9 100644 --- a/testsuite/bsc.names/signal_names/MethodActionValue.bsv.bsc-vcomp-out.expected +++ b/testsuite/bsc.names/signal_names/MethodActionValue.bsv.bsc-vcomp-out.expected @@ -81,7 +81,7 @@ i :: ABSTRACT: MethodActionValue.Ifc­ = mkMethodActionValue_Sub []) [clock { osc: CLK gate: 1'd1 }, reset { wire: RST_N }] [] - meth types=[([], Just (Bit 1), Just (Bit 8)), ([], Nothing, Just (Bit 1))] + meth types=[([], Just (Bit 1), [Bit 8]), ([], Nothing, [Bit 1])] port types=m -> Prelude.Bit 8 -- AP local definitions i_m_PLUS_8___d2 :: Bit 8; diff --git a/testsuite/bsc.names/signal_names/MethodRead.bsv.bsc-vcomp-out.expected b/testsuite/bsc.names/signal_names/MethodRead.bsv.bsc-vcomp-out.expected index d6a707799..bdb5827d3 100644 --- a/testsuite/bsc.names/signal_names/MethodRead.bsv.bsc-vcomp-out.expected +++ b/testsuite/bsc.names/signal_names/MethodRead.bsv.bsc-vcomp-out.expected @@ -29,7 +29,7 @@ rg :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd8] [] - meth types=[([], Nothing, Just (Bit 8)), ([Bit 8], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 8]), ([Bit 8], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 8 Q_OUT -> Prelude.Bit 8 -- AP local definitions diff --git a/testsuite/bsc.scheduler/SplitIf.bsv.bsc-sched-out.expected b/testsuite/bsc.scheduler/SplitIf.bsv.bsc-sched-out.expected index 3b9ed6a6d..08348949d 100644 --- a/testsuite/bsc.scheduler/SplitIf.bsv.bsc-sched-out.expected +++ b/testsuite/bsc.scheduler/SplitIf.bsv.bsc-sched-out.expected @@ -70,7 +70,7 @@ order: [RL_r, RL_toggleDir, RL_done, RL_incr] (dir.read, [(dir.read, 1)]), (dir.write, [(dir.write NOT_dir___d2, 1)]), (test.RDY_xfer, [(test.RDY_xfer, 1)]), - (test.xfer, [(test.xfer dir__h205, 1)])] + (test.xfer, [(test.xfer dir___d1, 1)])] ----- diff --git a/testsuite/bsc.scheduler/SplitIf2.bsv.bsc-sched-out.expected b/testsuite/bsc.scheduler/SplitIf2.bsv.bsc-sched-out.expected index aca7ed8ea..51f702f9d 100644 --- a/testsuite/bsc.scheduler/SplitIf2.bsv.bsc-sched-out.expected +++ b/testsuite/bsc.scheduler/SplitIf2.bsv.bsc-sched-out.expected @@ -75,7 +75,7 @@ order: [RL_r, RL_toggleDir, RL_done, RL_incr] (dir.read, [(dir.read, 1)]), (dir.write, [(dir.write NOT_dir___d2, 1)]), (test.RDY_xfer, [(test.RDY_xfer, 1)]), - (test.xfer, [(test.xfer dir__h208, 1)])] + (test.xfer, [(test.xfer dir___d1, 1)])] ----- diff --git a/testsuite/bsc.scheduler/avmeth/AVArgUse_C.bsv.bsc-sched-out.expected b/testsuite/bsc.scheduler/avmeth/AVArgUse_C.bsv.bsc-sched-out.expected index c2842b2ee..5f1f97015 100644 --- a/testsuite/bsc.scheduler/avmeth/AVArgUse_C.bsv.bsc-sched-out.expected +++ b/testsuite/bsc.scheduler/avmeth/AVArgUse_C.bsv.bsc-sched-out.expected @@ -45,7 +45,7 @@ order: [RL_rA, RL_rB] ----- === resources (AVArgUse_C sysAVArgUse_C): -[(dut.m, [(dut.m r1__h275 32'd1, 1), (dut.m 32'd5 r1__h275, 1)]), +[(dut.m, [(dut.m r1___d1 32'd1, 1), (dut.m 32'd5 r1___d1, 1)]), (r1.read, [(r1.read, 1)]), (r1.write, [(r1.write r1_PLUS_1___d4, 1)])] diff --git a/testsuite/bsc.scheduler/avmeth/AVArgUse_SBR.bsv.bsc-sched-out.expected b/testsuite/bsc.scheduler/avmeth/AVArgUse_SBR.bsv.bsc-sched-out.expected index 61a1e33fd..f3e1b2f46 100644 --- a/testsuite/bsc.scheduler/avmeth/AVArgUse_SBR.bsv.bsc-sched-out.expected +++ b/testsuite/bsc.scheduler/avmeth/AVArgUse_SBR.bsv.bsc-sched-out.expected @@ -43,7 +43,7 @@ order: [RL_rB, RL_rA] ----- === resources (AVArgUse_SBR sysAVArgUse_SBR): -[(dut.m, [(dut.m r1__h275 32'd1, 1), (dut.m 32'd5 r1__h275, 1)]), +[(dut.m, [(dut.m r1___d1 32'd1, 1), (dut.m 32'd5 r1___d1, 1)]), (r1.read, [(r1.read, 1)]), (r1.write, [(r1.write r1_PLUS_1___d4, 1)])] diff --git a/testsuite/bsc.scheduler/paths/AVEnArgMuxPath.bs b/testsuite/bsc.scheduler/paths/AVEnArgMuxPath.bs new file mode 100644 index 000000000..29ba01573 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/AVEnArgMuxPath.bs @@ -0,0 +1,48 @@ +package AVEnArgMuxPath where + +import SplitPorts +import Vector + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- Single-ported combinational lookup submodule (RegFile-like): the read is +-- combinational from the index argument. +interface LookupIfc = + lookup :: Bit 4 -> Bool + +{-# synthesize mkAVEnArgMuxSub #-} +mkAVEnArgMuxSub :: Module LookupIfc +mkAVEnArgMuxSub = + module + rs :: Vector 16 (Reg Bool) <- replicateM (mkReg False) + interface + lookup i = (select rs i)._read + +-- ActionValue method whose SPLIT input port upd_1_p1 selects an index into +-- the single-ported submodule. Because a rule in the same module also uses +-- that one read port, BSC muxes the read index by the method's enable, so +-- the split output port upd_p1 is combinational on BOTH the split input +-- (upd_1_p1) and the enable (EN_upd). This exercises the enable-to-output +-- edge for a split AV result. upd_p2 is registered: no combinational path. +interface AVIfc = + upd :: ShallowSplit Pair -> ActionValue (ShallowSplit Pair) + +{-# synthesize mkAVEnArgMuxPath #-} +mkAVEnArgMuxPath :: Module AVIfc +mkAVEnArgMuxPath = + module + sub <- mkAVEnArgMuxSub + ptr :: Reg (Bit 4) <- mkRegU + r :: Reg Bool <- mkReg False + rules + "bump": when True ==> + action + ptr := ptr + 1 + r := sub.lookup ptr + interface + upd (ShallowSplit a) = + do ptr := ptr + (if a.p1 then 1 else 0) -- makes the rule conflict with the method + return (ShallowSplit (Pair { p1 = sub.lookup (if a.p1 then 3 else 5); p2 = r })) diff --git a/testsuite/bsc.scheduler/paths/AVSplitInPath.bs b/testsuite/bsc.scheduler/paths/AVSplitInPath.bs new file mode 100644 index 000000000..5c8481c3f --- /dev/null +++ b/testsuite/bsc.scheduler/paths/AVSplitInPath.bs @@ -0,0 +1,26 @@ +package AVSplitInPath where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface AVIfc = + -- ActionValue method with BOTH a split input arg and a split result. + -- The output p1 is combinational from the *crossed* input field p2, and + -- the output p2 is combinational from the input field p1. This pins down + -- per-input-port path tracking: each split output port depends on exactly + -- one specific split input port, and the "diagonal" edges are absent. + upd :: ShallowSplit Pair -> ActionValue (ShallowSplit Pair) + +{-# synthesize mkAVSplitInPath #-} +mkAVSplitInPath :: Module AVIfc +mkAVSplitInPath = + module + r :: Reg Bool <- mkReg False + interface + upd (ShallowSplit a) = + do r := a.p1 + return (ShallowSplit (Pair { p1 = a.p2; p2 = a.p1 })) diff --git a/testsuite/bsc.scheduler/paths/AVSubmodInPath.bs b/testsuite/bsc.scheduler/paths/AVSubmodInPath.bs new file mode 100644 index 000000000..8102d3b97 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/AVSubmodInPath.bs @@ -0,0 +1,42 @@ +package AVSubmodInPath where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- A value submodule with a split input and split output: result p1 is +-- combinational from input p1, result p2 from a register. +interface SubIfc = + get :: ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkAVSubmodInSub #-} +mkAVSubmodInSub :: Module SubIfc +mkAVSubmodInSub = + module + r :: Reg Bool <- mkReg False + interface + get (ShallowSplit a) = ShallowSplit (Pair { p1 = a.p1; p2 = r }) + +-- A top-level ActionValue method whose split input arg is wired straight +-- into the submodule's split input, and whose split result is the +-- submodule's split result. This threads per-port paths through a +-- submodule from an AV method: upd_1_p1 -> upd_p1 only. upd_1_p2 reaches +-- only the submodule's registered field, so no path to either output, and +-- upd_p2 (the registered field) has no combinational path at all. +interface AVIfc = + upd :: ShallowSplit Pair -> ActionValue (ShallowSplit Pair) + +{-# synthesize mkAVSubmodInPath #-} +mkAVSubmodInPath :: Module AVIfc +mkAVSubmodInPath = + module + s <- mkAVSubmodInSub + cnt :: Reg Bool <- mkReg False + interface + upd (ShallowSplit a) = + do cnt := a.p2 + case s.get (ShallowSplit a) of + ShallowSplit res -> return (ShallowSplit res) diff --git a/testsuite/bsc.scheduler/paths/ArgSelectorPath.bs b/testsuite/bsc.scheduler/paths/ArgSelectorPath.bs new file mode 100644 index 000000000..82ba75701 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/ArgSelectorPath.bs @@ -0,0 +1,31 @@ +package ArgSelectorPath where + +import SplitPorts + +-- Split input: a selector field, one data field, one unused field. +struct Cmd = + sel :: Bool + d :: Bool + dead :: Bool + deriving (Bits) + +interface TopIfc = + -- split input (3 ports), single unsplit Bool output + run :: ShallowSplit Cmd -> Bool + +-- The synthesized module takes a Bool MODULE ARGUMENT (port input) 'v'. +-- A split method-input field 'sel' selects between the module-argument-driven +-- value 'v' and the split data field 'd'. The path therefore ENTERS via the +-- split method input (run_1_sel / run_1_d) and exits through logic that also +-- depends on the module argument 'v': +-- run = sel ? v : d +-- so the output 'run' is combinationally reachable from run_1_sel, run_1_d, +-- AND the module-argument port v. The unused field 'dead' yields no path. +-- This exercises a split method input feeding a mux whose other leg is the +-- module's own argument port (the missing module-argument + split-input case). +{-# synthesize mkArgSelectorPath #-} +mkArgSelectorPath :: Bool -> Module TopIfc +mkArgSelectorPath v = + module + interface + run (ShallowSplit c) = if c.sel then v else c.d diff --git a/testsuite/bsc.scheduler/paths/DeepLeafBasic.bs b/testsuite/bsc.scheduler/paths/DeepLeafBasic.bs new file mode 100644 index 000000000..f4a1603c0 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/DeepLeafBasic.bs @@ -0,0 +1,28 @@ +package DeepLeafBasic where + +import SplitPorts + +-- Inner nested struct +struct Inner = + a :: Bool + b :: Bool + deriving (Bits) + +-- Outer struct whose fields are themselves structs +struct Outer = + x :: Inner + y :: Inner + deriving (Bits) + +interface Ifc = + get :: DeepSplit Outer -> DeepSplit Outer + +{-# synthesize mkDeepLeafBasic #-} +mkDeepLeafBasic :: Module Ifc +mkDeepLeafBasic = + module + r :: Reg Bool <- mkReg False + interface + get (DeepSplit a) = + DeepSplit (Outer { x = Inner { a = a.x.a; b = r } + ; y = Inner { a = r; b = a.y.b } }) diff --git a/testsuite/bsc.scheduler/paths/DeepLeafConst.bs b/testsuite/bsc.scheduler/paths/DeepLeafConst.bs new file mode 100644 index 000000000..e7fcc5eb0 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/DeepLeafConst.bs @@ -0,0 +1,35 @@ +package DeepLeafConst where + +import SplitPorts + +-- Nested struct (Outer field is itself a struct). +struct Inner = + a :: Bool + b :: Bool + deriving (Bits) + +struct Outer = + x :: Inner + y :: Inner + deriving (Bits) + +interface Ifc = + get :: DeepSplit Outer -> DeepSplit Outer + +-- Each of the four deep leaves is driven by a different kind of source, so +-- path analysis must produce a path for exactly one of them: +-- get_x_a <- a.x.a (combinational input => get_1_x_a -> get_x_a) +-- get_x_b <- True (constant => no path) +-- get_y_a <- r (register => no path) +-- get_y_b <- False (constant => no path) +-- Crucially, only ONE input leaf is even used, so none of the other input +-- leaves (get_1_x_b, get_1_y_a, get_1_y_b) may appear as a path source. +{-# synthesize mkDeepLeafConst #-} +mkDeepLeafConst :: Module Ifc +mkDeepLeafConst = + module + r :: Reg Bool <- mkReg False + interface + get (DeepSplit a) = + DeepSplit (Outer { x = Inner { a = a.x.a; b = True } + ; y = Inner { a = r; b = False } }) diff --git a/testsuite/bsc.scheduler/paths/DeepLeafCross.bs b/testsuite/bsc.scheduler/paths/DeepLeafCross.bs new file mode 100644 index 000000000..8c71fd2e2 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/DeepLeafCross.bs @@ -0,0 +1,34 @@ +package DeepLeafCross where + +import SplitPorts + +-- Nested struct: Outer has two Inner-struct fields. +struct Inner = + a :: Bool + b :: Bool + deriving (Bits) + +struct Outer = + x :: Inner + y :: Inner + deriving (Bits) + +interface Ifc = + -- Deep split: every leaf becomes its own port (get_1_x_a, get_x_a, ...). + get :: DeepSplit Outer -> DeepSplit Outer + +-- The output leaves are wired from *different* input leaves than the +-- same-named one, so path analysis must follow the actual data flow rather +-- than matching port names: +-- get_x_a <- a.y.b (so edge: get_1_y_b -> get_x_a, NOT get_1_x_a) +-- get_y_b <- a.x_a (so edge: get_1_x_a -> get_y_b, NOT get_1_y_b) +-- The other two leaves are registered, so they have no incoming path. +{-# synthesize mkDeepLeafCross #-} +mkDeepLeafCross :: Module Ifc +mkDeepLeafCross = + module + r :: Reg Bool <- mkReg False + interface + get (DeepSplit a) = + DeepSplit (Outer { x = Inner { a = a.y.b; b = r } + ; y = Inner { a = r; b = a.x.a } }) diff --git a/testsuite/bsc.scheduler/paths/DeepLeafLoop.bs b/testsuite/bsc.scheduler/paths/DeepLeafLoop.bs new file mode 100644 index 000000000..f7c4ac1c1 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/DeepLeafLoop.bs @@ -0,0 +1,45 @@ +package DeepLeafLoop where + +import SplitPorts + +-- Nested struct (Outer field is itself a struct), deep-split into leaf ports. +struct Inner = + a :: Bool + b :: Bool + deriving (Bits) + +struct Outer = + x :: Inner + y :: Inner + deriving (Bits) + +interface SubIfc = + -- Deep-split combinational method: each leaf output is wired straight from + -- the matching leaf input, so e.g. get_1_x_a -> get_x_a is combinational. + get :: DeepSplit Outer -> DeepSplit Outer + +{-# synthesize mkDeepLeafLoopSub #-} +mkDeepLeafLoopSub :: Module SubIfc +mkDeepLeafLoopSub = + module + interface + get (DeepSplit a) = + DeepSplit (Outer { x = Inner { a = a.x.a; b = a.x.b } + ; y = Inner { a = a.y.a; b = a.y.b } }) + +-- Close a combinational loop through the submodule's deep leaf port x.a: +-- rw.wget -> get's deep input leaf x.a -> get's deep output leaf x.a -> rw.wset +-- Path analysis must detect this through the per-leaf result node, so +-- compilation fails with G0032. +{-# synthesize mkDeepLeafLoop #-} +mkDeepLeafLoop :: Module Empty +mkDeepLeafLoop = + module + s <- mkDeepLeafLoopSub + rw :: RWire Bool <- mkRWire + let fb = isValid (rw.wget) + rules + "close_loop": when True ==> + case s.get (DeepSplit (Outer { x = Inner { a = fb; b = False } + ; y = Inner { a = False; b = False } })) of + DeepSplit res -> if res.x.a then rw.wset True else noAction diff --git a/testsuite/bsc.scheduler/paths/DeepLeafTwoLevels.bs b/testsuite/bsc.scheduler/paths/DeepLeafTwoLevels.bs new file mode 100644 index 000000000..a10928491 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/DeepLeafTwoLevels.bs @@ -0,0 +1,41 @@ +package DeepLeafTwoLevels where + +import SplitPorts + +-- Three levels of nesting: Top -> Mid -> Leaf. +struct Leaf = + lo :: Bool + hi :: Bool + deriving (Bits) + +struct Mid = + p :: Leaf + q :: Leaf + deriving (Bits) + +struct Top = + m :: Mid + n :: Mid + deriving (Bits) + +interface Ifc = + -- Deep split recurses two levels of nested structs down to leaf ports, + -- e.g. input get_1_m_p_lo, output get_m_p_lo. + get :: DeepSplit Top -> DeepSplit Top + +-- Only two of the eight deep leaves are combinational from their matching +-- input leaf; the rest come from a register. This checks that path analysis +-- reaches two-levels-deep leaf ports and isolates them: +-- get_m_p_lo <- a.m.p.lo => get_1_m_p_lo -> get_m_p_lo +-- get_n_q_hi <- a.n.q.hi => get_1_n_q_hi -> get_n_q_hi +{-# synthesize mkDeepLeafTwoLevels #-} +mkDeepLeafTwoLevels :: Module Ifc +mkDeepLeafTwoLevels = + module + r :: Reg Bool <- mkReg False + interface + get (DeepSplit a) = + DeepSplit (Top { m = Mid { p = Leaf { lo = a.m.p.lo; hi = r } + ; q = Leaf { lo = r; hi = r } } + ; n = Mid { p = Leaf { lo = r; hi = r } + ; q = Leaf { lo = r; hi = a.n.q.hi } } }) diff --git a/testsuite/bsc.scheduler/paths/DeepWireFanout.bs b/testsuite/bsc.scheduler/paths/DeepWireFanout.bs new file mode 100644 index 000000000..15c019985 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/DeepWireFanout.bs @@ -0,0 +1,37 @@ +package DeepWireFanout where + +import SplitPorts + +struct Inner = + x :: Bool + y :: Bool + deriving (Bits) + +struct Outer = + a :: Inner + b :: Bool + deriving (Bits) + +interface Ifc = + -- DeepSplit input recurses to leaf ports (put_1_a_x, put_1_a_y, put_1_b). + -- One Action method forwards ONLY the deep leaf a.x onto a combinational + -- wire; two distinct value methods read it. The single deep leaf input + -- sub-port put_1_a_x fans out to the outputs of TWO different methods, while + -- its siblings put_1_a_y and put_1_b reach neither output. + put :: DeepSplit Outer -> Action + outA :: Bool + outB :: Bool + +{-# synthesize mkDeepWireFanout #-} +mkDeepWireFanout :: Module Ifc +mkDeepWireFanout = + module + w :: RWire Bool <- mkRWire + interface + put (DeepSplit o) = w.wset o.a.x + outA = case w.wget of + Just v -> v + Nothing -> False + outB = case w.wget of + Just v -> not v + Nothing -> True diff --git a/testsuite/bsc.scheduler/paths/EnRdyAVEnResult.bs b/testsuite/bsc.scheduler/paths/EnRdyAVEnResult.bs new file mode 100644 index 000000000..64a8363d5 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/EnRdyAVEnResult.bs @@ -0,0 +1,28 @@ +package EnRdyAVEnResult where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface Ifc = + -- An ActionValue method with a split result. Field p1 is combinational from + -- the split input sub-port (upd_1_p1). Field p2 is combinational from the + -- method's own enable EN_upd: it forwards EN onto an RWire whose validity is + -- read by a separate value method 'busy', so EN_upd reaches RDY/busy while + -- upd_1_p1 reaches the split result port upd_p1. + upd :: ShallowSplit Pair -> ActionValue (ShallowSplit Pair) + busy :: Bool + +{-# synthesize mkEnRdyAVEnResult #-} +mkEnRdyAVEnResult :: Module Ifc +mkEnRdyAVEnResult = + module + w :: RWire Bool <- mkRWire + interface + upd (ShallowSplit a) = + do w.wset a.p2 + return (ShallowSplit (Pair { p1 = a.p1; p2 = a.p2 })) + busy = isValid (w.wget) diff --git a/testsuite/bsc.scheduler/paths/EnRdyDeepEnOut.bs b/testsuite/bsc.scheduler/paths/EnRdyDeepEnOut.bs new file mode 100644 index 000000000..bfe95c146 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/EnRdyDeepEnOut.bs @@ -0,0 +1,32 @@ +package EnRdyDeepEnOut where + +import SplitPorts + +struct Inner = + a :: Bool + b :: Bool + deriving (Bits) + +struct Outer = + x :: Inner + y :: Bool + deriving (Bits) + +interface Ifc = + -- An Action method 'fire' with an enable, and a value method 'rd' whose + -- DEEP-split result has a leaf (x_a) driven combinationally by EN_fire, + -- while sibling leaves (x_b, y) come from registers. Path analysis should + -- report a path only to the deep leaf output port rd_x_a. + fire :: Bool -> Action + rd :: DeepSplit Outer + +{-# synthesize mkEnRdyDeepEnOut #-} +mkEnRdyDeepEnOut :: Module Ifc +mkEnRdyDeepEnOut = + module + w :: RWire Bool <- mkRWire + rb :: Reg Bool <- mkReg False + ry :: Reg Bool <- mkReg False + interface + fire v = w.wset v + rd = DeepSplit (Outer { x = Inner { a = isValid (w.wget); b = rb }; y = ry }) diff --git a/testsuite/bsc.scheduler/paths/EnRdyEnToSplitOut.bs b/testsuite/bsc.scheduler/paths/EnRdyEnToSplitOut.bs new file mode 100644 index 000000000..10e6a5770 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/EnRdyEnToSplitOut.bs @@ -0,0 +1,23 @@ +package EnRdyEnToSplitOut where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface Ifc = + -- An Action method with an enable, plus a value method whose split result + -- depends combinationally on whether that Action method fired (its EN). + doit :: Bool -> Action + rd :: ShallowSplit Pair + +{-# synthesize mkEnRdyEnToSplitOut #-} +mkEnRdyEnToSplitOut :: Module Ifc +mkEnRdyEnToSplitOut = + module + w :: RWire Bool <- mkRWire + interface + doit x = w.wset x + rd = ShallowSplit (Pair { p1 = isValid (w.wget); p2 = False }) diff --git a/testsuite/bsc.scheduler/paths/EnRdyInToRdy.bs b/testsuite/bsc.scheduler/paths/EnRdyInToRdy.bs new file mode 100644 index 000000000..ddc6ef34f --- /dev/null +++ b/testsuite/bsc.scheduler/paths/EnRdyInToRdy.bs @@ -0,0 +1,25 @@ +package EnRdyInToRdy where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface Ifc = + -- 'put' takes a split argument and forwards one sub-port (p1) onto an RWire. + -- 'gate' is a value method whose readiness (RDY) is the *value* carried on + -- that RWire, so RDY_gate combinationally depends on the split input port + -- put_1_p1 (and not on put_1_p2, which is never forwarded). + put :: ShallowSplit Pair -> Action + gate :: Bool + +{-# synthesize mkEnRdyInToRdy #-} +mkEnRdyInToRdy :: Module Ifc +mkEnRdyInToRdy = + module + w :: RWire Bool <- mkRWire + interface + put (ShallowSplit a) = w.wset a.p1 + gate = False when fromMaybe False (w.wget) diff --git a/testsuite/bsc.scheduler/paths/EnRdyTwoEnSplit.bs b/testsuite/bsc.scheduler/paths/EnRdyTwoEnSplit.bs new file mode 100644 index 000000000..170440029 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/EnRdyTwoEnSplit.bs @@ -0,0 +1,29 @@ +package EnRdyTwoEnSplit where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface Ifc = + -- Two independent Action methods, each forwarding onto its own RWire. A + -- value method 'rd' has a split result where p1 is gated by setA's enable and + -- p2 is gated by setB's enable. Path analysis should report EN_setA only to + -- rd_p1 and EN_setB only to rd_p2 (no crossed edges), demonstrating per-port + -- routing of distinct method enables. + setA :: Action + setB :: Action + rd :: ShallowSplit Pair + +{-# synthesize mkEnRdyTwoEnSplit #-} +mkEnRdyTwoEnSplit :: Module Ifc +mkEnRdyTwoEnSplit = + module + wa :: RWire Bool <- mkRWire + wb :: RWire Bool <- mkRWire + interface + setA = wa.wset True + setB = wb.wset True + rd = ShallowSplit (Pair { p1 = isValid (wa.wget); p2 = isValid (wb.wget) }) diff --git a/testsuite/bsc.scheduler/paths/GranDeepNested.bs b/testsuite/bsc.scheduler/paths/GranDeepNested.bs new file mode 100644 index 000000000..6b214c64d --- /dev/null +++ b/testsuite/bsc.scheduler/paths/GranDeepNested.bs @@ -0,0 +1,31 @@ +package GranDeepNested where + +import SplitPorts + +struct Inner = + a :: Bool + b :: Bool + deriving (Bits) + +struct Outer = + x :: Inner + y :: Bool + deriving (Bits) + +-- DeepSplit recurses into the nested struct: the field `x` becomes leaf ports +-- `get_x_a` / `get_x_b` (inputs `get_1_x_a` / `get_1_x_b`), giving per-leaf +-- path granularity. Only x.a is combinational from input x.a, so the path is +-- exactly `get_1_x_a -> get_x_a` and nothing flows to get_x_b or get_y. +-- Contrast with GranShallowNested, where the same struct gives the coarse +-- packed path get_1_x -> get_x. +interface Ifc = + get :: DeepSplit Outer -> DeepSplit Outer + +{-# synthesize mkGranDeepNested #-} +mkGranDeepNested :: Module Ifc +mkGranDeepNested = + module + r :: Reg Bool <- mkReg False + interface + get (DeepSplit o) = + DeepSplit (Outer { x = Inner { a = o.x.a; b = r }; y = r }) diff --git a/testsuite/bsc.scheduler/paths/GranNoSplit.bs b/testsuite/bsc.scheduler/paths/GranNoSplit.bs new file mode 100644 index 000000000..2d4bd738a --- /dev/null +++ b/testsuite/bsc.scheduler/paths/GranNoSplit.bs @@ -0,0 +1,30 @@ +package GranNoSplit where + +import SplitPorts + +struct Inner = + a :: Bool + b :: Bool + deriving (Bits) + +-- The field `x` is wrapped in NoSplit, which terminates the DeepSplit +-- recursion: instead of leaf ports x_a / x_b, x stays as ONE packed port +-- get_x (input get_1_x). The field `y` is an ordinary leaf. So this is a +-- middle ground between Shallow and Deep: DeepSplit everywhere except where +-- NoSplit caps it. +struct Outer = + x :: NoSplit Inner + y :: Bool + deriving (Bits) + +interface Ifc = + get :: DeepSplit Outer -> DeepSplit Outer + +{-# synthesize mkGranNoSplit #-} +mkGranNoSplit :: Module Ifc +mkGranNoSplit = + module + r :: Reg Bool <- mkReg False + interface + get (DeepSplit o) = + DeepSplit (Outer { x = o.x; y = r }) diff --git a/testsuite/bsc.scheduler/paths/GranShallowNested.bs b/testsuite/bsc.scheduler/paths/GranShallowNested.bs new file mode 100644 index 000000000..11f2eb69d --- /dev/null +++ b/testsuite/bsc.scheduler/paths/GranShallowNested.bs @@ -0,0 +1,30 @@ +package GranShallowNested where + +import SplitPorts + +struct Inner = + a :: Bool + b :: Bool + deriving (Bits) + +struct Outer = + x :: Inner + y :: Bool + deriving (Bits) + +-- ShallowSplit splits only the TOP level: the nested struct field `x` stays +-- PACKED as a single port `get_x` (and input `get_1_x`), while `y` is its own +-- port. So even though only x.a is combinational from the input, the whole +-- packed `x` port carries the path; there is no per-leaf granularity. +interface Ifc = + get :: ShallowSplit Outer -> ShallowSplit Outer + +{-# synthesize mkGranShallowNested #-} +mkGranShallowNested :: Module Ifc +mkGranShallowNested = + module + r :: Reg Bool <- mkReg False + interface + -- x.a is combinational from input x.a; x.b is registered; y is registered + get (ShallowSplit o) = + ShallowSplit (Outer { x = Inner { a = o.x.a; b = r }; y = r }) diff --git a/testsuite/bsc.scheduler/paths/GranTwoArgs.bs b/testsuite/bsc.scheduler/paths/GranTwoArgs.bs new file mode 100644 index 000000000..6eb658176 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/GranTwoArgs.bs @@ -0,0 +1,27 @@ +package GranTwoArgs where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- A value method with TWO split arguments, named "lhs"/"rhs" via the arg_names +-- pragma. Each argument is split into its own field ports (combine_lhs_p1, +-- combine_rhs_p2, ...) and the result is split too. The result field p1 is +-- combinational from the lhs argument's p1, and result field p2 is +-- combinational from the rhs argument's p2. Path analysis must distinguish +-- sub-ports of arg lhs vs arg rhs: the path goes lhs_p1 -> p1 and rhs_p2 -> p2, +-- but NOT the cross edges lhs_p2 -> p2 or rhs_p1 -> p1. +interface Ifc = + combine :: ShallowSplit Pair -> ShallowSplit Pair -> ShallowSplit Pair + {-# arg_names = ["lhs", "rhs"] #-} + +{-# synthesize mkGranTwoArgs #-} +mkGranTwoArgs :: Module Ifc +mkGranTwoArgs = + module + interface + combine (ShallowSplit l) (ShallowSplit r) = + ShallowSplit (Pair { p1 = l.p1; p2 = r.p2 }) diff --git a/testsuite/bsc.scheduler/paths/GranVec.bs b/testsuite/bsc.scheduler/paths/GranVec.bs new file mode 100644 index 000000000..d4f2d669e --- /dev/null +++ b/testsuite/bsc.scheduler/paths/GranVec.bs @@ -0,0 +1,22 @@ +package GranVec where + +import SplitPorts +import Vector + +-- DeepSplit of a (Vector 3 Bool) result produces one output port per element +-- (get_0, get_1, get_2), and the split argument produces one input port per +-- element (get_1_0, get_1_1, get_1_2; the leading 1 is the argument number). +-- Element 2 of the result is combinational from element 2 of the input; the +-- other elements come from a register. Path analysis should report exactly +-- the element-2 edge get_1_2 -> get_2 and no path to get_0 / get_1. +interface Ifc = + get :: DeepSplit (Vector 3 Bool) -> DeepSplit (Vector 3 Bool) + +{-# synthesize mkGranVec #-} +mkGranVec :: Module Ifc +mkGranVec = + module + r :: Reg Bool <- mkReg False + interface + get (DeepSplit v) = + DeepSplit (update (replicate r) 2 (v !! 2)) diff --git a/testsuite/bsc.scheduler/paths/IOMatrixCombine.bs b/testsuite/bsc.scheduler/paths/IOMatrixCombine.bs new file mode 100644 index 000000000..148e31ef0 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/IOMatrixCombine.bs @@ -0,0 +1,23 @@ +package IOMatrixCombine where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface Ifc = + -- A value method whose split output field p1 COMBINES both split input + -- fields (p1 && p2), while output field p2 comes from a register. Path + -- analysis must report TWO edges fanning into get_p1 (from both input + -- ports) and NO edge into get_p2. + get :: ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkIOMatrixCombine #-} +mkIOMatrixCombine :: Module Ifc +mkIOMatrixCombine = + module + r :: Reg Bool <- mkReg False + interface + get (ShallowSplit a) = ShallowSplit (Pair { p1 = a.p1 && a.p2; p2 = r }) diff --git a/testsuite/bsc.scheduler/paths/IOMatrixCross.bs b/testsuite/bsc.scheduler/paths/IOMatrixCross.bs new file mode 100644 index 000000000..734b05674 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/IOMatrixCross.bs @@ -0,0 +1,22 @@ +package IOMatrixCross where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface Ifc = + -- A value method whose split result CROSSES the split input: output field + -- p1 is wired from input field p2, and output field p2 is wired from input + -- field p1. Path analysis must report exactly the crossed edges and NONE + -- of the straight-through edges. + get :: ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkIOMatrixCross #-} +mkIOMatrixCross :: Module Ifc +mkIOMatrixCross = + module + interface + get (ShallowSplit a) = ShallowSplit (Pair { p1 = a.p2; p2 = a.p1 }) diff --git a/testsuite/bsc.scheduler/paths/IOMatrixDeepCombine.bs b/testsuite/bsc.scheduler/paths/IOMatrixDeepCombine.bs new file mode 100644 index 000000000..c15db1ba8 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/IOMatrixDeepCombine.bs @@ -0,0 +1,31 @@ +package IOMatrixDeepCombine where + +import SplitPorts + +struct Inner = + a :: Bool + b :: Bool + deriving (Bits) + +struct Outer = + x :: Inner + y :: Bool + deriving (Bits) + +interface Ifc = + -- DeepSplit recurses into Inner. The two inner output leaves each COMBINE + -- disjoint pairs of input leaves: out x_a <= (in x_a && in y), and + -- out x_b <= (in x_b && in y). The top-level output y comes from a + -- register, so it has NO incoming combinational path. Path analysis must + -- report the two combined deep edges into x_a and x_b and NO edge into y. + get :: DeepSplit Outer -> DeepSplit Outer + +{-# synthesize mkIOMatrixDeepCombine #-} +mkIOMatrixDeepCombine :: Module Ifc +mkIOMatrixDeepCombine = + module + r :: Reg Bool <- mkReg False + interface + get (DeepSplit o) = + DeepSplit (Outer { x = Inner { a = o.x.a && o.y; b = o.x.b && o.y } + ; y = r }) diff --git a/testsuite/bsc.scheduler/paths/IOMatrixDeepCross.bs b/testsuite/bsc.scheduler/paths/IOMatrixDeepCross.bs new file mode 100644 index 000000000..15fc9ae9b --- /dev/null +++ b/testsuite/bsc.scheduler/paths/IOMatrixDeepCross.bs @@ -0,0 +1,30 @@ +package IOMatrixDeepCross where + +import SplitPorts + +struct Inner = + a :: Bool + b :: Bool + deriving (Bits) + +struct Outer = + x :: Inner + y :: Bool + deriving (Bits) + +interface Ifc = + -- DeepSplit recurses into the nested Inner struct, giving leaf ports + -- get_1_x_a, get_1_x_b, get_1_y on the input and get_x_a, get_x_b, get_y + -- on the output. The wiring CROSSES the two inner leaves (out x_a <= in + -- x_b, out x_b <= in x_a) and passes the top-level y straight through. + -- Path analysis must report the crossed deep edges and the straight y edge, + -- and NONE of the straight inner edges. + get :: DeepSplit Outer -> DeepSplit Outer + +{-# synthesize mkIOMatrixDeepCross #-} +mkIOMatrixDeepCross :: Module Ifc +mkIOMatrixDeepCross = + module + interface + get (DeepSplit o) = + DeepSplit (Outer { x = Inner { a = o.x.b; b = o.x.a }; y = o.y }) diff --git a/testsuite/bsc.scheduler/paths/IOMatrixFanout.bs b/testsuite/bsc.scheduler/paths/IOMatrixFanout.bs new file mode 100644 index 000000000..27af864ca --- /dev/null +++ b/testsuite/bsc.scheduler/paths/IOMatrixFanout.bs @@ -0,0 +1,22 @@ +package IOMatrixFanout where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface Ifc = + -- A value method whose single split input field p1 FANS OUT to BOTH split + -- output fields (p1 = a.p1, p2 = not a.p1), while input field p2 feeds + -- nothing. Path analysis must report two edges OUT of get_1_p1 (to both + -- output ports) and NO edge from get_1_p2. + get :: ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkIOMatrixFanout #-} +mkIOMatrixFanout :: Module Ifc +mkIOMatrixFanout = + module + interface + get (ShallowSplit a) = ShallowSplit (Pair { p1 = a.p1; p2 = not a.p1 }) diff --git a/testsuite/bsc.scheduler/paths/LoopAVPortLoop.bs b/testsuite/bsc.scheduler/paths/LoopAVPortLoop.bs new file mode 100644 index 000000000..c776a0d3e --- /dev/null +++ b/testsuite/bsc.scheduler/paths/LoopAVPortLoop.bs @@ -0,0 +1,41 @@ +package LoopAVPortLoop where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- An ActionValue method with a split argument and a split result whose output +-- port p1 is combinational from input port p1. (p2 comes from a register.) +interface AVIfc = + upd :: ShallowSplit Pair -> ActionValue (ShallowSplit Pair) + +{-# synthesize mkLoopAVPortLoopSub #-} +mkLoopAVPortLoopSub :: Module AVIfc +mkLoopAVPortLoopSub = + module + r :: Reg Bool <- mkReg False + interface + upd (ShallowSplit a) = + do r := a.p2 + return (ShallowSplit (Pair { p1 = a.p1; p2 = r })) + +-- Close a combinational loop through the ActionValue method's split ports: +-- rw.wget -> upd's split input p1 -> upd's split output p1 -> rw.wset +-- The AV result is consumed combinationally and drives the same RWire whose +-- value feeds the AV input, so the cycle runs through "Argument 1" and +-- "Return value 1" of the ActionValue method `upd` => G0032. +{-# synthesize mkLoopAVPortLoop #-} +mkLoopAVPortLoop :: Module Empty +mkLoopAVPortLoop = + module + s <- mkLoopAVPortLoopSub + rw :: RWire Bool <- mkRWire + let fb = isValid (rw.wget) + rules + "close": when True ==> + do res <- s.upd (ShallowSplit (Pair { p1 = fb; p2 = False })) + case res of + ShallowSplit v -> if v.p1 then rw.wset True else noAction diff --git a/testsuite/bsc.scheduler/paths/LoopConfinedArg2.bs b/testsuite/bsc.scheduler/paths/LoopConfinedArg2.bs new file mode 100644 index 000000000..153a8481e --- /dev/null +++ b/testsuite/bsc.scheduler/paths/LoopConfinedArg2.bs @@ -0,0 +1,47 @@ +package LoopConfinedArg2 where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- A TWO-argument method. Each argument is a split Pair, so the method has +-- split input ports op_1_p1/op_1_p2 (argument 1) and op_2_p1/op_2_p2 +-- (argument 2). The split result field p1 is combinational ONLY from the +-- SECOND argument's field p1; result field p2 just passes the first argument's +-- field p1 through. +interface SubIfc = + op :: ShallowSplit Pair -> ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkLoopConfinedArg2Sub #-} +mkLoopConfinedArg2Sub :: Module SubIfc +mkLoopConfinedArg2Sub = + module + interface + op (ShallowSplit x) (ShallowSplit y) = + ShallowSplit (Pair { p1 = y.p1; p2 = x.p1 }) + +-- Close a genuine combinational loop confined to the SECOND argument: +-- rw.wget -> op's argument-2 split input p1 -> op's split output p1 -> rw.wset +-- Argument 1 is fed a constant and its contribution (result p2) is sunk into a +-- register, so argument 1's ports are NOT part of the cycle. G0032 must name +-- "Argument 2"/"Return value 1" of method `op' and NOT "Argument 1". This +-- exercises per-port precision on the ARGUMENT index (with multiple split +-- arguments), the counterpart to the single-argument no-loop tests. +{-# synthesize mkLoopConfinedArg2 #-} +mkLoopConfinedArg2 :: Module Empty +mkLoopConfinedArg2 = + module + s <- mkLoopConfinedArg2Sub + rw :: RWire Bool <- mkRWire + sink :: Reg Bool <- mkReg False + let fb = isValid (rw.wget) + rules + "close_arg2_only": when True ==> + case s.op (ShallowSplit (Pair { p1 = False; p2 = False })) + (ShallowSplit (Pair { p1 = fb; p2 = False })) of + ShallowSplit res -> + do (if res.p1 then rw.wset True else noAction) + sink := res.p2 diff --git a/testsuite/bsc.scheduler/paths/LoopConfinedP1.bs b/testsuite/bsc.scheduler/paths/LoopConfinedP1.bs new file mode 100644 index 000000000..8b2935391 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/LoopConfinedP1.bs @@ -0,0 +1,44 @@ +package LoopConfinedP1 where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- A submodule whose split output port p1 is combinational from split input +-- port p1, while output port p2 is combinational from input port p2 -- the +-- two split fields are kept on INDEPENDENT combinational paths (no crossing). +interface SubIfc = + get :: ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkLoopConfinedP1Sub #-} +mkLoopConfinedP1Sub :: Module SubIfc +mkLoopConfinedP1Sub = + module + interface + get (ShallowSplit a) = ShallowSplit (Pair { p1 = a.p1; p2 = a.p2 }) + +-- Close a genuine combinational loop through ONLY split field p1: +-- rw1.wget -> get's split input p1 -> get's split output p1 -> rw1.wset +-- Split field p2 is driven by a CONSTANT into the input and its output is +-- consumed by a register write (no feedback), so p2's ports cannot be part of +-- any cycle. The cycle therefore runs through "Argument 1"/"Return value 1" +-- of method `get' but NOT "Argument 2"/"Return value 2". This is the per-port +-- precision counterpart to the passing no-loop tests: G0032 must name exactly +-- the p1 port and never the p2 port. +{-# synthesize mkLoopConfinedP1 #-} +mkLoopConfinedP1 :: Module Empty +mkLoopConfinedP1 = + module + s <- mkLoopConfinedP1Sub + rw1 :: RWire Bool <- mkRWire + sink :: Reg Bool <- mkReg False + let fb = isValid (rw1.wget) + rules + "close_p1_only": when True ==> + case s.get (ShallowSplit (Pair { p1 = fb; p2 = False })) of + ShallowSplit res -> + do (if res.p1 then rw1.wset True else noAction) + sink := res.p2 diff --git a/testsuite/bsc.scheduler/paths/LoopConfinedP2.bs b/testsuite/bsc.scheduler/paths/LoopConfinedP2.bs new file mode 100644 index 000000000..9e2646a08 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/LoopConfinedP2.bs @@ -0,0 +1,43 @@ +package LoopConfinedP2 where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- Same independent-paths submodule as the p1 case: output p1 from input p1, +-- output p2 from input p2 (no field crossing). +interface SubIfc = + get :: ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkLoopConfinedP2Sub #-} +mkLoopConfinedP2Sub :: Module SubIfc +mkLoopConfinedP2Sub = + module + interface + get (ShallowSplit a) = ShallowSplit (Pair { p1 = a.p1; p2 = a.p2 }) + +-- Mirror image of LoopConfinedP1: close the genuine combinational loop through +-- ONLY split field p2: +-- rw2.wget -> get's split input p2 -> get's split output p2 -> rw2.wset +-- Field p1 is fed a constant and its output is sunk to a register, so p1's +-- ports are NOT part of the cycle. G0032 must name "Argument 2"/"Return +-- value 2" of method `get' and NOT "Return value 1". Together with +-- LoopConfinedP1 this proves the positional port index in the cycle report +-- genuinely discriminates the offending split field (it is not always "1"). +{-# synthesize mkLoopConfinedP2 #-} +mkLoopConfinedP2 :: Module Empty +mkLoopConfinedP2 = + module + s <- mkLoopConfinedP2Sub + rw2 :: RWire Bool <- mkRWire + sink :: Reg Bool <- mkReg False + let fb = isValid (rw2.wget) + rules + "close_p2_only": when True ==> + case s.get (ShallowSplit (Pair { p1 = False; p2 = fb })) of + ShallowSplit res -> + do (if res.p2 then rw2.wset True else noAction) + sink := res.p1 diff --git a/testsuite/bsc.scheduler/paths/LoopInputArgLoop.bs b/testsuite/bsc.scheduler/paths/LoopInputArgLoop.bs new file mode 100644 index 000000000..ae22a71a0 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/LoopInputArgLoop.bs @@ -0,0 +1,37 @@ +package LoopInputArgLoop where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- A submodule that combinationally SWAPS its split fields: +-- out_p1 = in_p2 and out_p2 = in_p1 +-- So output port p2 depends on input port p1 (and vice versa). +interface SubIfc = + get :: ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkLoopInputArgLoopSub #-} +mkLoopInputArgLoopSub :: Module SubIfc +mkLoopInputArgLoopSub = + module + interface + get (ShallowSplit a) = ShallowSplit (Pair { p1 = a.p2; p2 = a.p1 }) + +-- Close a combinational loop that re-enters the SPLIT INPUT arg port p1: +-- rw.wget -> get's split input p1 -> (swap) -> get's split output p2 -> rw.wset +-- The cycle passes through "Argument 1 ... get" (the split p1 input port) and +-- the swapped output p2. Per-port input tracking must detect it => G0032. +{-# synthesize mkLoopInputArgLoop #-} +mkLoopInputArgLoop :: Module Empty +mkLoopInputArgLoop = + module + s <- mkLoopInputArgLoopSub + rw :: RWire Bool <- mkRWire + let fb = isValid (rw.wget) + rules + "close": when True ==> + case s.get (ShallowSplit (Pair { p1 = fb; p2 = False })) of + ShallowSplit res -> if res.p2 then rw.wset True else noAction diff --git a/testsuite/bsc.scheduler/paths/LoopNoFalseLoop.bs b/testsuite/bsc.scheduler/paths/LoopNoFalseLoop.bs new file mode 100644 index 000000000..2f70b1dc4 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/LoopNoFalseLoop.bs @@ -0,0 +1,46 @@ +package LoopNoFalseLoop where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- Submodule split output: p1 is combinational from split input p1, p2 from a +-- register. Crucially, output p1 depends ONLY on input p1 (not on input p2). +interface SubIfc = + get :: ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkLoopNoFalseLoopSub #-} +mkLoopNoFalseLoopSub :: Module SubIfc +mkLoopNoFalseLoopSub = + module + r :: Reg Bool <- mkReg False + interface + get (ShallowSplit a) = ShallowSplit (Pair { p1 = a.p1; p2 = r }) + +interface TopIfc = + top :: Bool -> Bool + +-- The top's value method feeds its input into submodule g1's split input p1, +-- then feeds g1's combinational split OUTPUT p1 into submodule g2's split INPUT +-- p2, returning g2's split output p1. Because out-p1 depends only on in-p1 +-- (never in-p2), routing a value into g2.in_p2 cannot close a cycle: the chain +-- top -> g1.in_p1 -> g1.out_p1 -> g2.in_p2 (dead end; out never reads in_p2) +-- and the returned value comes from g2.in_p1 = x, so the only real path is +-- top -> top. Per-port tracking proves there is NO combinational loop; with +-- packed ports the whole-struct feedback would risk a false loop. +{-# synthesize mkLoopNoFalseLoop #-} +mkLoopNoFalseLoop :: Module TopIfc +mkLoopNoFalseLoop = + module + g1 <- mkLoopNoFalseLoopSub + g2 <- mkLoopNoFalseLoopSub + interface + top x = + let firstOut = case g1.get (ShallowSplit (Pair { p1 = x; p2 = False })) of + ShallowSplit r1 -> r1.p1 + secondOut = case g2.get (ShallowSplit (Pair { p1 = x; p2 = firstOut })) of + ShallowSplit r2 -> r2.p1 + in secondOut diff --git a/testsuite/bsc.scheduler/paths/LoopSwapNoLoop.bs b/testsuite/bsc.scheduler/paths/LoopSwapNoLoop.bs new file mode 100644 index 000000000..ede72d750 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/LoopSwapNoLoop.bs @@ -0,0 +1,40 @@ +package LoopSwapNoLoop where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- The same combinational SWAP submodule as the input-arg loop test: +-- out_p1 = in_p2 and out_p2 = in_p1 +interface SubIfc = + get :: ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkLoopSwapNoLoopSub #-} +mkLoopSwapNoLoopSub :: Module SubIfc +mkLoopSwapNoLoopSub = + module + interface + get (ShallowSplit a) = ShallowSplit (Pair { p1 = a.p2; p2 = a.p1 }) + +interface TopIfc = + top :: Bool -> Bool + +-- Feed the top input into the swap submodule's split INPUT p1, but RETURN the +-- swap submodule's split OUTPUT p1. Because out_p1 = in_p2 (NOT in_p1), the +-- value that came in on in_p1 only reaches out_p2, which is discarded here. +-- So the only real combinational path is from the constant on in_p2... and the +-- top input that drives in_p1 reaches NO output port. Per-port tracking +-- discriminates the swapped ports, so there is NO path top_1 -> top and (had a +-- feedback been wired) NO loop. Sibling to LoopInputArgLoop, which DOES loop +-- because it reads the swapped out_p2. +{-# synthesize mkLoopSwapNoLoop #-} +mkLoopSwapNoLoop :: Module TopIfc +mkLoopSwapNoLoop = + module + s <- mkLoopSwapNoLoopSub + interface + top x = case s.get (ShallowSplit (Pair { p1 = x; p2 = False })) of + ShallowSplit res -> res.p1 diff --git a/testsuite/bsc.scheduler/paths/MaybeDeep.bs b/testsuite/bsc.scheduler/paths/MaybeDeep.bs new file mode 100644 index 000000000..e5be13a0b --- /dev/null +++ b/testsuite/bsc.scheduler/paths/MaybeDeep.bs @@ -0,0 +1,30 @@ +package MaybeDeep where + +import SplitPorts + +-- Outer struct that is DeepSplit. Its 'lo' field is a plain Bool (a leaf +-- port), and its 'mb' field is a Maybe Bool. DeepSplit recurses into the +-- struct fields, but Maybe has 2 constructors, so the DeepSplitPorts' +-- recursion TERMINATES at 'mb', producing a single packed port (tag+payload) +-- rather than separate tag/payload ports. +struct Outer = + lo :: Bool + mb :: Maybe Bool + deriving (Bits) + +interface Ifc = + get :: DeepSplit Outer -> DeepSplit Outer + +{-# synthesize mkMaybeDeep #-} +mkMaybeDeep :: Module Ifc +mkMaybeDeep = + module + r :: Reg Bool <- mkReg False + interface + get (DeepSplit a) = + -- The single packed union output (mb) is built combinationally from + -- the packed union input (mb): tag and payload both flow through. + -- The leaf output lo comes from a register, so it has no path, and the + -- leaf input lo is unused. + DeepSplit (Outer { lo = r + ; mb = if isValid a.mb then a.mb else Invalid }) diff --git a/testsuite/bsc.scheduler/paths/MaybeShallow.bs b/testsuite/bsc.scheduler/paths/MaybeShallow.bs new file mode 100644 index 000000000..e53fd2616 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/MaybeShallow.bs @@ -0,0 +1,25 @@ +package MaybeShallow where + +import SplitPorts + +-- A struct with one plain field and one Maybe field. Maybe is a +-- 2-constructor (tagged-union) type, so even a ShallowSplit must keep it +-- packed as a single port (tag + payload together), rather than splitting it. +struct Rec = + flag :: Bool + mb :: Maybe Bool + deriving (Bits) + +interface Ifc = + get :: ShallowSplit Rec -> ShallowSplit Rec + +{-# synthesize mkMaybeShallow #-} +mkMaybeShallow :: Module Ifc +mkMaybeShallow = + module + r :: Reg (Maybe Bool) <- mkReg Nothing + interface + get (ShallowSplit a) = + -- flag is combinational from the (packed Maybe) input mb; + -- the output mb field comes from a register, so no path to it. + ShallowSplit (Rec { flag = isValid a.mb; mb = r }) diff --git a/testsuite/bsc.scheduler/paths/PackedInSplitOut.bs b/testsuite/bsc.scheduler/paths/PackedInSplitOut.bs new file mode 100644 index 000000000..cc7c4e1d3 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/PackedInSplitOut.bs @@ -0,0 +1,23 @@ +package PackedInSplitOut where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface Ifc = + -- Mixed-kind method (reverse direction): a single PACKED Bool argument feeds + -- a SPLIT result. The plain input fans into the first split output field + -- (get_p1) combinationally; the second split output field (get_p2) comes from + -- a register. So analysis should report get_1 -> get_p1 but NOT get_1 -> get_p2. + get :: Bool -> ShallowSplit Pair + +{-# synthesize mkPackedInSplitOut #-} +mkPackedInSplitOut :: Module Ifc +mkPackedInSplitOut = + module + r :: Reg Bool <- mkReg False + interface + get b = ShallowSplit (Pair { p1 = b; p2 = r }) diff --git a/testsuite/bsc.scheduler/paths/RWireFanout.bs b/testsuite/bsc.scheduler/paths/RWireFanout.bs new file mode 100644 index 000000000..8c74d1119 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/RWireFanout.bs @@ -0,0 +1,32 @@ +package RWireFanout where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface Ifc = + -- One Action method takes a split input (p1, p2) and forwards ONLY field + -- p1 onto a combinational RWire. Two distinct value methods (outA, outB) + -- both read that wire. So the single split input sub-port put_1_p1 fans out + -- combinationally to the outputs of TWO different methods, while its sibling + -- field put_1_p2 (never written to the wire) reaches neither output. + put :: ShallowSplit Pair -> Action + outA :: Bool + outB :: Bool + +{-# synthesize mkRWireFanout #-} +mkRWireFanout :: Module Ifc +mkRWireFanout = + module + w :: RWire Bool <- mkRWire + interface + put (ShallowSplit a) = w.wset a.p1 + outA = case w.wget of + Just v -> v + Nothing -> False + outB = case w.wget of + Just v -> not v + Nothing -> False diff --git a/testsuite/bsc.scheduler/paths/SelectorMuxPath.bs b/testsuite/bsc.scheduler/paths/SelectorMuxPath.bs new file mode 100644 index 000000000..1b481c045 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/SelectorMuxPath.bs @@ -0,0 +1,55 @@ +package SelectorMuxPath where + +import SplitPorts +import Vector + +-- Split input has a selector field plus two data fields and one unused field. +-- The selector field (sel) chooses which of TWO combinational submodule reads +-- is forwarded to the (single, unsplit) output. +struct Cmd = + sel :: Bool + a :: Bit 4 + b :: Bit 4 + dead :: Bit 4 + deriving (Bits) + +-- A single-ported combinational lookup submodule (RegFile-like): the read is +-- combinational from the index argument. +interface LookupIfc = + lookup :: Bit 4 -> Bool + +{-# synthesize mkSelectorMuxSubA #-} +mkSelectorMuxSubA :: Module LookupIfc +mkSelectorMuxSubA = + module + rs :: Vector 16 (Reg Bool) <- replicateM (mkReg False) + interface + lookup i = (select rs i)._read + +{-# synthesize mkSelectorMuxSubB #-} +mkSelectorMuxSubB :: Module LookupIfc +mkSelectorMuxSubB = + module + rs :: Vector 16 (Reg Bool) <- replicateM (mkReg False) + interface + lookup i = (select rs i)._read + +interface TopIfc = + -- split input (Cmd -> 4 ports), single unsplit Bool output + run :: ShallowSplit Cmd -> Bool + +-- The split input field 'sel' index-selects between two distinct combinational +-- submodule reads: subA.lookup indexed by the 'a' data field, subB.lookup +-- indexed by the 'b' data field. Because the mux is data-dependent on the +-- split fields, the single output 'run' is combinationally reachable from the +-- selector port (run_1_sel) AND from BOTH selected data ports (run_1_a, +-- run_1_b). The 'dead' field drives nothing, so run_1_dead must NOT appear. +{-# synthesize mkSelectorMuxPath #-} +mkSelectorMuxPath :: Module TopIfc +mkSelectorMuxPath = + module + subA <- mkSelectorMuxSubA + subB <- mkSelectorMuxSubB + interface + run (ShallowSplit c) = + if c.sel then subA.lookup c.a else subB.lookup c.b diff --git a/testsuite/bsc.scheduler/paths/SelectorSplitOutPath.bs b/testsuite/bsc.scheduler/paths/SelectorSplitOutPath.bs new file mode 100644 index 000000000..b9b012d37 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/SelectorSplitOutPath.bs @@ -0,0 +1,64 @@ +package SelectorSplitOutPath where + +import SplitPorts +import Vector + +-- Split input: a selector field plus two data fields and one unused field. +struct Cmd = + sel :: Bool + a :: Bit 4 + b :: Bit 4 + dead :: Bit 4 + deriving (Bits) + +-- Split output with two independent fields. +struct Out = + o1 :: Bool + o2 :: Bool + deriving (Bits) + +-- Single-ported combinational lookup submodule. +interface LookupIfc = + lookup :: Bit 4 -> Bool + +{-# synthesize mkSelectorSplitOutSubA #-} +mkSelectorSplitOutSubA :: Module LookupIfc +mkSelectorSplitOutSubA = + module + rs :: Vector 16 (Reg Bool) <- replicateM (mkReg False) + interface + lookup i = (select rs i)._read + +{-# synthesize mkSelectorSplitOutSubB #-} +mkSelectorSplitOutSubB :: Module LookupIfc +mkSelectorSplitOutSubB = + module + rs :: Vector 16 (Reg Bool) <- replicateM (mkReg False) + interface + lookup i = (select rs i)._read + +interface TopIfc = + -- both split input (4 ports) and split output (2 ports) + run :: ShallowSplit Cmd -> ShallowSplit Out + +-- Each split OUTPUT port gets its own data-dependent mux driven by the SAME +-- selector field but DIFFERENT data fields: +-- o1 = sel ? subA.lookup a : False => depends on (sel, a) +-- o2 = sel ? r : subB.lookup b => depends on (sel, b) (r registered) +-- Per-(input,output)-port tracking should therefore report: +-- o1 reachable from run_1_sel and run_1_a but NOT run_1_b +-- o2 reachable from run_1_sel and run_1_b but NOT run_1_a +-- and 'dead' reaches neither output. This confirms the selector edge is +-- attributed per output port together with only the data field that output +-- actually consumes. +{-# synthesize mkSelectorSplitOutPath #-} +mkSelectorSplitOutPath :: Module TopIfc +mkSelectorSplitOutPath = + module + subA <- mkSelectorSplitOutSubA + subB <- mkSelectorSplitOutSubB + r :: Reg Bool <- mkReg False + interface + run (ShallowSplit c) = + ShallowSplit (Out { o1 = if c.sel then subA.lookup c.a else False + ; o2 = if c.sel then r else subB.lookup c.b }) diff --git a/testsuite/bsc.scheduler/paths/SiblingDisjointFanout.bs b/testsuite/bsc.scheduler/paths/SiblingDisjointFanout.bs new file mode 100644 index 000000000..632832b4e --- /dev/null +++ b/testsuite/bsc.scheduler/paths/SiblingDisjointFanout.bs @@ -0,0 +1,41 @@ +package SiblingDisjointFanout where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface Ifc = + -- An Action method takes a split input (p1, p2) and forwards EACH field onto + -- its OWN combinational wire. Field p1 fans out to two methods (outA, outB); + -- the sibling field p2 fans out to a DIFFERENT third method (outC) only. + -- Path analysis must keep the two sources disjoint across method boundaries: + -- put_1_p1 -> outA, put_1_p1 -> outB (and NOT put_1_p1 -> outC) + -- put_1_p2 -> outC (and NOT put_1_p2 -> outA/outB) + put :: ShallowSplit Pair -> Action + outA :: Bool + outB :: Bool + outC :: Bool + +{-# synthesize mkSiblingDisjointFanout #-} +mkSiblingDisjointFanout :: Module Ifc +mkSiblingDisjointFanout = + module + w1 :: RWire Bool <- mkRWire + w2 :: RWire Bool <- mkRWire + interface + put (ShallowSplit a) = + action + w1.wset a.p1 + w2.wset a.p2 + outA = case w1.wget of + Just v -> v + Nothing -> False + outB = case w1.wget of + Just v -> not v + Nothing -> False + outC = case w2.wget of + Just v -> v + Nothing -> False diff --git a/testsuite/bsc.scheduler/paths/SplitAVPath.bs b/testsuite/bsc.scheduler/paths/SplitAVPath.bs new file mode 100644 index 000000000..955fbb003 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/SplitAVPath.bs @@ -0,0 +1,24 @@ +package SplitAVPath where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface AVIfc = + -- ActionValue method with a split result: p1 is combinational from the + -- (split) input, p2 is registered. Exercises the AIActionValue arm of the + -- per-port path edge construction. + upd :: ShallowSplit Pair -> ActionValue (ShallowSplit Pair) + +{-# synthesize mkSplitAVPath #-} +mkSplitAVPath :: Module AVIfc +mkSplitAVPath = + module + r :: Reg Bool <- mkReg False + interface + upd (ShallowSplit a) = + do r := a.p2 + return (ShallowSplit (Pair { p1 = a.p1; p2 = r })) diff --git a/testsuite/bsc.scheduler/paths/SplitInPackedCombine.bs b/testsuite/bsc.scheduler/paths/SplitInPackedCombine.bs new file mode 100644 index 000000000..dac4e42bd --- /dev/null +++ b/testsuite/bsc.scheduler/paths/SplitInPackedCombine.bs @@ -0,0 +1,22 @@ +package SplitInPackedCombine where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface Ifc = + -- Mixed-kind method: the ARGUMENT is split into ports (get_1_p1, get_1_p2) + -- but the RESULT is a single packed Bool port (get). Both split input + -- ports feed combinationally into the one packed output, so analysis should + -- report BOTH get_1_p1 -> get AND get_1_p2 -> get. + get :: ShallowSplit Pair -> Bool + +{-# synthesize mkSplitInPackedCombine #-} +mkSplitInPackedCombine :: Module Ifc +mkSplitInPackedCombine = + module + interface + get (ShallowSplit a) = a.p1 || a.p2 diff --git a/testsuite/bsc.scheduler/paths/SplitInPackedOneField.bs b/testsuite/bsc.scheduler/paths/SplitInPackedOneField.bs new file mode 100644 index 000000000..74bbd28cf --- /dev/null +++ b/testsuite/bsc.scheduler/paths/SplitInPackedOneField.bs @@ -0,0 +1,24 @@ +package SplitInPackedOneField where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface Ifc = + -- Mixed-kind method: SPLIT argument, single PACKED Bool result. The result + -- depends ONLY on the first split input field (p1); the second split input + -- field (p2) is ignored (instead the result mixes in a register). So the + -- packed output has a path from get_1_p1 but NOT from get_1_p2 -- finer + -- per-input tracking across the split/packed boundary. + get :: ShallowSplit Pair -> Bool + +{-# synthesize mkSplitInPackedOneField #-} +mkSplitInPackedOneField :: Module Ifc +mkSplitInPackedOneField = + module + r :: Reg Bool <- mkReg False + interface + get (ShallowSplit a) = a.p1 || r diff --git a/testsuite/bsc.scheduler/paths/SplitOutputLoop.bs b/testsuite/bsc.scheduler/paths/SplitOutputLoop.bs new file mode 100644 index 000000000..58c3c57c4 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/SplitOutputLoop.bs @@ -0,0 +1,34 @@ +package SplitOutputLoop where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface SubIfc = + -- both result fields are combinational from the (split) input + get :: ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkSplitLoopSub #-} +mkSplitLoopSub :: Module SubIfc +mkSplitLoopSub = + module + interface + get (ShallowSplit a) = ShallowSplit (Pair { p1 = a.p1; p2 = a.p2 }) + +-- Close a combinational loop through the submodule's split output port p1: +-- rw.wget -> get's split input p1 -> get's split output p1 -> rw.wset +-- Path analysis must detect this through the per-port result node. +{-# synthesize sysSplitOutputLoop #-} +sysSplitOutputLoop :: Module Empty +sysSplitOutputLoop = + module + s <- mkSplitLoopSub + rw :: RWire Bool <- mkRWire + let fb = isValid (rw.wget) + rules + "close_loop": when True ==> + case s.get (ShallowSplit (Pair { p1 = fb; p2 = False })) of + ShallowSplit res -> if res.p1 then rw.wset True else noAction diff --git a/testsuite/bsc.scheduler/paths/SplitOutputPath.bs b/testsuite/bsc.scheduler/paths/SplitOutputPath.bs new file mode 100644 index 000000000..132064690 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/SplitOutputPath.bs @@ -0,0 +1,23 @@ +package SplitOutputPath where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface Ifc = + -- A value method whose result is split into separate output ports. + -- The first field is combinational from the (split) input argument, + -- the second field comes from a register. Path analysis should therefore + -- report a combinational path to the first output port only. + get :: ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkSplitOutputPath #-} +mkSplitOutputPath :: Module Ifc +mkSplitOutputPath = + module + r :: Reg Bool <- mkReg False + interface + get (ShallowSplit a) = ShallowSplit (Pair { p1 = a.p1; p2 = r }) diff --git a/testsuite/bsc.scheduler/paths/SplitSubmodPath.bs b/testsuite/bsc.scheduler/paths/SplitSubmodPath.bs new file mode 100644 index 000000000..5ebe035ec --- /dev/null +++ b/testsuite/bsc.scheduler/paths/SplitSubmodPath.bs @@ -0,0 +1,47 @@ +package SplitSubmodPath where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface SubIfc = + -- result is split into ports; p1 is combinational from the input, p2 is registered + get :: ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkSplitSubmod #-} +mkSplitSubmod :: Module SubIfc +mkSplitSubmod = + module + r :: Reg Bool <- mkReg False + interface + get (ShallowSplit a) = ShallowSplit (Pair { p1 = a.p1; p2 = r }) + +interface TopIfc = + top :: Bool -> Bool + +-- Routes the top input through the submodule's *combinational* split output +-- field (p1). There should be a combinational path from the input to the +-- output, established via the submodule's per-port result node. +{-# synthesize mkSubmodPathComb #-} +mkSubmodPathComb :: Module TopIfc +mkSubmodPathComb = + module + s <- mkSplitSubmod + interface + top x = case s.get (ShallowSplit (Pair { p1 = x; p2 = False })) of + ShallowSplit res -> res.p1 + +-- Routes the top input through the submodule's *registered* split output +-- field (p2). There should be no combinational path, even though the input +-- still feeds the submodule's (combinational) p1 input port. +{-# synthesize mkSubmodPathReg #-} +mkSubmodPathReg :: Module TopIfc +mkSubmodPathReg = + module + s <- mkSplitSubmod + interface + top x = case s.get (ShallowSplit (Pair { p1 = x; p2 = False })) of + ShallowSplit res -> res.p2 diff --git a/testsuite/bsc.scheduler/paths/SubmodCrossbarPath.bs b/testsuite/bsc.scheduler/paths/SubmodCrossbarPath.bs new file mode 100644 index 000000000..af54c53a4 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/SubmodCrossbarPath.bs @@ -0,0 +1,50 @@ +package SubmodCrossbarPath where + +import SplitPorts + +struct Triple = + p1 :: Bool + p2 :: Bool + p3 :: Bool + deriving (Bits) + +struct Pair = + q1 :: Bool + q2 :: Bool + deriving (Bits) + +interface SubIfc = + -- submodule result split into three ports: p1, p2 combinational from the + -- matching input arg ports; p3 registered. + get :: ShallowSplit Triple -> ShallowSplit Triple + +{-# synthesize mkSubmodCrossbarSub #-} +mkSubmodCrossbarSub :: Module SubIfc +mkSubmodCrossbarSub = + module + r :: Reg Bool <- mkReg False + interface + get (ShallowSplit a) = + ShallowSplit (Triple { p1 = a.p1; p2 = a.p2; p3 = r }) + +interface TopIfc = + -- top argument and result are both split (into two ports each) + top :: ShallowSplit Pair -> ShallowSplit Pair + +-- Routes DISTINCT submodule split output ports to DISTINCT top output ports, +-- crossed over: +-- top_q1 <- submodule get_p2 (fed by top_1_q2) => top_1_q2 -> top_q1 +-- top_q2 <- submodule get_p1 (fed by top_1_q1) => top_1_q1 -> top_q2 +-- The submodule's registered output get_p3 is selected by neither, so it +-- contributes no path. This shows path analysis distinguishes individual +-- submodule split output ports and maps them to individual top output ports +-- (a crossbar), with no straight-through top_1_q1 -> top_q1 edge. +{-# synthesize mkSubmodCrossbarPath #-} +mkSubmodCrossbarPath :: Module TopIfc +mkSubmodCrossbarPath = + module + s <- mkSubmodCrossbarSub + interface + top (ShallowSplit a) = + case s.get (ShallowSplit (Triple { p1 = a.q1; p2 = a.q2; p3 = False })) of + ShallowSplit res -> ShallowSplit (Pair { q1 = res.p2; q2 = res.p1 }) diff --git a/testsuite/bsc.scheduler/paths/SubmodDeepLeafPath.bs b/testsuite/bsc.scheduler/paths/SubmodDeepLeafPath.bs new file mode 100644 index 000000000..81e3b0d65 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/SubmodDeepLeafPath.bs @@ -0,0 +1,49 @@ +package SubmodDeepLeafPath where + +import SplitPorts + +struct Inner = + a :: Bool + b :: Bool + deriving (Bits) + +struct Outer = + x :: Inner + y :: Bool + deriving (Bits) + +interface SubIfc = + -- DEEP split: nested Inner is recursed to leaf ports. + -- result x.a is combinational from input arg x.a (comb leaf) + -- result x.b comes from a register (reg leaf) + -- result y is combinational from input arg y + get :: DeepSplit Outer -> DeepSplit Outer + +{-# synthesize mkSubmodDeepLeafSub #-} +mkSubmodDeepLeafSub :: Module SubIfc +mkSubmodDeepLeafSub = + module + r :: Reg Bool <- mkReg False + interface + get (DeepSplit o) = + DeepSplit (Outer { x = Inner { a = o.x.a; b = r }; y = o.y }) + +interface TopIfc = + top :: DeepSplit Outer -> DeepSplit Outer + +-- Threads the top's deep-split leaf input ports through the submodule's +-- deep-split leaf argument/result ports. At leaf granularity: +-- top_1_x_a -> top_x_a exists (comb leaf through the submodule) +-- top_1_y -> top_y exists (comb leaf through the submodule) +-- nothing reaches top_x_b (the submodule's registered leaf) +-- This shows path tracking recurses to leaves rather than treating the nested +-- Inner struct as one port. +{-# synthesize mkSubmodDeepLeafPath #-} +mkSubmodDeepLeafPath :: Module TopIfc +mkSubmodDeepLeafPath = + module + s <- mkSubmodDeepLeafSub + interface + top (DeepSplit o) = + case s.get (DeepSplit (Outer { x = Inner { a = o.x.a; b = o.x.b }; y = o.y })) of + DeepSplit res -> DeepSplit res diff --git a/testsuite/bsc.scheduler/paths/SubmodInputArgPath.bs b/testsuite/bsc.scheduler/paths/SubmodInputArgPath.bs new file mode 100644 index 000000000..3522b9158 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/SubmodInputArgPath.bs @@ -0,0 +1,41 @@ +package SubmodInputArgPath where + +import SplitPorts + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +interface SubIfc = + -- result p1 is combinational from the input arg p1, result p2 is registered. + get :: ShallowSplit Pair -> ShallowSplit Pair + +{-# synthesize mkSubmodInputArgSub #-} +mkSubmodInputArgSub :: Module SubIfc +mkSubmodInputArgSub = + module + r :: Reg Bool <- mkReg False + interface + get (ShallowSplit a) = ShallowSplit (Pair { p1 = a.p1; p2 = r }) + +interface TopIfc = + -- top method's argument AND result are both split into ports + top :: ShallowSplit Pair -> ShallowSplit Pair + +-- Threads the top's split input ports straight into the submodule's split +-- *argument* ports, and the submodule's split result ports straight out to the +-- top's split output ports. Because the submodule's result p1 is +-- combinational from its arg p1 (and result p2 is registered), the only path +-- is top_1_p1 -> top_p1, exercised THROUGH the submodule's per-port argument +-- node get_1_p1. There is no top_1_p2 -> top_p1 cross-edge and no path to +-- top_p2. +{-# synthesize mkSubmodInputArgPath #-} +mkSubmodInputArgPath :: Module TopIfc +mkSubmodInputArgPath = + module + s <- mkSubmodInputArgSub + interface + top (ShallowSplit a) = + case s.get (ShallowSplit (Pair { p1 = a.p1; p2 = a.p2 })) of + ShallowSplit res -> ShallowSplit (Pair { p1 = res.p1; p2 = res.p2 }) diff --git a/testsuite/bsc.scheduler/paths/SubmodSelectOutPath.bs b/testsuite/bsc.scheduler/paths/SubmodSelectOutPath.bs new file mode 100644 index 000000000..b0f196fa5 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/SubmodSelectOutPath.bs @@ -0,0 +1,43 @@ +package SubmodSelectOutPath where + +import SplitPorts + +struct Triple = + p1 :: Bool + p2 :: Bool + p3 :: Bool + deriving (Bits) + +interface SubIfc = + -- result is split into three ports; p1 and p2 are combinational from the + -- corresponding input arg ports, p3 comes from a register. + get :: ShallowSplit Triple -> ShallowSplit Triple + +{-# synthesize mkSubmodSelectOutSub #-} +mkSubmodSelectOutSub :: Module SubIfc +mkSubmodSelectOutSub = + module + r :: Reg Bool <- mkReg False + interface + get (ShallowSplit a) = + ShallowSplit (Triple { p1 = a.p1; p2 = a.p2; p3 = r }) + +interface TopIfc = + -- single (unsplit) Bool output, plus a select input + top :: Bool -> Bool -> Bool + +-- Muxes between TWO of the submodule's split *output* ports (get_p1 and +-- get_p2) under a select input, then drives a single top output. Both +-- selected submodule output ports are combinational, so the top output is +-- combinationally reachable from BOTH data inputs (top_1, the data feeding +-- both submodule arg ports) AND the select input (top_2). The submodule's +-- registered output port get_p3 is never selected, so it contributes no path. +{-# synthesize mkSubmodSelectOutPath #-} +mkSubmodSelectOutPath :: Module TopIfc +mkSubmodSelectOutPath = + module + s <- mkSubmodSelectOutSub + interface + top d sel = + case s.get (ShallowSplit (Triple { p1 = d; p2 = d; p3 = False })) of + ShallowSplit res -> if sel then res.p1 else res.p2 diff --git a/testsuite/bsc.scheduler/paths/UnionPayload.bs b/testsuite/bsc.scheduler/paths/UnionPayload.bs new file mode 100644 index 000000000..f0811692b --- /dev/null +++ b/testsuite/bsc.scheduler/paths/UnionPayload.bs @@ -0,0 +1,37 @@ +package UnionPayload where + +import SplitPorts + +-- A user-defined 2-constructor tagged union with a payload. Like Maybe, it +-- has n /= 1 constructors, so SplitPorts keeps it packed as ONE port (tag + +-- payload) under both ShallowSplit and DeepSplit. +data Cmd = Nop | Run Bool + deriving (Bits) + +-- Two-field struct, ShallowSplit: a plain Bool field and the union field. +struct In = + sel :: Bool + cmd :: Cmd + deriving (Bits) + +struct Out = + echo :: Cmd + ack :: Bool + deriving (Bits) + +interface Ifc = + step :: ShallowSplit In -> ShallowSplit Out + +{-# synthesize mkUnionPayload #-} +mkUnionPayload :: Module Ifc +mkUnionPayload = + module + r :: Reg Bool <- mkReg False + interface + step (ShallowSplit a) = + -- The packed union input (cmd) flows combinationally to the packed + -- union output (echo) only. The plain Bool output (ack) comes from a + -- register, so the union input does NOT reach it: this shows per-port + -- granularity where an input touching only the union port produces a + -- single path to that one packed output port. + ShallowSplit (Out { echo = a.cmd; ack = r }) diff --git a/testsuite/bsc.scheduler/paths/VecNestedDeep.bs b/testsuite/bsc.scheduler/paths/VecNestedDeep.bs new file mode 100644 index 000000000..596e3ec76 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/VecNestedDeep.bs @@ -0,0 +1,49 @@ +package VecNestedDeep where + +import SplitPorts +import Vector + +struct Inner = + a :: Bool + b :: Bool + deriving (Bits) + +-- Cell has a nested struct field `c` (DeepSplit recurses into it) and a field `d` +-- wrapped in NoSplit so the DeepSplit recursion TERMINATES there, leaving `d` +-- packed even at the leaf level. +struct Cell = + c :: Inner + d :: NoSplit Bool + deriving (Bits) + +-- DeepSplit of a (Vector 2 Cell): each vector element recurses through Cell into +-- Inner, producing multi-level leaf names under a vector index: +-- outputs: get_0_c_a get_0_c_b get_0_d get_1_c_a get_1_c_b get_1_d +-- inputs : get_1_0_c_a ... get_1_1_d +-- (the NoSplit field d stays a single port get_0_d, NOT recursed further). +-- +-- Combinational edges chosen to exercise multi-level leaves AND cross-index +-- isolation: +-- element 0 deep leaf c.a straight-through from input elem 0 c.a +-- get_1_0_c_a -> get_0_c_a +-- element 1 NoSplit-packed leaf d crossed from input elem 0 d +-- get_1_0_d -> get_1_d +-- everything else registered: no get_0_c_b path, no get_1_c_a path, and the +-- crossed d edge proves index isolation (source elem 0, dest elem 1). +interface Ifc = + get :: DeepSplit (Vector 2 Cell) -> DeepSplit (Vector 2 Cell) + +{-# synthesize mkVecNestedDeep #-} +mkVecNestedDeep :: Module Ifc +mkVecNestedDeep = + module + r :: Reg Bool <- mkReg False + interface + get (DeepSplit v) = + let unD :: NoSplit Bool -> Bool + unD (NoSplit x) = x + c0 = Cell { c = Inner { a = (v !! 0).c.a; b = r } -- c0.c.a comb from in elem 0 + ; d = NoSplit r } + c1 = Cell { c = Inner { a = r; b = r } -- registered + ; d = NoSplit (unD ((v !! 0).d)) } -- c1.d comb from in elem 0 d + in DeepSplit (c0 :> c1 :> nil) diff --git a/testsuite/bsc.scheduler/paths/VecStructDeepMulti.bs b/testsuite/bsc.scheduler/paths/VecStructDeepMulti.bs new file mode 100644 index 000000000..4ba0698ff --- /dev/null +++ b/testsuite/bsc.scheduler/paths/VecStructDeepMulti.bs @@ -0,0 +1,35 @@ +package VecStructDeepMulti where + +import SplitPorts +import Vector + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- DeepSplit of a (Vector 3 Pair): each element recurses to leaf ports, so the +-- result ports are get_0_p1 get_0_p2 get_1_p1 get_1_p2 get_2_p1 get_2_p2 and the +-- argument ports are get_1_0_p1 ... get_1_2_p2 (leading 1 = argument number). +-- +-- Several distinct elements are simultaneously combinational, with one CROSSED +-- across vector indices: +-- element 0 : p1 straight-through from input element 0 p1 (get_1_0_p1 -> get_0_p1) +-- element 2 : p2 crossed from input element 1 p2 (get_1_1_p2 -> get_2_p2) +-- everything else is registered, so there must be NO other edges -- in +-- particular no same-index sibling like get_1_0_p2 -> get_0_p1 and no +-- get_1_2_p2 -> get_2_p2 (the source is element 1, not element 2). +interface Ifc = + get :: DeepSplit (Vector 3 Pair) -> DeepSplit (Vector 3 Pair) + +{-# synthesize mkVecStructDeepMulti #-} +mkVecStructDeepMulti :: Module Ifc +mkVecStructDeepMulti = + module + r :: Reg Bool <- mkReg False + interface + get (DeepSplit v) = + let e0 = Pair { p1 = (v !! 0).p1; p2 = r } -- e0.p1 comb from in elem 0 + e1 = Pair { p1 = r; p2 = r } -- all registered + e2 = Pair { p1 = r; p2 = (v !! 1).p2 } -- e2.p2 comb from in elem 1 + in DeepSplit (e0 :> e1 :> e2 :> nil) diff --git a/testsuite/bsc.scheduler/paths/VecStructShallow.bs b/testsuite/bsc.scheduler/paths/VecStructShallow.bs new file mode 100644 index 000000000..ae1950be1 --- /dev/null +++ b/testsuite/bsc.scheduler/paths/VecStructShallow.bs @@ -0,0 +1,36 @@ +package VecStructShallow where + +import SplitPorts +import Vector + +struct Pair = + p1 :: Bool + p2 :: Bool + deriving (Bits) + +-- ShallowSplit of a (Vector 3 Pair): the TOP level (the vector) is unpacked into +-- one port per element, but each element's Pair stays PACKED -- so the ports are +-- get_0 get_1 get_2 (outputs) and get_1_0 get_1_1 get_1_2 (inputs), NOT per-leaf +-- get_0_p1 etc. Contrast with VecStructDeepMulti, where DeepSplit gives leaf +-- ports get_0_p1 / get_0_p2. +-- +-- Two distinct elements are combinational, one crossed across indices: +-- element 0 packed value is combinational from input element 0 (get_1_0 -> get_0) +-- element 2 packed value is combinational from input element 1 (get_1_1 -> get_2) +-- element 1 is fully registered. Because the struct is packed, even a single +-- combinational field makes the whole element's port combinational, and there is +-- no per-field granularity (no get_0_p1). +interface Ifc = + get :: ShallowSplit (Vector 3 Pair) -> ShallowSplit (Vector 3 Pair) + +{-# synthesize mkVecStructShallow #-} +mkVecStructShallow :: Module Ifc +mkVecStructShallow = + module + r :: Reg Bool <- mkReg False + interface + get (ShallowSplit v) = + let e0 = Pair { p1 = (v !! 0).p1; p2 = r } -- only p1 comb, but whole elem 0 port carries it + e1 = Pair { p1 = r; p2 = r } -- fully registered + e2 = Pair { p1 = r; p2 = (v !! 1).p2 } -- p2 comb from input elem 1 + in ShallowSplit (e0 :> e1 :> e2 :> nil) diff --git a/testsuite/bsc.scheduler/paths/paths.exp b/testsuite/bsc.scheduler/paths/paths.exp index 131f684e4..8f2c61f8f 100644 --- a/testsuite/bsc.scheduler/paths/paths.exp +++ b/testsuite/bsc.scheduler/paths/paths.exp @@ -28,6 +28,45 @@ find_regexp sysMethodEnableToArgMux.v { compile_verilog_fail_error PortPath.bsv G0032 +# -------------------------------------------------- +# Tests for path analysis through split (multi-port) method inputs/outputs. +# Each method result is split into one port per struct field, so paths are +# tracked per output port rather than per method. + +# A value method whose result is split into ports: a combinational path is +# reported only to the output port (p1) that depends on the input; the port +# fed from a register (p2) has no path. +compile_verilog_pass SplitOutputPath.bs +find_regexp mkSplitOutputPath.v { +// Combinational paths from inputs to outputs: +// get_1_p1 -> get_p1 +} +find_regexp_fail mkSplitOutputPath.v {-> get_p2} + +# Paths through a submodule's split output method: routing through the +# submodule's combinational result field (p1) yields a path; routing through +# its registered field (p2) does not. +compile_verilog_pass SplitSubmodPath.bs +find_regexp mkSubmodPathComb.v { +// Combinational paths from inputs to outputs: +// top_1 -> top +} +find_regexp mkSubmodPathReg.v { +// No combinational paths from inputs to outputs +} + +# An ActionValue method with a split result: combinational path only to the +# input-dependent output port (p1). +compile_verilog_pass SplitAVPath.bs +find_regexp mkSplitAVPath.v { +// Combinational paths from inputs to outputs: +// upd_1_p1 -> upd_p1 +} +find_regexp_fail mkSplitAVPath.v {-> upd_p2} + +# A combinational loop through a submodule's split output port is detected. +compile_verilog_fail_error SplitOutputLoop.bs G0032 + # -------------------------------------------------- # When methods are allowed to be less urgent than rules, # we will need tests here that check that the "&& !CF_rl" @@ -36,4 +75,645 @@ compile_verilog_fail_error PortPath.bsv G0032 #... # -------------------------------------------------- + +# ================================================== +# Additional path-analysis tests for split (multi-port) method ports +# (deep/shallow, value & ActionValue, submodule, loops, granularity, EN/RDY) +# ================================================== + + +# -------------------------------------------------- +# Deep-split path analysis through NESTED structs (struct whose field is a +# struct). Deep splitting recurses to leaf ports (__), and path +# analysis tracks paths per deep-leaf (input-port, output-port) pair. + +# Outer{x::Inner, y::Inner}: a deep-split value method where each output leaf +# that is combinational from an input leaf shows that exact edge, while leaves +# fed from a register show none. Per-leaf isolation: get_x_a comes from +# get_1_x_a and get_y_b from get_1_y_b; the registered leaves get_x_b / get_y_a +# have no incoming path, and no cross-leaf (e.g. get_1_x_a -> get_x_b) edge. +compile_verilog_pass DeepLeafBasic.bs +find_regexp mkDeepLeafBasic.v { +// Combinational paths from inputs to outputs: +// get_1_x_a -> get_x_a +// get_1_y_b -> get_y_b +} +find_regexp_fail mkDeepLeafBasic.v {-> get_x_b} +find_regexp_fail mkDeepLeafBasic.v {-> get_y_a} + +# Deep-split leaves wired from a DIFFERENT input leaf than the same-named one, +# so path analysis must follow actual data flow, not port-name matching: +# get_x_a <- a.y.b => get_1_y_b -> get_x_a +# get_y_b <- a.x.a => get_1_x_a -> get_y_b +# The naive name-matching edges (get_1_x_a -> get_x_a, get_1_y_b -> get_y_b) +# must NOT appear. +compile_verilog_pass DeepLeafCross.bs +find_regexp mkDeepLeafCross.v { +// Combinational paths from inputs to outputs: +// get_1_x_a -> get_y_b +// get_1_y_b -> get_x_a +} +find_regexp_fail mkDeepLeafCross.v {get_1_x_a -> get_x_a} +find_regexp_fail mkDeepLeafCross.v {get_1_y_b -> get_y_b} + +# Two levels of nesting: Top{m::Mid, n::Mid}, Mid{p::Leaf, q::Leaf}. Deep +# split produces three-component leaf ports (get_1_m_p_lo -> get_m_p_lo). Only +# two of the eight leaves are combinational from their matching input leaf; the +# rest come from a register, isolating the two-levels-deep leaves. +compile_verilog_pass DeepLeafTwoLevels.bs +find_regexp mkDeepLeafTwoLevels.v { +// Combinational paths from inputs to outputs: +// get_1_m_p_lo -> get_m_p_lo +// get_1_n_q_hi -> get_n_q_hi +} +find_regexp_fail mkDeepLeafTwoLevels.v {-> get_m_p_hi} +find_regexp_fail mkDeepLeafTwoLevels.v {get_1_m_q_lo ->} + +# Each deep leaf of Outer{x::Inner, y::Inner} is driven by a different source: +# combinational input (get_x_a <- a.x.a), constant (get_x_b <- True, +# get_y_b <- False), and register (get_y_a <- r). Only the combinational leaf +# yields a path; constant- and register-fed leaves do not, and no unused input +# leaf (get_1_x_b / get_1_y_a / get_1_y_b) appears as a path source. +compile_verilog_pass DeepLeafConst.bs +find_regexp mkDeepLeafConst.v { +// Combinational paths from inputs to outputs: +// get_1_x_a -> get_x_a +} +find_regexp_fail mkDeepLeafConst.v {-> get_x_b} +find_regexp_fail mkDeepLeafConst.v {-> get_y_a} +find_regexp_fail mkDeepLeafConst.v {get_1_y_b ->} + +# A combinational loop closed through a submodule's DEEP leaf port (the x.a leaf +# is combinational input->output in the submodule, and an RWire feeds its output +# leaf back to its input leaf). Path analysis detects the cycle through the +# per-leaf result node, so compilation fails with G0032. +compile_verilog_fail_error DeepLeafLoop.bs G0032 + + +# IOMatrixCross: value method, ShallowSplit Pair in+out, output fields are +# CROSSED from the inputs (out p1 <= in p2, out p2 <= in p1). Asserts both +# crossed edges exist and neither straight-through edge does. +compile_verilog_pass IOMatrixCross.bs +find_regexp mkIOMatrixCross.v { +// get_1_p1 -> get_p2 +// get_1_p2 -> get_p1 +} +find_regexp_fail mkIOMatrixCross.v {get_1_p1 -> get_p1} +find_regexp_fail mkIOMatrixCross.v {get_1_p2 -> get_p2} + +# IOMatrixCombine: value method, ShallowSplit Pair in+out, output field p1 +# COMBINES both split inputs (a.p1 && a.p2); output field p2 is registered. +# Asserts the single combined edge (both inputs -> get_p1) exists and that +# nothing reaches get_p2. +compile_verilog_pass IOMatrixCombine.bs +find_regexp mkIOMatrixCombine.v {\(get_1_p1, get_1_p2\) -> get_p1} +find_regexp_fail mkIOMatrixCombine.v {-> get_p2} + +# IOMatrixFanout: value method, ShallowSplit Pair in+out, single input field +# p1 FANS OUT to both output fields (p1 = a.p1, p2 = not a.p1); input field p2 +# feeds nothing. Asserts both fan-out edges exist and that get_1_p2 drives no +# output. +compile_verilog_pass IOMatrixFanout.bs +find_regexp mkIOMatrixFanout.v { +// get_1_p1 -> get_p1 +// get_1_p1 -> get_p2 +} +find_regexp_fail mkIOMatrixFanout.v {get_1_p2 ->} + +# IOMatrixDeepCross: value method, DeepSplit of a nested struct (Outer with an +# Inner field). DeepSplit recurses to leaf ports get_1_x_a/get_1_x_b/get_1_y. +# The two inner leaves are CROSSED (out x_a <= in x_b, out x_b <= in x_a) and +# the top-level y passes straight through. Asserts the crossed deep edges and +# the straight y edge, and that neither straight inner edge exists. +compile_verilog_pass IOMatrixDeepCross.bs +find_regexp mkIOMatrixDeepCross.v { +// get_1_x_a -> get_x_b +// get_1_x_b -> get_x_a +// get_1_y -> get_y +} +find_regexp_fail mkIOMatrixDeepCross.v {get_1_x_a -> get_x_a} +find_regexp_fail mkIOMatrixDeepCross.v {get_1_x_b -> get_x_b} + +# IOMatrixDeepCombine: value method, DeepSplit nested struct. Each inner +# output leaf COMBINES a disjoint pair of input leaves (x_a <= x_a && y, +# x_b <= x_b && y); the top-level output y is registered. Asserts both +# combined deep edges exist and that nothing reaches get_y. +compile_verilog_pass IOMatrixDeepCombine.bs +find_regexp mkIOMatrixDeepCombine.v {\(get_1_x_a, get_1_y\) -> get_x_a} +find_regexp mkIOMatrixDeepCombine.v {\(get_1_x_b, get_1_y\) -> get_x_b} +find_regexp_fail mkIOMatrixDeepCombine.v {-> get_y} + + +# -------------------------------------------------- +# AV dimension: ActionValue methods with SPLIT INPUT args. + +# An ActionValue method with both a split input arg and a split result, +# wired "crossed": output upd_p1 is combinational from input upd_1_p2 and +# output upd_p2 from input upd_1_p1. Demonstrates per-INPUT-port tracking: +# each split output depends on exactly one specific split input, and the +# "diagonal" edges (upd_1_p1 -> upd_p1, upd_1_p2 -> upd_p2) are absent. +compile_verilog_pass AVSplitInPath.bs +find_regexp mkAVSplitInPath.v { +// Combinational paths from inputs to outputs: +// upd_1_p1 -> upd_p2 +// upd_1_p2 -> upd_p1 +} +find_regexp_fail mkAVSplitInPath.v {upd_1_p1 -> upd_p1} +find_regexp_fail mkAVSplitInPath.v {upd_1_p2 -> upd_p2} + +# An ActionValue method whose split input arg is threaded straight through a +# submodule's split input/output. Only input upd_1_p1 reaches the +# submodule's combinational result field, so the single path is +# upd_1_p1 -> upd_p1; input upd_1_p2 feeds only the submodule's registered +# field (no path), and output upd_p2 (registered) has no path. +compile_verilog_pass AVSubmodInPath.bs +find_regexp mkAVSubmodInPath.v { +// Combinational paths from inputs to outputs: +// upd_1_p1 -> upd_p1 +} +find_regexp_fail mkAVSubmodInPath.v {upd_1_p2 ->} +find_regexp_fail mkAVSubmodInPath.v {-> upd_p2} + +# An ActionValue method whose split input port indexes a single-ported +# combinational submodule read, with a rule using the same read port (so the +# index is muxed by EN_upd). The data path upd_1_p1 -> upd_p1 is reported; +# the analysis does NOT add a spurious EN_upd -> upd_p1 edge, and the +# registered field upd_p2 has no path. Exercises split AV input through a +# submodule's declared combinational result with an enable-muxed argument. +compile_verilog_pass AVEnArgMuxPath.bs +find_regexp mkAVEnArgMuxPath.v { +// Combinational paths from inputs to outputs: +// upd_1_p1 -> upd_p1 +} +find_regexp_fail mkAVEnArgMuxPath.v {EN_upd ->} +find_regexp_fail mkAVEnArgMuxPath.v {-> upd_p2} + + + +# -------------------------------------------------- +# Tests for path analysis through a SUBMODULE's split (multi-port) method +# ports. The top module threads its (possibly split) inputs through a +# submodule whose argument and/or result are split into per-field ports, and +# path analysis must track reachability at the per-port granularity through +# the submodule's argument and result nodes. + +# Routes the top's split input ports straight through the submodule's split +# *argument* ports and out the submodule's split result ports. The submodule +# result p1 is combinational from arg p1 while p2 is registered, so the only +# path is top_1_p1 -> top_p1 (established through the submodule's per-port +# argument node get_1_p1). There is no cross-edge into top_p2. +compile_verilog_pass SubmodInputArgPath.bs +find_regexp mkSubmodInputArgPath.v { +// Combinational paths from inputs to outputs: +// top_1_p1 -> top_p1 +} +find_regexp_fail mkSubmodInputArgPath.v {-> top_p2} + +# A DEEP-split submodule: the nested Inner struct is recursed to leaf ports. +# Leaf x.a and field y are combinational through the submodule while leaf x.b +# is registered, so paths are tracked at leaf granularity: +# top_1_x_a -> top_x_a and top_1_y -> top_y, with nothing reaching the +# registered leaf top_x_b. +compile_verilog_pass SubmodDeepLeafPath.bs +find_regexp mkSubmodDeepLeafPath.v { +// Combinational paths from inputs to outputs: +// top_1_x_a -> top_x_a +// top_1_y -> top_y +} +find_regexp_fail mkSubmodDeepLeafPath.v {-> top_x_b} + +# Muxes between TWO of the submodule's combinational split output ports +# (get_p1 / get_p2) under a select input, driving a single top output. Both +# the data input (top_1, feeding both submodule arg ports) and the select +# input (top_2) reach the output: (top_1, top_2) -> top. The submodule's +# registered output port get_p3 is never selected and contributes no path. +compile_verilog_pass SubmodSelectOutPath.bs +find_regexp mkSubmodSelectOutPath.v { +// Combinational paths from inputs to outputs: +// \(top_1\, top_2\) -> top +} + +# Crossbar through DISTINCT submodule split output ports: top output q1 is fed +# from submodule output get_p2 and top output q2 from get_p1, so the paths are +# crossed (top_1_q1 -> top_q2 and top_1_q2 -> top_q1) with NO straight-through +# top_1_q1 -> top_q1. The submodule's registered output get_p3 reaches +# neither top output port. +compile_verilog_pass SubmodCrossbarPath.bs +find_regexp mkSubmodCrossbarPath.v { +// Combinational paths from inputs to outputs: +// top_1_q1 -> top_q2 +// top_1_q2 -> top_q1 +} +find_regexp_fail mkSubmodCrossbarPath.v {top_1_q1 -> top_q1} + + +# -------------------------------------------------- +# Per-port combinational LOOP detection through SPLIT (multi-port) method ports. + + +# Splitting AVOIDS a false loop: the top feeds its input into a submodule's +# split input p1 and the submodule's combinational output p1 into a *second* +# submodule's split input p2. Since out-p1 depends only on in-p1 (never in-p2), +# the feedback into in-p2 is a dead end, so there is no loop -- only the real +# path top_1 -> top (from g2.in_p1) remains. Packed ports would risk a false +# loop here. +compile_verilog_pass LoopNoFalseLoop.bs +find_regexp mkLoopNoFalseLoop.v { +// Combinational paths from inputs to outputs: +// top_1 -> top +} + +# A combinational loop that re-enters the SPLIT INPUT arg port p1 of a submodule +# that combinationally SWAPS its fields (out_p1 = in_p2, out_p2 = in_p1). The +# feedback drives in_p1 and reads the swapped out_p2, closing the cycle through +# "Argument 1" of the split method => G0032. +compile_verilog_fail_error LoopInputArgLoop.bs G0032 + +# A combinational loop through an ActionValue method's SPLIT ports: the AV +# result's split output p1 (combinational from split input p1) is consumed and +# drives the RWire whose value feeds the AV's split input p1 => G0032. +compile_verilog_fail_error LoopAVPortLoop.bs G0032 + +# Sibling to LoopInputArgLoop: feed the top input into the same SWAP submodule's +# split input p1 but RETURN its split output p1. Because out_p1 = in_p2 (not +# in_p1), the input on p1 reaches only the discarded out_p2, so per-port +# discrimination reports NO combinational paths (and no loop). Reading the +# *wrong* swapped port is what made LoopInputArgLoop loop. +compile_verilog_pass LoopSwapNoLoop.bs +find_regexp mkLoopSwapNoLoop.v { +// No combinational paths from inputs to outputs +} + + +# -------------------------------------------------- +# Granularity + composition tests for split (multi-port) method ports. + +# Same nested struct as a ShallowSplit result: only the TOP level is split, so +# the nested field x stays PACKED as one port (get_x). The combinational path +# is reported at the coarse packed granularity: get_1_x -> get_x. No per-leaf +# ports (get_x_a) exist. Contrast with GranDeepNested below. +compile_verilog_pass GranShallowNested.bs +find_regexp mkGranShallowNested.v { +// Combinational paths from inputs to outputs: +// get_1_x -> get_x +} +find_regexp_fail mkGranShallowNested.v {get_x_a} + +# Same nested struct as a DeepSplit result: recursion splits the nested field +# into leaf ports (get_x_a, get_x_b). Only x.a is combinational from the input, +# so the path is reported at per-leaf granularity (get_1_x_a -> get_x_a) and the +# registered leaves get_x_b / get_y have no path. This shows the finer +# granularity of DeepSplit vs the packed ShallowSplit path above. +compile_verilog_pass GranDeepNested.bs +find_regexp mkGranDeepNested.v { +// Combinational paths from inputs to outputs: +// get_1_x_a -> get_x_a +} +find_regexp_fail mkGranDeepNested.v {-> get_x_b} +find_regexp_fail mkGranDeepNested.v {-> get_y} + +# Two split arguments named lhs/rhs via the arg_names pragma. Path analysis +# distinguishes sub-ports of arg lhs from arg rhs: result p1 is combinational +# from lhs.p1 and result p2 from rhs.p2, yielding exactly the edges +# combine_lhs_p1 -> combine_p1 and combine_rhs_p2 -> combine_p2, but NOT the +# cross edges combine_lhs_p2 -> combine_p2 or combine_rhs_p1 -> combine_p1. +compile_verilog_pass GranTwoArgs.bs +find_regexp mkGranTwoArgs.v { +// Combinational paths from inputs to outputs: +// combine_lhs_p1 -> combine_p1 +// combine_rhs_p2 -> combine_p2 +} +find_regexp_fail mkGranTwoArgs.v {combine_lhs_p2 -> combine_p2} +find_regexp_fail mkGranTwoArgs.v {combine_rhs_p1 -> combine_p1} + +# DeepSplit of a (Vector 3 Bool): each element becomes its own port (input +# get_1_0/get_1_1/get_1_2, output get_0/get_1/get_2). Result element 2 is +# combinational from input element 2, so the path is exactly get_1_2 -> get_2; +# the register-fed elements get_0 / get_1 have no incoming path. +compile_verilog_pass GranVec.bs +find_regexp mkGranVec.v { +// Combinational paths from inputs to outputs: +// get_1_2 -> get_2 +} +find_regexp_fail mkGranVec.v {-> get_0} + +# NoSplit terminates the DeepSplit recursion: the field x (wrapped in NoSplit) +# stays as ONE packed port (get_x) instead of leaf ports get_x_a / get_x_b, so +# the path is reported at the packed granularity get_1_x -> get_x. The leaf y +# is register-fed and has no path. +compile_verilog_pass GranNoSplit.bs +find_regexp mkGranNoSplit.v { +// Combinational paths from inputs to outputs: +// get_1_x -> get_x +} +find_regexp_fail mkGranNoSplit.v {get_x_a} +find_regexp_fail mkGranNoSplit.v {-> get_y} + + +# -------------------------------------------------- +# EN/RDY interaction with split (multi-port) method ports. + +# An Action method's enable (EN_doit) feeds a *split* value-output port: only the +# field driven by EN (rd_p1) has a combinational path; the constant field rd_p2 +# has none. Shows EN_ -> _ per split output port. +compile_verilog_pass EnRdyEnToSplitOut.bs +find_regexp mkEnRdyEnToSplitOut.v { +// Combinational paths from inputs to outputs: +// EN_doit -> rd_p1 +} +find_regexp_fail mkEnRdyEnToSplitOut.v {-> rd_p2} + +# A split INPUT sub-port feeds another method's RDY. 'put' forwards its split +# input field p1 onto an RWire whose value gates value-method 'gate', so the path +# is (put_1_p1, EN_put) -> RDY_gate. The other split input port (put_1_p2) is +# never forwarded, so it does not appear in any path; RDY_put has none either. +compile_verilog_pass EnRdyInToRdy.bs +find_regexp mkEnRdyInToRdy.v { +// Combinational paths from inputs to outputs: +// \(put_1_p1, EN_put\) -> RDY_gate +} +find_regexp_fail mkEnRdyInToRdy.v {put_1_p2 ->} +find_regexp_fail mkEnRdyInToRdy.v {-> RDY_put} + +# An Action method's enable reaches a DEEP-split leaf output port. rd's deep +# result has nested struct field x.a (port rd_x_a) driven by EN_fire; sibling +# leaves rd_x_b and rd_y come from registers, so only rd_x_a has a path. +compile_verilog_pass EnRdyDeepEnOut.bs +find_regexp mkEnRdyDeepEnOut.v { +// Combinational paths from inputs to outputs: +// EN_fire -> rd_x_a +} +find_regexp_fail mkEnRdyDeepEnOut.v {-> rd_x_b} +find_regexp_fail mkEnRdyDeepEnOut.v {-> rd_y} + +# An ActionValue method with a split result combined with an EN edge. Each split +# input port maps to its own split output port (upd_1_p1 -> upd_p1, +# upd_1_p2 -> upd_p2) with no crossed edges, and the method's enable reaches a +# separate value output (EN_upd -> busy). +compile_verilog_pass EnRdyAVEnResult.bs +find_regexp mkEnRdyAVEnResult.v { +// Combinational paths from inputs to outputs: +// upd_1_p1 -> upd_p1 +// upd_1_p2 -> upd_p2 +// EN_upd -> busy +} +find_regexp_fail mkEnRdyAVEnResult.v {upd_1_p1 -> upd_p2} +find_regexp_fail mkEnRdyAVEnResult.v {upd_1_p2 -> upd_p1} + +# Two distinct method enables route to two distinct split output ports: +# EN_setA -> rd_p1 and EN_setB -> rd_p2, with no crossed edges. Demonstrates +# per-port tracking of separate enables into a single split result. +compile_verilog_pass EnRdyTwoEnSplit.bs +find_regexp mkEnRdyTwoEnSplit.v { +// Combinational paths from inputs to outputs: +// EN_setA -> rd_p1 +// EN_setB -> rd_p2 +} +find_regexp_fail mkEnRdyTwoEnSplit.v {EN_setA -> rd_p2} +find_regexp_fail mkEnRdyTwoEnSplit.v {EN_setB -> rd_p1} + + +# MIXED-KIND: split argument, single PACKED result depending on ONE split input +# field. The packed output port (get) has a path from get_1_p1 only; the other +# split input field (get_1_p2) is ignored, so no get_1_p2 -> get edge. Verifies +# per-input tracking across the split->packed boundary. +compile_verilog_pass SplitInPackedOneField.bs +find_regexp mkSplitInPackedOneField.v { +// Combinational paths from inputs to outputs: +// get_1_p1 -> get +} +find_regexp_fail mkSplitInPackedOneField.v {get_1_p2 -> get} + +# MIXED-KIND (reverse): single PACKED Bool argument feeding a SPLIT result. The +# plain input fans into the first split output field (get_p1) combinationally; +# the second split output field (get_p2) is registered. So get_1 -> get_p1 is +# reported but get_1 -> get_p2 is not -- asymmetric edge across the packed->split +# boundary. +compile_verilog_pass PackedInSplitOut.bs +find_regexp mkPackedInSplitOut.v { +// Combinational paths from inputs to outputs: +// get_1 -> get_p1 +} +find_regexp_fail mkPackedInSplitOut.v {get_1 -> get_p2} + +# MIXED-KIND (merge): split argument (BOTH fields), single PACKED Bool result +# (a.p1 || a.p2). Both split input ports combine into the one packed output, so +# the analysis reports a single combined edge (get_1_p1, get_1_p2) -> get rather +# than two separate edges. Asserts the combined edge exists and the individual +# get_1_p1 -> get edge does NOT. +compile_verilog_pass SplitInPackedCombine.bs +find_regexp mkSplitInPackedCombine.v { +// Combinational paths from inputs to outputs: +// \(get_1_p1\, get_1_p2\) -> get +} +find_regexp_fail mkSplitInPackedCombine.v {get_1_p1 -> get} + + +# A single split INPUT sub-port fanning out across METHOD boundaries: one Action +# method forwards only field p1 of its split arg onto a combinational RWire, and +# two DISTINCT value methods (outA, outB) both read it. So put_1_p1 reaches the +# outputs of two different methods, while its sibling put_1_p2 (never written to +# the wire) reaches neither. +compile_verilog_pass RWireFanout.bs +find_regexp mkRWireFanout.v {// Combinational paths from inputs to outputs: +// \(put_1_p1\, EN_put\) -> outA +// \(put_1_p1\, EN_put\) -> outB} +find_regexp_fail mkRWireFanout.v {put_1_p2 ->} + +# DeepSplit version of the cross-method fanout: the shared source is a deep leaf +# sub-port (put_1_a_x) of a nested struct. One Action method forwards only that +# leaf onto a combinational wire; two distinct value methods read it, so the leaf +# fans out to outputs of two methods, while sibling leaves put_1_a_y and put_1_b +# reach neither. +compile_verilog_pass DeepWireFanout.bs +find_regexp mkDeepWireFanout.v {// Combinational paths from inputs to outputs: +// \(put_1_a_x\, EN_put\) -> outA +// \(put_1_a_x\, EN_put\) -> outB} +find_regexp_fail mkDeepWireFanout.v {put_1_a_y ->} +find_regexp_fail mkDeepWireFanout.v {put_1_b ->} + +# Disjoint per-source fanout across method boundaries: the Action method forwards +# each split input field onto its own wire. Field p1 fans out to TWO methods +# (outA, outB); the sibling field p2 reaches a DIFFERENT third method (outC) only. +# Path analysis keeps the two sources independent: no put_1_p1 -> outC edge and +# no put_1_p2 -> outA edge. +compile_verilog_pass SiblingDisjointFanout.bs +find_regexp mkSiblingDisjointFanout.v {// Combinational paths from inputs to outputs: +// \(put_1_p1\, EN_put\) -> outA +// \(put_1_p1\, EN_put\) -> outB +// \(put_1_p2\, EN_put\) -> outC} +find_regexp_fail mkSiblingDisjointFanout.v {put_1_p1\, EN_put\) -> outC} +find_regexp_fail mkSiblingDisjointFanout.v {put_1_p2\, EN_put\) -> outA} + + +# -------------------------------------------------- +# Tagged-union / multi-constructor split: a struct field that is a 2-constructor +# type (Maybe, or a user enum-with-payload) is kept PACKED as one port, even +# under ShallowSplit/DeepSplit, since SplitPorts only splits single-constructor +# structs/vectors. These verify the tag+payload port naming and that paths are +# tracked at the granularity of that single packed union port. + +# ShallowSplit: the Maybe field stays a single packed port (get_1_mb / get_mb). +# The plain output flag is combinational from the packed union input, so the +# only path is get_1_mb -> get_flag. The union output (get_mb) is register-fed +# (no path), and the flat input get_1_flag is unused (no path). +compile_verilog_pass MaybeShallow.bs +find_regexp mkMaybeShallow.v { +// Combinational paths from inputs to outputs: +// get_1_mb -> get_flag +} +find_regexp_fail mkMaybeShallow.v {-> get_mb} +find_regexp_fail mkMaybeShallow.v {get_1_flag ->} + +# DeepSplit: recursion splits the outer struct into leaf ports but TERMINATES +# at the 2-constructor Maybe field, so get_1_mb / get_mb are single packed ports +# (no get_1_mb_* subports). Tag and payload both flow through, giving the only +# path get_1_mb -> get_mb. The leaf output get_lo is register-fed (no path) and +# the leaf input get_1_lo is unused (no path). +compile_verilog_pass MaybeDeep.bs +find_regexp mkMaybeDeep.v { +// Combinational paths from inputs to outputs: +// get_1_mb -> get_mb +} +find_regexp_fail mkMaybeDeep.v {-> get_lo} +find_regexp_fail mkMaybeDeep.v {get_1_lo ->} +find_regexp_fail mkMaybeDeep.v {get_1_mb_} + +# A user-defined 2-constructor union WITH a payload (data Cmd = Nop | Run Bool): +# the same packing applies (step_1_cmd / step_echo are single packed ports). +# The packed union input flows only to the packed union output (step_1_cmd -> +# step_echo); the plain Bool output step_ack is register-fed and the plain input +# step_1_sel is unused, demonstrating per-port granularity. +compile_verilog_pass UnionPayload.bs +find_regexp mkUnionPayload.v { +// Combinational paths from inputs to outputs: +// step_1_cmd -> step_echo +} +find_regexp_fail mkUnionPayload.v {-> step_ack} +find_regexp_fail mkUnionPayload.v {step_1_sel ->} + + +# -------------------------------------------------- +# A split method-input SELECTOR field data-dependently muxes between two +# distinct single-ported combinational submodule reads (each read indexed by a +# separate split data field), driving one unsplit output. The selector edge +# must appear alongside both selected data fields, while the unused 'dead' field +# (still a real input port) contributes no path. +compile_verilog_pass SelectorMuxPath.bs +find_regexp mkSelectorMuxPath.v { +// Combinational paths from inputs to outputs: +// \(run_1_sel, run_1_a, run_1_b\) -> run +} +find_regexp_fail mkSelectorMuxPath.v {run_1_dead ->} + +# -------------------------------------------------- +# Same selector-mux pattern, but with a SPLIT output: each split output port is +# muxed by the SAME selector field but a DIFFERENT data field (o1 from a, o2 +# from b). Per-(input,output)-port tracking attributes the selector edge to +# each output port together with ONLY the data field that output consumes: +# (sel, a) -> o1 and (sel, b) -> o2, with no cross edges and no 'dead'. +compile_verilog_pass SelectorSplitOutPath.bs +find_regexp mkSelectorSplitOutPath.v { +// Combinational paths from inputs to outputs: +// \(run_1_sel, run_1_a\) -> run_o1 +// \(run_1_sel, run_1_b\) -> run_o2 +} +find_regexp_fail mkSelectorSplitOutPath.v {run_1_b\) -> run_o1} +find_regexp_fail mkSelectorSplitOutPath.v {run_1_a\) -> run_o2} +find_regexp_fail mkSelectorSplitOutPath.v {run_1_dead.*->} + +# -------------------------------------------------- +# A split method-input selector field muxes between a MODULE ARGUMENT (port +# input 'v') and a split data field, driving one unsplit output. The path +# enters via the split method input and exits through the module's own +# argument-driven logic, so the output depends on (run_1_sel, run_1_d, v); the +# unused split field 'dead' contributes no path. +compile_verilog_pass ArgSelectorPath.bs +find_regexp mkArgSelectorPath.v { +// Combinational paths from inputs to outputs: +// \(run_1_sel, run_1_d, v\) -> run +} +find_regexp_fail mkArgSelectorPath.v {run_1_dead ->} + + +# VecStructDeepMulti: DeepSplit (Vector 3 Pair) -> leaf ports per element +# (get_0_p1 .. get_2_p2). Two simultaneous combinational edges, one CROSSED across +# vector indices: elem0 p1 straight-through (get_1_0_p1 -> get_0_p1) and elem2 p2 +# sourced from input elem1 p2 (get_1_1_p2 -> get_2_p2). Asserts both edges exist +# and that no same-index sibling / wrong-source edge appears. +compile_verilog_pass VecStructDeepMulti.bs +find_regexp mkVecStructDeepMulti.v { +// Combinational paths from inputs to outputs: +// get_1_0_p1 -> get_0_p1 +// get_1_1_p2 -> get_2_p2 +} +find_regexp_fail mkVecStructDeepMulti.v {get_1_0_p2 -> get_0_p1} +find_regexp_fail mkVecStructDeepMulti.v {get_1_2_p2 -> get_2_p2} + +# VecStructShallow: ShallowSplit (Vector 3 Pair) -> the vector is unpacked into +# one PACKED port per element (get_0 get_1 get_2 / get_1_0 ..), with NO per-field +# leaf granularity (contrast VecStructDeepMulti). Two edges, one crossed across +# indices: get_1_0 -> get_0 and get_1_1 -> get_2. Asserts the packed edges exist and +# that no leaf port name like get_0_p1 ever appears. +compile_verilog_pass VecStructShallow.bs +find_regexp mkVecStructShallow.v { +// Combinational paths from inputs to outputs: +// get_1_0 -> get_0 +// get_1_1 -> get_2 +} +find_regexp_fail mkVecStructShallow.v {get_0_p1} +find_regexp_fail mkVecStructShallow.v {get_1_2 ->} + +# VecNestedDeep: DeepSplit (Vector 2 Cell) where Cell has a nested struct field +# c (recursed to multi-level leaves get_0_c_a / get_0_c_b) and a NoSplit field d that +# TERMINATES recursion (stays packed as get_0_d). Two edges, one crossed across +# indices: deep leaf get_1_0_c_a -> get_0_c_a and NoSplit-packed leaf get_1_0_d -> +# get_1_d (source elem0, dest elem1). Asserts both edges and absence of the +# registered / wrong-index siblings. +compile_verilog_pass VecNestedDeep.bs +find_regexp mkVecNestedDeep.v { +// Combinational paths from inputs to outputs: +// get_1_0_c_a -> get_0_c_a +// get_1_0_d -> get_1_d +} +find_regexp_fail mkVecNestedDeep.v {get_1_1_d -> get_1_d} +find_regexp_fail mkVecNestedDeep.v {-> get_0_c_b} + + +# Per-port loop discrimination: a genuine combinational loop confined to split +# field p1 of method `get'. The cycle MUST be detected (G0032) and the cycle +# report must name exactly the offending split port -- "Argument 1"/"Return +# value 1" of `get' -- and NOT the sibling field p2's ports. Counterpart to the +# passing no-loop tests, proving per-port (not whole-method) cycle reporting. +compile_verilog_fail_error LoopConfinedP1.bs G0032 +find_regexp LoopConfinedP1.bs.bsc-vcomp-out {Argument 1 of method `get'} +find_regexp LoopConfinedP1.bs.bsc-vcomp-out {Return value 1 of method `get'} +find_regexp_fail LoopConfinedP1.bs.bsc-vcomp-out {Argument 2 of method `get'} +find_regexp_fail LoopConfinedP1.bs.bsc-vcomp-out {Return value 2 of method `get'} + +# Mirror image of LoopConfinedP1: the loop is confined to split field p2, so the +# G0032 cycle report must name "Argument 2"/"Return value 2" of `get' and NOT +# "Argument 1"/"Return value 1". Together with LoopConfinedP1 this proves the +# positional split-port index in the cycle report genuinely discriminates the +# offending field (it is not always reported as port "1"). +compile_verilog_fail_error LoopConfinedP2.bs G0032 +find_regexp LoopConfinedP2.bs.bsc-vcomp-out {Argument 2 of method `get'} +find_regexp LoopConfinedP2.bs.bsc-vcomp-out {Return value 2 of method `get'} +find_regexp_fail LoopConfinedP2.bs.bsc-vcomp-out {Argument 1 of method `get'} +find_regexp_fail LoopConfinedP2.bs.bsc-vcomp-out {Return value 1 of method `get'} + +# Per-split-port discrimination across MULTIPLE split arguments. Method `op' +# takes two split Pair arguments, so its input split ports are numbered 1,2 +# (arg1.p1, arg1.p2) and 3,4 (arg2.p1, arg2.p2). The loop is confined to +# arg2's field p1 == split input port 3, reaching result field p1 == return +# value 1. G0032 must name "Argument 3"/"Return value 1" of `op' and NOT +# "Argument 1", "Argument 2", or "Return value 2" -- demonstrating that the +# cycle report indexes the precise split port, not the whole method argument. +compile_verilog_fail_error LoopConfinedArg2.bs G0032 +find_regexp LoopConfinedArg2.bs.bsc-vcomp-out {Argument 3 of method `op'} +find_regexp LoopConfinedArg2.bs.bsc-vcomp-out {Return value 1 of method `op'} +find_regexp_fail LoopConfinedArg2.bs.bsc-vcomp-out {Argument 1 of method `op'} +find_regexp_fail LoopConfinedArg2.bs.bsc-vcomp-out {Argument 2 of method `op'} +find_regexp_fail LoopConfinedArg2.bs.bsc-vcomp-out {Return value 2 of method `op'} + } diff --git a/testsuite/bsc.syntax/bsv05/statename/sysStateNameTest.atsexpand.expected b/testsuite/bsc.syntax/bsv05/statename/sysStateNameTest.atsexpand.expected index d17fd6768..f8a25e7e7 100644 --- a/testsuite/bsc.syntax/bsv05/statename/sysStateNameTest.atsexpand.expected +++ b/testsuite/bsc.syntax/bsv05/statename/sysStateNameTest.atsexpand.expected @@ -26,7 +26,7 @@ b :: ABSTRACT: Prelude.VReg = RegN []) [clock { osc: CLK gate: 1'd1 }, reset { wire: RST_N }, 32'd16, 16'd11] [] - meth types=[([], Nothing, Just (Bit 16)), ([Bit 16], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 16]), ([Bit 16], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 16 Q_OUT -> Prelude.Bit 16 -- AP rules diff --git a/testsuite/bsc.syntax/bsv05/statename/sysStateNameTest2.atsexpand.expected b/testsuite/bsc.syntax/bsv05/statename/sysStateNameTest2.atsexpand.expected index 927832b19..07d0442fc 100644 --- a/testsuite/bsc.syntax/bsv05/statename/sysStateNameTest2.atsexpand.expected +++ b/testsuite/bsc.syntax/bsv05/statename/sysStateNameTest2.atsexpand.expected @@ -26,7 +26,7 @@ b :: ABSTRACT: Prelude.VReg = RegN []) [clock { osc: CLK gate: 1'd1 }, reset { wire: RST_N }, 32'd16, 16'd11] [] - meth types=[([], Nothing, Just (Bit 16)), ([Bit 16], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 16]), ([Bit 16], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 16 Q_OUT -> Prelude.Bit 16 -- AP rules diff --git a/testsuite/bsc.syntax/bsv05/statename/sysUseMod2.atsexpand.expected b/testsuite/bsc.syntax/bsv05/statename/sysUseMod2.atsexpand.expected index 0d67520e6..d1c6302b1 100644 --- a/testsuite/bsc.syntax/bsv05/statename/sysUseMod2.atsexpand.expected +++ b/testsuite/bsc.syntax/bsv05/statename/sysUseMod2.atsexpand.expected @@ -27,7 +27,7 @@ the_e_the_r :: ABSTRACT: Prelude.VReg = RegN []) [clock { osc: CLK gate: 1'd1 }, reset { wire: RST_N }, 32'd32, 32'd0] [] - meth types=[([], Nothing, Just (Bit 32)), ([Bit 32], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 32]), ([Bit 32], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 32 Q_OUT -> Prelude.Bit 32 -- AP rules diff --git a/testsuite/bsc.syntax/bsv05/statename/sysUseMod2Arrow.atsexpand.expected b/testsuite/bsc.syntax/bsv05/statename/sysUseMod2Arrow.atsexpand.expected index 0112a34a6..392d85adb 100644 --- a/testsuite/bsc.syntax/bsv05/statename/sysUseMod2Arrow.atsexpand.expected +++ b/testsuite/bsc.syntax/bsv05/statename/sysUseMod2Arrow.atsexpand.expected @@ -27,7 +27,7 @@ e_r :: ABSTRACT: Prelude.VReg = RegN []) [clock { osc: CLK gate: 1'd1 }, reset { wire: RST_N }, 32'd32, 32'd0] [] - meth types=[([], Nothing, Just (Bit 32)), ([Bit 32], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 32]), ([Bit 32], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 32 Q_OUT -> Prelude.Bit 32 -- AP rules diff --git a/testsuite/bsc.typechecker/dontcare/DummyInRuleQual.bs.bsc-vcomp-out.expected b/testsuite/bsc.typechecker/dontcare/DummyInRuleQual.bs.bsc-vcomp-out.expected index ae51d3faf..48db7e8b2 100644 --- a/testsuite/bsc.typechecker/dontcare/DummyInRuleQual.bs.bsc-vcomp-out.expected +++ b/testsuite/bsc.typechecker/dontcare/DummyInRuleQual.bs.bsc-vcomp-out.expected @@ -33,7 +33,7 @@ r :: ABSTRACT: Prelude.VReg = RegUN []) [clock { osc: CLK gate: 1'd1 }, 32'd12] [] - meth types=[([], Nothing, Just (Bit 12)), ([Bit 12], Just (Bit 1), Nothing)] + meth types=[([], Nothing, [Bit 12]), ([Bit 12], Just (Bit 1), [])] port types=D_IN -> Prelude.Bit 12 Q_OUT -> Prelude.Bit 12 -- AP local definitions diff --git a/testsuite/bsc.verilog/noinline/NoInline_ResNotInBits.bsv.bsc-vcomp-out.expected b/testsuite/bsc.verilog/noinline/NoInline_ResNotInBits.bsv.bsc-vcomp-out.expected index 4a6acf299..fb77799ff 100644 --- a/testsuite/bsc.verilog/noinline/NoInline_ResNotInBits.bsv.bsc-vcomp-out.expected +++ b/testsuite/bsc.verilog/noinline/NoInline_ResNotInBits.bsv.bsc-vcomp-out.expected @@ -4,12 +4,6 @@ Error: "NoInline_ResNotInBits.bsv", line 4, column 12: (T0043) Cannot synthesize `module_fnNoInline_ResNotInBits­': The interface method `fnNoInline_ResNotInBits' uses type(s) that are not in the Bits or SplitPorts typeclasses: NoInline_ResNotInBits::L -Error: "NoInline_ResNotInBits.bsv", line 4, column 12: (T0029) - Signature mismatch (given too general): - given: - function b__ f(Bit#(1) x1) provisos (Bits#(NoInline_ResNotInBits::L, a__)) - deduced: - function Bit#(c__) f(Bit#(1) x1) provisos (Bits#(NoInline_ResNotInBits::L, c__)) Error: Unknown position: (T0031) The provisos for this expression could not be resolved because there are no instances of the form: diff --git a/testsuite/bsc.verilog/splitports/DeepSplit.bs b/testsuite/bsc.verilog/splitports/DeepSplit.bs index 9cab5afea..0a133a22d 100644 --- a/testsuite/bsc.verilog/splitports/DeepSplit.bs +++ b/testsuite/bsc.verilog/splitports/DeepSplit.bs @@ -47,11 +47,19 @@ interface SplitTest = putBaz :: DeepSplit Baz -> Action putZug :: DeepSplit Zug -> Action + getFoo :: DeepSplit Foo + getBar :: DeepSplit Foo -> DeepSplit Bar {-# result = "GET_BAR" #-} + getZug :: DeepSplit Zug + + update :: DeepSplit Foo -> ActionValue (DeepSplit Bar) + {-# synthesize mkDeepSplitTest #-} mkDeepSplitTest :: Module SplitTest mkDeepSplitTest = module + theCond <- mkReg False + theFoo <- mkReg (Foo { x = 0; y = 0; }) interface putFoo (DeepSplit x) = $display "putFoo: " (cshow x) putBar (DeepSplit x) = $display "putBar: " (cshow x) @@ -59,6 +67,13 @@ mkDeepSplitTest = putFoos (DeepSplit x) = $display "putFoos: " (cshow x) putBaz (DeepSplit x) = $display "putBaz: " (cshow x) putZug (DeepSplit x) = $display "putZug: " (cshow x) + getFoo = DeepSplit $ Foo { x = 42; y = 43; } + getBar (DeepSplit f) = DeepSplit $ Bar { v = vec True False True; w = (False, 0x4321); z = f; } + getZug = DeepSplit $ Zug { qs = vec (Quix { q = negate 2; v = True }) (Quix { q = 2; v = False }); blob = True; } + update (DeepSplit f) = do + theCond := not theCond + theFoo := f + return $ DeepSplit $ Bar { v = vec (f.x == 33) theCond (not theCond); w = (theCond, 0xDEAD); z = theFoo; } {-# synthesize sysDeepSplit #-} sysDeepSplit :: Module Empty @@ -74,4 +89,13 @@ sysDeepSplit = when i == 3 ==> s.putFoos $ DeepSplit $ genWith $ \ j -> Foo { x = fromInteger $ 9 + j / 2; y = fromInteger $ 10 - 2*j / 3; } when i == 4 ==> s.putBaz $ DeepSplit $ Baz { a = Just $ Foo { x = 9; y = 10; }; b = Bar { v = vec True False False; w = (True, 0x1234); z = Foo { x = 3; y = 4; }; }; c = vec (vec (Foo { x = 11; y = 12; }) (Foo { x = 13; y = 14; }) (Foo { x = 15; y = 16; }) (Foo { x = 17; y = 18; }) (Foo { x = 19; y = 20; }) (Foo { x = 21; y = 22; }) (Foo { x = 23; y = 24; }) (Foo { x = 25; y = 26; }), Bar { v = vec True False True; w = (True, 0xBEEF); z = Foo { x = 3; y = 4; } }) (vec (Foo { x = 27; y = 28; }) (Foo { x = 29; y = 30; }) (Foo { x = 31; y = 32; }) (Foo { x = 33; y = 34; }) (Foo { x = 35; y = 36; }) (Foo { x = 37; y = 38; }) (Foo { x = 39; y = 40; }) (Foo { x = 41; y = 42; }), Bar { v = vec True False True; w = (True, 0x4321); z = Foo { x = 123; y = 42; } }) (vec (Foo { x = 43; y = 44; }) (Foo { x = 45; y = 46; }) (Foo { x = 47; y = 48; }) (Foo { x = 49; y = 50; }) (Foo { x = 51; y = 52; }) (Foo { x = 53; y = 54; }) (Foo { x = 55; y = 56; }) (Foo { x = 57; y = 58; }), Bar { v = vec True True True; w = (True, 0xAABB); z = Foo { x = 3; y = 4; } }); d = (); e = nil; } when i == 5 ==> s.putZug $ DeepSplit $ Zug { qs = vec (Quix { q = 1; v = True }) (Quix { q = 2; v = False }); blob = False; } - when i == 6 ==> $finish + when i == 6 ==> $display "getFoo: " (cshow s.getFoo) + when i == 7 ==> $display "getBar: " (cshow $ s.getBar s.getFoo) + when i == 8 ==> $display "getZug: " (cshow s.getZug) + when i == 9 ==> do + res <- s.update (DeepSplit $ Foo { x = 77; y = 88; }) + $display "update: " (cshow res) + when i == 10 ==> do + res <- s.update (DeepSplit $ Foo { x = 33; y = 44; }) + $display "update: " (cshow res) + when i == 11 ==> $finish diff --git a/testsuite/bsc.verilog/splitports/InstanceSplit.bs b/testsuite/bsc.verilog/splitports/InstanceSplit.bs index 83c2ce7da..2b2a537f8 100644 --- a/testsuite/bsc.verilog/splitports/InstanceSplit.bs +++ b/testsuite/bsc.verilog/splitports/InstanceSplit.bs @@ -22,7 +22,7 @@ struct Bar = deriving (Bits) -- XXX would be nice to be able to derive this -instance (ShallowSplitPorts Bar p) => SplitPorts Bar p where +instance SplitPorts Bar (ShallowPortsOf Bar) where splitPorts = shallowSplitPorts unsplitPorts = shallowUnsplitPorts portNames = shallowSplitPortNames @@ -36,7 +36,7 @@ struct Baz = -- No Bits instance needed -- XXX would be nice to be able to derive this -instance (ShallowSplitPorts Baz p) => SplitPorts Baz p where +instance SplitPorts Baz (ShallowPortsOf Baz) where splitPorts = shallowSplitPorts unsplitPorts = shallowUnsplitPorts portNames = shallowSplitPortNames @@ -48,17 +48,30 @@ interface SplitTest = putFoos :: (Vector 50 Foo) -> Action putBaz :: Baz -> Action + getFoo :: Foo + getBar :: Foo -> Bar {-# result = "GET_BAR" #-} + + update :: Foo -> ActionValue Bar + {-# synthesize mkInstanceSplitTest #-} mkInstanceSplitTest :: Module SplitTest mkInstanceSplitTest = module + theCond <- mkReg False + theFoo <- mkReg (Foo { x = 0; y = 0; }) interface putFoo x = $display "putFoo: " (cshow x) putBar x = $display "putBar: " (cshow x) putFooBar x y = $display "putFooBar: " (cshow x) " " (cshow y) putFoos x = $display "putFoos: " (cshow x) putBaz x = $display "putBaz: " (cshow x) + getFoo = Foo { x = 42; y = 43; } + getBar f = Bar { v = vec True False True; w = (False, 0x4321); z = f; } + update f = do + theCond := not theCond + theFoo := f + return $ Bar { v = vec (f.x == 33) theCond (not theCond); w = (theCond, 0xDEAD); z = theFoo; } {-# synthesize sysInstanceSplit #-} sysInstanceSplit :: Module Empty @@ -73,4 +86,12 @@ sysInstanceSplit = when i == 2 ==> s.putFooBar (Foo { x = 5; y = 6; }) (Bar { v = vec False True False; w = (False, 0x5678); z = Foo { x = 7; y = 8; } }) when i == 3 ==> s.putFoos $ genWith $ \ j -> Foo { x = fromInteger $ 9 + j / 2; y = fromInteger $ 10 - 2*j / 3; } when i == 4 ==> s.putBaz $ Baz { a = Just $ Foo { x = 9; y = 10; }; b = Bar { v = vec True False False; w = (True, 0x1234); z = Foo { x = 3; y = 4; }; }; c = vec (vec (Foo { x = 11; y = 12; }) (Foo { x = 13; y = 14; }) (Foo { x = 15; y = 16; }) (Foo { x = 17; y = 18; }) (Foo { x = 19; y = 20; }) (Foo { x = 21; y = 22; }) (Foo { x = 23; y = 24; }) (Foo { x = 25; y = 26; }), Bar { v = vec True False True; w = (True, 0xBEEF); z = Foo { x = 3; y = 4; } }) (vec (Foo { x = 27; y = 28; }) (Foo { x = 29; y = 30; }) (Foo { x = 31; y = 32; }) (Foo { x = 33; y = 34; }) (Foo { x = 35; y = 36; }) (Foo { x = 37; y = 38; }) (Foo { x = 39; y = 40; }) (Foo { x = 41; y = 42; }), Bar { v = vec True False True; w = (True, 0x4321); z = Foo { x = 123; y = 42; } }) (vec (Foo { x = 43; y = 44; }) (Foo { x = 45; y = 46; }) (Foo { x = 47; y = 48; }) (Foo { x = 49; y = 50; }) (Foo { x = 51; y = 52; }) (Foo { x = 53; y = 54; }) (Foo { x = 55; y = 56; }) (Foo { x = 57; y = 58; }), Bar { v = vec True True True; w = (True, 0xAABB); z = Foo { x = 3; y = 4; } }); d = (); e = nil; } - when i == 5 ==> $finish + when i == 5 ==> $display "getFoo: " (cshow s.getFoo) + when i == 6 ==> $display "getBar: " (cshow $ s.getBar (s.getFoo)) + when i == 7 ==> do + res <- s.update (Foo { x = 77; y = 88; }) + $display "update: " (cshow res) + when i == 8 ==> do + res <- s.update (Foo { x = 33; y = 44; }) + $display "update: " (cshow res) + when i == 9 ==> $finish diff --git a/testsuite/bsc.verilog/splitports/PortNameConflict.bs b/testsuite/bsc.verilog/splitports/PortNameConflict.bs index 145bb557c..ba3a70ee7 100644 --- a/testsuite/bsc.verilog/splitports/PortNameConflict.bs +++ b/testsuite/bsc.verilog/splitports/PortNameConflict.bs @@ -8,7 +8,7 @@ struct Foo = y :: Int 8 deriving (Bits) -instance (ShallowSplitPorts Foo p) => SplitPorts Foo p where +instance SplitPorts Foo (ShallowPortsOf Foo) where splitPorts = shallowSplitPorts unsplitPorts = shallowUnsplitPorts portNames = shallowSplitPortNames @@ -18,7 +18,7 @@ struct Bar = f_x :: Int 16 deriving (Bits) -instance (ShallowSplitPorts Bar p) => SplitPorts Bar p where +instance SplitPorts Bar (ShallowPortsOf Bar) where splitPorts = shallowSplitPorts unsplitPorts = shallowUnsplitPorts portNames = shallowSplitPortNames diff --git a/testsuite/bsc.verilog/splitports/ShallowSplit.bs b/testsuite/bsc.verilog/splitports/ShallowSplit.bs index 1c96ac47b..9c7f9e294 100644 --- a/testsuite/bsc.verilog/splitports/ShallowSplit.bs +++ b/testsuite/bsc.verilog/splitports/ShallowSplit.bs @@ -31,17 +31,30 @@ interface SplitTest = putFoos :: ShallowSplit (Vector 50 Foo) -> Action putBaz :: ShallowSplit Baz -> Action + getFoo :: ShallowSplit Foo + getBar :: ShallowSplit Foo -> ShallowSplit Bar {-# result = "GET_BAR" #-} + + update :: ShallowSplit Foo -> ActionValue (ShallowSplit Bar) + {-# synthesize mkShallowSplitTest #-} mkShallowSplitTest :: Module SplitTest mkShallowSplitTest = module + theCond <- mkReg False + theFoo <- mkReg (Foo { x = 0; y = 0; }) interface putFoo (ShallowSplit x) = $display "putFoo: " (cshow x) putBar (ShallowSplit x) = $display "putBar: " (cshow x) putFooBar (ShallowSplit x) (ShallowSplit y) = $display "putFooBar: " (cshow x) " " (cshow y) putFoos (ShallowSplit x) = $display "putFoos: " (cshow x) putBaz (ShallowSplit x) = $display "putBaz: " (cshow x) + getFoo = ShallowSplit $ Foo { x = 42; y = 43; } + getBar (ShallowSplit f) = ShallowSplit $ Bar { v = vec True False True; w = (False, 0x4321); z = f; } + update (ShallowSplit f) = do + theCond := not theCond + theFoo := f + return $ ShallowSplit $ Bar { v = vec (f.x == 33) theCond (not theCond); w = (theCond, 0xDEAD); z = theFoo; } {-# synthesize sysShallowSplit #-} sysShallowSplit :: Module Empty @@ -56,4 +69,12 @@ sysShallowSplit = when i == 2 ==> s.putFooBar (ShallowSplit $ Foo { x = 5; y = 6; }) (ShallowSplit $ Bar { v = vec False True False; w = (False, 0x5678); z = Foo { x = 7; y = 8; } }) when i == 3 ==> s.putFoos $ ShallowSplit $ genWith $ \ j -> Foo { x = fromInteger $ 9 + j / 2; y = fromInteger $ 10 - 2*j / 3; } when i == 4 ==> s.putBaz $ ShallowSplit $ Baz { a = Just $ Foo { x = 9; y = 10; }; b = Bar { v = vec True False False; w = (True, 0x1234); z = Foo { x = 3; y = 4; }; }; c = vec (vec (Foo { x = 11; y = 12; }) (Foo { x = 13; y = 14; }) (Foo { x = 15; y = 16; }) (Foo { x = 17; y = 18; }) (Foo { x = 19; y = 20; }) (Foo { x = 21; y = 22; }) (Foo { x = 23; y = 24; }) (Foo { x = 25; y = 26; }), Bar { v = vec True False True; w = (True, 0xBEEF); z = Foo { x = 3; y = 4; } }) (vec (Foo { x = 27; y = 28; }) (Foo { x = 29; y = 30; }) (Foo { x = 31; y = 32; }) (Foo { x = 33; y = 34; }) (Foo { x = 35; y = 36; }) (Foo { x = 37; y = 38; }) (Foo { x = 39; y = 40; }) (Foo { x = 41; y = 42; }), Bar { v = vec True False True; w = (True, 0x4321); z = Foo { x = 123; y = 42; } }) (vec (Foo { x = 43; y = 44; }) (Foo { x = 45; y = 46; }) (Foo { x = 47; y = 48; }) (Foo { x = 49; y = 50; }) (Foo { x = 51; y = 52; }) (Foo { x = 53; y = 54; }) (Foo { x = 55; y = 56; }) (Foo { x = 57; y = 58; }), Bar { v = vec True True True; w = (True, 0xAABB); z = Foo { x = 3; y = 4; } }); d = (); e = nil; } - when i == 5 ==> $finish + when i == 5 ==> $display "getFoo: " (cshow s.getFoo) + when i == 6 ==> $display "getBar: " (cshow $ s.getBar s.getFoo) + when i == 7 ==> do + res <- s.update (ShallowSplit $ Foo { x = 77; y = 88; }) + $display "update: " (cshow res) + when i == 8 ==> do + res <- s.update (ShallowSplit $ Foo { x = 33; y = 44; }) + $display "update: " (cshow res) + when i == 9 ==> $finish diff --git a/testsuite/bsc.verilog/splitports/SomeArgNames.bs b/testsuite/bsc.verilog/splitports/SomeArgNames.bs index fd2b871fe..af506a28b 100644 --- a/testsuite/bsc.verilog/splitports/SomeArgNames.bs +++ b/testsuite/bsc.verilog/splitports/SomeArgNames.bs @@ -8,7 +8,7 @@ struct Foo = y :: Int 8 deriving (Bits) -instance (ShallowSplitPorts Foo p) => SplitPorts Foo p where +instance SplitPorts Foo (ShallowPortsOf Foo) where splitPorts = shallowSplitPorts unsplitPorts = shallowUnsplitPorts portNames = shallowSplitPortNames @@ -18,7 +18,7 @@ struct Bar = b :: Bool deriving (Bits) -instance (ShallowSplitPorts Bar p) => SplitPorts Bar p where +instance SplitPorts Bar (ShallowPortsOf Bar) where splitPorts = shallowSplitPorts unsplitPorts = shallowUnsplitPorts portNames = shallowSplitPortNames diff --git a/testsuite/bsc.verilog/splitports/TooManyArgNames.bs b/testsuite/bsc.verilog/splitports/TooManyArgNames.bs index 9a97f196f..19a598f4d 100644 --- a/testsuite/bsc.verilog/splitports/TooManyArgNames.bs +++ b/testsuite/bsc.verilog/splitports/TooManyArgNames.bs @@ -8,7 +8,7 @@ struct Foo = y :: Int 8 deriving (Bits) -instance (ShallowSplitPorts Foo p) => SplitPorts Foo p where +instance SplitPorts Foo (ShallowPortsOf Foo) where splitPorts = shallowSplitPorts unsplitPorts = shallowUnsplitPorts portNames = shallowSplitPortNames @@ -18,7 +18,7 @@ struct Bar = b :: Bool deriving (Bits) -instance (ShallowSplitPorts Bar p) => SplitPorts Bar p where +instance SplitPorts Bar (ShallowPortsOf Bar) where splitPorts = shallowSplitPorts unsplitPorts = shallowUnsplitPorts portNames = shallowSplitPortNames diff --git a/testsuite/bsc.verilog/splitports/splitports.exp b/testsuite/bsc.verilog/splitports/splitports.exp index 0987ba1ba..12c8fa783 100644 --- a/testsuite/bsc.verilog/splitports/splitports.exp +++ b/testsuite/bsc.verilog/splitports/splitports.exp @@ -9,6 +9,17 @@ if { $vtest == 1 } { find_regexp mkShallowSplitTest.v {input \[15 : 0\] putFoos_1_49;} find_regexp mkShallowSplitTest.v {input \[16 : 0\] putBaz_1_a;} find_regexp mkShallowSplitTest.v {input \[491 : 0\] putBaz_1_c;} + find_regexp mkShallowSplitTest.v {output \[7 : 0\] getFoo_x;} + find_regexp mkShallowSplitTest.v {output \[7 : 0\] getFoo_y;} + find_regexp mkShallowSplitTest.v {output \[2 : 0\] GET_BAR_v;} + find_regexp mkShallowSplitTest.v {output \[15 : 0\] GET_BAR_z;} + find_regexp mkShallowSplitTest.v {input \[7 : 0\] update_1_x;} + find_regexp mkShallowSplitTest.v {input EN_update;} + find_regexp mkShallowSplitTest.v {output \[16 : 0\] update_w;} + find_regexp mkShallowSplitTest.v {output RDY_update;} + + find_regexp mkShallowSplitTest.v {\(getBar_1_x, getBar_1_y\) -> GET_BAR_z} + find_regexp mkShallowSplitTest.v {update_1_x -> update_v} } test_c_veri DeepSplit @@ -24,6 +35,23 @@ if { $vtest == 1 } { find_regexp mkDeepSplitTest.v {input \[7 : 0\] putBaz_1_c_2_1_7_y;} find_regexp mkDeepSplitTest.v {input \[15 : 0\] putBaz_1_c_2_2_w_2;} find_regexp mkDeepSplitTest.v {input \[3 : 0\] putZug_1_qs_1;} + find_regexp mkDeepSplitTest.v {output \[7 : 0\] getFoo_x;} + find_regexp mkDeepSplitTest.v {output \[7 : 0\] getFoo_y;} + find_regexp mkDeepSplitTest.v {output GET_BAR_v_0;} + find_regexp mkDeepSplitTest.v {output GET_BAR_v_2;} + find_regexp mkDeepSplitTest.v {output \[15 : 0\] GET_BAR_w_2;} + find_regexp mkDeepSplitTest.v {output \[7 : 0\] GET_BAR_z_y;} + find_regexp mkDeepSplitTest.v {output \[3 : 0\] getZug_qs_0;} + find_regexp mkDeepSplitTest.v {output \[3 : 0\] getZug_qs_1;} + find_regexp mkDeepSplitTest.v {output getZug_blob;} + find_regexp mkDeepSplitTest.v {input \[7 : 0\] update_1_x;} + find_regexp mkDeepSplitTest.v {input EN_update;} + find_regexp mkDeepSplitTest.v {output \[15 : 0\] update_w_2;} + find_regexp mkDeepSplitTest.v {output RDY_update;} + + find_regexp mkDeepSplitTest.v {getBar_1_x -> GET_BAR_z_x} + find_regexp mkDeepSplitTest.v {getBar_1_y -> GET_BAR_z_y} + find_regexp mkDeepSplitTest.v {update_1_x -> update_v_0} } test_c_veri InstanceSplit @@ -37,6 +65,20 @@ if { $vtest == 1 } { find_regexp mkInstanceSplitTest.v {input \[799 : 0\] putFoos_1;} find_regexp mkInstanceSplitTest.v {input \[16 : 0\] putBaz_1_a;} find_regexp mkInstanceSplitTest.v {input \[491 : 0\] putBaz_1_c;} + find_regexp mkInstanceSplitTest.v {output \[7 : 0\] getFoo_x;} + find_regexp mkInstanceSplitTest.v {output getFoo_ysign;} + find_regexp mkInstanceSplitTest.v {output \[6 : 0\] getFoo_yvalue;} + find_regexp mkInstanceSplitTest.v {output \[2 : 0\] GET_BAR_v;} + find_regexp mkInstanceSplitTest.v {output GET_BAR_z_ysign;} + find_regexp mkInstanceSplitTest.v {input \[7 : 0\] update_1_x;} + find_regexp mkInstanceSplitTest.v {input EN_update;} + find_regexp mkInstanceSplitTest.v {output \[6 : 0\] update_z_yvalue;} + find_regexp mkInstanceSplitTest.v {output RDY_update;} + + find_regexp mkInstanceSplitTest.v {getBar_1_x -> GET_BAR_z_x} + find_regexp mkInstanceSplitTest.v {\(getBar_1_ysign, getBar_1_yvalue\) -> GET_BAR_z_ysign} + find_regexp mkInstanceSplitTest.v {\(getBar_1_ysign, getBar_1_yvalue\) -> GET_BAR_z_yvalue} + find_regexp mkInstanceSplitTest.v {update_1_x -> update_v} } # Supplying an arg_names pragma that is shorter than the number of arguments diff --git a/testsuite/bsc.verilog/splitports/sysDeepSplit.out.expected b/testsuite/bsc.verilog/splitports/sysDeepSplit.out.expected index fa26cd6e1..af9d18ba2 100644 --- a/testsuite/bsc.verilog/splitports/sysDeepSplit.out.expected +++ b/testsuite/bsc.verilog/splitports/sysDeepSplit.out.expected @@ -4,3 +4,8 @@ putFooBar: Foo {x= 5; y= 6} Bar {v=[False, True, False]; w=(False, 22136); z putFoos: [Foo {x= 9; y= 10}, Foo {x= 9; y= 10}, Foo {x= 10; y= 9}, Foo {x= 10; y= 8}, Foo {x= 11; y= 8}, Foo {x= 11; y= 7}, Foo {x= 12; y= 6}, Foo {x= 12; y= 6}, Foo {x= 13; y= 5}, Foo {x= 13; y= 4}, Foo {x= 14; y= 4}, Foo {x= 14; y= 3}, Foo {x= 15; y= 2}, Foo {x= 15; y= 2}, Foo {x= 16; y= 1}, Foo {x= 16; y= 0}, Foo {x= 17; y= 0}, Foo {x= 17; y= -1}, Foo {x= 18; y= -2}, Foo {x= 18; y= -2}, Foo {x= 19; y= -3}, Foo {x= 19; y= -4}, Foo {x= 20; y= -4}, Foo {x= 20; y= -5}, Foo {x= 21; y= -6}, Foo {x= 21; y= -6}, Foo {x= 22; y= -7}, Foo {x= 22; y= -8}, Foo {x= 23; y= -8}, Foo {x= 23; y= -9}, Foo {x= 24; y= -10}, Foo {x= 24; y= -10}, Foo {x= 25; y= -11}, Foo {x= 25; y= -12}, Foo {x= 26; y= -12}, Foo {x= 26; y= -13}, Foo {x= 27; y= -14}, Foo {x= 27; y= -14}, Foo {x= 28; y= -15}, Foo {x= 28; y= -16}, Foo {x= 29; y= -16}, Foo {x= 29; y= -17}, Foo {x= 30; y= -18}, Foo {x= 30; y= -18}, Foo {x= 31; y= -19}, Foo {x= 31; y= -20}, Foo {x= 32; y= -20}, Foo {x= 32; y= -21}, Foo {x= 33; y= -22}, Foo {x= 33; y= -22}] putBaz: Baz {a=Valid (Foo {x= 9; y= 10}); b=Bar {v=[True, False, False]; w=(True, 4660); z=Foo {x= 3; y= 4}}; c=[([Foo {x= 11; y= 12}, Foo {x= 13; y= 14}, Foo {x= 15; y= 16}, Foo {x= 17; y= 18}, Foo {x= 19; y= 20}, Foo {x= 21; y= 22}, Foo {x= 23; y= 24}, Foo {x= 25; y= 26}], Bar {v=[True, False, True]; w=(True, 48879); z=Foo {x= 3; y= 4}}), ([Foo {x= 27; y= 28}, Foo {x= 29; y= 30}, Foo {x= 31; y= 32}, Foo {x= 33; y= 34}, Foo {x= 35; y= 36}, Foo {x= 37; y= 38}, Foo {x= 39; y= 40}, Foo {x= 41; y= 42}], Bar {v=[True, False, True]; w=(True, 17185); z=Foo {x= 123; y= 42}}), ([Foo {x= 43; y= 44}, Foo {x= 45; y= 46}, Foo {x= 47; y= 48}, Foo {x= 49; y= 50}, Foo {x= 51; y= 52}, Foo {x= 53; y= 54}, Foo {x= 55; y= 56}, Foo {x= 57; y= 58}], Bar {v=[True, True, True]; w=(True, 43707); z=Foo {x= 3; y= 4}})]; d=(); e=[]} putZug: Zug {qs=[Quix {q= 1; v=True}, Quix {q= 2; v=False}]; blob=False} +getFoo: DeepSplit (Foo {x= 42; y= 43}) +getBar: DeepSplit (Bar {v=[True, False, True]; w=(False, 17185); z=Foo {x= 42; y= 43}}) +getZug: DeepSplit (Zug {qs=[Quix {q=-2; v=True}, Quix {q= 2; v=False}]; blob=True}) +update: DeepSplit (Bar {v=[False, False, True]; w=(False, 57005); z=Foo {x= 0; y= 0}}) +update: DeepSplit (Bar {v=[True, True, False]; w=(True, 57005); z=Foo {x= 77; y= 88}}) diff --git a/testsuite/bsc.verilog/splitports/sysInstanceSplit.out.expected b/testsuite/bsc.verilog/splitports/sysInstanceSplit.out.expected index bb4f2dc03..00bf5618c 100644 --- a/testsuite/bsc.verilog/splitports/sysInstanceSplit.out.expected +++ b/testsuite/bsc.verilog/splitports/sysInstanceSplit.out.expected @@ -3,3 +3,7 @@ putBar: Bar {v=[True, False, True]; w=(True, 4660); z=Foo {x= 3; y= 4}} putFooBar: Foo {x= 5; y= 6} Bar {v=[False, True, False]; w=(False, 22136); z=Foo {x= 7; y= 8}} putFoos: [Foo {x= 9; y= 10}, Foo {x= 9; y= 10}, Foo {x= 10; y= 9}, Foo {x= 10; y= 8}, Foo {x= 11; y= 8}, Foo {x= 11; y= 7}, Foo {x= 12; y= 6}, Foo {x= 12; y= 6}, Foo {x= 13; y= 5}, Foo {x= 13; y= 4}, Foo {x= 14; y= 4}, Foo {x= 14; y= 3}, Foo {x= 15; y= 2}, Foo {x= 15; y= 2}, Foo {x= 16; y= 1}, Foo {x= 16; y= 0}, Foo {x= 17; y= 0}, Foo {x= 17; y= -1}, Foo {x= 18; y= -2}, Foo {x= 18; y= -2}, Foo {x= 19; y= -3}, Foo {x= 19; y= -4}, Foo {x= 20; y= -4}, Foo {x= 20; y= -5}, Foo {x= 21; y= -6}, Foo {x= 21; y= -6}, Foo {x= 22; y= -7}, Foo {x= 22; y= -8}, Foo {x= 23; y= -8}, Foo {x= 23; y= -9}, Foo {x= 24; y= -10}, Foo {x= 24; y= -10}, Foo {x= 25; y= -11}, Foo {x= 25; y= -12}, Foo {x= 26; y= -12}, Foo {x= 26; y= -13}, Foo {x= 27; y= -14}, Foo {x= 27; y= -14}, Foo {x= 28; y= -15}, Foo {x= 28; y= -16}, Foo {x= 29; y= -16}, Foo {x= 29; y= -17}, Foo {x= 30; y= -18}, Foo {x= 30; y= -18}, Foo {x= 31; y= -19}, Foo {x= 31; y= -20}, Foo {x= 32; y= -20}, Foo {x= 32; y= -21}, Foo {x= 33; y= -22}, Foo {x= 33; y= -22}] putBaz: Baz {a=Valid (Foo {x= 9; y= 10}); b=Bar {v=[True, False, False]; w=(True, 4660); z=Foo {x= 3; y= 4}}; c=[([Foo {x= 11; y= 12}, Foo {x= 13; y= 14}, Foo {x= 15; y= 16}, Foo {x= 17; y= 18}, Foo {x= 19; y= 20}, Foo {x= 21; y= 22}, Foo {x= 23; y= 24}, Foo {x= 25; y= 26}], Bar {v=[True, False, True]; w=(True, 48879); z=Foo {x= 3; y= 4}}), ([Foo {x= 27; y= 28}, Foo {x= 29; y= 30}, Foo {x= 31; y= 32}, Foo {x= 33; y= 34}, Foo {x= 35; y= 36}, Foo {x= 37; y= 38}, Foo {x= 39; y= 40}, Foo {x= 41; y= 42}], Bar {v=[True, False, True]; w=(True, 17185); z=Foo {x= 123; y= 42}}), ([Foo {x= 43; y= 44}, Foo {x= 45; y= 46}, Foo {x= 47; y= 48}, Foo {x= 49; y= 50}, Foo {x= 51; y= 52}, Foo {x= 53; y= 54}, Foo {x= 55; y= 56}, Foo {x= 57; y= 58}], Bar {v=[True, True, True]; w=(True, 43707); z=Foo {x= 3; y= 4}})]; d=(); e=[]} +getFoo: Foo {x= 42; y= 43} +getBar: Bar {v=[True, False, True]; w=(False, 17185); z=Foo {x= 42; y= 43}} +update: Bar {v=[False, False, True]; w=(False, 57005); z=Foo {x= 0; y= 0}} +update: Bar {v=[True, True, False]; w=(True, 57005); z=Foo {x= 77; y= 88}} diff --git a/testsuite/bsc.verilog/splitports/sysShallowSplit.out.expected b/testsuite/bsc.verilog/splitports/sysShallowSplit.out.expected index bb4f2dc03..40e21a373 100644 --- a/testsuite/bsc.verilog/splitports/sysShallowSplit.out.expected +++ b/testsuite/bsc.verilog/splitports/sysShallowSplit.out.expected @@ -3,3 +3,7 @@ putBar: Bar {v=[True, False, True]; w=(True, 4660); z=Foo {x= 3; y= 4}} putFooBar: Foo {x= 5; y= 6} Bar {v=[False, True, False]; w=(False, 22136); z=Foo {x= 7; y= 8}} putFoos: [Foo {x= 9; y= 10}, Foo {x= 9; y= 10}, Foo {x= 10; y= 9}, Foo {x= 10; y= 8}, Foo {x= 11; y= 8}, Foo {x= 11; y= 7}, Foo {x= 12; y= 6}, Foo {x= 12; y= 6}, Foo {x= 13; y= 5}, Foo {x= 13; y= 4}, Foo {x= 14; y= 4}, Foo {x= 14; y= 3}, Foo {x= 15; y= 2}, Foo {x= 15; y= 2}, Foo {x= 16; y= 1}, Foo {x= 16; y= 0}, Foo {x= 17; y= 0}, Foo {x= 17; y= -1}, Foo {x= 18; y= -2}, Foo {x= 18; y= -2}, Foo {x= 19; y= -3}, Foo {x= 19; y= -4}, Foo {x= 20; y= -4}, Foo {x= 20; y= -5}, Foo {x= 21; y= -6}, Foo {x= 21; y= -6}, Foo {x= 22; y= -7}, Foo {x= 22; y= -8}, Foo {x= 23; y= -8}, Foo {x= 23; y= -9}, Foo {x= 24; y= -10}, Foo {x= 24; y= -10}, Foo {x= 25; y= -11}, Foo {x= 25; y= -12}, Foo {x= 26; y= -12}, Foo {x= 26; y= -13}, Foo {x= 27; y= -14}, Foo {x= 27; y= -14}, Foo {x= 28; y= -15}, Foo {x= 28; y= -16}, Foo {x= 29; y= -16}, Foo {x= 29; y= -17}, Foo {x= 30; y= -18}, Foo {x= 30; y= -18}, Foo {x= 31; y= -19}, Foo {x= 31; y= -20}, Foo {x= 32; y= -20}, Foo {x= 32; y= -21}, Foo {x= 33; y= -22}, Foo {x= 33; y= -22}] putBaz: Baz {a=Valid (Foo {x= 9; y= 10}); b=Bar {v=[True, False, False]; w=(True, 4660); z=Foo {x= 3; y= 4}}; c=[([Foo {x= 11; y= 12}, Foo {x= 13; y= 14}, Foo {x= 15; y= 16}, Foo {x= 17; y= 18}, Foo {x= 19; y= 20}, Foo {x= 21; y= 22}, Foo {x= 23; y= 24}, Foo {x= 25; y= 26}], Bar {v=[True, False, True]; w=(True, 48879); z=Foo {x= 3; y= 4}}), ([Foo {x= 27; y= 28}, Foo {x= 29; y= 30}, Foo {x= 31; y= 32}, Foo {x= 33; y= 34}, Foo {x= 35; y= 36}, Foo {x= 37; y= 38}, Foo {x= 39; y= 40}, Foo {x= 41; y= 42}], Bar {v=[True, False, True]; w=(True, 17185); z=Foo {x= 123; y= 42}}), ([Foo {x= 43; y= 44}, Foo {x= 45; y= 46}, Foo {x= 47; y= 48}, Foo {x= 49; y= 50}, Foo {x= 51; y= 52}, Foo {x= 53; y= 54}, Foo {x= 55; y= 56}, Foo {x= 57; y= 58}], Bar {v=[True, True, True]; w=(True, 43707); z=Foo {x= 3; y= 4}})]; d=(); e=[]} +getFoo: ShallowSplit (Foo {x= 42; y= 43}) +getBar: ShallowSplit (Bar {v=[True, False, True]; w=(False, 17185); z=Foo {x= 42; y= 43}}) +update: ShallowSplit (Bar {v=[False, False, True]; w=(False, 57005); z=Foo {x= 0; y= 0}}) +update: ShallowSplit (Bar {v=[True, True, False]; w=(True, 57005); z=Foo {x= 77; y= 88}})