packages feed

language-bluespec-0.1: src/Language/Bluespec/Classic/AST/VModInfo.hs

-- This corresponds to src/comp/VModInfo.hs in bsc.
module Language.Bluespec.Classic.AST.VModInfo
  ( VName(..)
  , VPathInfo(..)
  , VeriPortProp(..)
  , VArgInfo(..)
  , VPort
  , VSchedInfo
  , VFieldInfo(..)
  , InputClockInf
  , OutputClockInf
  , VOscPort
  , VInputGatePort
  , VOutputGatePort
  , VClockInfo(..)
  , ResetInf
  , VResetInfo(..)
  ) where

import qualified Data.List as L
import Text.PrettyPrint.HughesPJClass

import Language.Bluespec.Classic.AST.Id
import Language.Bluespec.Classic.AST.Position
import Language.Bluespec.Classic.AST.SchedInfo
import Language.Bluespec.Prelude
import Language.Bluespec.Pretty

newtype VName = VName String
        deriving (Eq, Ord, Show)

instance Pretty VName where
    pPrintPrec _ _ (VName s) = text s

newtype VPathInfo = VPathInfo [(VName, VName)]
                  deriving (Eq, Ord, Show)

instance Pretty VPathInfo where
    pPrintPrec _d _p (VPathInfo []) =
        s2par "No combinational paths from inputs to outputs"
    pPrintPrec d p (VPathInfo nns) =
        let
            -- function to join paths going to the same output
            joinPaths [] = []
            joinPaths zs@((_,o):_) =
                case (L.partition ((== o) . snd) zs) of
                    (xs, ys) -> (map fst xs, o) : joinPaths ys

            -- function to display one pair
            ppOne ([i],out) = pPrintPrec d p i <+> text "->" <+> pPrintPrec d p out
            ppOne (ins,out) = text "(" <>
                              sepList (map (pPrintPrec d p) ins) (text ",") <>
                              text ")" <+> text "->" <+> pPrintPrec d p out
        in
            s2par "Combinational paths from inputs to outputs:" $+$
            nest 2 (vcat (map ppOne (joinPaths nns)))

instance HasPosition VFieldInfo where
  getPosition (Method { vf_name = n }) = getPosition n
  getPosition (Clock i)                 = getPosition i -- or noPosition?
  getPosition (Reset i)                 = getPosition i -- or noPosition?
  getPosition (Inout { vf_name = n })  = getPosition n

-- the order is important for VIOProps ("unused" should come last)
data VeriPortProp = VPreg
                  | VPconst
                  | VPinhigh
                  | VPouthigh
                  | VPclock
                  | VPclockgate
                  | VPreset
                  | VPinout
                  | VPunused
        deriving (Eq, Ord, Show)

instance Pretty VeriPortProp where
    pPrintPrec _ _ VPreg = text "reg"
    pPrintPrec _ _ VPclock = text "clock"
    pPrintPrec _ _ VPconst = text "const"
    pPrintPrec _ _ VPinhigh = text "inhigh"
    pPrintPrec _ _ VPouthigh = text "outhigh"
    pPrintPrec _ _ VPunused = text "unused"
    pPrintPrec _ _ VPreset  = text "reset"
    pPrintPrec _ _ VPinout  = text "inout"
    pPrintPrec _ _ VPclockgate = text "clock gate"

data VArgInfo = Param VName    -- named module parameter
              -- named module port, with associated clock and reset
              | Port VPort (Maybe Id) (Maybe Id)
              | ClockArg Id    -- named clock
              | ResetArg Id    -- named reset
              -- named module inout, with associated clock and reset
              | InoutArg VName (Maybe Id) (Maybe Id)
              deriving (Eq, Ord, Show)

instance Pretty VArgInfo where
    pPrintPrec d _p (Param x) = text "param " <> pPrintPrec d 0 x <> text ";"
    pPrintPrec d _p (Port x mclk mrst) =
        text "port " <> pPrintPrec d 0 x <+>
        ppMClk d mclk <+> ppMRst d mrst <>
        text ";"
    pPrintPrec d p (ClockArg x) = text "clockarg " <> pPrintPrec d p x <> text ";"
    pPrintPrec d p (ResetArg x) = text "resetarg " <> pPrintPrec d p x <> text ";"
    pPrintPrec d _p (InoutArg x mclk mrst) =
        text "inoutarg " <> pPrintPrec d 0 x <+>
        ppMClk d mclk <+> ppMRst d mrst <>
        text ";"

ppMClk :: PDetail -> Maybe Id -> Doc
ppMClk d mclk =
    let clk = case mclk of
                  Nothing -> text "no_clock"
                  Just c  -> pPrintPrec d 0 c
    in  text "clocked_by (" <> clk <> text ")"

ppMRst :: PDetail -> Maybe Id -> Doc
ppMRst d mrst =
    let rst = case mrst of
                  Nothing -> text "no_reset"
                  Just r  -> pPrintPrec d 0 r
    in  text "reset_by (" <> rst <> text ")"

type VPort = (VName, [VeriPortProp])

type VSchedInfo = SchedInfo Id

-- XXX why does the VFieldInfo not contain a ready signal?
data VFieldInfo = Method { vf_name   :: Id, -- method name
                           vf_clock  :: (Maybe Id), -- optional clock
                           -- optional because the method may be combinational
                           vf_reset  :: (Maybe Id), -- optional reset
                           -- optional because the method may be independent of a reset signal
                           vf_mult   :: Integer, -- multiplicity
                           vf_inputs :: [VPort],
                           vf_output :: Maybe VPort,
                           vf_enable :: Maybe VPort }
                | Clock { vf_name :: Id } -- output clock name
                                           -- connection information is in the ClockInfo
                | Reset { vf_name :: Id } -- output reset name
                                           -- connection information is in the ResetInfo
                | Inout { vf_name :: Id, -- output inout name
                          vf_inout :: VName,
                          vf_clock :: (Maybe Id), -- optional clock
                          vf_reset :: (Maybe Id) } -- optional reset
                deriving (Eq, Ord, Show)

instance Pretty VFieldInfo where
    pPrintPrec d p (Method n c r m i o e) =
      text "method " <> pout o <> pPrintPrec d p n <> pmult m <>
      pins i <> pena e <+> ppMClk d c <+> ppMRst d r <>
      text ";"
        where pout Nothing = empty
              pout (Just po) = pPrintPrec d p po
              pmult 1  = empty
              pmult n' = text "[" <> pPrintPrec d p n' <> text "]"
              pins []  = empty
              pins i'  = text "(" <> sepList (map (pPrintPrec d p) i') (text ",") <> text ")"
              pena Nothing = empty
              pena (Just en) = text " enable (" <> pPrintPrec d p en <> text ")"
    pPrintPrec d p (Clock i) = text "clock " <> pPrintPrec d p i <> text ";"
    pPrintPrec d p (Reset i) = text "reset " <> pPrintPrec d p i <> text ";"
    pPrintPrec d p (Inout n port c r) =
        text "inout " <> pPrintPrec d p n <+>
        text "(" <> pPrintPrec d p port <> text ")" <+>
        ppMClk d c <+> ppMRst d r <> text ";"

-- describes the clocks imported by a module
type InputClockInf = (Id, Maybe (VOscPort, VInputGatePort))

-- describes the clocks exported by a module
type OutputClockInf = (Id, Maybe (VOscPort, VOutputGatePort))

-- no VeriPortProp needed, so we use VName and not VPort
type VOscPort = VName

-- gate port for input clocks
-- Either there is no port, in which case the boolean indicates
-- whether the gate is assumed True or is unneeded, or there is gate port.
type VInputGatePort = Either Bool VName

-- gate port for output clocks
-- Either there is no port, in which case users should assume a value True,
-- or there is a port, and we annotate whether it is "outhigh" with a
-- port property (VPouthigh)
type VOutputGatePort = Maybe VPort

data VClockInfo = ClockInfo {
                 -- named list of input clocks
                 input_clocks :: [InputClockInf],
                 -- named list of output clocks
                 output_clocks :: [OutputClockInf],
                 -- edges in the ancestor relationships (transitive)
                 -- first clock is parent, second is child
                 ancestorClocks :: [(Id, Id)],
                 -- other sibling relationships
                 -- transitive (but often trumped by ancestry)
                 -- method calls are permitted across sibling relationships
                 -- but *both* gate conditions must be enforced
                 siblingClocks :: [(Id, Id)] }
                deriving (Eq, Ord, Show)

instance Pretty VClockInfo where
    pPrintPrec d _p (ClockInfo in_cs out_cs as ss) =
        vcat (map pOutCInf out_cs ++
              map pInCInf in_cs ++
              map pAnc as ++
              map pSib ss)
        where
              pOutCInf (i,mc) = text "clock " <> pPrintPrec d 0 i <>
                                text "(" <> pOutMClk mc <> text ");"
              pOutMClk Nothing = empty
              pOutMClk (Just (vn, mg)) = pPrintPrec d 0 vn <> pOutMGate mg
              pOutMGate Nothing = empty
              pOutMGate (Just (vn, vpps)) =
                  text ", " <> pPortProps vpps <> pPrintPrec d 0 vn
              pPortProps [] = empty
              pPortProps (vp:vpps) =
                  text "{-" <> pPrintPrec d 0 vp <> text "-} " <> pPortProps vpps

              pInCInf (i,mc) = text "clock " <> pPrintPrec d 0 i <>
                               text "(" <> pInMClk mc <> text ");"
              pInMClk Nothing = empty
              pInMClk (Just (vn, mg)) = pPrintPrec d 0 vn <> pInMGate mg
              pInMGate (Left True)  = text ", {-inhigh-}"
              pInMGate (Left False) = text ", {-unused-}"
              pInMGate (Right vn)   = text ", " <> pPrintPrec d 0 vn

              pAnc (i,j) = text "ancestor (" <> pPrintPrec d 0 i <> text ", " <>
                           pPrintPrec d 0 j <> text ");"
              pSib (i,j) = text "sibling (" <> pPrintPrec d 0 i <> text ", " <>
                           pPrintPrec d 0 j <> text ");"

instance HasPosition VClockInfo where
  getPosition (ClockInfo { output_clocks = ((id',_):_)}) = getPosition id'
  getPosition (ClockInfo { input_clocks = ((id',_):_)}) = getPosition id'
  getPosition _ = noPosition

-- reset name, Verilog port (optional), clock (optional)
type ResetInf = (Id, (Maybe VName, Maybe Id))

-- basic information on reset signals
-- more information to be added (sync/async, clock relationships, etc.)
data VResetInfo = ResetInfo {
                   input_resets  :: [ResetInf],
                   output_resets :: [ResetInf]
                  }
  deriving (Eq, Ord, Show)

instance Pretty VResetInfo where
    pPrintPrec d p (ResetInfo in_rs out_rs) = vcat (map pRInf (out_rs ++ in_rs))
      where t = text
            pRInf (i,(mn,mc)) =
                t"reset " <> pPrintPrec d p i <>
                t"(" <> pMRst mn <> t")" <+>
                t"clocked_by(" <> pMClk mc <> t");"
            pMRst Nothing  = empty
            pMRst (Just n) = pPrintPrec d p n
            pMClk Nothing  = t"no_clock"
            pMClk (Just c) = pPrintPrec d p c