-- | A library that generates new clocks based on a base period. -- Usage, supposing @v@ is a Copilot variable, then -- @ -- clk ( period 3 ) ( phase 1 ) -- @ -- is equivalent to a stream of values like: -- @ -- cycle [False, True, False] -- @ -- that generates a stream of values -- @ -- False True False False True False False True False ... -- 0 1 2 3 4 5 6 7 8 -- @ -- That is true every 3 ticks (the period) starting on the 1st tick (the phase). -- Constraints: -- The period must be greater than 0. -- The phase must be greater than or equal to 0. -- The phase must be less than the period. module Copilot.Library.Clocks ( clk, clk1, period, phase ) where import Prelude ( Integral, fromIntegral, ($)) import qualified Prelude as P import Copilot.Language import Data.Bool import Data.List (replicate) data ( Integral a ) => Period a = Period a data ( Integral a ) => Phase a = Phase a period :: ( Integral a ) => a -> Period a period = Period phase :: ( Integral a ) => a -> Phase a phase = Phase -- clk generates a clock that counts n ticks by using an array of size n clk :: ( Integral a ) => Period a -> Phase a -> Stream Bool clk ( Period period' ) ( Phase phase' ) = clk' where clk' = if period' P.< 1 then badUsage ( "clk: clock period must be 1 or greater" ) else if phase' P.< 0 then badUsage ( "clk: clock phase must be 0 or greater" ) else if phase' P.>= period' then badUsage ( "clk: clock phase must be less than period") else replicate ( fromIntegral phase' ) False P.++ True : replicate ( fromIntegral $ period' P.- phase' P.- 1 ) False ++ clk' -- clk1 generates a clock that counts n ticks by using a -- counter variable of integral type a clk1 :: ( Integral a, Typed a ) => Period a -> Phase a -> Stream Bool clk1 ( Period period' ) ( Phase phase' ) = if period' P.< 1 then badUsage ( "clk1: clock period must be 1 or greater" ) else if phase' P.< 0 then badUsage ( "clk1: clock phase must be 0 or greater" ) else if phase' P.>= period' then badUsage ( "clk1: clock phase must be less than period") else let counter = [ P.fromInteger 0 ] ++ mux ( counter /= ( constant $ period' P.- 1 ) ) ( counter P.+ 1 ) ( 0 ) in counter == fromIntegral phase'