import List::*; // //@ \subsection{Clocks and Resets} //@ \index{Clocks@\te{Clocks} (package)|textbf} //@ //@ The BSV \te{Clocks} library provide features to access and change //@ the default clock. Moreover, there are hardware primitives to //@ generate clocks of various shapes, plus several primitives which //@ allow the safe crossing of signals and data from one clock domain //@ to another. //@ //@ \subsubsection{Clock Generators and Manipulation} //@ //XXX@ exposeCurrentClock needs to be documented. //X@ //X@ \index{ClockGenIfc@\te{ClockGenIfc} (interface)|textbf} //X@ An interface for a module which provides (generates) a clock. //X@ # 3 // Needed for module BVI, users should not need this interface ClockGenIfc; interface Clock gen_clk; endinterface //@ //@ \index{mkAbsoluteClock@\te{mkAbsoluteClock} (module)|textbf} //@ \te{mkAbsoluteClock} provides a parameterizable clock //@ generation module, with its first rising edge (start) and period //@ defined by parameters. //@ This module is not synthesizable. //@ # 3 module mkAbsoluteClock #( Integer start, Integer period ) ( Clock ); (* hide *) ClockGenIfc _m <- vMkAbsoluteClock(start,period); return _m.gen_clk(); endmodule import "BVI" ClockGen = module vMkAbsoluteClock #( Integer start, Integer period ) ( ClockGenIfc ); let halfPeriod = div( period, 2) ; default_clock no_clock; parameter v1Width = halfPeriod ; parameter v2Width = period - halfPeriod ; parameter initDelay = start; parameter initValue = 0 ; parameter otherValue = 1 ; no_reset; output_clock gen_clk(CLK_OUT); endmodule //@ //@ \index{mkAbsoluteClockFull@\te{mkAbsoluteClockFull} (module)|textbf} //@ \te{mkAbsoluteClockFull} provides a fully parameterizable clock //@ generation module. //@ \te{initValue} is held until time start, and then the clock //@ oscillates with from, with \te{not(initValue)} held for time //@ \te{compValTime} followed by \te{initValue} held for time //@ \te{initValTime}. Hence the clock period after startup is //@ \te{compValTime + initValTime}. //@ This module is not synthesizable, it is provided by the Verilog //@ module \te{ClockGen.v} //@ # 5 module mkAbsoluteClockFull #( Integer start, Bit#(1) initValue, Integer compValTime, Integer initValTime ) ( Clock ); (* hide *) ClockGenIfc _m <- vMkAbsoluteClockFull(start, initValue, compValTime, initValTime); return _m.gen_clk(); endmodule import "BVI" ClockGen = module vMkAbsoluteClockFull #( Integer start, Bit#(1) initValue, Integer compValTime, Integer initValTime ) ( ClockGenIfc ); default_clock no_clock; parameter v1Width = compValTime ; parameter v2Width = initValTime ; parameter initDelay = start ; parameter initValue = initValue ; parameter otherValue = ~ initValue ; no_reset; output_clock gen_clk(CLK_OUT); endmodule // The MakeClockIfc supports user-defined clocks with // irregular waveforms created with mkClock, as opposed to the // fixed-period waveforms created with the mkAbsoluteClock family. interface MakeClockIfc#(type one_bit_type); method Action setClockValue(one_bit_type value) ; method one_bit_type getClockValue() ; method Action setGateCond(Bool gate) ; method Bool getGateCond() ; interface Clock new_clk ; endinterface // Internal use only interface MakeUngatedClockIfc#(type one_bit_type); method Action setClockValue(one_bit_type value) ; method one_bit_type getClockValue() ; method Action setGateCond(Bool gate) ; method Bool getGateCond() ; method Bool unused(); interface Clock new_clk ; endinterface //@ //@ \index{mkClock@\te{mkClock} (module)|textbf} //@ The mkClock module creates a Clock type from a one-bit oscillator //@ and a Boolean gate condition. //@ There are no relations between the current clock and the clock //@ generated by this module. //@ The initial values of the oscillator and gate are passed //@ as parameters to the module. When the module is out of reset, //@ the oscillator value can be changed using the {\tt setClockValue} //@ method and the gate condition can be changed by calling the //@ {\tt setGateCond} method. The oscillator value and gate condition //@ can be queried with the {\tt getClockValue} and {\tt getGateCond} //@ methods, respectively. //@ The clock created by {\tt mkClock} is available as the //@ {\tt new_clk} subinterface. //@ When setting the gate condition, the change does not affect the //@ generated clock until is low, to prevent glitches. //@ # 3 module mkClock #( one_bit_type initVal, Bool initGate) ( MakeClockIfc#(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1) ) ; (* hide *) MakeClockIfc#(Bit#(1)) _m <- vMkClock(pack(initVal), initGate); method Action setClockValue(one_bit_type value); _m.setClockValue(pack(value)); endmethod method one_bit_type getClockValue(); return unpack(_m.getClockValue()); endmethod method setGateCond = _m.setGateCond; method getGateCond = _m.getGateCond; interface new_clk = _m.new_clk; endmodule import "BVI" MakeClock = module vMkClock #( Bit#(1) init_osc, Bool init_gate ) ( MakeClockIfc#(Bit#(1)) ); parameter initVal = init_osc; parameter initGate = pack(init_gate); default_clock clk(CLK, (* unused *) CLK_GATE) ; default_reset rst(RST) ; method setClockValue(CLK_IN) enable(CLK_IN_EN) ; method CLK_VAL_OUT getClockValue() ; method setGateCond(COND_IN) enable(COND_IN_EN) ; method COND_OUT getGateCond() ; // clock and gate methods are CF with each other schedule setClockValue CF setGateCond; schedule setClockValue CF getGateCond; schedule getClockValue CF getGateCond; schedule getClockValue CF setGateCond; // get methods are CF with themselves schedule getClockValue CF getClockValue; schedule getGateCond CF getGateCond; // get methods sequence before matching set methods schedule getClockValue SB setClockValue; schedule getGateCond SB setGateCond; // we could allow these methods to be SBR, but we choose not to schedule setGateCond C setGateCond; schedule setClockValue C setClockValue; output_clock new_clk(CLK_OUT, CLK_GATE_OUT); endmodule // version of mkClock without a gate port module mkUngatedClock #( one_bit_type initOsc ) ( MakeClockIfc#(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1) ) ; (* hide *) MakeUngatedClockIfc#(Bit#(1)) _m <- vMkUngatedClock(pack(initOsc)); method Action setClockValue(one_bit_type value); _m.setClockValue(pack(value)); endmethod method one_bit_type getClockValue(); return unpack(_m.getClockValue()); endmethod method Action setGateCond (Bool gate); error ("The method 'setGateCond' is not provided by the module 'mkUngatedClock'."); endmethod method getGateCond = True; interface new_clk = _m.new_clk; endmodule import "BVI" MakeClock = module vMkUngatedClock #( Bit#(1) init_osc ) ( MakeUngatedClockIfc#(Bit#(1)) ); parameter initVal = init_osc; parameter initGate = Bit#(1)'(1); default_clock clk(CLK, (* unused *) CLK_GATE) ; default_reset rst(RST) ; method setClockValue(CLK_IN) enable(CLK_IN_EN) ; method CLK_VAL_OUT getClockValue() ; // it has these methods, but don't use them method setGateCond(COND_IN) enable(COND_IN_EN) ; method COND_OUT getGateCond() ; method CLK_GATE_OUT unused(); // clock and gate methods are CF with each other schedule setClockValue CF setGateCond; schedule setClockValue CF getGateCond; schedule getClockValue CF getGateCond; schedule getClockValue CF setGateCond; // get methods are CF with themselves schedule getClockValue CF getClockValue; schedule getGateCond CF getGateCond; // get methods sequence before matching set methods schedule getClockValue SB setClockValue; schedule getGateCond SB setGateCond; // we could allow these methods to be SBR, but we choose not to schedule setGateCond C setGateCond; schedule setClockValue C setClockValue; // no one should use unused so tie it down with conflicts schedule unused C (unused, setClockValue, getClockValue, setGateCond, getGateCond); output_clock new_clk(CLK_OUT); endmodule //X@ //X@ \index{GatedClockIfc@\te{GatedClockIfc} (interface)|textbf} //X@ //X@ # 5 interface GatedClockIfc ; method Action setGateCond(Bool gate) ; method Bool getGateCond() ; interface Clock new_clk ; endinterface //@ //@ \index{mkGatedClock@\te{mkGatedClock} (module)|textbf} //@ The \te{mkGatedClock} module adds (logic and) a Boolean gate condition //@ to an existing clock, thus creating another clock in the same family. //@ The source clock is provided as the argument \tt{clk\_in}. //@ The gate condition is controlled by an asynchronously-reset register //@ inside the module. The register is set with the \tt{setGateCond} Action //@ method of the interface and can be read with \tt{getGateCond} method. //@ The reset value of the gate condition register is provided as an //@ instantiation parameter. The clock for register (and thus these set //@ and get methods) is the default clock of the module; to change this //@ clock use the \tt{clocked\_by} directive. import "BVI" GatedClock = //@ # 1 module mkGatedClock#(Bool v) ( Clock clk_in, GatedClockIfc ifc ); parameter init = pack(v); default_clock clk(CLK, (*unused*)CLK_GATE) ; default_reset rst(RST) ; method setGateCond(COND) enable(COND_EN) ; method COND_OUT getGateCond() ; schedule getGateCond CF getGateCond; schedule getGateCond SB setGateCond; // we could allow the method to be SBR with itself, but we choose not to schedule setGateCond C setGateCond; input_clock clk_in(CLK_IN, CLK_GATE_IN) = clk_in ; output_clock new_clk(CLK_OUT, CLK_GATE_OUT); ancestor(new_clk, clk_in); endmodule //@ For convenience, we provide an alternate version in which the source //@ clock is the default clock of the module //@ # 1 module mkGatedClockFromCC#(Bool v) ( GatedClockIfc ifc ); Clock clk_in <- exposeCurrentClock ; (* hide *) GatedClockIfc _i <- mkGatedClock(v, clk_in) ; return (_i) ; endmodule //XXX@ Ravi -- what is the specification for this module? //XXX@ # 1 module mkJoinedClock #(Clock c)(Clock); (* hide *) ClockGenIfc _m <- vMkJoinedClock(c); return _m.gen_clk(); endmodule import "BVI" JoinClock = module vMkJoinedClock #(Clock c)( ClockGenIfc ); default_clock clk(CLK, CLK_GATE); no_reset; input_clock c(JOIN_CLK, JOIN_CLK_GATE) = c; output_clock gen_clk(CLK_OUT, CLK_GATE_OUT); same_family(clk, c); ancestor(gen_clk, clk); ancestor(gen_clk, c); endmodule ///////////////////////////////////////////////////////////////////////// //@ \subsubsection{Clock Multiplexing} //@ \index{SelectClkIfc@\te{SelectClkIfc} (interface)|textbf} //@ \index{mkClockMux@\te{mkClockMux} (module)|textbf} //@ \index{mkClockSelect@\te{mkClockSelect} (module)|textbf} //@ //@ Bluespec provides two clock multiplexing primitives: a simple //@ combinational multiplexor and a stateful module which generates an //@ appropriate reset signal when the clock changes. //@ # 4 interface MuxClkIfc ; method Action select ( Bool ab ) ; interface Clock clock_out ; endinterface // //@ The \te{mkClockMux} module is a simple combinational multiplexor, //@ which selects between the aClk and bClk. The provided Verilog module //@ does not provide any glitch detection or removal logic; it is the //@ responsibility of the user to provide additional logic to provide //@ glitch-free behavior. The \te{mkClockMux} module uses three //@ arguments and provides a Clock interface. The {\tt aClk} is selected if //@ {\tt ab} is True, while {\tt bClk} is selected otherwise. The //@ underlying Verilog //@ module is {\tt ClockMux.v}. import "BVI" ClockMux = //@ # 1 module mkClockMux (Clock aClk, Clock bClk, MuxClkIfc ifcout) ; default_clock xclk(CLK, (*unused*)CLKGATE) ; no_reset; input_clock aClk(A_CLK, A_CLKGATE) = aClk ; input_clock bClk(B_CLK, B_CLKGATE) = bClk ; // Generate the clock output interface output_clock clock_out(CLK_OUT, CLK_GATE_OUT) ; // other methods method select( SELECT ) enable( SELECT_ENABLE ) reset_by(no_reset) ; schedule select C select ; endmodule import "BVI" UngatedClockMux = module mkUngatedClockMux (Clock aClk, Clock bClk, MuxClkIfc ifcout) ; default_clock xclk(CLK, (*unused*)CLKGATE) ; no_reset; input_clock aClk(A_CLK) = aClk ; input_clock bClk(B_CLK) = bClk ; // Generate the clock output interface output_clock clock_out(CLK_OUT) ; // other methods method select( SELECT ) enable( SELECT_ENABLE ) reset_by(no_reset) ; schedule select C select ; endmodule //@ //@ The \te{mkClockSelect} module is a clock multiplexor //@ containing additional logic which generates a reset whenever a new //@ clock is selected. As such the interface for the module includes //@ an \te{Action} method to select the clock (if {\tt ab} is True //@ clock\_out is taken from {\tt aClk}), //@ provides a \te{Clock} interface, and also a \te{Reset} //@ interface. The interface definition is described here. //@ # 5 interface SelectClkIfc ; method Action select ( Bool ab ) ; interface Clock clock_out ; interface Reset reset_out ; endinterface // //@ The constructor for the module uses two clock arguments, and //@ provides the \te{SelectClkIfc} interface. The underlying Verilog //@ module is {\tt ClockSelect.v}; it is expected that users can //@ substitute their own modules to meet any additional requirements //@ they may have. The parameter {\tt stages} is the number of clock //@ cycles in which the reset is asserted after the clock changes. import "BVI" ClockSelect = //@ # 5 module mkClockSelect #( Integer stages ) ( Clock aClk, Clock bClk, SelectClkIfc ifcout ) ; default_clock xclk(CLK, (*unused*)CLKGATE) ; default_reset xrst(RST) ; parameter RSTDELAY = (stages >= 0) ? stages : error("Reset synchronizer built with negative number of stage?") ; input_clock aClk(A_CLK, A_CLKGATE) = aClk ; input_clock bClk(B_CLK, B_CLKGATE) = bClk ; // Generate the clock output interface output_clock clock_out(CLK_OUT, CLK_GATE_OUT) ; // Generate the reset output interface output_reset reset_out( OUT_RST ) clocked_by(clock_out); // other methods method select( SELECT ) enable( SELECT_ENABLE ) reset_by(no_reset) ; schedule select C select ; endmodule import "BVI" UngatedClockSelect = module mkUngatedClockSelect #( Integer stages ) ( Clock aClk, Clock bClk, SelectClkIfc ifcout ) ; default_clock xclk(CLK, (*unused*)CLKGATE) ; default_reset xrst(RST) ; parameter RSTDELAY = (stages >= 0) ? stages : error("Reset synchronizer built with negative number of stage?") ; input_clock aClk(A_CLK) = aClk ; input_clock bClk(B_CLK) = bClk ; // Generate the clock output interface output_clock clock_out(CLK_OUT) ; // Generate the reset output interface output_reset reset_out( OUT_RST ) clocked_by(clock_out); // other methods method select( SELECT ) enable( SELECT_ENABLE ) reset_by(no_reset) ; schedule select C select ; endmodule // //////////////////////////////////////////////////////////////////////// //@ \subsubsection{Clock Division} //@ //@ \index{ClockDividerIfc@\te{ClockDividerIfc} (interface)|textbf} //@ \index{mkClockDivider@\te{mkClockDivider} (module)|textbf} //@ \index{mkClockDividerOffset@\te{mkClockDividerOffset} (module)|textbf} //@ \index{mkClockInverter@\te{mkClockInverter} (module)|textbf} //@ //@ A clock divider provides a derived clock and also a \te{ClkNextRdy} //@ signal, which indicates that divided //@ clock will rise in the next cycle. This signal is associated with //@ the input clock, and can only be used within that clock domain. //@ //@ See {\tt mkSyncRegToSlow}, {\tt mkSyncRegToFast}, {\tt mkSyncFIFOToSlow}, and {\tt mkSyncFIFOToFast} //@ for some specialized synchronizers //@ which can be used with divided clocks, and other systems when the //@ clock edges are known to be aligned. //@ //@ Define a new type and then the interface //@ # 1 typedef Bool ClkNextRdy ; //@ # 5 interface ClockDividerIfc ; interface Clock fastClock ; // The original clock interface Clock slowClock ; // The derived clock method ClkNextRdy clockReady() ; // endinterface //@ //@ The {\tt divider} parameter may be any integer greater than 1. //@ For even dividers the generated clock's duty cycle is 50\%, while //@ for odd dividers, the duty cycle is $(divider/2) / divider$. The //@ current clock (or the clocked\_by argument) is used as the //@ source clock. //@ //@ The {\tt mkClockDividerOffset} module provides a clock divider, //@ where the rising edge can be defined relative to other clock //@ dividers which have the same divisor. An offset of value 2, will //@ produce a rising edge one fast clock after a divider with offset //@ 1. The //@ {\tt mkClockDivider} modules are provided by the Verilog module //@ \te{ClockDiv.v} //@ # 2 module mkClockDivider #( Integer divisor )( ClockDividerIfc ifc ) ; Clock currentClock <- exposeCurrentClock ; ClockDivider_internal iifc() ; vClockDivider#( divisor ) _idivider( 0, iifc ) ; interface slowClock = iifc.slowClock ; interface fastClock = currentClock ; method clockReady = iifc.clockReady ; endmodule module mkGatedClockDivider #( Integer divisor )( ClockDividerIfc ifc ) ; Clock currentClock <- exposeCurrentClock ; ClockDivider_internal iifc() ; vGatedClockDivider#( divisor ) _idivider( 0, iifc ) ; interface slowClock = iifc.slowClock ; interface fastClock = currentClock ; method clockReady = iifc.clockReady ; endmodule //@ # 3 module mkClockDividerOffset #( Integer divisor, Integer offset )( ClockDividerIfc ifc ) ; Clock currentClock <- exposeCurrentClock ; ClockDivider_internal iifc() ; vClockDivider #( divisor ) _idivider( offset, iifc ) ; interface slowClock = iifc.slowClock ; interface fastClock = currentClock ; method clockReady = iifc.clockReady ; endmodule //@ The {\tt mkClockInverter} module generates a inverted clock having //@ the same period but opposite phase as the source clock. //@ # 1 module mkClockInverter ( ClockDividerIfc ifc ) ; Clock currentClock <- exposeCurrentClock ; ClockDivider_internal iifc() ; vClockInverter _idivider( iifc ) ; interface slowClock = iifc.slowClock ; interface fastClock = currentClock ; method clockReady = iifc.clockReady ; endmodule module mkGatedClockInverter ( ClockDividerIfc ifc ) ; Clock currentClock <- exposeCurrentClock ; ClockDivider_internal iifc() ; vGatedClockInverter _idivider( iifc ) ; interface slowClock = iifc.slowClock ; interface fastClock = currentClock ; method clockReady = iifc.clockReady ; endmodule // internal interface interface ClockDivider_internal ; interface Clock slowClock ; // The derived clock method ClkNextRdy clockReady () ; // endinterface import "BVI" ClockInverter = module vClockInverter ( ClockDivider_internal ifc ) ; default_clock clk(CLK_IN) ; no_reset ; output_clock slowClock(CLK_OUT) ; method PREEDGE clockReady() clocked_by( clk ) reset_by( no_reset ) ; schedule clockReady CF clockReady ; endmodule module invertCurrentClock(Clock); let _m <- mkClockInverter; return _m.slowClock; endmodule: invertCurrentClock import "BVI" GatedClockInverter = module vGatedClockInverter ( ClockDivider_internal ifc ) ; default_clock clk(CLK_IN, CLK_GATE_IN) ; no_reset ; output_clock slowClock(CLK_OUT, CLK_GATE_OUT) ; method PREEDGE clockReady() clocked_by( clk ) reset_by( no_reset ) ; schedule clockReady CF clockReady ; endmodule import "BVI" ClockDiv = module vClockDivider #( Integer divisor, Integer offseta ) ( ClockDivider_internal ifc ) ; let logDepth = (divisor > 1) ? log2( divisor ) : error( "mkClockDivider requires a integer > 1 for its clock division" ) ; let pwrDepth = 2 ** logDepth ; let halfD = 2 ** (logDepth - 1) ; let halfPer = div( divisor, 2) ; let up = halfD + halfPer - 1 ; let lo = (up + 1) - divisor ; let offs = ((offseta >= 0) && (offseta <= (divisor - 1))) ? offseta : ( error( "mkClockDivider requires the offset to be between 0 and the divisor. " + "The offset, " + fromInteger ( offseta ) + ", is greater than or equal to " + "the divisor, " + fromInteger ( divisor ) + "." ) ) ; parameter width = logDepth ; parameter lower = lo ; parameter upper = up ; parameter offset = offs ; default_clock clk(CLK_IN) ; default_reset rst(RST) ; output_clock slowClock(CLK_OUT) ; method PREEDGE clockReady() clocked_by( clk ) reset_by(rst) ; schedule clockReady CF clockReady; endmodule import "BVI" GatedClockDiv = module vGatedClockDivider #( Integer divisor, Integer offseta ) ( ClockDivider_internal ifc ) ; let logDepth = (divisor > 1) ? log2( divisor ) : error( "mkClockDivider requires a integer > 1 for its clock division" ) ; let pwrDepth = 2 ** logDepth ; let halfD = 2 ** (logDepth - 1) ; let halfPer = div( divisor, 2) ; let up = halfD + halfPer - 1 ; let lo = (up + 1) - divisor ; let offs = ((offseta >= 0) && (offseta <= (divisor - 1))) ? offseta : ( error( "mkClockDivider requires the offset to be between 0 and the divisor. " + "The offset, " + fromInteger ( offseta ) + ", is greater than or equal to " + "the divisor, " + fromInteger ( divisor ) + "." ) ) ; parameter width = logDepth ; parameter lower = lo ; parameter upper = up ; parameter offset = offs ; default_clock clk(CLK_IN, CLK_GATE_IN) ; default_reset rst(RST) ; output_clock slowClock(CLK_OUT, CLK_GATE_OUT) ; method PREEDGE clockReady() clocked_by( clk ) reset_by(rst) ; schedule clockReady CF clockReady; endmodule // //////////////////////////////////////////////////////////////////////// //@ \subsubsection{Bit Synchronizers} //@ //@ \index{SyncBitIfc@\te{SyncBitIfc} (interface)|textbf} //@ The Sync Bit interface provides a \te{send} method which transmits //@ one bit of information from one clock domain to the \te{read} //@ method in a second domain. //@ # 4 interface SyncBitIfc #(type one_bit_type) ; method Action send ( one_bit_type bitData ) ; method one_bit_type read () ; endinterface // Synchronize a bit from the current domain to the dClkIn //@ //@ \index{mkSyncBit@\te{mkSyncBit} (module)|textbf} //@ \index{mkSyncBit15@\te{mkSyncBit15} (module)|textbf} //@ \index{mkSyncBit1@\te{mkSyncBit1} (module)|textbf} //@ The \te{mkSyncBit}, \te{mkSyncBitFromCC} and \te{mkSyncBitToCC} modules provide a //@ \te{SyncBitIfc} across clock domains. The send //@ method is in the one clock domain, and the read method is in //@ a second clock domain. The FromCC version and ToCC versions //@ differ in that the former moves data from the current clock //@ (module's clock), while //@ the later move data into the current clock domain //@ The hardware implementation is a two //@ register synchronizer, which can be found in SyncBit.v in the //@ Bluespec Verilog library directory. //@ //@ The \te{mkSyncBit15} module (one and a half) and its variants provide the same //@ interface as the \te{mkSyncBit} modules, but the underlying //@ hardware is slightly modified. For these synchronizers, the first //@ register clocked by the destination clock triggers on the falling //@ edge of the clock. The Verilog can in found in SyncBit15.v in the //@ Bluespec Verilog library directory. //@ //@ The \te{mkSyncBit1} module also provides the same interface, but //@ only uses one register in the destination domain. Synchronizers //@ like this, which use with only one //@ register, are not generally used since meta-stable output //@ is very probable. However, one can use this synchronizer provided //@ special meta-stable resistant flops are selected during physical //@ synthesis or (for example) if the output is immediately registered. //@ //@ The \te{mkSyncBit05} module is similar, but the destination register //@ triggers on the falling edge of the clock. // A general module which not use the current clock or reset import "BVI" SyncBit = module vSyncBit( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncBitIfc#(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; default_clock no_clock ; no_reset ; parameter init = Bit#(1) '(0); input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ; input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn ; input_reset (sRST) clocked_by (clk_src) = sRstIn ; method send ( sD_IN ) enable(sEN) clocked_by ( clk_src ) reset_by( sRstIn ); method dD_OUT read() clocked_by ( clk_dst ) reset_by( no_reset); schedule read CF read ; schedule read CF send ; schedule send C send ; endmodule //@ //@ # 4 module mkSyncBit ( Clock sClkIn, Reset sRst, Clock dClkIn, SyncBitIfc #(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; SyncBitIfc#(one_bit_type) ifc() ; vSyncBit#(sClkIn, sRst, dClkIn) _SyncBit( ifc ) ; return ifc ; endmodule //@ # 3 module mkSyncBitFromCC ( Clock dClkIn, SyncBitIfc #(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; Clock sClk <- exposeCurrentClock ; Reset sRst <- exposeCurrentReset ; SyncBitIfc#(one_bit_type) ifc() ; vSyncBit #(sClk, sRst, dClkIn) _SyncBit( ifc ) ; return ifc ; endmodule //@ # 3 module mkSyncBitToCC ( Clock sClkIn, Reset sRstIn, SyncBitIfc #(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; Clock dClk <- exposeCurrentClock ; SyncBitIfc#(one_bit_type) ifc() ; vSyncBit#(sClkIn, sRstIn, dClk) _SyncBit( ifc ) ; return ifc ; endmodule // A general module which not use the current clock or reset import "BVI" SyncBit15 = module vSyncBit15( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncBitIfc#(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; default_clock no_clock ; no_reset ; parameter init = Bit#(1) ' (0); input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ; input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn ; input_reset (sRST) clocked_by (clk_src) = sRstIn ; method send ( sD_IN ) enable(sEN) clocked_by ( clk_src ) reset_by( sRstIn ); method dD_OUT read() clocked_by ( clk_dst ) reset_by( no_reset); schedule read CF read ; schedule read CF send ; schedule send C send ; endmodule //@ //@ # 4 module mkSyncBit15 ( Clock sClkIn, Reset sRst, Clock dClkIn, SyncBitIfc #(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; SyncBitIfc#(one_bit_type) ifc() ; vSyncBit15#(sClkIn, sRst, dClkIn) _SyncBit( ifc ) ; return ifc ; endmodule //@ # 3 module mkSyncBit15FromCC ( Clock dClkIn, SyncBitIfc #(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; Clock sClk <- exposeCurrentClock ; Reset sRst <- exposeCurrentReset ; SyncBitIfc#(one_bit_type) ifc() ; vSyncBit15#(sClk, sRst, dClkIn) _SyncBit( ifc ) ; return ifc ; endmodule //@ # 3 module mkSyncBit15ToCC ( Clock sClkIn, Reset sRstIn, SyncBitIfc #(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; Clock dClk <- exposeCurrentClock ; SyncBitIfc#(one_bit_type) ifc() ; vSyncBit15#(sClkIn, sRstIn, dClk) _SyncBit( ifc ) ; return ifc ; endmodule // A general module which not use the current clock or reset import "BVI" SyncBit1 = module vSyncBit1( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncBitIfc#(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; default_clock no_clock ; no_reset ; parameter init = Bit#(1) ' (0); input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ; input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn ; input_reset (sRST) clocked_by (clk_src) = sRstIn ; method send ( sD_IN ) enable(sEN) clocked_by ( clk_src ) reset_by( sRstIn ); method dD_OUT read() clocked_by ( clk_dst ) reset_by( no_reset); schedule read CF read ; schedule read CF send ; schedule send C send ; endmodule //@ //@ # 4 module mkSyncBit1 ( Clock sClkIn, Reset sRst, Clock dClkIn, SyncBitIfc #(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; SyncBitIfc#(one_bit_type) ifc() ; vSyncBit1#(sClkIn, sRst, dClkIn) _SyncBit( ifc ) ; return ifc ; endmodule //@ # 3 module mkSyncBit1FromCC ( Clock dClkIn, SyncBitIfc #(one_bit_type) ifc ) provisos( Bits #(one_bit_type, 1)) ; Clock sClk <- exposeCurrentClock ; Reset sRst <- exposeCurrentReset ; SyncBitIfc#(one_bit_type) ifc() ; vSyncBit1#(sClk, sRst, dClkIn) _SyncBit( ifc ) ; return ifc ; endmodule //@ # 3 module mkSyncBit1ToCC ( Clock sClkIn, Reset sRstIn, SyncBitIfc #(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; Clock dClk <- exposeCurrentClock ; SyncBitIfc#(one_bit_type) ifc() ; vSyncBit1#(sClkIn, sRstIn, dClk) _SyncBit( ifc ) ; return ifc ; endmodule // A general module which not use the current clock or reset import "BVI" SyncBit05 = module vSyncBit05( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncBitIfc #(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; default_clock no_clock ; no_reset ; parameter init = Bit#(1) ' (0); input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ; input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn ; input_reset (sRST) clocked_by (clk_src) = sRstIn ; method send ( sD_IN ) enable(sEN) clocked_by ( clk_src ) reset_by( sRstIn ); method dD_OUT read() clocked_by ( clk_dst ) reset_by( no_reset); schedule read CF read ; schedule read CF send ; schedule send C send ; endmodule //@ //@ # 4 module mkSyncBit05 ( Clock sClkIn, Reset sRst, Clock dClkIn, SyncBitIfc #(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; SyncBitIfc#(one_bit_type) ifc() ; vSyncBit05#(sClkIn, sRst, dClkIn) _SyncBit( ifc ) ; return ifc ; endmodule //@ # 3 module mkSyncBit05FromCC ( Clock dClkIn, SyncBitIfc #(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; Clock sClk <- exposeCurrentClock ; Reset sRst <- exposeCurrentReset ; SyncBitIfc#(one_bit_type) ifc() ; vSyncBit05#(sClk, sRst, dClkIn) _SyncBit( ifc ) ; return ifc ; endmodule //@ # 3 module mkSyncBit05ToCC ( Clock sClkIn, Reset sRstIn, SyncBitIfc #(one_bit_type) ifc ) provisos( Bits#(one_bit_type, 1)) ; Clock dClk <- exposeCurrentClock ; SyncBitIfc#(one_bit_type) ifc() ; vSyncBit05#(sClkIn, sRstIn, dClk) _SyncBit( ifc ) ; return ifc ; endmodule // ///////////////////////////////////////////////////////////////////// // send a pulse across clock domains, send and read are in different domains // //@ \subsubsection{Pulse Synchronizers} //@ //@ \index{SyncPulseIfc@\te{SyncPulseIfc} (interface)|textbf} //@ The Sync Pulse interface provides an Action \te{send} method which when //@ invoked causes a pulse on a \te{read} method in a second clock domain. //@ # 4 interface SyncPulseIfc ; method Action send () ; method Bool pulse () ; endinterface import "BVI" SyncPulse = module vSyncPulse ( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncPulseIfc ifc ) ; default_clock no_clock ; no_reset ; input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ; input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn; input_reset (sRST) clocked_by (clk_src) = sRstIn ; method send () enable(sEN) clocked_by ( clk_src ) reset_by( sRstIn ); method dPulse pulse () clocked_by ( clk_dst ) reset_by( no_reset) ; schedule pulse CF pulse ; schedule pulse CF send ; schedule send C send ; // 1 bit of send can be conflict free endmodule //@ //@ \index{mkSyncPulse@\te{mkSyncPulse} (module)|textbf} //@ The \te{mkSyncPulse}, \te{mkSyncPulseFromCC} and \te{mkSyncPulseToCC} modules //@ provide clock domain crossing modules for pulses. When the //@ \te{send} method is called from the one clock domain, a pulse will //@ be seen on the \te{read} method in the second. Note that there is //@ no handshaking between the domains, so when sending data //@ from a fast clock domain to a slower one, not all pulses sent may //@ be seen in the slower receiving clock domain. The pulse delay is //@ two destination clocks cycles. //@ The hardware implementation can be found in SyncPulse.v in the //@ Bluespec Verilog library directory. //@ //@ # 3 module mkSyncPulse ( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncPulseIfc ifc ) ; SyncPulseIfc ifc() ; vSyncPulse#(sClkIn, sRstIn, dClkIn) _SyncPulse( ifc ) ; return ifc ; endmodule //@ # 2 module mkSyncPulseFromCC ( Clock dClkIn, SyncPulseIfc ifc ) ; Clock sClk <- exposeCurrentClock ; Reset sRst <- exposeCurrentReset ; SyncPulseIfc ifc() ; vSyncPulse#(sClk, sRst, dClkIn) _SyncPulse( ifc ) ; return ifc ; endmodule //@ # 2 module mkSyncPulseToCC ( Clock sClkIn, Reset sRstIn, SyncPulseIfc ifc ) ; Clock dClk <- exposeCurrentClock ; SyncPulseIfc ifc() ; vSyncPulse#(sClkIn, sRstIn, dClk) _SyncPulse( ifc ) ; return ifc ; endmodule import "BVI" SyncHandshake = module vSyncHandshake( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncPulseIfc ifc ) ; default_clock no_clock ; no_reset ; input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ; input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn ; input_reset rstn_src(sRST) clocked_by (clk_src) = sRstIn ; method send () enable(sEN) ready(sRDY) clocked_by ( clk_src ) reset_by( rstn_src ); method dPulse pulse () clocked_by ( clk_dst ) reset_by( no_reset ); schedule pulse CF pulse ; schedule pulse CF send ; schedule send C send ; // 1 bit of send can be conflict free endmodule //@ //@ \index{mkSyncHandshake@\te{mkSyncHandshake} (module)|textbf} //@ The \te{mkSyncHandshake}, \te{mkSyncHandshakeFromCC} and \te{mkSyncHandshakeToCC} modules //@ provide clock domain crossing modules for pulses in a similar way //@ as \te{mkSyncPulse} modules, except that a handshake is provided //@ in the \te{mkSyncHandshake} versions. The handshake enforces that //@ another send does not occur before the first pulse crosses to the //@ other domain. //@ The pulse delay from the \te{send} method to the \te{read} method //@ is two destination clocks. The \te{send} method is re-enabled in //@ two destination clock cycles plus two source clock cycles after the //@ \te{send} method is called. //@ //@ # 3 module mkSyncHandshake ( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncPulseIfc ifc ) ; SyncPulseIfc ifc() ; vSyncHandshake#(sClkIn, sRstIn, dClkIn) _SyncPulse( ifc ) ; return ifc ; endmodule //@ # 2 module mkSyncHandshakeFromCC ( Clock dClkIn, SyncPulseIfc ifc ) ; Clock sClk <- exposeCurrentClock ; Reset sRst <- exposeCurrentReset ; SyncPulseIfc ifc() ; vSyncHandshake#(sClk, sRst, dClkIn) _SyncPulse( ifc ) ; return ifc ; endmodule //@ # 2 module mkSyncHandshakeToCC ( Clock sClkIn, Reset sRstIn, SyncPulseIfc ifc ) ; Clock dClk <- exposeCurrentClock ; SyncPulseIfc ifc() ; vSyncHandshake#(sClkIn, sRstIn, dClk) _SyncPulse( ifc ) ; return ifc ; endmodule ///////////////////////////////////////////////////////////////////// //@ \subsubsection{Word Synchronizers} //@ //@ Word synchronizers use the common \te{Reg} interface (redescribed //@ below), but there //@ are a few subtle differences which the designer should be aware. //@ First, the {\em \_read} and {\em \_write} methods are in //@ difference clock domains, and second the {\em \_write} method //@ has an implicit ``ready'' condition which means that some //@ synchronization modules cannot be written every clock cycle. Both //@ of these conditions are handled automatically by the Bluespec //@ compiler relieving the designer of these checks. //@ //@ \begin{libverbatim} //@ interface Reg #(a_type); //@ method Action _write(a_type x1); //@ method a_type _read(); //@ endinterface: Reg //@ \end{libverbatim} //@ //@ // internal interface interface RegI #(type a_type); method Action write(a_type x1); method a_type read(); endinterface: RegI // Common import BVI code import "BVI" SyncRegister = module vSyncReg#(a initValue) ( Clock sClkIn, Reset sRstIn, Clock dClkIn, RegI#(a) ifc ) provisos (Bits#(a,sa)) ; default_clock no_clock ; no_reset ; parameter width = valueOf( sa ) ; parameter init = pack(initValue) ; input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ; input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn ; input_reset (sRST) clocked_by (clk_src) = sRstIn ; method write( sD_IN ) enable (sEN) ready (sRDY) clocked_by (clk_src) reset_by( sRstIn ); method dD_OUT read() clocked_by (clk_dst) reset_by(no_reset); schedule read CF read ; schedule read CF write ; schedule write C write ; // unlike our mkReg since reading is in another clock endmodule //@ \index{mkSyncReg@\te{mkSyncReg} (module)|textbf} //@ The \te{mkSyncReg}, \te{mkSyncRegToCC} and \te{mkSyncRegFromCC} modules provide //@ word synchronization across clock domains. The crossing are //@ handshaked, such that a second write cannot occur until the first //@ is acknowledge by the destination side. The destination read is //@ registered. //@ The hardware implementation can be found in SyncRegister.v in the //@ Bluespec Verilog library directory. //@ //@ # 5 module mkSyncReg #( a_type initValue )( Clock sClkIn, Reset sRstIn, Clock dClkIn, Reg #(a_type) ifc ) provisos (Bits#(a_type,sa) ) ; RegI #(a_type) ifci() ; vSyncReg#(initValue, sClkIn, sRstIn, dClkIn) _SyncWord( ifci ) ; method Action _write(din); ifci.write( din ) ; endmethod method a_type _read() ; return ifci.read ; endmethod endmodule //@ # 4 module mkSyncRegFromCC #( a_type initValue )( Clock dClkIn, Reg #(a_type) ifc) provisos (Bits#(a_type,sa)) ; Clock sClk <- exposeCurrentClock ; Reset sRst <- exposeCurrentReset ; RegI#(a_type) ifci() ; vSyncReg#(initValue, sClk, sRst, dClkIn) _SyncWord( ifci ) ; method Action _write(din); ifci.write( din ) ; endmethod method a_type _read() ; return ifci.read ; endmethod endmodule //@ # 4 module mkSyncRegToCC #( a_type initValue )( Clock sClkIn, Reset sRstIn, Reg #(a_type) ifc) provisos (Bits#(a_type,sa)) ; Clock dClk <- exposeCurrentClock ; RegI#(a_type) ifci() ; vSyncReg#(initValue, sClkIn, sRstIn, dClk) _SyncWord( ifci ) ; method Action _write(din); ifci.write( din ) ; endmethod method a_type _read() ; return ifci.read ; endmethod endmodule // /////////////////////////////////////////////////////////////////// //@ \subsubsection{FIFO Synchronizers} //@ //@ \index{SyncFIFOIfc@\te{SyncFIFOIfc} (interface)|textbf} //@ The sync FIFO interface defines an interface similar to the FIFOF //@ interface, except it does not have a clear method. //@ # 5 interface SyncFIFOIfc #(type a_type) ; method Action enq ( a_type sendData ) ; method Action deq () ; method a_type first () ; method Bool notFull () ; method Bool notEmpty () ; endinterface // Internal interface for zero-width SyncFIFO interface SyncFIFO0Ifc; method Action enq () ; method Action deq () ; method Bool notFull () ; method Bool notEmpty () ; endinterface import "BVI" SyncFIFO = module vSyncFIFO #(Integer depthIn )( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncFIFOIfc #(a) ifc) provisos (Bits#(a,sa)); let logDepth = log2( depthIn ) ; let pwrDepth = 2 ** logDepth ; if (pwrDepth < 2) error( "mkSyncFIFO depth must be greater than 1 for correct operation" ) ; parameter dataWidth = valueOf( sa ) ; parameter depth = pwrDepth ; // must be power of 2 ! parameter indxWidth = logDepth ; default_clock no_clock ; no_reset ; input_clock clk_src ( sCLK, (*unused*)sCLK_GATE ) = sClkIn; input_clock clk_dst ( dCLK, (*unused*)dCLK_GATE ) = dClkIn; input_reset (sRST) clocked_by (clk_src) = sRstIn ; method enq ( sD_IN ) ready(sFULL_N) enable(sENQ) clocked_by(clk_src) reset_by(sRstIn); method deq () ready(dEMPTY_N) enable(dDEQ) clocked_by(clk_dst) reset_by(no_reset); method dD_OUT first() ready(dEMPTY_N) clocked_by(clk_dst) reset_by(no_reset); method dEMPTY_N notEmpty() clocked_by(clk_dst) reset_by(no_reset); method sFULL_N notFull() clocked_by(clk_src) reset_by(sRstIn); schedule first SB deq; schedule first CF (notFull, notEmpty, enq, first); schedule notFull CF (notEmpty, notFull, deq); //schedule (notFull, notEmpty) SB (enq, deq); schedule notFull SB enq; schedule notEmpty SB deq; schedule notEmpty CF (notEmpty, enq); schedule enq CF deq; schedule deq C deq; schedule enq C enq; endmodule // Version for depth 1 import "BVI" SyncFIFO1 = module vSyncFIFO1 ( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncFIFOIfc #(a) ifc) provisos (Bits#(a,sa)); parameter dataWidth = valueOf( sa ) ; default_clock no_clock ; no_reset ; input_clock clk_src ( sCLK, (*unused*)sCLK_GATE ) = sClkIn; input_clock clk_dst ( dCLK, (*unused*)dCLK_GATE ) = dClkIn; input_reset (sRST) clocked_by (clk_src) = sRstIn ; method enq ( sD_IN ) ready(sFULL_N) enable(sENQ) clocked_by(clk_src) reset_by(sRstIn); method deq () ready(dEMPTY_N) enable(dDEQ) clocked_by(clk_dst) reset_by(no_reset); method dD_OUT first() ready(dEMPTY_N) clocked_by(clk_dst) reset_by(no_reset); method dEMPTY_N notEmpty() clocked_by(clk_dst) reset_by(no_reset); method sFULL_N notFull() clocked_by(clk_src) reset_by(sRstIn); schedule first SB deq; schedule first CF (notFull, notEmpty, enq, first); schedule notFull CF (notEmpty, notFull, deq); schedule notFull SB enq; schedule notEmpty SB deq; schedule notEmpty CF (notEmpty, enq); schedule enq CF deq; schedule deq C deq; schedule enq C enq; endmodule // Version for data width 0 import "BVI" SyncFIFO0 = module vSyncFIFO0 #(Integer depthIn )( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncFIFO0Ifc ifc); let logDepth = log2( depthIn ) ; let pwrDepth = 2 ** logDepth ; if (pwrDepth < 2) error( "mkSyncFIFO depth must be greater than 1 for correct operation" ) ; parameter depth = pwrDepth ; // must be power of 2 ! parameter indxWidth = logDepth ; default_clock no_clock ; no_reset ; input_clock clk_src ( sCLK, (*unused*)sCLK_GATE ) = sClkIn; input_clock clk_dst ( dCLK, (*unused*)dCLK_GATE ) = dClkIn; input_reset (sRST) clocked_by (clk_src) = sRstIn ; method enq () ready(sFULL_N) enable(sENQ) clocked_by(clk_src) reset_by(sRstIn); method deq () ready(dEMPTY_N) enable(dDEQ) clocked_by(clk_dst) reset_by(no_reset); method dEMPTY_N notEmpty() clocked_by(clk_dst) reset_by(no_reset); method sFULL_N notFull() clocked_by(clk_src) reset_by(sRstIn); schedule notFull CF (notEmpty, notFull, deq); //schedule (notFull, notEmpty) SB (enq, deq); schedule notFull SB enq; schedule notEmpty SB deq; schedule notEmpty CF (notEmpty, enq); schedule enq CF deq; schedule deq C deq; schedule enq C enq; endmodule // Version for depth 1, data width 0 import "BVI" SyncFIFO10 = module vSyncFIFO10 ( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncFIFO0Ifc ifc); default_clock no_clock ; no_reset ; input_clock clk_src ( sCLK, (*unused*)sCLK_GATE ) = sClkIn; input_clock clk_dst ( dCLK, (*unused*)dCLK_GATE ) = dClkIn; input_reset (sRST) clocked_by (clk_src) = sRstIn ; method enq () ready(sFULL_N) enable(sENQ) clocked_by(clk_src) reset_by(sRstIn); method deq () ready(dEMPTY_N) enable(dDEQ) clocked_by(clk_dst) reset_by(no_reset); method dEMPTY_N notEmpty() clocked_by(clk_dst) reset_by(no_reset); method sFULL_N notFull() clocked_by(clk_src) reset_by(sRstIn); schedule notFull CF (notEmpty, notFull, deq); schedule notFull SB enq; schedule notEmpty SB deq; schedule notEmpty CF (notEmpty, enq); schedule enq CF deq; schedule deq C deq; schedule enq C enq; endmodule //@ //@ \index{mkSyncFIFO@\te{mkSyncFIFO} (module)|textbf} //@ The \te{mkSyncFIFO}, \te{mkSyncFIFOFromCC} and \te{mkSyncFIFOToCC} modules //@ provide FIFOs for sending data across clock domains. //@ The \te{enq} method is in one domain, while the \te{deq} and //@ \te{first} methods are in a second domain. //@ Depth of the instantiated FIFO may be increased to the next //@ power of 2, FIFOs of depth 1 are allowed. //@ The hardware implementation can be found in SyncFIFO.v in the //@ Bluespec Verilog library directory. //@ //@ # 5 module mkSyncFIFO #( Integer depthIn )( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncFIFOIfc #(a_type) ifc ) provisos (Bits#(a_type,sa)); SyncFIFOIfc#(a_type) _ifc; if (valueOf(sa) == 0) begin (*hide*) SyncFIFO0Ifc _vifc <- (depthIn == 1) ? vSyncFIFO10(sClkIn, sRstIn, dClkIn) : vSyncFIFO0(depthIn, sClkIn, sRstIn, dClkIn) ; _ifc = (interface SyncFIFOIfc; method enq (sendData) = _vifc.enq() ; method deq () = _vifc.deq() ; method first () = ? ; method notFull = _vifc.notFull ; method notEmpty = _vifc.notEmpty ; endinterface) ; end else begin (*hide*) _ifc <- (depthIn == 1) ? vSyncFIFO1(sClkIn, sRstIn, dClkIn) : vSyncFIFO(depthIn, sClkIn, sRstIn, dClkIn) ; end return _ifc ; endmodule //@ A variation of the Sync FIFO which allow the empty and full //@ signals to be registered. Registering the signals can give better //@ synthesis results, since a comparator is removed from the empty or //@ full path. However, there is an additional cycle of latency //@ before the empty or full signal is visible. //@ # 7 (* deprecate = "This module is deprecated, use mkSyncFIFO instead" *) module mkSyncFIFOFull #( Integer depthIn, Bool regEmpty, Bool regFull )( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncFIFOIfc #(a_type) ifc ) provisos (Bits#(a_type,sa)); SyncFIFOIfc#(a_type) ifc ; if (regEmpty && regFull) begin ifc <- mkSyncFIFO(depthIn, sClkIn, sRstIn, dClkIn) ; end else begin ifc = error ("mkSyncFIFOFull can only be used when regEmpty and regFull are both True."); end return ifc ; endmodule //@ # 4 module mkSyncFIFOFromCC #( Integer depthIn )( Clock dClkIn, SyncFIFOIfc #(a_type) ifc) provisos (Bits#(a_type,sa)); Clock sClk <- exposeCurrentClock ; Reset sRst <- exposeCurrentReset ; (*hide*) SyncFIFOIfc#(a_type) _ifc <- mkSyncFIFO(depthIn, sClk, sRst, dClkIn) ; return _ifc ; endmodule //@ # 4 module mkSyncFIFOToCC #( Integer depthIn )( Clock sClkIn, Reset sRstIn, SyncFIFOIfc #(a_type) ifc) provisos (Bits#(a_type,sa)); Clock dClk <- exposeCurrentClock ; (*hide*) SyncFIFOIfc#(a_type) _ifc <- mkSyncFIFO(depthIn, sClkIn, sRstIn, dClk) ; return _ifc ; endmodule //@ # 6 (* deprecate = "This module is deprecated, use mkSyncFIFOFromCC instead" *) module mkSyncFIFOFromCCFull #( Integer depthIn, Bool regEmpty, Bool regFull )( Clock dClkIn, SyncFIFOIfc #(a_type) ifc) provisos (Bits#(a_type,sa)); Clock sClk <- exposeCurrentClock ; Reset sRst <- exposeCurrentReset ; SyncFIFOIfc#(a_type) ifc ; if (regEmpty && regFull) begin ifc <- mkSyncFIFO(depthIn, sClk, sRst, dClkIn); end else begin ifc = error ("mkSyncFIFOFromCCFull can only be used when regEmpty and regFull are both True."); end return ifc ; endmodule //@ # 6 (* deprecate = "This module is deprecated, use mkSyncFIFOToCC instead" *) module mkSyncFIFOToCCFull #( Integer depthIn, Bool regEmpty, Bool regFull )( Clock sClkIn, Reset sRstIn, SyncFIFOIfc #(a_type) ifc) provisos (Bits#(a_type,sa)); Clock dClk <- exposeCurrentClock ; SyncFIFOIfc#(a_type) ifc ; if (regFull && regEmpty) begin ifc <- mkSyncFIFO(depthIn, sClkIn, sRstIn, dClk) ; end else begin ifc = error ("mkSyncFIFOFromCCFull can only be used when regEmpty and regFull are both True."); end return ifc ; endmodule ///////////////////////////////////////////////////////////////////////// //@ \subsubsection{Asynchronous RAMs} //@ \index{DualPortRamIfc@\te{DualPortRamIfc} (interface)|textbf} //@ \index{mkDualRam@\te{mkDualRam} (module)|textbf} //@ //@ # 4 interface DualPortRamIfc #(type addr_t, type data_t); method Action write( addr_t wr_addr, data_t din ); method data_t read ( addr_t rd_addr); endinterface: DualPortRamIfc import "BVI" DualPortRam = //@ # 3 module mkDualRam( DualPortRamIfc #(addr_t, data_t) ) provisos ( Bits#(addr_t,sa), Bits#(data_t,da) ) ; parameter addrWidth = valueOf(sa); parameter dataWidth = valueOf(da); default_clock clk(CLK, (*unused*)CLK_GATE) ; no_reset ; method write(WADDR, DIN) enable(WE) clocked_by( clk ) reset_by( no_reset ) ; method DOUT read(RADDR) clocked_by( no_clock ) reset_by( no_reset ) ; // read and write are independent schedule write CF read ; schedule read CF read ; schedule write C write ; endmodule ///////////////////////////////////////////////////////////////////////// //@ \subsubsection{A Crossing Primitive using Only Wires} (* deprecate = "Replaced by mkNullCrossingWire" *) import "BVI" SyncWire = //@ # 3 module mkNullCrossing( Clock dClk, a_type dataIn, ReadOnly#(a_type) ifc ) provisos (Bits#(a_type, sizeOfa)) ; default_clock no_clock; no_reset; parameter width = valueOf( sizeOfa ) ; input_clock ssClk() = clockOf(dataIn); input_reset ssRst() = resetOf(dataIn); input_clock ddClk() = dClk; port DIN clocked_by( ssClk ) reset_by( ssRst ) = dataIn ; method DOUT _read() clocked_by( ddClk ) reset_by( no_reset ) ; schedule _read CF _read ; endmodule // An undocumented (for now) primitive that implements a // working null crossing in both Verilog and Bluesim import "BVI" CrossingBypassWire = module vMkCrossingBypassWire (Clock dClk, VWire#(a) ifc) provisos (Bits#(a,sa)); parameter width = valueOf(sa); no_reset; default_clock clk(CLK, (*unused*) GATE); input_clock dstClk() = dClk; method wset(WVAL) enable((*inhigh*)WSET); method WGET wget clocked_by( dstClk ) reset_by( no_reset ); schedule wset C wset ; schedule wget CF wget ; path (WVAL, WGET) ; unsync wget ; endmodule: vMkCrossingBypassWire module mkBypassCrossingWire#(Clock dClk) (Tuple2#(Wire#(data_t), Maybe#(Name__))) provisos (Bits#(data_t, data_t_size)); // using VWire is an ugly hack to work around // the _read desugaring VWire#(data_t) ifc; Maybe#(Name__) mname = Nothing; if (valueOf(data_t_size) == 0) begin ifc = (interface VWire method Action wset(x); noAction; endmethod method wget = unpack(0); endinterface); end else begin VWire#(data_t) _r() ; vMkCrossingBypassWire __(dClk,_r) ; Name__ nm = primGetModuleName(asIfc(_r)); mname = tagged Valid nm; ifc = _r; end Reg#(data_t) ifc2 = interface Reg method _write = ifc.wset; method _read = ifc.wget; endinterface; return (tuple2(asIfc(ifc2), mname)); endmodule: mkBypassCrossingWire module mkNullCrossingWire(Clock dClk, a_type dataIn, ReadOnly#(a_type) ifc) provisos (Bits#(a_type, sizeOfa)) ; if (valueOf(sizeOfa) == 0) begin method a_type _read(); return unpack('0); endmethod end else begin List#(Clock) sourceClks = clocksOf(pack(dataIn)); if(isNull(sourceClks)) begin String msg = "Attempt to synchronize an unclocked value with nullCrossingWire "; // bogus wire only used to get a name for the error message Tuple2#(Wire#(Bit#(1)), Maybe#(Name__)) _blob <- mkBypassCrossingWire(dClk, clocked_by dClk); String name_str = ""; Position__ name_pos = noPosition; if (tpl_2(_blob) matches tagged Valid .name) begin name_str = "\140" + primGetNameString(name) + "'"; name_pos = primGetNamePosition(name); end String full_msg = msg + name_str + "."; primGenerateError(7,name_pos,full_msg); end Clock sClk = head(sourceClks); (*hide*) let _crossed <- mkBypassCrossingWire(dClk, clocked_by sClk); match {._w, ._mname} = _crossed; if(_mname matches tagged Valid .name) chkClockDomain(name, "nullCrossingWire", dataIn); // if there is no name, the "bad" error message is the best we can do (* can_schedule_first *) (* clock_crossing_rule *) rule clock_domain_crossing; _w <= dataIn; endrule: clock_domain_crossing method _read = _w; end endmodule: mkNullCrossingWire interface CrossingReg #( type a ) ; method Action _write(a datain) ; method a _read() ; method a crossed() ; endinterface function a readCrossingRegSrc(CrossingReg#(a) ifc); return ifc._read(); endfunction function a readCrossingRegDst(CrossingReg#(a) ifc); return ifc.crossed(); endfunction function Action writeCrossingReg(CrossingReg#(a) ifc, a x); action ifc._write(x); endaction endfunction function Reg#(a) crossingRegToReg(CrossingReg#(a) ifc); return (interface Reg method _read = ifc._read; method _write = ifc._write; endinterface); endfunction function ReadOnly#(a) crossingRegSrcToReadOnly(CrossingReg#(a) ifc); return (interface ReadOnly method _read = ifc._read; endinterface); endfunction function ReadOnly#(a) crossingRegDstToReadOnly(CrossingReg#(a) ifc); return (interface ReadOnly method _read = ifc.crossed; endinterface); endfunction // for data width == 0 (pointless, but included for generality) module vMkNullCrossing0(Clock dstClk, CrossingReg#(a) ifc) provisos(Bits#(a, sz_a)); method Action _write(a x) = noAction; method a _read() = unpack(0); method a crossed() = unpack(0); endmodule // only for data width > 0 import "BVI" CrossingRegN = module vMkNullCrossingReg( Clock dstClk, a initVal, CrossingReg#(a) ifc ) provisos (Bits#(a, sz_a)) ; default_clock sClk (CLK, (*unused*) GATE); default_reset sRst (RST); parameter width = valueOf(sz_a) ; parameter init = pack(initVal); input_clock dClk() = dstClk; method _write(D_IN) enable(EN) clocked_by(sClk) reset_by(sRst); method Q_OUT _read() clocked_by(sClk) reset_by(sRst) ; method Q_OUT crossed() clocked_by(dClk) reset_by(no_reset) ; schedule _write C _write ; schedule _read CF _read ; schedule _read SB _write; schedule crossed CF crossed ; endmodule // only for data width > 0 import "BVI" CrossingRegA = module vMkNullCrossingRegA( Clock dstClk, a initVal, CrossingReg#(a) ifc ) provisos (Bits#(a, sz_a)) ; default_clock sClk (CLK, (*unused*) GATE); default_reset sRst (RST); parameter width = valueOf(sz_a) ; parameter init = pack(initVal); input_clock dClk() = dstClk; method _write(D_IN) enable(EN) clocked_by(sClk) reset_by(sRst); method Q_OUT _read() clocked_by(sClk) reset_by(sRst) ; method Q_OUT crossed() clocked_by(dClk) reset_by(no_reset) ; schedule _write C _write ; schedule _read CF _read ; schedule _read SB _write; schedule crossed CF crossed ; endmodule // only for data width > 0 import "BVI" CrossingRegUN = module vMkNullCrossingRegU( Clock dstClk, CrossingReg#(a) ifc ) provisos (Bits#(a, sz_a)) ; default_clock sClk (CLK, (*unused*) GATE); no_reset; parameter width = valueOf(sz_a) ; input_clock dClk() = dstClk; method _write(D_IN) enable(EN) clocked_by(sClk) reset_by(no_reset); method Q_OUT _read() clocked_by(sClk) reset_by(no_reset); method Q_OUT crossed() clocked_by(dClk) reset_by(no_reset) ; schedule _write C _write ; schedule _read CF _read ; schedule _read SB _write; schedule crossed CF crossed ; endmodule module mkNullCrossingReg( Clock dstClk, a initVal, CrossingReg#(a) ifc ) provisos (Bits#(a, sz_a)) ; CrossingReg#(a) _ifc; if (valueOf(sz_a) == 0) (*hide*) _ifc <- vMkNullCrossing0(dstClk); else (*hide*) _ifc <- vMkNullCrossingReg(dstClk,initVal); return _ifc; endmodule: mkNullCrossingReg module mkNullCrossingRegA( Clock dstClk, a initVal, CrossingReg#(a) ifc ) provisos (Bits#(a, sz_a)) ; CrossingReg#(a) _ifc; if (valueOf(sz_a) == 0) (*hide*) _ifc <- vMkNullCrossing0(dstClk); else (*hide*) _ifc <- vMkNullCrossingRegA(dstClk,initVal); return _ifc; endmodule: mkNullCrossingRegA module mkNullCrossingRegU( Clock dstClk, CrossingReg#(a) ifc ) provisos (Bits#(a, sz_a)) ; CrossingReg#(a) _ifc; if (valueOf(sz_a) == 0) (*hide*) _ifc <- vMkNullCrossing0(dstClk); else (*hide*) _ifc <- vMkNullCrossingRegU(dstClk); return _ifc; endmodule: mkNullCrossingRegU ///////////////////////////////////////////////////////////////////////// //@ \subsubsection{Specialized Crossing Primitives} //@ //@ \index{mkSyncRegToSlow@\te{mkSyncRegToSlow} (module)|textbf} //@ \index{mkSyncRegToFast@\te{mkSyncRegToFast} (module)|textbf} //@ \index{mkSyncFIFOToSlow@\te{mkSyncRegToSlow} (module)|textbf} //@ \index{mkSyncFIFOToFast@\te{mkSyncRegToFast} (module)|textbf} //@ // a Wrapper for RegAligned (duplicate of RegA where read and write // methods are in different domains) import "BVI" RegAligned = module vSyncRegAligned #( a_type initValue) ( Clock sClkIn, Reset sRstIn, Clock dClkIn, Reset dRstIn, Clock realClock, Reset realReset, Reg#(a_type) ifc ) provisos (Bits#(a_type,sizea)) ; parameter width = valueOf( sizea ) ; parameter init = pack(initValue) ; default_clock ( CLK, (*unused*)CLK_GATE ) = realClock; default_reset( RST ) = realReset ; input_clock clk_src( ) = sClkIn ; input_clock clk_dst( ) = dClkIn ; input_reset srst() clocked_by (clk_src) = sRstIn ; input_reset drst() clocked_by (clk_dst) = dRstIn ; method _write( D_IN ) enable(EN) clocked_by( clk_src ) reset_by(srst) ; method Q_OUT _read() clocked_by( clk_dst ) reset_by(drst) ; schedule _read CF _read ; schedule _read CF _write ; // Do not allow EXT for the _write method ! schedule _write C _write ; endmodule //@ The {\tt mkSyncRegToSlow} and {\tt mkSyncSyncRegToFast} are specialized crossing primitives //@ which can be used to transport data when clock edges are aligned, //@ between the domains. The divided clocks and the appropriate //@ interface needed for the module would typically be //@ generated using the {\tt mkClockDivider} module. //@ //@ The crossing primitive is implemented via a single register, //@ clocked by slower (divided) clock. For a fast to slow crossing, the register is only writable when {\tt //@ clockReady} bit of the divider interface is asserted. This is an implicit condition of the //@ module which prevent erroneous writes. For a slow to fast //@ crossing both the read and write methods are always available. //@ //@ # 5 module mkSyncRegToSlow #( a_type initValue )( ClockDividerIfc divider, Reset slowRstIn, Reg #(a_type) ifc ) provisos (Bits#(a_type,sizea)) ; Reg#(a_type) icrossReg() ; vSyncRegAligned#(initValue) crossREGsrc( divider.fastClock, noReset, divider.slowClock, slowRstIn, divider.slowClock, slowRstIn, icrossReg ) ; method _read () ; return icrossReg._read() ; endmethod // Write method is only available in the fast cycle before the slow clock rises method Action _write( a_type din ) if ( divider.clockReady ) ; icrossReg._write( din ) ; endmethod endmodule module mkSyncRegToFast #( a_type initValue )( ClockDividerIfc divider, Reset slowRstIn, Reg #(a_type) ifc ) provisos (Bits#(a_type,sizea)) ; Reg#(a_type) icrossReg() ; vSyncRegAligned#(initValue) crossREGdst( divider.slowClock, slowRstIn, divider.fastClock, noReset, divider.slowClock, slowRstIn, icrossReg ) ; // _read method is always available in the fast domain method _read () ; return icrossReg._read() ; endmethod // Write method is always available from the slow domain method Action _write( a_type din ) ; icrossReg._write( din ) ; endmethod endmodule /// Build a fifo crossing in the same way interface FIFOF_MC #(type a) ; method Action enq(a x1) ; method Action deq() ; method a first() ; method Bool notFull() ; method Bool i_notFull() ; method Bool notEmpty() ; method Bool i_notEmpty() ; endinterface // Depth >2, width > 0. import "BVI" SizedFIFO = module vFIFOFS_MC#( Integer depth ) ( Clock sClkIn, Reset sRstIn, Clock dClkIn, Reset dRstIn, Clock realClock, Reset realReset, FIFOF_MC#(a) ifc ) provisos (Bits#(a,sa)); parameter p1width = valueOf(sa); parameter p2depth = depth; parameter p3cntr_width = log2(depth-1); default_clock clk ( CLK, (*unused*)CLK_GATE ) = realClock; default_reset _rst__ ( RST ) = realReset ; input_clock clk_src( ) = sClkIn ; input_reset srst() clocked_by (clk_src) = sRstIn ; input_clock clk_dst( ) = dClkIn ; input_reset drst() clocked_by (clk_dst) = dRstIn ; method enq( D_IN ) enable(ENQ) clocked_by( clk_src ) reset_by( srst ) ; method FULL_N notFull clocked_by( clk_src ) reset_by( srst ) ; method FULL_N i_notFull clocked_by( clk_src ) reset_by( srst ) ; method deq() enable(DEQ) clocked_by( clk_dst ) reset_by( drst ) ; method D_OUT first clocked_by( clk_dst ) reset_by( drst ) ; method EMPTY_N notEmpty clocked_by( clk_dst ) reset_by( drst ) ; method EMPTY_N i_notEmpty clocked_by( clk_dst ) reset_by( drst ) ; // method clear() ; port CLR = pack(False) ; // Don't know which side clear belongs // Cross domain methods are CF // this has some implications that loopy fifos are not allowed. schedule (enq, notFull, i_notFull) CF (deq, first, notEmpty, i_notEmpty ) ; schedule deq CF (i_notEmpty) ; schedule enq CF (i_notFull) ; schedule (first, notEmpty) CF (first, i_notEmpty, notEmpty) ; schedule (notFull) CF (i_notFull, notFull) ; schedule (i_notEmpty) CF ( first, i_notEmpty, notEmpty) ; schedule (i_notFull) CF ( i_notFull, notFull) ; schedule first SB deq ; schedule (notEmpty) SB (deq) ; schedule (notFull) SB (enq) ; schedule deq C deq; schedule enq C enq; // Following taken from FIFOF_.bsv // schedule deq CF (enq, i_notEmpty, i_notFull) ; // schedule enq CF (deq, first, i_notEmpty, i_notFull) ; // schedule (first, notEmpty, notFull) CF // (first, i_notEmpty, i_notFull, notEmpty, notFull) ; // schedule (i_notEmpty, i_notFull) CF // (clear, first, i_notEmpty, i_notFull, notEmpty, notFull) ; // schedule (clear, deq, enq) SB clear ; // schedule first SB (clear, deq) ; // schedule (notEmpty, notFull) SB (clear, deq, enq) ; endmodule // Depth == 2, width > 0. import "BVI" FIFO2 = module vFIFOF2_MC ( Clock sClkIn, Reset sRstIn, Clock dClkIn, Reset dRstIn, Clock realClock, Reset realReset, FIFOF_MC#(a) ifc ) provisos (Bits#(a,sa)); parameter width = valueOf(sa); default_clock clk ( CLK, (*unused*)CLK_GATE ) = realClock; default_reset _rst__ ( RST ) = realReset ; input_clock clk_src( ) = sClkIn ; input_reset srst() clocked_by (clk_src) = sRstIn ; input_clock clk_dst( ) = dClkIn ; input_reset drst() clocked_by (clk_dst) = dRstIn ; method enq( D_IN ) enable(ENQ) clocked_by( clk_src ) reset_by( srst ) ; method FULL_N notFull clocked_by( clk_src ) reset_by( srst ) ; method FULL_N i_notFull clocked_by( clk_src ) reset_by( srst ) ; method deq() enable(DEQ) clocked_by( clk_dst ) reset_by( drst ) ; method D_OUT first clocked_by( clk_dst ) reset_by( drst ) ; method EMPTY_N notEmpty clocked_by( clk_dst ) reset_by( drst ) ; method EMPTY_N i_notEmpty clocked_by( clk_dst ) reset_by( drst ) ; // method clear() ; port CLR = pack(False) ; // Don't know which side clear belongs // Cross domain methods are CF // this has some implications that loopy fifos are not allowed. schedule (enq, notFull, i_notFull) CF (deq, first, notEmpty, i_notEmpty ) ; schedule deq CF (i_notEmpty) ; schedule enq CF (i_notFull) ; schedule (first, notEmpty) CF (first, i_notEmpty, notEmpty) ; schedule (notFull) CF (i_notFull, notFull) ; schedule (i_notEmpty) CF ( first, i_notEmpty, notEmpty) ; schedule (i_notFull) CF ( i_notFull, notFull) ; schedule first SB deq ; schedule (notEmpty) SB (deq) ; schedule (notFull) SB (enq) ; schedule deq C deq; schedule enq C enq; endmodule module vFIFOF_MC#( Integer depth) ( Clock sClkIn, Reset sRstIn, Clock dClkIn, Reset dRstIn, Clock realClock, Reset realReset, FIFOF_MC#(a) ifc ) provisos( Bits#(a,sa) ) ; (* hide *) FIFOF_MC#(a) _ifc <- (depth < 2 ) ? error( "Error SyncFIFO sizes must be 2 or greater" ) : ( depth == 2) ? vFIFOF2_MC ( sClkIn, sRstIn, dClkIn, dRstIn, realClock, realReset ) : vFIFOFS_MC (depth, sClkIn, sRstIn, dClkIn, dRstIn, realClock, realReset ) ; return _ifc ; endmodule //@ The {\tt mkSyncFIFOAlignedEdges} module is a specialized crossing //@ primitive which can be used to transport data when clock edges are //@ aligned, between a fast //@ sClkIn and a slower dClkIn. The derived clock and the //@ \te{ClkNextRdy} signal would typically be //@ generated using the {\tt mkClockDivider} module. //@ //@ The crossing primitive is implemented via a FIFO with the //@ specified depth //@ clocked by dClkIn. The FIFO is only writable when {\tt //@ syncBit} is asserted and the FIFO is not Full. //@ //@ # 5 module mkSyncFIFOToSlow #( Integer depth )( ClockDividerIfc divider, Reset slowRstIn, SyncFIFOIfc #(a_type) ifc ) provisos (Bits#(a_type,sizea)) ; FIFOF_MC#(a_type) cross_fifo() ; vFIFOF_MC#( depth ) crossFIFOsrc( divider.fastClock, noReset, divider.slowClock, slowRstIn, divider.slowClock, slowRstIn, cross_fifo ) ; method Bool notFull = (cross_fifo.i_notFull && divider.clockReady ) ; method Action enq( a_type din ) if (cross_fifo.i_notFull && divider.clockReady ) ; cross_fifo.enq( din ) ; endmethod // Deq and first are clocked by the slow clock, and hence have // usual valid condition method Bool notEmpty = cross_fifo.i_notEmpty; method Action deq() if (cross_fifo.i_notEmpty ) ; cross_fifo.deq( ) ; endmethod method a_type first () if (cross_fifo.i_notEmpty ); return cross_fifo.first ; endmethod endmodule //@ # 5 module mkSyncFIFOToFast #( Integer depth )( ClockDividerIfc divider, Reset slowRstIn, SyncFIFOIfc #(a_type) ifc ) provisos (Bits#(a_type,sizea)) ; FIFOF_MC#(a_type) cross_fifo() ; vFIFOF_MC#( depth ) crossFIFOdst( divider.slowClock, slowRstIn, divider.fastClock, noReset, divider.slowClock, slowRstIn, cross_fifo ) ; // Enq is in the slow clock domain, and thus is ready as long as it is not full method Bool notFull = (cross_fifo.i_notFull ) ; method Action enq( a_type din ) if (cross_fifo.i_notFull ) ; cross_fifo.enq( din ) ; endmethod // Dequeue can only happen when the slow clock will tick method Bool notEmpty = (cross_fifo.i_notEmpty && divider.clockReady ) ; method Action deq() if (cross_fifo.i_notEmpty && divider.clockReady ) ; cross_fifo.deq( ) ; endmethod // The first is always ready if there is an element present method a_type first () if (cross_fifo.i_notEmpty ); return cross_fifo.first ; endmethod endmodule ///////////////////////////////////////////////////////////////////////// //@ \subsubsection{Reset Generation and Synchronization} //@ \index{mkReset@\te{mkReset} (module)|textbf} //@ \index{mkResetSync@\te{mkResetSync} (module)|textbf} //@ \index{mkSyncReset@\te{mkSyncReset} (module)|textbf} //@ \index{mkSyncResetFromCR@\te{mkSyncResetFromCR} (module)|textbf} //@ \index{mkAsyncReset@\te{mkAsyncReset} (module)|textbf} //@ \index{mkAsyncResetFromCR@\te{mkAsyncResetFromCR} (module)|textbf} //@ \index{mkInitialReset@\te{mkInitialReset} (module)|textbf} //@ \index{mkResetMux@\te{mkResetMux} (module)|textbf} //@ \index{mkResetEither@\te{mkResetEither} (module)|textbf} //@ // Seen by users of mkReset and mkResetSync interface MakeResetIfc; method Action assertReset(); method Bool isAsserted(); interface Reset new_rst; endinterface import "BVI" MakeReset = module vMkReset#( Integer stages, Bool startInRst ) ( Clock dClkIn, MakeResetIfc ifc ) ; default_clock clk(CLK, (*unused*)CLK_GATE) ; default_reset rst(RST) ; parameter RSTDELAY = (stages > 0) ? (stages - 1) : error("Reset synchronizers must have 1 or more stages") ; parameter init = pack(!startInRst); method assertReset () enable(ASSERT_IN) ; method ASSERT_OUT isAsserted() ; schedule isAsserted CF isAsserted; schedule isAsserted SB assertReset; schedule assertReset C assertReset; input_clock dst_clk(DST_CLK, (*unused*)DST_CLK_GATE) = dClkIn ; output_reset new_rst(OUT_RST) clocked_by(dst_clk) ; endmodule import "BVI" MakeResetA = module vMkResetA#( Integer stages, Bool startInRst ) ( Clock dClkIn, MakeResetIfc ifc ) ; default_clock clk(CLK, (*unused*)CLK_GATE) ; default_reset rst(RST) ; parameter RSTDELAY = (stages > 0) ? (stages ) : error("Reset synchronizers must have 1 or more stages") ; parameter init = pack(!startInRst); method assertReset () enable(ASSERT_IN) ; method ASSERT_OUT isAsserted() ; schedule isAsserted CF isAsserted; schedule isAsserted SB assertReset; schedule assertReset C assertReset; input_clock dst_clk(DST_CLK, (*unused*)DST_CLK_GATE) = dClkIn ; output_reset new_rst(OUT_RST) clocked_by(dst_clk) ; endmodule import "BVI" MakeReset0 = module vMkReset0 #( Bool startInRst ) ( Clock dClkIn, MakeResetIfc ifc ) ; default_clock clk(CLK, (*unused*)CLK_GATE) ; default_reset rst(RST) ; parameter init = pack(! startInRst); method assertReset () enable(ASSERT_IN) ; method ASSERT_OUT isAsserted() ; schedule isAsserted CF isAsserted; schedule isAsserted SB assertReset; schedule assertReset C assertReset; input_clock dst_clk() = dClkIn ; output_reset new_rst(OUT_RST) clocked_by(dst_clk) ; endmodule // Needed for module BVI, users should not need this interface ResetGenIfc; interface Reset gen_rst; endinterface import "BVI" SyncResetA = module vSyncResetA#( Integer stages ) ( Reset rstIn, ResetGenIfc rstOut ) ; default_clock clk(CLK, (*unused*)CLK_GATE) ; no_reset ; // we don't care what the clock is of the input reset input_reset rst(IN_RST) clocked_by (no_clock) = rstIn ; parameter RSTDELAY = (stages > 0) ? (stages - 1) : error("Reset synchronizers must have 1 or more stages") ; output_reset gen_rst(OUT_RST) clocked_by( clk) ; endmodule import "BVI" SyncReset = module vSyncReset#(Integer stages ) ( Reset rstIn, ResetGenIfc rstOut ) ; default_clock clk(CLK, (*unused*)CLK_GATE) ; no_reset ; // we don't care what the clock is of the input reset input_reset rst(IN_RST) clocked_by (no_clock) = rstIn ; parameter RSTDELAY = (stages > 0) ? (stages - 1) : error("Reset synchronizers must have 1 or more stages") ; output_reset gen_rst(OUT_RST) clocked_by( clk) ; endmodule import "BVI" SyncReset0 = module vSyncReset0 ( Reset rstIn, ResetGenIfc rstOut ) ; default_clock clk(); no_reset ; // we don't care what the clock is of the input reset input_reset rst(IN_RST) clocked_by (no_clock) = rstIn ; output_reset gen_rst(OUT_RST) clocked_by( clk) ; //path ( IN_RST, OUT_RST ) ; endmodule import "BVI" InitialReset = module vInitialReset#(Integer cycles ) ( ResetGenIfc rstOut ); default_clock clk(CLK, (*unused*)CLK_GATE) ; no_reset ; parameter RSTHOLD = (cycles > 0) ? cycles : error("Reset generator built with hold cycles less than 1") ; output_reset gen_rst(OUT_RST) clocked_by( clk) ; endmodule //@ Reset generation allows the conversion of a Boolean type to a //@ Reset type, where the reset is associated with the default (or //@ {\tt clocked\_by}) clock domain. //@ Two modules provide this function, {\tt mkReset} and {\tt //@ mkResetSync}, where each module has one parameter, {\tt stages}. //@ The {\tt stages} argument is the number of full clock //@ cycles the output reset is held after the input reset is //@ deasserted. Specifying a 0 for the {\tt stages} argument results //@ in the creation of a simple wire between the {\tt bRstIn} and {\tt //@ rstOut}. That is, the reset is asserted immediately and not held //@ after the {\tt bRstIn} is deasserted. It becomes the designer's //@ responsibility to ensure that {\tt bRstIn} is asserted for //@ sufficient time to allow the design to reset properly. //@ Note that the Boolean input {\tt bRstIn} is asserted //@ low, and can be taken from any clock domain. //@ //@ The difference between {\tt mkReset} and {\tt mkResetSync} //@ is that for the former, the assertion of reset is immediate, while //@ the later asserts reset at the next rising edge of the clock. //@ Note that the use //@ mkResetSync is less common, since the reset requires clock edges //@ to take effect; failure to assert reset for a clock edge will not //@ result in a reset being seen at {\tt rstOut}. //@ //@ # 2 module mkReset #( Integer stages, Bool startInRst )( Clock dClkIn, MakeResetIfc ifc ) ; (* hide *) MakeResetIfc _ifc <- ( stages == 0 ) ? vMkReset0(startInRst, dClkIn) : vMkResetA(stages, startInRst, dClkIn) ; return _ifc ; endmodule //@ # 2 module mkResetSync #( Integer stages, Bool startInRst )( Clock dClkIn, MakeResetIfc ifc ) ; (* hide *) MakeResetIfc _ifc <- ( stages == 0 ) ? vMkReset0(startInRst, dClkIn) : vMkReset(stages, startInRst, dClkIn) ; return _ifc ; endmodule //@ To synchronize resets from one clock domain to another, several //@ modules are provided. The {\tt mkAsyncReset} family is similar to //@ the {\tt mkReset} module; the {\tt stages} argument has the same //@ behavior. //@ # 4 module mkAsyncReset #( Integer stages )( Reset sRst, Clock dClkIn, Reset dRstOut ) ; (* hide *) ResetGenIfc _ifc <- ( stages == 0 ) ? vSyncReset0( sRst, clocked_by( dClkIn ) ) : vSyncResetA( stages, sRst, clocked_by( dClkIn ) ) ; return _ifc.gen_rst ; endmodule //@ # 3 module mkAsyncResetFromCR #( Integer stages )( Clock dClkIn, Reset dRstOut ) ; (* hide *) Reset _sRst <- exposeCurrentReset ; (* hide *) Reset _dRst <- mkAsyncReset(stages, _sRst, dClkIn) ; return _dRst ; endmodule //@ The less common {\tt mkSyncReset} modules are provided for //@ convenience, but these modules {\em require} that {\tt sRst} be held //@ during a positive edge of {\tt dClkIn} for the reset assertion to //@ be noticed. //@ # 4 module mkSyncReset #( Integer stages )( Reset sRst, Clock dClkIn, Reset dRstOut ) ; let msg = "The use of a mkSyncReset may not always result in a reset" + " signal being seen on the destination side." + " Recommend replacement with mkAsyncReset"; (* hide *) ResetGenIfc _ifc <- ( stages == 0 ) ? vSyncReset0( sRst, clocked_by( dClkIn ) ) : vSyncReset( stages, sRst, clocked_by( dClkIn ) ) ; return warning ( msg, _ifc.gen_rst ) ; endmodule //@ # 3 module mkSyncResetFromCR #( Integer stages )( Clock dClkIn, Reset dRstOut ) ; let msg = "The use of a mkSyncResetFromCR may not always result in a reset" + " signal being seen on the destination side." + " Recommend replacement with mkAsyncResetFromCR"; (* hide *) Reset _sRst <- exposeCurrentReset ; // We could use this if we didn't mind the message being the same //Reset _dRst <- mkSyncReset(stages, _sRst, dClkIn) ; //return _dRst ; (* hide *) ResetGenIfc _ifc <- ( stages == 0 ) ? vSyncReset0( _sRst, clocked_by( dClkIn ) ) : vSyncReset( stages, _sRst, clocked_by( dClkIn ) ) ; return warning ( msg, _ifc.gen_rst ) ; endmodule //@ For testbenches, in which an absolute clock is being created, //@ it is helpful to generate a reset for that clock. //@ The module {\tt mkInitialReset} generates a reset on the first //@ clock that it receives. The reset is asserted for a number of //@ cycles specified by the parameter, which must be greater than zero. //@ This module is not consider synthesizable. //@ # 2 module mkInitialReset #( Integer cycles )( Reset rstOut ) ; (*hide*) ResetGenIfc _ifc <- vInitialReset(cycles); return _ifc.gen_rst ; endmodule //@ For selecting between two resets, {\tt mkResetMux} is available. //@ This module provides protection for the user by requiring that the //@ resets be associated with the same clock and, further, that the //@ selector signal is in the same domain. //@ # 4 interface MuxRstIfc; method Action select ( Bool ab ) ; interface Reset reset_out ; endinterface import "BVI" ResetMux = //@ # 1 module mkResetMux (Reset aRst, Reset bRst, MuxRstIfc ifcout) ; default_clock xclk(CLK, (*unused*)CLKGATE) ; no_reset; input_reset aRst(A_RST) clocked_by(xclk) = aRst ; input_reset bRst(B_RST) clocked_by(xclk) = bRst ; output_reset reset_out(RST_OUT) clocked_by(xclk) ; method select(SELECT) enable(SELECT_ENABLE) clocked_by (xclk) reset_by (no_reset) ; schedule select C select ; endmodule // used internally only interface JoinRstIfc; interface Reset reset_out; endinterface import "BVI" ResetEither = module vMkResetEither (Reset aRst, Reset bRst, JoinRstIfc ifcout) ; default_clock xclk(); no_reset; input_reset aRst(A_RST) clocked_by(xclk) = aRst; input_reset bRst(B_RST) clocked_by(xclk) = bRst; output_reset reset_out(RST_OUT) clocked_by(xclk); endmodule module mkResetEither(Reset aRst, Reset bRst, Reset ifc); (* hide *) JoinRstIfc _r <- vMkResetEither(aRst,bRst); return _r.reset_out; endmodule //@ The isResetAsserted module tests whether a Reset is asserted, //@ yielding a Boolean value in the clock domain associated with //@ the reset. module isResetAsserted (ReadOnly#(Bool) ifc ); Reg#(Bool) isInReset <- mkRegA(True); rule isResetAssertedUpdate (isInReset); isInReset <= False; endrule method Bool _read = isInReset._read; endmodule import "BVI" ResetToBool = module isResetAssertedDirect( ReadOnly#(Bool) ifc ) ; default_clock clk() ; default_reset rst(RST) ; method VAL _read() clocked_by(clk) reset_by(no_reset); schedule _read CF _read; path (RST,VAL); endmodule module mkResetInverter#(Reset in)(Reset); let _inv <- vResetInverter(in); return _inv.gen_rst; endmodule import "BVI" ResetInverter = module vResetInverter(Reset in, ResetGenIfc out); default_clock clk(); no_reset; input_reset (RESET_IN) clocked_by (no_clock) = in; output_reset gen_rst(RESET_OUT) clocked_by (clk); endmodule module invertCurrentReset(Reset); let in <- exposeCurrentReset; let _m <- vResetInverter(in); return _m.gen_rst; endmodule: invertCurrentReset typeclass ClockConv#(type a); module mkConverter#(Integer d, a to_conv)(a); endtypeclass instance ClockConv#(ActionValue#(a)) provisos (Bits#(a,sa)); module mkConverter#(Integer d)(ActionValue#(a) av, ActionValue#(a) ifc); SyncFIFOIfc#(a) ff <- mkSyncFIFOToCC(d, clockOf(av), resetOf(av)); rule enqueue; let v <- av; ff.enq(v); endrule let ifc = (actionvalue let v = ff.first; ff.deq; return v; endactionvalue); return ifc; endmodule endinstance instance ClockConv#(function Action af(a x)) provisos (Bits#(a,sa)); module mkConverter#(Integer d)(function Action af(a x), function Action af(a x)); SyncFIFOIfc#(a) ff <- mkSyncFIFOFromCC(d, clockOf(af)); rule dequeue; af(ff.first); ff.deq; endrule return (ff.enq); endmodule endinstance // a sloppy way to make a "disabled clock", with oscillator 0 and gate 1 module primMakeDisabledClockM(Clock); (* hide *) MakeUngatedClockIfc#(Bit#(1)) _m <- vMkUngatedClock(0); return(_m.new_clk); endmodule Clock primMakeDisabledClock = primBuildModule(primGetName(disabled_clock), noClock, noReset, primMakeDisabledClockM);