\subsubsection{ModuleContext} \label{sec-ModuleContext} \index{ModuleContext (package)} {\bf Package} \begin{verbatim} import ModuleContext :: * ; \end{verbatim} {\bf Description} An ordinary Bluespec module, when instantiated, adds state elements and rules to the growing accumulation of elements and rules already in the design. In some designs, items other than state elements and rules must be accumulated as well. While there is a need to add these items, it is also desirable to keep these additional design details separate from the main design, keeping the natural structure of the design intact. The \te{ModuleContext} package provides the capability of accumulating items and maintaining the compile-time state of additional items, in such a way that it doesn't change the structure of the original design. The \te{ModuleContext} mechanism allows the designer to {\em hide} the details of the additional interfaces. Before the module can be synthesized, it must be converted (or {\em exposed}) into a module containing only rules and state elements, as the compiler does not know how to handle the other items. The \te{ModuleContext} package provides the mechanisms to allow additional items to be collected, processed, and exposed. {\bf Types and Type Classes} The default BSV module type is \te{Module}, but you can define other BSV module types as well. The \te{ModuleContext} type is a variation on the \te{Module} type that allows additional items, other than states and rules, to be collected while elaborating the module structure. The \te{ModuleContext} package defines the typeclass \te{Context}, which includes functions \te{getContext} and \te{putContext}. A \te{Context} typeclass has two type parameters: a module type (\te{mc1}) and the context (\te{c2}). \begin{verbatim} typeclass Context#(type mc1, type c2); module [mc1] getContext(c2) provisos (IsModule#(mc1, a)); module [mc1] putContext#(c2 s)(Empty) provisos (IsModule#(mc1, a)); endtypeclass \end{verbatim} A regular module type (\te{Module}) will have a context of \te{void}: \begin{verbatim} instance Context#(Module, void); \end{verbatim} A module type of \te{ModuleContext} will return the context of the module: \begin{verbatim} instance Context#(ModuleContext#(st1), st1); \end{verbatim} An instance is defined where the context type \te{st1} of the \te{ModuleContext} and the context type \te{st2} are different, but \te{Gettable} (as defined in \te{Hlist} Section \ref{sec-HList}): \begin{verbatim} instance Context#(ModuleContext#(st1), st2) provisos (Gettable#(st1, st2)); \end{verbatim} The modules \te{applyToContext} and \te{applyToContextM} are used to apply a function over a context. The \te{applyToContextM} modules is used for monadic functions. \index{applyToContext@\te{applyToContext} (module)} \index[function]{ModuleContext!applyToContext} \begin{tabular}{|p{1.1 in}|p{4.5 in}|} \hline & \\ \te{applyToContext} &Applies a function over a context.\\ \cline{2-2} & \begin{libverbatim} module [mc1] applyToContext#(function c2 f(c2 c))(Empty) provisos (IsModule#(mc1, a), Context#(mc1, c2)); \end{libverbatim} \\ \hline \end{tabular} \index{applyToContextM@\te{applyToContextM} (module)} \index[function]{ModuleContext!applyToContextM} \begin{tabular}{|p{1.1 in}|p{4.5 in}|} \hline & \\ \te{applyToContextM} &Applies a monadic function over a context.\\ \cline{2-2} & \begin{libverbatim} module [mc1] applyToContextM#(function module#(c2) m(c2 c)) (Empty) provisos (IsModule#(mc1, a), Context#(mc1, c2)); \end{libverbatim} \\ \hline \end{tabular} {\bf ClockContext} The structure \te{ClockContext} is defined to be comprised of two clocks: \te{clk1} and \te{clk2} and two resets: \te{rst1} and \te{rst2}. \begin{verbatim} typedef struct { Clock clk1; Clock clk2; Reset rst1; Reset rst2; } ClockContext; \end{verbatim} An \te{initClockContext} is defined with the values of both clocks set to \te{noClock} and both resets set to \te{noReset}: \begin{verbatim} ClockContext initClockContext = ClockContext { clk1: noClock, clk2: noClock, rst1: noReset, rst2: noReset }; \end{verbatim} {\bf Expose} The \te{Expose} typeclass converts a context to an interface for a synthesis boundary, converting it to a module type of \te{Module}. The \te{Expose} typeclass provides the modules \te{unburyContext} and \te{unburyContextWithClocks}. \begin{verbatim} typeclass Expose#(type c, type ifc) dependencies (c determines ifc); \end{verbatim} An \te{HList} of contexts is convertible if its elements are, and results in a \te{Tuple} of subinterfaces. \begin{verbatim} instance Expose#(HList1#(ct1), ifc1) provisos (Expose#(ct1,ifc1)); \end{verbatim} \begin{verbatim} instance Expose#(HCons#(c1,c2), Tuple2#(ifc1,ifc2)) provisos (Expose#(c1,ifc1), Expose#(c2,ifc2)); instance Expose#(ClockContext, Empty); \end{verbatim} \index{unburyContext@\te{unburyContext} (module)} \index[function]{ModuleContext!unburyContext} The \te{unburyContext} module is for use at the top level of a module to be separately synthesized. It takes as an argument a module which is to be instantiated in a particular context, and an initial state for that context. The module is instantiated, and the final context converted into an extra interface, returned in pair with the intantiated module's own interface. \begin{tabular}{|p{1.2 in}|p{4.6 in}|} \hline & \\ \te{unburyContext} &Converts a context to an interface for a synthesis boundary. An \te{HList} of contexts is convertible if its elements are, and results in a tuple of subinterfaces. \\ \cline{2-2} & \begin{libverbatim} module unburyContext#(c x)(ifc); module unburyContext#(HList1#(ct1) c1)(ifc1); module unburyContext#(HCons#(c1,c2) c12)(Tuple2#(ifc1,ifc2)); module unburyContext#(ClockContext x)(); \end{libverbatim} \\ \hline \end{tabular} \index{unburyContextWithClocks@\te{unburyContextWithClocks} (module)} \index[function]{ModuleContext!unburyContextWithClocks} The \te{unburyContextWithClocks} takes a \te{ClockContext} along with the \te{Context} it is specifically handling % The \te{unburyWithClocks} module is a top-level module for use within % a separately synthesized module. It takes two clocks and two resets as % extra arguments, and embeds them in the \te{ClockContext} before % supplying the \te{CompleteContext} to the argument module. \begin{tabular}{|p{1.6 in}|p{4.2 in}|} \hline &\\ \te{unburyContextWithClocks}& Converts a context to an interface for a synthesis boundary and takes a ClockContext as a second argument.\\ \cline{2-2} & \begin{libverbatim} module unburyContextWithClocks#(c x, ClockContext cc) (ifc); module unburyContextWithClocks#(HList1#(ct1) c1, ClockContext cc)(ifc1); module unburyContextWithClocks#(HCons#(c1,c2) c12, ClockContext cc) (Tuple2#(ifc1,ifc2)); module unburyContextWithClocks#(ClockContext x, ClockContext cc)(); \end{libverbatim} \\ \hline \end{tabular} {\bf Hide} The \te{Hide} typeclass provides the module \te{reburyContext}, which takes an interface as an argument (and provides an Empty interface). It is intended to be run in a context which can absorb the information from the interface. As with \te{Expose}, a \te{Tuple} of interfaces can be hidden if each element can be hidden. \index{reburyContext@\te{reburyContext} (module)} \index[function]{ModuleContext!reburyContext} \begin{tabular}{|p{1.2 in}|p{4.6 in}|} \hline & \\ \te{reburyContext} &Connects the provided interface with the surrounding context. \\ \cline{2-2} & \begin{libverbatim} module [mc] reburyContext#(ifc i)(Empty); module [mc] reburyContext#(Empty i)(Empty); module [mc] reburyContext#(Tuple2#(ifc1,ifc2) i12)(Empty); \end{libverbatim} \\ \hline \end{tabular} {\bf ContextRun} The \te{ContextRun} and \te{ContextsRun} typeclasses provides modules to run modules in contexts. The module \te{runWithContext} runs a module with an entirely new context. % The modules % \te{runWithOneMoreContext} and \te{runWithMoreContexts} adds items % onto a context. In both cases, the module takes as an argument the % initial state of the new part of the context, and the final version % of the new part of the context is returned as the result of the run, % and the old part of the context continues to accumulate. \begin{verbatim} typeclass ContextRun#(type m, type c1, type ctx2) dependencies ((m, c1) determines ctx2); \end{verbatim} \begin{verbatim} typeclass ContextsRun#(type m, type c1, type ctx2) dependencies ((m, c1) determines ctx2); \end{verbatim} \index{runWithContext@\te{runWithContext} (function)} \index[function]{ModuleContext!runWithContext} \begin{tabular}{|p{1.2 in}|p{4.6 in}|} \hline & \\ \te{runWithContext} &Runs a module with an entirely new context.\\ \cline{2-2} & \begin{libverbatim} module [m] runWithContext #(c1 initState, ModuleContext#(ctx2, ifcType) mkI) (Tuple2#(c1, ifcType)); module [ModuleContext#(ctx)] runWithContext#(c1 initState, ModuleContext#(HCons#(c1, ctx), ifcType) mkI) (Tuple2#(c1, ifcType)); module [Module] runWithContext#(c1 initState, ModuleContext#(c1,ifcType) mkI) (Tuple2#(c1, ifcType)); \end{libverbatim} \\ \hline \end{tabular} \index{runWithContexts@\te{runWithContexts} (function)} \index[function]{ModuleContext!runWithContext} \begin{tabular}{|p{1.2 in}|p{4.6 in}|} \hline & \\ \te{runWithContexts} &Runs a module with an entirely new context.\\ \cline{2-2} & \begin{libverbatim} module [m] runWithContexts#(c1 initState, ModuleContext#(ctx2, ifcType) mkI) (Tuple2#(c1, ifcType)); module [ModuleContext#(ctx)] runWithContexts#(c1 initState, ModuleContext#(ctx2, ifcType) mkI) (Tuple2#(c1, ifcType)); module [Module] runWithContexts#(c1 initState, ModuleContext#(c1, ifcType) mkI) (Tuple2#(c1, ifcType)); \end{libverbatim} \\ \hline \end{tabular} {\bf Contexts.defines} BSC provides macros in the \te{Context.defines} file to handle the treatment of the module contexts at synthesis boundaries. \begin{enumerate} \item The designer defines a leaf or intermediate node module, with module type \te{[ErrorReporter]} or \te{[ErrorReporterA]}, appending a \te{0} to its name (e.g. \te{mkM0}). Elsewhere in the package the appropriate macro is chosen from the macros \te{SynthBoundary} and \te{SynthBoundaryWithClocks}. \item The macro defines a synthesizable version of the module, \te{mkMV}, which provides the original interface together with an error-reporting subinterface. It also defines a module with the original name \te{mkM} to be used for instantiating the original module. It uses the Context mechanism to re-bury the error-reporting plumbing and returns the original interface of the original \te{mkM)} module \end{enumerate} These macros assume that the complete module context (such as an \te{HList} of individual contexts) is named \te{CompleteContext} and that its initial value may be obtained from either \te{mkInitialCompleteContext} or \te{mkInitialCompleteContextWithClocks}. {\bf Example Without Clocks} \begin{verbatim} SynthBoundary(mkM,IM) \end{verbatim} Becomes \begin{verbatim} (*synthesize*) module [Module] mkMV(Tuple2#(CompleteContextIfc,IM)); let init <- mkInitialCompleteContext; let _ifc <- unbury(init, mkM0); return _ifc; endmodule module [ModuleContext#(CompleteContext)] mkM(IM); let _ifc <- rebury(mkMV); return _ifc; endmodule \end{verbatim} {\bf Example With Clocks} \begin{verbatim} SynthBoundaryWithClocks(mkM,IM) \end{verbatim} Becomes \begin{verbatim} (*synthesize*) module [Module] mkMV#(Clock c1,Reset r1,Clock c2,Reset r2)(Tuple2#(CompleteContextIfc,IM)); let init <- mkInitialCompleteContextWithClocks(c1, r1, c2, r2); let _ifc <- unburyWithClocks(initialCompleteContext, c1, r1, c2, r2, mkM0); return _ifc; endmodule module [ModuleContext#(CompleteContext)] mkM(IM); let _ifc <- reburyWithClocks(mkMV); return _ifc; endmodule \end{verbatim}