content: {-# LANGUAGE CPP #-}
  {-# LANGUAGE DeriveDataTypeable #-}
  module VModInfo(VModInfo, mkVModInfo,
                  vName, vClk, vRst, vArgs, vFields, vSched, vPath,
                  VName(..), VPort, VSchedInfo, VMethodConflictInfo,
                  VPathInfo(..), VeriPortProp(..),
                  VArgInfo(..), isParam, isPort, isClock, isReset, isInout,
                  VFieldInfo(..),
                  VClockInfo(..), InputClockInf, OutputClockInf,
                  VOscPort, VInputGatePort, VOutputGatePort,
                  VResetInfo(..), ResetInf, VWireInfo(..),
                  getInputClockPorts, getInputResetPorts,
                  lookupOutputClockWires, lookupOutputClockPorts,
                  lookupInputClockWires,
                  lookupOutputResetWire, lookupOutputResetPort,
                  lookupInputResetWire,
                  lookupIfcInoutWire,
                  getOutputClockPortTable, getOutputResetPortTable,
                  getVNameString, id_to_vName, id_to_vPort,
                  vName_to_id, vPort_to_id,
                  getVArgInfoName, getVArgPortClock, getVArgPortReset,
                  getVArgInoutClock, getVArgInoutReset,
                  getIfcIdPosition,
                  str_to_vPort,getVPortString,
                  mkNamedEnable,
                  mkNamedOutput,
                  mkNamedReady,
                  mkNamedInout,
                  extractNames
                  ) where
  
  #if defined(__GLASGOW_HASKELL__) && (__GLASGOW_HASKELL__ >= 804)
  import Prelude hiding ((<>))
  #endif
  
  import Data.List(partition, nub)
  import Data.Maybe(catMaybes)
  import qualified Data.Map as M
  import qualified Data.Set as S
  import qualified Data.Generics as Generic
  
  import ErrorUtil
  import Id
  import IdPrint()
  import Position
  import SchedInfo
  import Util
  import Eval
  import PPrint
  
  -- VMODINFO AND SUBSIDIARIES:
  
  -- ===============
  -- VName
  
  newtype VName = VName String
          deriving (Show, Ord, Eq, Generic.Data, Generic.Typeable)
  
  instance PPrint VName where
      pPrint _ _ (VName s) = text s
  
  instance Hyper VName where
      hyper (VName s) y = hyper s y
  
  getVNameString :: VName -> String
  getVNameString (VName string) = string
  
  -- convert Bluespec identifier to Verilog names
  id_to_vName :: Id -> VName
  id_to_vName i = VName (getIdString i)
  
  vName_to_id :: VName -> Id
  vName_to_id (VName s) = mk_homeless_id s
  
  vPort_to_id :: VPort -> Id
  vPort_to_id (VName s, _) = mk_homeless_id s
  
  -- ===============
  -- VeriPortProp
  
  -- the order is important for VIOProps ("unused" should come last)
  data VeriPortProp = VPreg
                    | VPconst
                    | VPinhigh
                    | VPouthigh
                    | VPclock
                    | VPclockgate
                    | VPreset
                    | VPinout
                    | VPunused
          deriving (Show, Eq, Ord, Generic.Data, Generic.Typeable)
  
  instance Hyper VeriPortProp where
      hyper x y = x `seq` y
  
  instance PPrint VeriPortProp where
      pPrint _ _ VPreg = text "reg"
      pPrint _ _ VPclock = text "clock"
      pPrint _ _ VPconst = text "const"
      pPrint _ _ VPinhigh = text "inhigh"
      pPrint _ _ VPouthigh = text "outhigh"
      pPrint _ _ VPunused = text "unused"
      pPrint _ _ VPreset  = text "reset"
      pPrint _ _ VPinout  = text "inout"
      pPrint _ _ VPclockgate = text "clock gate"
  
  
  -- ===============
  -- VPort
  
  type VPort = (VName, [VeriPortProp])
  
  getVPortString :: VPort -> String
  getVPortString (vn,_) = getVNameString vn
  
  id_to_vPort :: Id -> VPort
  id_to_vPort i = (id_to_vName i, [])
  
  str_to_vPort :: String -> VPort
  str_to_vPort str = (VName str, [])
  
  
  -- ===============
  -- VSchedInfo
  
  type VSchedInfo = SchedInfo Id
  
  type VMethodConflictInfo = MethodConflictInfo Id
  
  -- ===============
  -- VPathInfo
  
  newtype VPathInfo = VPathInfo [(VName, VName)]
                    deriving (Show, Ord, Eq, Generic.Data, Generic.Typeable)
  
  instance PPrint VPathInfo where
      pPrint d p (VPathInfo []) =
          s2par "No combinational paths from inputs to outputs"
      pPrint d p (VPathInfo nns) =
          let
              -- function to join paths going to the same output
              joinPaths [] = []
              joinPaths zs@((_,o):_) =
                  case (partition ((== o) . snd) zs) of
                      (xs, ys) -> (map fst xs, o) : joinPaths ys
  
              -- function to display one pair
              ppOne ([i],out) = pPrint d p i <+> text "->" <+> pPrint d p out
              ppOne (ins,out) = text "(" <>
                                sepList (map (pPrint d p) ins) (text ",") <>
                                text ")" <+> text "->" <+> pPrint d p out
          in
              s2par "Combinational paths from inputs to outputs:" $+$
              nest 2 (vcat (map ppOne (joinPaths nns)))
  
  -- for debug output
  pShowVPathInfo :: PDetail -> Int -> VPathInfo -> Doc
  pShowVPathInfo d p (VPathInfo nns) = pPrint d p nns
  
  instance Hyper VPathInfo where
      hyper (VPathInfo nns) = hyper nns
  
  
  -- ===============
  -- VArgInfo
  
  -- describes what an argument to a Verilog module is
  -- note that because of Param vs. Port, vNParam is no longer required
  -- XXX Port could contain field for the default value?
  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 (Show, Ord, Eq, Generic.Data, Generic.Typeable)
  
  isParam :: VArgInfo -> Bool
  isParam (Param {}) = True
  isParam _ = False
  
  isPort :: VArgInfo -> Bool
  isPort (Port {}) = True
  isPort _ = False
  
  isClock :: VArgInfo -> Bool
  isClock (ClockArg {}) = True
  isClock _ = False
  
  isReset :: VArgInfo -> Bool
  isReset (ResetArg {}) = True
  isReset _ = False
  
  isInout :: VArgInfo -> Bool
  isInout (InoutArg {}) = True
  isInout _ = False
  
  getVArgInfoName :: VArgInfo -> Id
  getVArgInfoName (Param vn)    = vName_to_id vn
  getVArgInfoName (Port vp _ _) = vName_to_id (fst vp)
  getVArgInfoName (ClockArg i)  = i
  getVArgInfoName (ResetArg i)  = i
  getVArgInfoName (InoutArg vn _ _) = vName_to_id vn
  
  getVArgPortClock :: VArgInfo -> Maybe Id
  getVArgPortClock (Port _ mclk _) = mclk
  getVArgPortClock _ = internalError ("getVArgPortClock: not a port")
  
  getVArgPortReset :: VArgInfo -> Maybe Id
  getVArgPortReset (Port _ _ mrst) = mrst
  getVArgPortReset _ = internalError ("getVArgPortReset: not a port")
  
  -- XXX do these need to be separate from the Port versions?
  getVArgInoutClock :: VArgInfo -> Maybe Id
  getVArgInoutClock (InoutArg _ mclk _) = mclk
  getVArgInoutClock _ = internalError ("getVArgInoutClock: not an inout")
  
  getVArgInoutReset :: VArgInfo -> Maybe Id
  getVArgInoutReset (InoutArg _ _ mrst) = mrst
  getVArgInoutReset _ = internalError ("getVArgInoutReset: not an inout")
  
  instance Hyper VArgInfo where
      hyper (Param x) y = hyper x y
      hyper (Port x1 x2 x3) y = hyper3 x1 x2 x3 y
      hyper (ClockArg x) y = hyper x y
      hyper (ResetArg x) y = hyper x y
      hyper (InoutArg x1 x2 x3) y = hyper3 x1 x2 x3 y
  
  instance PPrint VArgInfo where
      pPrint d p (Param x) = text "param " <> pPrint d 0 x <> text ";"
      pPrint d p (Port x mclk mrst) =
          text "port " <> pPrint d 0 x <+>
          ppMClk d mclk <+> ppMRst d mrst <>
          text ";"
      pPrint d p (ClockArg x) = text "clockarg " <> pPrint d p x <> text ";"
      pPrint d p (ResetArg x) = text "resetarg " <> pPrint d p x <> text ";"
      pPrint d p (InoutArg x mclk mrst) =
          text "inoutarg " <> pPrint 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  -> pPrint 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  -> pPrint d 0 r
      in  text "reset_by (" <> rst <> text ")"
  
  
  -- ===============
  -- VFieldInfo
  
  -- 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 (Show, Ord, Eq, Generic.Data, Generic.Typeable)
  
  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
  
  instance Hyper VFieldInfo where
      hyper (Method x1 x2 x3 x4 x5 x6 x7) y = hyper7 x1 x2 x3 x4 x5 x6 x7 y
      hyper (Clock x) y = hyper x y
      hyper (Reset x) y = hyper x y
      hyper (Inout x1 x2 x3 x4) y = hyper4 x1 x2 x3 x4 y
  
  instance PPrint VFieldInfo where
      pPrint d p (Method n c r m i o e) =
        text "method " <> pout o <> pPrint d p n <> pmult m <>
        pins i <> pena e <+> ppMClk d c <+> ppMRst d r <>
        text ";"
          where pout Nothing = empty
                pout (Just po) = pPrint d p po
                pmult 1 = empty
                pmult n = text "[" <> pPrint d p n <> text "]"
                pins [] = empty
                pins i  = text "(" <> sepList (map (pPrint d p) i) (text ",") <> text ")"
                pena Nothing = empty
                pena (Just en) = text " enable (" <> pPrint d p en <> text ")"
      pPrint d p (Clock i) = text "clock " <> pPrint d p i <> text ";"
      pPrint d p (Reset i) = text "reset " <> pPrint d p i <> text ";"
      pPrint d p (Inout n port c r) =
          text "inout " <> pPrint d p n <+>
          text "(" <> pPrint d p port <> text ")" <+>
          ppMClk d c <+> ppMRst d r <> text ";"
  
  
  -- ===============
  -- VClockInfo
  
  -- 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 (Show, Ord, Eq, Generic.Data, Generic.Typeable)
  
  -- Gets information needed to construct the signals from an output clock clock.
  -- If there is no gate port or if the port is outhigh, Nothing is returned.
  -- Otherwise, Just the port name is returned.
  lookupOutputClockWires :: Id -> VModInfo -> (VName, Maybe VName)
  lookupOutputClockWires i vmi =
      case (lookupOutputClock i vmi) of
          -- no gating signal
          (osc_vn, Nothing) -> (osc_vn, Nothing)
          -- outhigh gate port
          (osc_vn, Just (_, pprops))
              | (VPouthigh `elem` pprops) -> (osc_vn, Nothing)
          -- gate port
          (osc_vn, Just (gate_vname,_)) -> (osc_vn, Just gate_vname)
  
  -- Like lookupOutputClockVNames, except that outhigh ports are included
  lookupOutputClockPorts :: Id -> VModInfo -> (VName, Maybe VPort)
  lookupOutputClockPorts i vmi =
      case (lookupOutputClock i vmi) of
          -- no gating signal
          (osc_vn, Nothing) -> (osc_vn, Nothing)
          -- gate port
          (osc_vn, Just gate_vp) -> (osc_vn, Just gate_vp)
  
  lookupOutputClock :: Id -> VModInfo -> (VOscPort, VOutputGatePort)
  lookupOutputClock i vmi =
      case (lookup i (output_clocks (vClk vmi))) of
          Nothing ->
              internalError ("lookupOutputClock unknown clock " ++
                             ppReadable i ++ ppReadable (vClk vmi))
          Just Nothing ->
              internalError ("lookupOutputClock unconnected output clock" ++
                             ppReadable i ++ ppReadable (vClk vmi))
          Just (Just ci) -> ci
  
  -- returns nothing if there are no wires to hook up
  lookupInputClockWires :: Id -> VModInfo -> Maybe (VName, Maybe VName)
  lookupInputClockWires i vmi =
      case (lookupInputClock i vmi) of
          -- no gating signal
          Just (osc_vn, Left _) -> Just (osc_vn, Nothing)
          -- gate port
          Just (osc_vn, Right gate_vname) -> Just (osc_vn, Just gate_vname)
          Nothing -> Nothing
  
  -- returns nothing if the input clock is unconnected
  lookupInputClock :: Id -> VModInfo -> Maybe (VOscPort, VInputGatePort)
  lookupInputClock i vmi =
      case (lookup i (input_clocks (vClk vmi))) of
          Nothing ->
              internalError ("lookupInputClock unknown clock " ++
                             ppReadable i ++ ppReadable (vClk vmi))
          Just mci -> mci
  
  -- Used in AState to create defs for output clock ports
  -- So this includes gate ports which are "outhigh", since they have to be
  -- generated.
  getOutputClockPortTable :: VClockInfo ->
                             M.Map Id (VOscPort, VOutputGatePort)
  getOutputClockPortTable ClockInfo { output_clocks = ci } =
      M.fromList [(i, ports) | (i, Just ports) <- ci ]
  
  -- Used in APaths, to sanity check that the port names in AAbstractInfo
  -- match the port names declared for input clocks in VClockInfo
  getInputClockPorts :: VClockInfo -> [VName]
  getInputClockPorts (ClockInfo { input_clocks = clocks }) =
      osc_vnames ++ gate_vnames
    where connected_clocks = catMaybes (map snd clocks)
          osc_vnames = map fst connected_clocks
          gate_vnames = snd $ separate (map snd connected_clocks)
  
  instance Hyper VClockInfo where
      hyper (ClockInfo x1 x2 x3 x4) y = hyper4 x1 x2 x3 x4 y
  
  instance HasPosition VClockInfo where
    getPosition (ClockInfo { output_clocks = ((id,_):_)}) = getPosition id
    getPosition (ClockInfo { input_clocks = ((id,_):_)}) = getPosition id
    getPosition _ = noPosition
  
  instance PPrint VClockInfo where
      pPrint 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 " <> pPrint d 0 i <>
                                  text "(" <> pOutMClk mc <> text ");"
                pOutMClk Nothing = empty
                pOutMClk (Just (vn, mg)) = pPrint d 0 vn <> pOutMGate mg
                pOutMGate Nothing = empty
                pOutMGate (Just (vn, vpps)) =
                    text ", " <> pPortProps vpps <> pPrint d 0 vn
                pPortProps [] = empty
                pPortProps (vp:vpps) =
                    text "{-" <> pPrint d 0 vp <> text "-} " <> pPortProps vpps
  
                pInCInf (i,mc) = text "clock " <> pPrint d 0 i <>
                                 text "(" <> pInMClk mc <> text ");"
                pInMClk Nothing = empty
                pInMClk (Just (vn, mg)) = pPrint d 0 vn <> pInMGate mg
                pInMGate (Left True)  = text ", {-inhigh-}"
                pInMGate (Left False) = text ", {-unused-}"
                pInMGate (Right vn)   = text ", " <> pPrint d 0 vn
  
                pAnc (i,j) = text "ancestor (" <> pPrint d 0 i <> text ", " <>
                             pPrint d 0 j <> text ");"
                pSib (i,j) = text "sibling (" <> pPrint d 0 i <> text ", " <>
                             pPrint d 0 j <> text ");"
  
  
  -- ===============
  -- VResetInfo
  
  -- 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(Show, Ord, Eq, Generic.Data, Generic.Typeable)
  
  -- Gets info needed to construct the signals from an output reset.
  -- (Currently the same as getting the port name.)
  lookupOutputResetWire :: Id -> VModInfo -> VName
  lookupOutputResetWire = lookupOutputResetPort
  
  lookupOutputResetPort :: Id -> VModInfo -> VName
  lookupOutputResetPort = lookupOutputReset -- no interpretation needed
  
  lookupOutputReset :: Id -> VModInfo -> VName
  lookupOutputReset i vmi =
      case (lookup i (output_resets (vRst vmi))) of
          Nothing ->
              internalError ("lookupOutputReset unknown reset " ++
                             ppReadable i ++ ppReadable (vRst vmi))
          Just (Nothing, _) ->
              internalError ("lookupOutputReset unconnected output reset" ++
                             ppReadable i ++ ppReadable (vRst vmi))
          Just (Just ri, _) -> ri
  
  -- returns nothing if there is no wire to hook up
  lookupInputResetWire :: Id -> VModInfo -> Maybe VName
  lookupInputResetWire = lookupInputReset -- no interpretation needed
  
  -- returns nothing if the input reset is unconnected
  lookupInputReset :: Id -> VModInfo -> Maybe VName
  lookupInputReset i vmi =
      case (lookup i (input_resets (vRst vmi))) of
          Nothing ->
              internalError ("lookupInputReset unknown reset " ++
                             ppReadable i ++ ppReadable (vRst vmi))
          Just (mri, _) -> mri
  
  -- Used in AState to create defs for output reset ports
  getOutputResetPortTable :: VResetInfo -> M.Map Id VName
  getOutputResetPortTable ResetInfo { output_resets = out_rinfos } =
      M.fromList [(i, vn) | (i, (Just vn, _)) <- out_rinfos]
  
  instance PPrint VResetInfo where
      pPrint d p (ResetInfo in_rs out_rs) = vcat (map pRInf (out_rs ++ in_rs))
        where t = text
              pRInf (i,(mn,mc)) =
                  t"reset " <> pPrint d p i <>
                  t"(" <> pMRst mn <> t")" <+>
                  t"clocked_by(" <> pMClk mc <> t");"
              pMRst Nothing  = empty
              pMRst (Just n) = pPrint d p n
              pMClk Nothing  = t"no_clock"
              pMClk (Just c) = pPrint d p c
  
  -- Used in APaths, to sanity check that the port names in AAbstractInfo
  -- match the port names declared for input resets in VResetInfo
  getInputResetPorts :: VResetInfo -> [VName]
  getInputResetPorts (ResetInfo { input_resets = in_resets }) =
      catMaybes (map (fst . snd) in_resets)
  
  instance Hyper VResetInfo where
    hyper (ResetInfo x1 x2) y = hyper2 x1 x2 y
  
  -- ===============
  -- Inout
  
  -- There is no VInoutInfo, but AConv needs to be able to lookup a port name
  -- the same as it does for clocks and reset.
  
  lookupIfcInoutWire :: Id -> VModInfo -> VName
  lookupIfcInoutWire i vmi =
      let fis = vFields vmi
          vports = [ p | f@(Inout { vf_inout = p }) <- fis,
                         (vf_name f == unQualId i) ]
      in  case vports of
              [p] -> p
              _ -> internalError ("lookupIfcInoutWire: " ++
                                  ppReadable (i,vports))
  
  -- ===============
  -- VModInfo
  
  data VModInfo = VModInfo {
          -- name of Verilog module to use
          vName  :: VName,
          vClk   :: VClockInfo,
          vRst   :: VResetInfo,
          vArgs  :: [VArgInfo],
          vFields :: [VFieldInfo],
          vSched :: VSchedInfo,
          vPath  :: VPathInfo
          }
          deriving (Show, Ord, Eq, Generic.Data, Generic.Typeable)
  
  mkVModInfo :: VName -> VClockInfo -> VResetInfo ->
                [VArgInfo] -> [VFieldInfo] ->
                VSchedInfo -> VPathInfo -> VModInfo
  mkVModInfo vName vClk vRst
             vArgs vFields
             vSched vPath | check = vm
                          | otherwise = internalError ("VModInfo: " ++ ppReadable vm ++
                                                       ppReadable sched_pairs ++
                                                       ppReadable meth_pairs)
  
   where vm = VModInfo vName vClk vRst vArgs vFields vSched vPath
         -- ----------
         -- check the method conflict info for consistency and completeness
         -- XXX check the rest of the SchedInfo fields?
  
         vMethConf = methodConflictInfo vSched
  
         check = -- every pair is accounted for
                 S.fromList sched_pairs == S.fromList meth_pairs &&
                 -- no pair has more than one annotation
                 length sched_pairs == length meth_pairs
         -- remove duplicates within a commutative annotation set
         -- e.g. (a, b) CF (a, b) ==> (a, a) (a, b) (b, b)
         -- NOT  (a, b) CF (a, b) ==> (a, a) (a, b) (b, a) (a, b)
         cleanup = fastNub . (map ordPair)
         sched_pairs = map ordPair $
                       (cleanup (sCF vMethConf)) ++ sSB vMethConf ++
                       (cleanup (sP  vMethConf)) ++ sSBR vMethConf ++
                       (cleanup (sC  vMethConf)) ++ me_pairs ++ ext_pairs
         ext_pairs  = selfPairs (sEXT vMethConf)
         -- might have duplicates if a method is annotated ME with itself
         me_pairs   = nub $ concatMap allPairs (sME vMethConf)
         meth_pairs = map ordPair $ uniquePairs meths ++ selfPairs meths
         meths      = [ n | Method { vf_name = n } <- vFields ]
  
  {-
  -- This is presumably for debugging output?
  pePrint d p v = text $ concat [
              "VModInfo {vName = ", show (vName v),
              ", vClk = ", show (vClk v),
              ", vRst = ", show (vRst v),
              ", vArgs = ", show (vArgs v),
              ", vFields = ", show (vFields v),
              ", vSched = VSchedInfo {sCF = ", sit re_id2 (sCF . vSched),
                  ", sSB = ", sit re_id2 (sSB . vSched),
              ", vPath = ", show (vPath v),
              "}}" ]
      where
          sit a b = "[" ++ intercalate "," (map a (b v)) ++ "]"
  { -
          re_id (a, b, c) =
                  "(" ++ getIdString a
                  ++ "," ++ show b
                  ++ "," ++ show c
                  ++ ")"
  - }
          re_id2 (a, b) = "(" ++ getIdString a ++ "," ++ getIdString b ++ ")"
  -}
  
  instance PPrint VModInfo where
      pPrint d p v = pparen True
          (sep
              [text "VModInfo",
              pPrint d 10 (vName v),
              pPrint d 10 (vClk v),
              pPrint d 10 (vRst v),
              pPrint d 10 (vArgs v),
              pPrint d 10 (vFields v),
              pPrint d 10 (vSched v),
              pShowVPathInfo d 10 (vPath v)])
  
  instance Hyper VModInfo where
      hyper x@(VModInfo x1 x2 x3 x4 x5 x6 x7) y = hyper7 x1 x2 x3 x4 x5 x6 x7 y
  
  
  -- ===============
  -- VWireInfo
  
  -- data that needs to be piped from the evaluator to wrapper generation
  data VWireInfo = WireInfo {
                    wClk  :: VClockInfo,
                    wRst  :: VResetInfo,
                    wArgs :: [VArgInfo]
                   } deriving (Eq, Show, Generic.Data, Generic.Typeable)
  
  
  instance Hyper VWireInfo where
    hyper (WireInfo clk rst args) y = hyper3 clk rst args y
  
  instance PPrint VWireInfo where
    pPrint d p (WireInfo clk rst args) =
      text "clock info " <+> pPrint d p clk $+$
      text "reset info " <+> pPrint d p rst $+$
      text "arg info "   <+> pPrint d p args
  
  
  -- #############################################################################
  -- #
  -- #############################################################################
  
  getIfcIdPosition :: VModInfo -> Position
  getIfcIdPosition (VModInfo _ clk _ _ [] _ _) = getPosition clk
  getIfcIdPosition (VModInfo mod_name clk reset args fields schedule path)
                                               = getPosition fields
  
  -- #############################################################################
  -- #
  -- #############################################################################
  
  -- The name is changed to keep the position information from the base id.
  mkNamedEnable :: VFieldInfo -> Id
  mkNamedEnable vfi = if (newStr == "") then baseid else setIdBaseString baseid newStr
      where  baseid = mkEnableId (vf_name vfi)
             newStr = maybe ""  getVPortString (vf_enable vfi)
  
  mkNamedOutput :: VFieldInfo -> Id
  mkNamedOutput vfi = if (newStr == "") then baseid else setIdBaseString baseid newStr
      where  baseid = (vf_name vfi)
             newStr = maybe ""  getVPortString (vf_output vfi)
  
  -- VFieldInfo does not have a ready field, so we just use the default construction for the ready signal.
  -- in aState we merge method and RDY_method to do the right thing.
  mkNamedReady :: VFieldInfo -> Id
  mkNamedReady vfi = baseid -- if (newStr == "") then baseid else setIdBaseString baseid newStr
      where  baseid = mkRdyId (vf_name vfi)
             -- newStr = maybe ""  getVPortString (vf_output vfi)
  
  mkNamedInout :: VFieldInfo -> Id
  mkNamedInout vfi = setIdBaseString baseid newStr
      where  baseid = (vf_name vfi)
             newStr = getVNameString (vf_inout vfi)
  
  ---------------------------   Name extraction from VFieldInfo
  -- extract possible port Ids from a VField Info
  -- return value  is result, ready, enable
  extractNames :: VFieldInfo -> (Id, Id, Id )
  extractNames vfi = (result, ready, enable)
      where result = mkNamedOutput vfi
            ready  = mkNamedReady vfi
            enable = mkNamedEnable vfi
  