    {-|
      Copyright   :  (C) 2019, Google Inc.,
                         2022, QBayLogic B.V.
      License     :  BSD2 (see the file LICENSE)
      Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com>

      I\/O actions that are translatable to HDL
    -}

    {-# LANGUAGE CPP #-}
    {-# LANGUAGE BangPatterns, MagicHash, TypeOperators, ScopedTypeVariables, FlexibleContexts #-}
    {-# LANGUAGE DataKinds, GADTs, TypeApplications #-}

    module Clash.Explicit.SimIO
      ( -- * I\/O environment for simulation
        mealyIO
      , SimIO
      -- * Display on stdout
      , display
      -- * End of simulation
      , finish
      -- * Mutable values
      , Reg
      , reg
      , readReg
      , writeReg
      -- * File I\/O
      , File
      , openFile
      , closeFile
      -- ** Reading and writing characters
      , getChar
      , putChar
      -- ** Reading strings
      , getLine
      -- ** Detecting the end of input
      , isEOF
        -- ** Buffering operations
      , flush
        -- ** Repositioning handles
      , seek
      , rewind
      , tell
      )
    where

    import Control.Monad (when)
    #if __GLASGOW_HASKELL__ < 900
    import Data.Coerce
    #endif
    import Data.IORef
    import GHC.TypeLits
    #if MIN_VERSION_base(4,18,0)
      hiding (SNat)
    #endif
    import Prelude hiding (getChar, putChar, getLine)
    import qualified System.IO as IO
    import System.IO.Unsafe

    import Clash.Annotations.Primitive (hasBlackBox)
    import Clash.Promoted.Nat
    import Clash.Signal.Internal
    import Clash.Sized.Unsigned
    import Clash.Sized.Vector (Vec (..))
    import Clash.XException (seqX)

    -- | Simulation-level I\/O environment; synthesizable to HDL I\/O, which in
    -- itself is unlikely to be synthesisable to a digital circuit.
    --
    -- See 'mealyIO' as to its use.
    #if __GLASGOW_HASKELL__ >= 900
    data SimIO a = SimIO {forall a. SimIO a -> IO a
    unSimIO :: !(IO a)}
    #else
    newtype SimIO a = SimIO {unSimIO :: IO a}
    #endif
    {-# ANN unSimIO hasBlackBox #-}

    instance Functor SimIO where
      fmap :: forall a b. (a -> b) -> SimIO a -> SimIO b
    fmap = (a -> b) -> SimIO a -> SimIO b
    forall a b. (a -> b) -> SimIO a -> SimIO b
    fmapSimIO#

    fmapSimIO# :: (a -> b) -> SimIO a -> SimIO b
    fmapSimIO# :: forall a b. (a -> b) -> SimIO a -> SimIO b
    fmapSimIO# a -> b
    f (SimIO IO a
    m) = IO b -> SimIO b
    forall a. IO a -> SimIO a
    SimIO ((a -> b) -> IO a -> IO b
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap a -> b
    f IO a
    m)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE fmapSimIO# #-}
    {-# ANN fmapSimIO# hasBlackBox #-}

    instance Applicative SimIO where
      pure :: forall a. a -> SimIO a
    pure  = a -> SimIO a
    forall a. a -> SimIO a
    pureSimIO#
      <*> :: forall a b. SimIO (a -> b) -> SimIO a -> SimIO b
    (<*>) = SimIO (a -> b) -> SimIO a -> SimIO b
    forall a b. SimIO (a -> b) -> SimIO a -> SimIO b
    apSimIO#

    pureSimIO# :: a -> SimIO a
    pureSimIO# :: forall a. a -> SimIO a
    pureSimIO# a
    a = IO a -> SimIO a
    forall a. IO a -> SimIO a
    SimIO (a -> IO a
    forall a. a -> IO a
    forall (f :: Type -> Type) a. Applicative f => a -> f a
    pure a
    a)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE pureSimIO# #-}
    {-# ANN pureSimIO# hasBlackBox #-}

    apSimIO# :: SimIO (a -> b) -> SimIO a -> SimIO b
    apSimIO# :: forall a b. SimIO (a -> b) -> SimIO a -> SimIO b
    apSimIO# (SimIO IO (a -> b)
    f) (SimIO IO a
    m) = IO b -> SimIO b
    forall a. IO a -> SimIO a
    SimIO (IO (a -> b)
    f IO (a -> b) -> IO a -> IO b
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> IO a
    m)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE apSimIO# #-}
    {-# ANN apSimIO# hasBlackBox #-}

    instance Monad SimIO where
    #if !MIN_VERSION_base(4,16,0)
      return = pureSimIO#
    #endif
      >>= :: forall a b. SimIO a -> (a -> SimIO b) -> SimIO b
    (>>=)  = SimIO a -> (a -> SimIO b) -> SimIO b
    forall a b. SimIO a -> (a -> SimIO b) -> SimIO b
    bindSimIO#

    bindSimIO# :: SimIO a -> (a -> SimIO b) -> SimIO b
    #if __GLASGOW_HASKELL__ >= 900
    bindSimIO# :: forall a b. SimIO a -> (a -> SimIO b) -> SimIO b
    bindSimIO# (SimIO IO a
    m) a -> SimIO b
    k = IO b -> SimIO b
    forall a. IO a -> SimIO a
    SimIO (IO a
    m IO a -> (a -> IO b) -> IO b
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
    >>= (\a
    x -> a
    x a -> IO b -> IO b
    forall a b. a -> b -> b
    `seqX` SimIO b -> IO b
    forall a. SimIO a -> IO a
    unSimIO (a -> SimIO b
    k a
    x)))
    #else
    bindSimIO# (SimIO m) k = SimIO (m >>= (\x -> x `seqX` coerce k x))
    #endif
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE bindSimIO# #-}
    {-# ANN bindSimIO# hasBlackBox #-}

    -- | Display a string on /stdout/
    display
      :: String
      -- ^ String you want to display
      -> SimIO ()
    display :: String -> SimIO ()
    display String
    s = IO () -> SimIO ()
    forall a. IO a -> SimIO a
    SimIO (String -> IO ()
    putStrLn String
    s)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE display #-}
    {-# ANN display hasBlackBox #-}

    -- | Finish the simulation with an exit code
    finish
      :: Integer
      -- ^ The exit code you want to return at the end of the simulation
      -> SimIO a
    finish :: forall a. Integer -> SimIO a
    finish Integer
    i = a -> SimIO a
    forall a. a -> SimIO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (String -> a
    forall a. HasCallStack => String -> a
    error (Integer -> String
    forall a. Show a => a -> String
    show Integer
    i))
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE finish #-}
    {-# ANN finish hasBlackBox #-}

    -- | Mutable reference
    #if __GLASGOW_HASKELL__ >= 900
    data Reg a = Reg !(IORef a)
    #else
    newtype Reg a = Reg (IORef a)
    #endif

    -- | Create a new mutable reference with the given starting value
    reg
      :: a
      -- ^ The starting value
      -> SimIO (Reg a)
    reg :: forall a. a -> SimIO (Reg a)
    reg a
    a = IO (Reg a) -> SimIO (Reg a)
    forall a. IO a -> SimIO a
    SimIO (IORef a -> Reg a
    forall a. IORef a -> Reg a
    Reg (IORef a -> Reg a) -> IO (IORef a) -> IO (Reg a)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> a -> IO (IORef a)
    forall a. a -> IO (IORef a)
    newIORef a
    a)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE reg #-}
    {-# ANN reg hasBlackBox #-}

    -- | Read value from a mutable reference
    readReg :: Reg a -> SimIO a
    readReg :: forall a. Reg a -> SimIO a
    readReg (Reg IORef a
    a) = IO a -> SimIO a
    forall a. IO a -> SimIO a
    SimIO (IORef a -> IO a
    forall a. IORef a -> IO a
    readIORef IORef a
    a)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE readReg #-}
    {-# ANN readReg hasBlackBox #-}

    -- | Write new value to the mutable reference
    writeReg
      :: Reg a
      -- ^ The mutable reference
      -> a
      -- ^ The new value
      -> SimIO ()
    writeReg :: forall a. Reg a -> a -> SimIO ()
    writeReg (Reg IORef a
    r) a
    a = IO () -> SimIO ()
    forall a. IO a -> SimIO a
    SimIO (IORef a -> a -> IO ()
    forall a. IORef a -> a -> IO ()
    writeIORef IORef a
    r a
    a)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE writeReg #-}
    {-# ANN writeReg hasBlackBox #-}

    -- | File handle
    #if __GLASGOW_HASKELL__ >= 900
    data File = File !IO.Handle
    #else
    newtype File = File IO.Handle
    #endif

    -- | Open a file
    openFile
      :: FilePath
      -- ^ File to open
      -> String
      -- ^ File mode:
      --
      -- * "r": Open for reading
      -- * "w": Create for writing
      -- * "a": Append
      -- * "r+": Open for update (reading and writing)
      -- * "w+": Create for update
      -- * "a+": Append, open or create for update at end-of-file
      -> SimIO File
    #if __GLASGOW_HASKELL__ >= 900
    openFile :: String -> String -> SimIO File
    openFile String
    fp String
    "r"   = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openFile String
    fp IOMode
    IO.ReadMode)
    openFile String
    fp String
    "w"   = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openFile String
    fp IOMode
    IO.WriteMode)
    openFile String
    fp String
    "a"   = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openFile String
    fp IOMode
    IO.AppendMode)
    openFile String
    fp String
    "rb"  = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openBinaryFile String
    fp IOMode
    IO.ReadMode)
    openFile String
    fp String
    "wb"  = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openBinaryFile String
    fp IOMode
    IO.WriteMode)
    openFile String
    fp String
    "ab"  = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openBinaryFile String
    fp IOMode
    IO.AppendMode)
    openFile String
    fp String
    "r+"  = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openFile String
    fp IOMode
    IO.ReadWriteMode)
    openFile String
    fp String
    "w+"  = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openFile String
    fp IOMode
    IO.WriteMode)
    openFile String
    fp String
    "a+"  = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openFile String
    fp IOMode
    IO.AppendMode)
    openFile String
    fp String
    "r+b" = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openBinaryFile String
    fp IOMode
    IO.ReadWriteMode)
    openFile String
    fp String
    "w+b" = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openBinaryFile String
    fp IOMode
    IO.WriteMode)
    openFile String
    fp String
    "a+b" = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openBinaryFile String
    fp IOMode
    IO.AppendMode)
    openFile String
    fp String
    "rb+" = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openBinaryFile String
    fp IOMode
    IO.ReadWriteMode)
    openFile String
    fp String
    "wb+" = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openBinaryFile String
    fp IOMode
    IO.WriteMode)
    openFile String
    fp String
    "ab+" = IO File -> SimIO File
    forall a. IO a -> SimIO a
    SimIO (IO File -> SimIO File) -> IO File -> SimIO File
    forall a b. (a -> b) -> a -> b
    $ (Handle -> File) -> IO Handle -> IO File
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Handle -> File
    File (String -> IOMode -> IO Handle
    IO.openBinaryFile String
    fp IOMode
    IO.AppendMode)
    #else
    openFile fp "r"   = coerce (IO.openFile fp IO.ReadMode)
    openFile fp "w"   = coerce (IO.openFile fp IO.WriteMode)
    openFile fp "a"   = coerce (IO.openFile fp IO.AppendMode)
    openFile fp "rb"  = coerce (IO.openBinaryFile fp IO.ReadMode)
    openFile fp "wb"  = coerce (IO.openBinaryFile fp IO.WriteMode)
    openFile fp "ab"  = coerce (IO.openBinaryFile fp IO.AppendMode)
    openFile fp "r+"  = coerce (IO.openFile fp IO.ReadWriteMode)
    openFile fp "w+"  = coerce (IO.openFile fp IO.WriteMode)
    openFile fp "a+"  = coerce (IO.openFile fp IO.AppendMode)
    openFile fp "r+b" = coerce (IO.openBinaryFile fp IO.ReadWriteMode)
    openFile fp "w+b" = coerce (IO.openBinaryFile fp IO.WriteMode)
    openFile fp "a+b" = coerce (IO.openBinaryFile fp IO.AppendMode)
    openFile fp "rb+" = coerce (IO.openBinaryFile fp IO.ReadWriteMode)
    openFile fp "wb+" = coerce (IO.openBinaryFile fp IO.WriteMode)
    openFile fp "ab+" = coerce (IO.openBinaryFile fp IO.AppendMode)
    #endif
    openFile String
    _  String
    m     = String -> SimIO File
    forall a. HasCallStack => String -> a
    error (String
    "openFile unknown mode: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> String
    forall a. Show a => a -> String
    show String
    m)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE openFile #-}
    {-# ANN openFile hasBlackBox #-}

    -- | Close a file
    closeFile
      :: File
      -> SimIO ()
    closeFile :: File -> SimIO ()
    closeFile (File Handle
    fp) = IO () -> SimIO ()
    forall a. IO a -> SimIO a
    SimIO (Handle -> IO ()
    IO.hClose Handle
    fp)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE closeFile #-}
    {-# ANN closeFile hasBlackBox #-}

    -- | Read one character from a file
    getChar
      :: File
      -- ^ File to read from
      -> SimIO Char
    getChar :: File -> SimIO Char
    getChar (File Handle
    fp) = IO Char -> SimIO Char
    forall a. IO a -> SimIO a
    SimIO (Handle -> IO Char
    IO.hGetChar Handle
    fp)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE getChar #-}
    {-# ANN getChar hasBlackBox #-}

    -- | Insert a character into a buffer specified by the file
    putChar
      :: Char
      -- ^ Character to insert
      -> File
      -- ^ Buffer to insert to
      -> SimIO ()
    putChar :: Char -> File -> SimIO ()
    putChar Char
    c (File Handle
    fp) = IO () -> SimIO ()
    forall a. IO a -> SimIO a
    SimIO (Handle -> Char -> IO ()
    IO.hPutChar Handle
    fp Char
    c)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE putChar #-}
    {-# ANN putChar hasBlackBox #-}

    -- | Read one line from a file
    getLine
      :: forall n
       . KnownNat n
      => File
      -- ^ File to read from
      -> Reg (Vec n (Unsigned 8))
      -- ^ Vector to store the content
      -> SimIO Int
    getLine :: forall (n :: Nat).
    KnownNat n =>
    File -> Reg (Vec n (Unsigned 8)) -> SimIO Int
    getLine (File Handle
    fp) (Reg IORef (Vec n (Unsigned 8))
    r) = IO Int -> SimIO Int
    forall a. IO a -> SimIO a
    SimIO (IO Int -> SimIO Int) -> IO Int -> SimIO Int
    forall a b. (a -> b) -> a -> b
    $ do
      s <- Handle -> IO String
    IO.hGetLine Handle
    fp
      let d = SNat n -> Int
    forall a (n :: Nat). Num a => SNat n -> a
    snatToNum (forall (n :: Nat). KnownNat n => SNat n
    SNat @n) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - String -> Int
    forall a. [a] -> Int
    forall (t :: Type -> Type) a. Foldable t => t a -> Int
    length String
    s
      when (d < 0) (IO.hSeek fp IO.RelativeSeek (toInteger d))
      modifyIORef r (rep s)
      return 0
     where
       rep :: String -> Vec m (Unsigned 8) -> Vec m (Unsigned 8)
       rep :: forall (m :: Nat).
    String -> Vec m (Unsigned 8) -> Vec m (Unsigned 8)
    rep []     Vec m (Unsigned 8)
    vs          = Vec m (Unsigned 8)
    vs
       rep (Char
    x:String
    xs) (Cons Unsigned 8
    _ Vec n (Unsigned 8)
    vs) = Unsigned 8 -> Vec n (Unsigned 8) -> Vec (n + 1) (Unsigned 8)
    forall b (n :: Nat). b -> Vec n b -> Vec (n + 1) b
    Cons (Int -> Unsigned 8
    forall a. Enum a => Int -> a
    toEnum (Char -> Int
    forall a. Enum a => a -> Int
    fromEnum Char
    x)) (String -> Vec n (Unsigned 8) -> Vec n (Unsigned 8)
    forall (m :: Nat).
    String -> Vec m (Unsigned 8) -> Vec m (Unsigned 8)
    rep String
    xs Vec n (Unsigned 8)
    vs)
       rep String
    _      Vec m (Unsigned 8)
    Nil         = Vec m (Unsigned 8)
    Vec 0 (Unsigned 8)
    forall b. Vec 0 b
    Nil
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE getLine #-}
    {-# ANN getLine hasBlackBox #-}

    -- | Determine whether we've reached the end of the file
    isEOF
      :: File
      -- ^ File we want to inspect
      -> SimIO Bool
    isEOF :: File -> SimIO Bool
    isEOF (File Handle
    fp) = IO Bool -> SimIO Bool
    forall a. IO a -> SimIO a
    SimIO (Handle -> IO Bool
    IO.hIsEOF Handle
    fp)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE isEOF #-}
    {-# ANN isEOF hasBlackBox #-}

    -- | Set the position of the next operation on the file
    seek
      :: File
      -- ^ File to set the position for
      -> Integer
      -- ^ Position
      -> Int
      -- ^ Mode:
      --
      -- * 0: From the beginning of the file
      -- * 1: From the current position
      -- * 2: From the end of the file
      -> SimIO Int
    seek :: File -> Integer -> Int -> SimIO Int
    seek (File Handle
    fp) Integer
    pos Int
    mode = IO Int -> SimIO Int
    forall a. IO a -> SimIO a
    SimIO (Handle -> SeekMode -> Integer -> IO ()
    IO.hSeek Handle
    fp (Int -> SeekMode
    forall a. Enum a => Int -> a
    toEnum Int
    mode) Integer
    pos IO () -> IO Int -> IO Int
    forall a b. IO a -> IO b -> IO b
    forall (m :: Type -> Type) a b. Monad m => m a -> m b -> m b
    >> Int -> IO Int
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return Int
    0)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE seek #-}
    {-# ANN seek hasBlackBox #-}

    -- | Set the position of the next operation to the beginning of the file
    rewind
      :: File
      -> SimIO Int
    rewind :: File -> SimIO Int
    rewind (File Handle
    fp) = IO Int -> SimIO Int
    forall a. IO a -> SimIO a
    SimIO (Handle -> SeekMode -> Integer -> IO ()
    IO.hSeek Handle
    fp SeekMode
    IO.AbsoluteSeek Integer
    0 IO () -> IO Int -> IO Int
    forall a b. IO a -> IO b -> IO b
    forall (m :: Type -> Type) a b. Monad m => m a -> m b -> m b
    >> Int -> IO Int
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return Int
    0)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE rewind #-}
    {-# ANN rewind hasBlackBox #-}

    -- | Returns the offset from the beginning of the file (in bytes).
    tell
      :: File
      -- ^ File we want to inspect
      -> SimIO Integer
    tell :: File -> SimIO Integer
    tell (File Handle
    fp) = IO Integer -> SimIO Integer
    forall a. IO a -> SimIO a
    SimIO (Handle -> IO Integer
    IO.hTell Handle
    fp)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE tell #-}
    {-# ANN tell hasBlackBox #-}

    -- | Write any buffered output to file
    flush
      :: File
      -> SimIO ()
    flush :: File -> SimIO ()
    flush (File Handle
    fp) = IO () -> SimIO ()
    forall a. IO a -> SimIO a
    SimIO (Handle -> IO ()
    IO.hFlush Handle
    fp)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE flush #-}
    {-# ANN flush hasBlackBox #-}

    -- | Simulation-level I/O environment that can be synthesized to HDL-level I\/O.
    -- Note that it is unlikely that the HDL-level I\/O can subsequently be
    -- synthesized to a circuit.
    --
    -- = Example
    --
    -- @
    -- tbMachine :: (File,File) -> Int -> SimIO Int
    -- tbMachine (fileIn,fileOut) regOut = do
    --   eofFileOut <- 'isEOF' fileOut
    --   eofFileIn  <- 'isEOF' fileIn
    --   when (eofFileIn || eofFileOut) $ do
    --     'display' "success"
    --     'finish' 0
    --
    --   goldenIn  <- 'getChar' fileIn
    --   goldenOut <- 'getChar' fileOut
    --   res <- if regOut == fromEnum goldenOut then do
    --            return (fromEnum goldenIn)
    --          else do
    --            'display' "Output doesn't match golden output"
    --            'finish' 1
    --   display ("Output matches golden output")
    --   return res
    --
    -- tbInit :: (File,File)
    -- tbInit = do
    --   fileIn  <- 'openFile' "./goldenInput00.txt" "r"
    --   fileOut <- 'openFile' "./goldenOutput00.txt" "r"
    --   return (fileIn,fileOut)
    --
    -- topEntity :: Signal System Int
    -- topEntity = regOut
    --   where
    --     clk = systemClockGen
    --     rst = resetGen
    --     ena = enableGen
    --
    --     regOut = register clk rst ena (fromEnum \'a\') regIn
    --     regIn  = 'mealyIO' clk tbMachine tbInit regOut
    -- @
    mealyIO
      :: KnownDomain dom
      => Clock dom
      -- ^ Clock at which rate the I\/O environment progresses
      -> (s -> i -> SimIO o)
      -- ^ Transition function inside an I\/O environment
      -> SimIO s
      -- ^ I/O action to create the initial state
      -> Signal dom i
      -> Signal dom o
    mealyIO :: forall (dom :: Domain) s i o.
    KnownDomain dom =>
    Clock dom
    -> (s -> i -> SimIO o) -> SimIO s -> Signal dom i -> Signal dom o
    mealyIO !Clock dom
    _ s -> i -> SimIO o
    f (SimIO IO s
    i) Signal dom i
    inp = IO (Signal dom o) -> Signal dom o
    forall a. IO a -> a
    unsafePerformIO (IO s
    i IO s -> (s -> IO (Signal dom o)) -> IO (Signal dom o)
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Signal dom i -> s -> IO (Signal dom o)
    go Signal dom i
    inp)
     where
      go :: Signal dom i -> s -> IO (Signal dom o)
    go q :: Signal dom i
    q@(~(i
    k :- Signal dom i
    ks)) s
    s =
        o -> Signal dom o -> Signal dom o
    forall (dom :: Domain) a. a -> Signal dom a -> Signal dom a
    (:-) (o -> Signal dom o -> Signal dom o)
    -> IO o -> IO (Signal dom o -> Signal dom o)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> SimIO o -> IO o
    forall a. SimIO a -> IO a
    unSimIO (s -> i -> SimIO o
    f s
    s i
    k) IO (Signal dom o -> Signal dom o)
    -> IO (Signal dom o) -> IO (Signal dom o)
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> IO (Signal dom o) -> IO (Signal dom o)
    forall a. IO a -> IO a
    unsafeInterleaveIO ((Signal dom i
    q Signal dom i -> IO (Signal dom o) -> IO (Signal dom o)
    forall a b. a -> b -> b
    `seq` Signal dom i -> s -> IO (Signal dom o)
    go Signal dom i
    ks s
    s))
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE mealyIO #-}