{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}

{- |
Module      : NITTA.Model.ProcessorUnits.IO.SPI
Description :
Copyright   : (c) Aleksandr Penskoi, 2019
License     : BSD3
Maintainer  : aleksandr.penskoi@gmail.com
Stability   : experimental
-}
module NITTA.Model.ProcessorUnits.IO.SPI (
    SPI,
    anySPI,
    Ports (..),
    IOPorts (..),
    spiMasterPorts,
    spiSlavePorts,
) where

import Data.Aeson
import Data.Default
import Data.HashMap.Strict qualified as HM
import Data.Map.Strict qualified as M
import Data.Maybe (fromMaybe, mapMaybe)
import Data.Set qualified as S
import Data.String.Interpolate
import NITTA.Intermediate.Functions
import NITTA.Intermediate.Types
import NITTA.Model.Problems
import NITTA.Model.ProcessorUnits.IO.SimpleIO
import NITTA.Model.ProcessorUnits.Types
import NITTA.Model.Time
import NITTA.Project
import NITTA.Utils
import Prettyprinter

data SPIinterface

instance SimpleIOInterface SPIinterface

type SPI v x t = SimpleIO SPIinterface v x t

anySPI :: Time t => Int -> Maybe Int -> SPI v x t
anySPI :: forall t v x. Time t => Int -> Maybe Int -> SPI v x t
anySPI Int
bounceFilter Maybe Int
bufferSize =
    SimpleIO
        { Int
bounceFilter :: Int
bounceFilter :: Int
bounceFilter
        , Maybe Int
bufferSize :: Maybe Int
bufferSize :: Maybe Int
bufferSize
        , receiveQueue :: [Q v x]
receiveQueue = []
        , receiveN :: Int
receiveN = Int
0
        , isReceiveOver :: Bool
isReceiveOver = Bool
False
        , sendQueue :: [Q v x]
sendQueue = []
        , sendN :: Int
sendN = Int
0
        , process_ :: Process t (StepInfo v x t)
process_ = Process t (StepInfo v x t)
forall a. Default a => a
def
        }

instance IOConnected (SPI v x t) where
    data IOPorts (SPI v x t)
        = SPIMaster
            { forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_mosi :: OutputPortTag
            , forall v x t. IOPorts (SPI v x t) -> InputPortTag
master_miso :: InputPortTag
            , forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_sclk :: OutputPortTag
            , forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_cs :: OutputPortTag
            }
        | SPISlave
            { forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_mosi :: InputPortTag
            , forall v x t. IOPorts (SPI v x t) -> OutputPortTag
slave_miso :: OutputPortTag
            , forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_sclk :: InputPortTag
            , forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_cs :: InputPortTag
            }
        deriving (Int -> IOPorts (SPI v x t) -> ShowS
[IOPorts (SPI v x t)] -> ShowS
IOPorts (SPI v x t) -> String
(Int -> IOPorts (SPI v x t) -> ShowS)
-> (IOPorts (SPI v x t) -> String)
-> ([IOPorts (SPI v x t)] -> ShowS)
-> Show (IOPorts (SPI v x t))
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall v x t. Int -> IOPorts (SPI v x t) -> ShowS
forall v x t. [IOPorts (SPI v x t)] -> ShowS
forall v x t. IOPorts (SPI v x t) -> String
$cshowsPrec :: forall v x t. Int -> IOPorts (SPI v x t) -> ShowS
showsPrec :: Int -> IOPorts (SPI v x t) -> ShowS
$cshow :: forall v x t. IOPorts (SPI v x t) -> String
show :: IOPorts (SPI v x t) -> String
$cshowList :: forall v x t. [IOPorts (SPI v x t)] -> ShowS
showList :: [IOPorts (SPI v x t)] -> ShowS
Show)

    inputPorts :: IOPorts (SPI v x t) -> Set InputPortTag
inputPorts SPISlave{OutputPortTag
InputPortTag
slave_mosi :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_miso :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
slave_sclk :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_cs :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_mosi :: InputPortTag
slave_miso :: OutputPortTag
slave_sclk :: InputPortTag
slave_cs :: InputPortTag
..} = [InputPortTag] -> Set InputPortTag
forall a. Ord a => [a] -> Set a
S.fromList [InputPortTag
slave_mosi, InputPortTag
slave_sclk, InputPortTag
slave_cs]
    inputPorts SPIMaster{OutputPortTag
InputPortTag
master_mosi :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_miso :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
master_sclk :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_cs :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_mosi :: OutputPortTag
master_miso :: InputPortTag
master_sclk :: OutputPortTag
master_cs :: OutputPortTag
..} = [InputPortTag] -> Set InputPortTag
forall a. Ord a => [a] -> Set a
S.fromList [InputPortTag
master_miso]

    outputPorts :: IOPorts (SPI v x t) -> Set OutputPortTag
outputPorts SPISlave{OutputPortTag
InputPortTag
slave_mosi :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_miso :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
slave_sclk :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_cs :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_mosi :: InputPortTag
slave_miso :: OutputPortTag
slave_sclk :: InputPortTag
slave_cs :: InputPortTag
..} = [OutputPortTag] -> Set OutputPortTag
forall a. Ord a => [a] -> Set a
S.fromList [OutputPortTag
slave_miso]
    outputPorts SPIMaster{OutputPortTag
InputPortTag
master_mosi :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_miso :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
master_sclk :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_cs :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_mosi :: OutputPortTag
master_miso :: InputPortTag
master_sclk :: OutputPortTag
master_cs :: OutputPortTag
..} = [OutputPortTag] -> Set OutputPortTag
forall a. Ord a => [a] -> Set a
S.fromList [OutputPortTag
master_mosi, OutputPortTag
master_sclk, OutputPortTag
master_cs]

spiMasterPorts :: Text -> IOPorts (SPI v x t)
spiMasterPorts Text
tag =
    SPIMaster
        { master_mosi :: OutputPortTag
master_mosi = Text -> OutputPortTag
OutputPortTag (Text -> OutputPortTag) -> Text -> OutputPortTag
forall a b. (a -> b) -> a -> b
$ Text
tag Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_mosi"
        , master_miso :: InputPortTag
master_miso = Text -> InputPortTag
InputPortTag (Text -> InputPortTag) -> Text -> InputPortTag
forall a b. (a -> b) -> a -> b
$ Text
tag Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_miso"
        , master_sclk :: OutputPortTag
master_sclk = Text -> OutputPortTag
OutputPortTag (Text -> OutputPortTag) -> Text -> OutputPortTag
forall a b. (a -> b) -> a -> b
$ Text
tag Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_sclk"
        , master_cs :: OutputPortTag
master_cs = Text -> OutputPortTag
OutputPortTag (Text -> OutputPortTag) -> Text -> OutputPortTag
forall a b. (a -> b) -> a -> b
$ Text
tag Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_cs"
        }

spiSlavePorts :: Text -> IOPorts (SPI v x t)
spiSlavePorts Text
tag =
    SPISlave
        { slave_mosi :: InputPortTag
slave_mosi = Text -> InputPortTag
InputPortTag (Text -> InputPortTag) -> Text -> InputPortTag
forall a b. (a -> b) -> a -> b
$ Text
tag Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_mosi"
        , slave_miso :: OutputPortTag
slave_miso = Text -> OutputPortTag
OutputPortTag (Text -> OutputPortTag) -> Text -> OutputPortTag
forall a b. (a -> b) -> a -> b
$ Text
tag Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_miso"
        , slave_sclk :: InputPortTag
slave_sclk = Text -> InputPortTag
InputPortTag (Text -> InputPortTag) -> Text -> InputPortTag
forall a b. (a -> b) -> a -> b
$ Text
tag Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_sclk"
        , slave_cs :: InputPortTag
slave_cs = Text -> InputPortTag
InputPortTag (Text -> InputPortTag) -> Text -> InputPortTag
forall a b. (a -> b) -> a -> b
$ Text
tag Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_cs"
        }

instance Time t => Default (SPI v x t) where
    def :: SPI v x t
def = Int -> Maybe Int -> SPI v x t
forall t v x. Time t => Int -> Maybe Int -> SPI v x t
anySPI Int
0 (Maybe Int -> SPI v x t) -> Maybe Int -> SPI v x t
forall a b. (a -> b) -> a -> b
$ Int -> Maybe Int
forall a. a -> Maybe a
Just Int
6

instance (ToJSON v, VarValTime v x t) => TargetSystemComponent (SPI v x t) where
    moduleName :: Text -> SPI v x t -> Text
moduleName Text
_ SPI v x t
_ = Text
"pu_spi"
    hardware :: Text -> SPI v x t -> Implementation
hardware Text
_tag SPI v x t
_pu =
        Maybe String -> [Implementation] -> Implementation
Aggregate
            Maybe String
forall a. Maybe a
Nothing
            [ String -> Implementation
FromLibrary String
"spi/pu_slave_spi_driver.v"
            , String -> Implementation
FromLibrary String
"spi/spi_slave_driver.v"
            , String -> Implementation
FromLibrary String
"spi/i2n_splitter.v"
            , String -> Implementation
FromLibrary String
"spi/buffer.v"
            , String -> Implementation
FromLibrary String
"spi/bounce_filter.v"
            , String -> Implementation
FromLibrary String
"spi/spi_master_driver.v"
            , String -> Implementation
FromLibrary String
"spi/n2i_splitter.v"
            , String -> Implementation
FromLibrary String
"spi/pu_slave_spi.v"
            , String -> Implementation
FromLibrary String
"spi/pu_master_spi.v"
            ]

    software :: Text -> SPI v x t -> Implementation
software Text
tag SPI v x t
pu = Text -> SPI v x t -> Text -> Implementation
forall i v x t.
(VarValTime v x t, SimpleIOInterface i, ToJSON v) =>
Text -> SimpleIO i v x t -> Text -> Implementation
protocolDescription Text
tag SPI v x t
pu Text
"SPI Processor Unit"

    hardwareInstance :: Text -> SPI v x t -> UnitEnv (SPI v x t) -> Verilog
hardwareInstance
        Text
tag
        SimpleIO{Int
bounceFilter :: forall i v x t. SimpleIO i v x t -> Int
bounceFilter :: Int
bounceFilter, Int
sendN :: forall i v x t. SimpleIO i v x t -> Int
sendN :: Int
sendN, Int
receiveN :: forall i v x t. SimpleIO i v x t -> Int
receiveN :: Int
receiveN}
        UnitEnv
            { Text
sigClk :: Text
sigClk :: forall m. UnitEnv m -> Text
sigClk
            , Text
sigRst :: Text
sigRst :: forall m. UnitEnv m -> Text
sigRst
            , Text
sigCycleBegin :: Text
sigCycleBegin :: forall m. UnitEnv m -> Text
sigCycleBegin
            , Text
sigInCycle :: Text
sigInCycle :: forall m. UnitEnv m -> Text
sigInCycle
            , Text
sigCycleEnd :: Text
sigCycleEnd :: forall m. UnitEnv m -> Text
sigCycleEnd
            , valueIn :: forall m. UnitEnv m -> Maybe (Text, Text)
valueIn = Just (Text
dataIn, Text
attrIn)
            , valueOut :: forall m. UnitEnv m -> Maybe (Text, Text)
valueOut = Just (Text
dataOut, Text
attrOut)
            , ctrlPorts :: forall m. UnitEnv m -> Maybe (Ports m)
ctrlPorts = Just SimpleIOPorts{String
SignalTag
wr :: SignalTag
oe :: SignalTag
stop :: String
stop :: forall i v x t. Ports (SimpleIO i v x t) -> String
oe :: forall i v x t. Ports (SimpleIO i v x t) -> SignalTag
wr :: forall i v x t. Ports (SimpleIO i v x t) -> SignalTag
..}
            , ioPorts :: forall m. UnitEnv m -> Maybe (IOPorts m)
ioPorts = Just IOPorts (SPI v x t)
ioPorts
            } =
            [__i|
                #{ module_ ioPorts } \#
                        ( .DATA_WIDTH( #{ dataWidth (def :: x) } )
                        , .ATTR_WIDTH( #{ attrWidth (def :: x) } )
                        , .BOUNCE_FILTER( #{ show bounceFilter } )
                        , .DISABLED( #{ if sendN == 0 && receiveN == 0 then (1 :: Int) else 0 } )
                        ) #{ tag }
                    ( .clk( #{ sigClk } )
                    , .rst( #{ sigRst } )
                    , .flag_stop( #{ stop } )
                    , .signal_cycle_begin( #{ sigCycleBegin } )
                    , .signal_in_cycle( #{ sigInCycle  } )
                    , .signal_cycle_end( #{ sigCycleEnd } )
                    , .signal_oe( #{ oe } )
                    , .signal_wr( #{ wr } )
                    , .data_in( #{ dataIn } ), .attr_in( #{ attrIn } )
                    , .data_out( #{ dataOut } ), .attr_out( #{ attrOut } )
                    #{ nest 4 $ extIO ioPorts  }
                    );
            |]
            where
                module_ :: IOPorts (SPI v x t) -> Verilog
module_ SPISlave{} = Verilog
"pu_slave_spi" :: Verilog
                module_ SPIMaster{} = Verilog
"pu_master_spi"
                extIO :: IOPorts (SPI v x t) -> Verilog
extIO SPISlave{OutputPortTag
InputPortTag
slave_mosi :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_miso :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
slave_sclk :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_cs :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_mosi :: InputPortTag
slave_miso :: OutputPortTag
slave_sclk :: InputPortTag
slave_cs :: InputPortTag
..} =
                    [__i|
                        , .mosi( #{ slave_mosi } )
                        , .miso( #{ slave_miso } )
                        , .sclk( #{ slave_sclk } )
                        , .cs( #{ slave_cs } )
                    |] ::
                        Verilog
                extIO SPIMaster{OutputPortTag
InputPortTag
master_mosi :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_miso :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
master_sclk :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_cs :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_mosi :: OutputPortTag
master_miso :: InputPortTag
master_sclk :: OutputPortTag
master_cs :: OutputPortTag
..} =
                    [__i|
                        , .mosi( #{ master_mosi } )
                        , .miso( #{ master_miso } )
                        , .sclk( #{ master_sclk } )
                        , .cs( #{ master_cs } )
                    |]
    hardwareInstance Text
_title SPI v x t
_pu UnitEnv (SPI v x t)
_env = String -> Verilog
forall a. HasCallStack => String -> a
error String
"internal error"

instance VarValTime v x t => IOTestBench (SPI v x t) v x where
    testEnvironmentInitFlag :: Text -> SPI v x t -> Maybe Text
testEnvironmentInitFlag Text
tag SPI v x t
_pu = Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text) -> Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ Text
tag Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_env_init_flag"

    testEnvironment :: Text
-> SPI v x t
-> UnitEnv (SPI v x t)
-> TestEnvironment v x
-> Maybe Verilog
testEnvironment
        Text
tag
        sio :: SPI v x t
sio@SimpleIO{Process t (StepInfo v x t)
process_ :: forall i v x t. SimpleIO i v x t -> Process t (StepInfo v x t)
process_ :: Process t (StepInfo v x t)
process_, Int
bounceFilter :: forall i v x t. SimpleIO i v x t -> Int
bounceFilter :: Int
bounceFilter}
        UnitEnv
            { Text
sigClk :: forall m. UnitEnv m -> Text
sigClk :: Text
sigClk
            , Text
sigRst :: forall m. UnitEnv m -> Text
sigRst :: Text
sigRst
            , ctrlPorts :: forall m. UnitEnv m -> Maybe (Ports m)
ctrlPorts = Just SimpleIOPorts{}
            , ioPorts :: forall m. UnitEnv m -> Maybe (IOPorts m)
ioPorts = Just IOPorts (SPI v x t)
ioPorts
            }
        TestEnvironment{teCntx :: forall v x. TestEnvironment v x -> Cntx v x
teCntx = cntx :: Cntx v x
cntx@Cntx{Int
cntxCycleNumber :: Int
cntxCycleNumber :: forall v x. Cntx v x -> Int
cntxCycleNumber, [CycleCntx v x]
cntxProcess :: [CycleCntx v x]
cntxProcess :: forall v x. Cntx v x -> [CycleCntx v x]
cntxProcess}, Int
teComputationDuration :: Int
teComputationDuration :: forall v x. TestEnvironment v x -> Int
teComputationDuration} =
            let receivedVariablesSeq :: [v]
receivedVariablesSeq =
                    (F v x -> Maybe v) -> [F v x] -> [v]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe
                        ( \F v x
f -> case F v x -> Maybe (Receive v x)
forall (f :: * -> * -> *) v x.
(Typeable f, Typeable v, Typeable x) =>
F v x -> Maybe (f v x)
castF F v x
f of
                            Just Receive{} -> v -> Maybe v
forall a. a -> Maybe a
Just (v -> Maybe v) -> v -> Maybe v
forall a b. (a -> b) -> a -> b
$ Set v -> v
forall {c}. Set c -> c
oneOf (Set v -> v) -> Set v -> v
forall a b. (a -> b) -> a -> b
$ F v x -> Set v
forall a v. Variables a v => a -> Set v
variables F v x
f
                            Maybe (Receive v x)
_ -> Maybe v
forall a. Maybe a
Nothing
                        )
                        ([F v x] -> [v]) -> [F v x] -> [v]
forall a b. (a -> b) -> a -> b
$ Process t (StepInfo v x t) -> [F v x]
forall a f. WithFunctions a f => a -> [f]
functions Process t (StepInfo v x t)
process_
                receivedVarsValues :: [Map v x]
receivedVarsValues = Int -> [Map v x] -> [Map v x]
forall a. Int -> [a] -> [a]
take Int
cntxCycleNumber ([Map v x] -> [Map v x]) -> [Map v x] -> [Map v x]
forall a b. (a -> b) -> a -> b
$ Cntx v x -> [Map v x]
forall v x. Ord v => Cntx v x -> [Map v x]
cntxReceivedBySlice Cntx v x
cntx
                sendedVariableSeq :: [v]
sendedVariableSeq =
                    (EndpointRole v -> Maybe v) -> [EndpointRole v] -> [v]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe
                        ( \case
                            (Target v
v) -> v -> Maybe v
forall a. a -> Maybe a
Just v
v
                            EndpointRole v
_ -> Maybe v
forall a. Maybe a
Nothing
                        )
                        ([EndpointRole v] -> [v]) -> [EndpointRole v] -> [v]
forall a b. (a -> b) -> a -> b
$ Process t (StepInfo v x t) -> [EndpointRole v]
forall {b} {v} {x} {t}.
Ord b =>
Process b (StepInfo v x t) -> [EndpointRole v]
getEndpoints Process t (StepInfo v x t)
process_
                sendedVarsValues :: [HashMap v x]
sendedVarsValues = Int -> [HashMap v x] -> [HashMap v x]
forall a. Int -> [a] -> [a]
take Int
cntxCycleNumber ([HashMap v x] -> [HashMap v x]) -> [HashMap v x] -> [HashMap v x]
forall a b. (a -> b) -> a -> b
$ (CycleCntx v x -> HashMap v x) -> [CycleCntx v x] -> [HashMap v x]
forall a b. (a -> b) -> [a] -> [b]
map CycleCntx v x -> HashMap v x
forall v x. CycleCntx v x -> HashMap v x
cycleCntx [CycleCntx v x]
cntxProcess
                wordWidth :: Int
wordWidth = x -> Int
forall x. Val x => x -> Int
dataWidth (x
forall a. Default a => a
def :: x)
                frameWordCount :: Int
frameWordCount = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max ([v] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [v]
receivedVariablesSeq) (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ [v] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [v]
sendedVariableSeq
                frameWidth :: Int
frameWidth = Int
frameWordCount Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
wordWidth
                timeLag :: Int
timeLag = Int
10 :: Int
                sendingDuration :: Int
sendingDuration =
                    Int -> Int -> Int
forall a. Ord a => a -> a -> a
max
                        (Int
teComputationDuration Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)
                        (Int
frameWidth Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
bounceFilter Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)

                toVerilogLiteral :: [x] -> Doc Any
toVerilogLiteral [x]
xs =
                    let xs' :: [Doc Any]
xs' = (x -> Doc Any) -> [x] -> [Doc Any]
forall a b. (a -> b) -> [a] -> [b]
map x -> Doc Any
toVerilogLiteral' [x]
xs
                        placeholder :: [Doc Any]
placeholder = Int -> Doc Any -> [Doc Any]
forall a. Int -> a -> [a]
replicate (Int
frameWordCount Int -> Int -> Int
forall a. Num a => a -> a -> a
- [x] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [x]
xs) [i|#{ wordWidth }'d00|]
                     in [Doc Any] -> Doc Any
forall ann. [Doc ann] -> Doc ann
hsep ([Doc Any] -> Doc Any) -> [Doc Any] -> Doc Any
forall a b. (a -> b) -> a -> b
$ Doc Any -> [Doc Any] -> [Doc Any]
forall ann. Doc ann -> [Doc ann] -> [Doc ann]
punctuate Doc Any
", " ([Doc Any]
xs' [Doc Any] -> [Doc Any] -> [Doc Any]
forall a. Semigroup a => a -> a -> a
<> [Doc Any]
placeholder)
                toVerilogLiteral' :: x -> Doc Any
toVerilogLiteral' x
x
                    | x -> x
forall a. Num a => a -> a
abs x
x x -> x -> Bool
forall a. Eq a => a -> a -> Bool
/= x
x = [i|-#{ wordWidth }'sd#{ dataLiteral (-x) }|]
                    | Bool
otherwise = [i|#{ wordWidth }'sd#{ dataLiteral x }|]

                disable :: Verilog
disable =
                    [__i|
                        initial begin
                            @(negedge #{ sigRst });
                            #{ envInitFlagName } <= 1;
                        end
                    |]

                envInitFlagName :: Text
envInitFlagName =
                    Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe (String -> Text
forall a. HasCallStack => String -> a
error String
"SPI: testEnvironment: internal error") (Maybe Text -> Text) -> Maybe Text -> Text
forall a b. (a -> b) -> a -> b
$
                        Text -> SPI v x t -> Maybe Text
forall pu v x. IOTestBench pu v x => Text -> pu -> Maybe Text
testEnvironmentInitFlag Text
tag SPI v x t
sio
             in case IOPorts (SPI v x t)
ioPorts of
                    SPISlave{OutputPortTag
InputPortTag
slave_mosi :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_miso :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
slave_sclk :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_cs :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
slave_mosi :: InputPortTag
slave_miso :: OutputPortTag
slave_sclk :: InputPortTag
slave_cs :: InputPortTag
..} ->
                        let receiveCycle :: Map v x -> Doc Any
receiveCycle Map v x
transmit =
                                let xs :: [x]
xs = (v -> x) -> [v] -> [x]
forall a b. (a -> b) -> [a] -> [b]
map (\v
v -> x -> Maybe x -> x
forall a. a -> Maybe a -> a
fromMaybe x
forall a. Default a => a
def (Maybe x -> x) -> Maybe x -> x
forall a b. (a -> b) -> a -> b
$ Map v x
transmit Map v x -> v -> Maybe x
forall k a. Ord k => Map k a -> k -> Maybe a
M.!? v
v) [v]
receivedVariablesSeq
                                 in [__i|
                                        $display( "set data for sending #{ viaShow xs } by #{ tag }_io_test_input" );
                                        #{ tag }_io_test_input = { #{ toVerilogLiteral xs } }; // #{ viaShow xs }
                                        #{ tag }_io_test_start_transaction = 1;                           @(posedge #{ sigClk });
                                        #{ tag }_io_test_start_transaction = 0;                           @(posedge #{ sigClk });
                                        repeat( #{ sendingDuration } ) @(posedge #{ sigClk });

                                    |]

                            sendingAssert :: HashMap v x -> Doc Any
sendingAssert HashMap v x
transmit =
                                let xs :: [x]
xs = (v -> x) -> [v] -> [x]
forall a b. (a -> b) -> [a] -> [b]
map (\v
v -> x -> Maybe x -> x
forall a. a -> Maybe a -> a
fromMaybe x
forall a. Default a => a
def (Maybe x -> x) -> Maybe x -> x
forall a b. (a -> b) -> a -> b
$ v -> HashMap v x -> Maybe x
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HM.lookup v
v HashMap v x
transmit) [v]
sendedVariableSeq
                                 in [__i|
                                        @(posedge #{ tag }_io_test_start_transaction);
                                            $write( "#{ tag }_io_test_output actual: %H except: %H ({ #{ toVerilogLiteral xs } })",
                                                #{ tag }_io_test_output, { #{ toVerilogLiteral xs } } );
                                            if ( #{ tag }_io_test_output != { #{ toVerilogLiteral xs } } ) $display("\t\tFAIL");
                                            else $display();

                                    |]

                            endDeviceInstance :: Verilog
endDeviceInstance =
                                [__i|
                                    /*
                                    #{ pretty sio }
                                    */
                                    reg #{ tag }_io_test_start_transaction;
                                    reg  [#{ frameWidth }-1:0] #{ tag }_io_test_input;
                                    wire #{ tag }_io_test_ready;
                                    wire [#{ frameWidth }-1:0] #{ tag }_io_test_output;
                                    initial #{ envInitFlagName } <= 0; // should be defined on the testbench level.
                                    spi_master_driver \#
                                            ( .DATA_WIDTH( #{ frameWidth } )
                                            , .SCLK_HALFPERIOD( 1 )
                                            ) #{ tag }_io_test
                                        ( .clk( #{ sigClk } )
                                        , .rst( #{ sigRst } )
                                        , .start_transaction( #{ tag }_io_test_start_transaction )
                                        , .data_in( #{ tag }_io_test_input )
                                        , .data_out( #{ tag }_io_test_output )
                                        , .ready( #{ tag }_io_test_ready )
                                        , .mosi( #{ slave_mosi } )
                                        , .miso( #{ slave_miso } )
                                        , .sclk( #{ slave_sclk } )
                                        , .cs( #{ slave_cs } )
                                        );
                                    initial #{ tag }_io_test.inner.shiftreg <= 0;
                                |]

                            envDeviceControl :: Verilog
envDeviceControl =
                                [__i|
                                    initial begin
                                        #{ tag }_io_test_start_transaction <= 0;
                                        #{ tag }_io_test_input <= 0;
                                        @(negedge #{ sigRst });
                                        repeat(#{ timeLag }) @(posedge #{ sigClk });

                                        #{ nest 4 $ vsep $ map receiveCycle receivedVarsValues }
                                        repeat ( 5 ) begin
                                            #{ nest 8 $ receiveCycle def }
                                        end

                                        // $finish; // DON'T DO THAT (with this line test can pass without data checking)
                                    end
                                |]
                            envDeviceCheck :: Verilog
envDeviceCheck =
                                [__i|
                                    initial begin
                                        @(negedge #{ sigRst });
                                        repeat ( OUTPUT_LATENCY ) @(posedge #{ tag }_io_test_start_transaction); // latency

                                        #{ nest 4 $ vsep $ map sendingAssert sendedVarsValues }
                                        forever begin
                                            @(posedge spi_io_test_start_transaction);
                                            $display( "#{ tag }_io_test_output actual: %H", #{ tag }_io_test_output );
                                        end
                                    end
                                |]
                         in -- FIXME: do not check output signals when we drop data
                            Verilog -> Maybe Verilog
forall a. a -> Maybe a
Just
                                [__i|
                                    ////////////////////////////////////////
                                    // SPI test environment
                                    localparam NITTA_LATENCY = 1;
                                    localparam OUTPUT_LATENCY = 3;

                                    // SPI device in test environment
                                    #{ endDeviceInstance :: Verilog }

                                    // SPI device in test environment control
                                    #{ if frameWordCount == 0 then disable else envDeviceControl }

                                    // SPI device in test environment check
                                    #{ if frameWordCount == 0 then disable else envDeviceCheck }

                                    // SPI environment initialization flag set
                                    initial begin
                                        repeat ( NITTA_LATENCY ) @(posedge spi_io_test_start_transaction);
                                        spi_env_init_flag <= 1;
                                    end
                                |]
                    SPIMaster{OutputPortTag
InputPortTag
master_mosi :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_miso :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
master_sclk :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_cs :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
master_mosi :: OutputPortTag
master_miso :: InputPortTag
master_sclk :: OutputPortTag
master_cs :: OutputPortTag
..} ->
                        let receiveCycle :: Map v x -> Doc Any
receiveCycle Map v x
transmit =
                                let xs :: [x]
xs = (v -> x) -> [v] -> [x]
forall a b. (a -> b) -> [a] -> [b]
map (\v
v -> x -> Maybe x -> x
forall a. a -> Maybe a -> a
fromMaybe x
forall a. Default a => a
def (Maybe x -> x) -> Maybe x -> x
forall a b. (a -> b) -> a -> b
$ Map v x
transmit Map v x -> v -> Maybe x
forall k a. Ord k => Map k a -> k -> Maybe a
M.!? v
v) [v]
receivedVariablesSeq
                                 in [__i|
                                        #{ tag }_io_test_input = { #{ toVerilogLiteral xs } }; // #{ xs }
                                        @(posedge #{ tag }_io_test_ready);
                                    |]

                            sendingAssert :: HashMap v x -> Doc Any
sendingAssert HashMap v x
transmit =
                                let xs :: [x]
xs = (v -> x) -> [v] -> [x]
forall a b. (a -> b) -> [a] -> [b]
map (\v
v -> x -> Maybe x -> x
forall a. a -> Maybe a -> a
fromMaybe x
forall a. Default a => a
def (Maybe x -> x) -> Maybe x -> x
forall a b. (a -> b) -> a -> b
$ v -> HashMap v x -> Maybe x
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HM.lookup v
v HashMap v x
transmit) [v]
sendedVariableSeq
                                 in [__i|
                                        @(posedge #{ tag }_io_test_ready);
                                            $display( "#{ tag }_io_test_output except: %H ({ #{ toVerilogLiteral xs } })", { #{ toVerilogLiteral xs } } );
                                            $display( "#{ tag }_io_test_output actual: %H", #{ tag }_io_test_output );
                                            if ( #{ tag }_io_test_output !=  { #{ toVerilogLiteral xs } } )
                                                $display("                       FAIL");
                                            $display();
                                    |]

                            envInstance :: Verilog
envInstance =
                                [__i|
                                    /*
                                    #{ pretty sio }
                                    */
                                    reg #{ tag }_io_test_start_transaction;
                                    reg  [#{ frameWidth }-1:0] #{ tag }_io_test_input;
                                    wire #{ tag }_io_test_ready;
                                    wire [#{ frameWidth }-1:0] #{ tag }_io_test_output;
                                    initial #{ envInitFlagName } <= 0; // should be defined on the testbench level.
                                    spi_slave_driver \#
                                            ( .DATA_WIDTH( #{ frameWidth } )
                                            ) #{ tag }_io_test_slave
                                        ( .clk( #{ sigClk } )
                                        , .rst( #{ sigRst } )
                                        , .data_in( #{ tag }_io_test_input )
                                        , .data_out( #{ tag }_io_test_output )
                                        , .ready( #{ tag }_io_test_ready )
                                        , .mosi( #{ master_mosi } )
                                        , .miso( #{ master_miso } )
                                        , .sclk( #{ master_sclk } )
                                        , .cs( #{ master_cs } )
                                        );
                                |]

                            interactions :: Verilog
interactions =
                                [__i|
                                    // SPI Input signal generation
                                    initial begin
                                        @(negedge #{ sigRst });
                                        #{ nest 4 $ receiveCycle $ head receivedVarsValues }
                                        #{ envInitFlagName } <= 1;

                                        #{ nest 4 $ vsep $ map receiveCycle $ tail receivedVarsValues }
                                        repeat(70) @(posedge #{ sigClk });
                                        // $finish; // DON'T DO THAT (with this line test can pass without data checking)
                                    end

                                    // SPI Output signal checking
                                    initial begin
                                        @(negedge #{ sigRst });
                                        repeat(2) @(posedge #{ tag }_io_test_ready);
                                        #{ nest 4 $ vsep $ map sendingAssert sendedVarsValues }
                                    end
                                |]
                         in Verilog -> Maybe Verilog
forall a. a -> Maybe a
Just (Verilog
envInstance Verilog -> Verilog -> Verilog
forall a. Semigroup a => a -> a -> a
<> Verilog
forall ann. Doc ann
line Verilog -> Verilog -> Verilog
forall a. Semigroup a => a -> a -> a
<> Verilog
forall ann. Doc ann
line Verilog -> Verilog -> Verilog
forall a. Semigroup a => a -> a -> a
<> if Int
frameWordCount Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then Verilog
disable else Verilog
interactions)
    testEnvironment Text
_title SPI v x t
_pu UnitEnv (SPI v x t)
_env TestEnvironment v x
_tEnv = String -> Maybe Verilog
forall a. HasCallStack => String -> a
error String
"internal error"