{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}
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
$sel:bounceFilter:SimpleIO :: Int
bounceFilter :: Int
bounceFilter
, Maybe Int
$sel:bufferSize:SimpleIO :: Maybe Int
bufferSize :: Maybe Int
bufferSize
, $sel:receiveQueue:SimpleIO :: [Q v x]
receiveQueue = []
, $sel:receiveN:SimpleIO :: Int
receiveN = Int
0
, $sel:isReceiveOver:SimpleIO :: Bool
isReceiveOver = Bool
False
, $sel:sendQueue:SimpleIO :: [Q v x]
sendQueue = []
, $sel:sendN:SimpleIO :: Int
sendN = Int
0
, $sel:process_:SimpleIO :: Process t (StepInfo v x t)
process_ = 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
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
showList :: [IOPorts (SPI v x t)] -> ShowS
$cshowList :: forall v x t. [IOPorts (SPI v x t)] -> ShowS
show :: IOPorts (SPI v x t) -> String
$cshow :: forall v x t. IOPorts (SPI v x t) -> String
showsPrec :: Int -> IOPorts (SPI v x t) -> ShowS
$cshowsPrec :: forall v x t. Int -> IOPorts (SPI v x t) -> ShowS
Show)
inputPorts :: IOPorts (SPI v x t) -> Set InputPortTag
inputPorts SPISlave{OutputPortTag
InputPortTag
slave_cs :: InputPortTag
slave_sclk :: InputPortTag
slave_miso :: OutputPortTag
slave_mosi :: InputPortTag
$sel:slave_cs:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
$sel:slave_sclk:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
$sel:slave_miso:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
$sel:slave_mosi:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
..} = forall a. Ord a => [a] -> Set a
S.fromList [InputPortTag
slave_mosi, InputPortTag
slave_sclk, InputPortTag
slave_cs]
inputPorts SPIMaster{OutputPortTag
InputPortTag
master_cs :: OutputPortTag
master_sclk :: OutputPortTag
master_miso :: InputPortTag
master_mosi :: OutputPortTag
$sel:master_cs:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
$sel:master_sclk:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
$sel:master_miso:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
$sel:master_mosi:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
..} = 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_cs :: InputPortTag
slave_sclk :: InputPortTag
slave_miso :: OutputPortTag
slave_mosi :: InputPortTag
$sel:slave_cs:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
$sel:slave_sclk:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
$sel:slave_miso:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
$sel:slave_mosi:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
..} = forall a. Ord a => [a] -> Set a
S.fromList [OutputPortTag
slave_miso]
outputPorts SPIMaster{OutputPortTag
InputPortTag
master_cs :: OutputPortTag
master_sclk :: OutputPortTag
master_miso :: InputPortTag
master_mosi :: OutputPortTag
$sel:master_cs:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
$sel:master_sclk:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
$sel:master_miso:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
$sel:master_mosi:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> 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
{ $sel:master_mosi:SPIMaster :: OutputPortTag
master_mosi = Text -> OutputPortTag
OutputPortTag forall a b. (a -> b) -> a -> b
$ Text
tag forall a. Semigroup a => a -> a -> a
<> Text
"_mosi"
, $sel:master_miso:SPIMaster :: InputPortTag
master_miso = Text -> InputPortTag
InputPortTag forall a b. (a -> b) -> a -> b
$ Text
tag forall a. Semigroup a => a -> a -> a
<> Text
"_miso"
, $sel:master_sclk:SPIMaster :: OutputPortTag
master_sclk = Text -> OutputPortTag
OutputPortTag forall a b. (a -> b) -> a -> b
$ Text
tag forall a. Semigroup a => a -> a -> a
<> Text
"_sclk"
, $sel:master_cs:SPIMaster :: OutputPortTag
master_cs = Text -> OutputPortTag
OutputPortTag forall a b. (a -> b) -> a -> b
$ Text
tag forall a. Semigroup a => a -> a -> a
<> Text
"_cs"
}
spiSlavePorts :: Text -> IOPorts (SPI v x t)
spiSlavePorts Text
tag =
SPISlave
{ $sel:slave_mosi:SPIMaster :: InputPortTag
slave_mosi = Text -> InputPortTag
InputPortTag forall a b. (a -> b) -> a -> b
$ Text
tag forall a. Semigroup a => a -> a -> a
<> Text
"_mosi"
, $sel:slave_miso:SPIMaster :: OutputPortTag
slave_miso = Text -> OutputPortTag
OutputPortTag forall a b. (a -> b) -> a -> b
$ Text
tag forall a. Semigroup a => a -> a -> a
<> Text
"_miso"
, $sel:slave_sclk:SPIMaster :: InputPortTag
slave_sclk = Text -> InputPortTag
InputPortTag forall a b. (a -> b) -> a -> b
$ Text
tag forall a. Semigroup a => a -> a -> a
<> Text
"_sclk"
, $sel:slave_cs:SPIMaster :: InputPortTag
slave_cs = Text -> InputPortTag
InputPortTag forall a b. (a -> b) -> a -> b
$ Text
tag forall a. Semigroup a => a -> a -> a
<> Text
"_cs"
}
instance Time t => Default (SPI v x t) where
def :: SPI v x t
def = forall t v x. Time t => Int -> Maybe Int -> SPI v x t
anySPI Int
0 forall a b. (a -> b) -> a -> b
$ 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
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 = 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 :: Int
$sel:bounceFilter:SimpleIO :: forall i v x t. SimpleIO i v x t -> Int
bounceFilter, Int
sendN :: Int
$sel:sendN:SimpleIO :: forall i v x t. SimpleIO i v x t -> Int
sendN, Int
receiveN :: Int
$sel:receiveN:SimpleIO :: forall i v x t. SimpleIO i v x t -> Int
receiveN}
UnitEnv
{ Text
sigClk :: forall m. UnitEnv m -> Text
sigClk :: Text
sigClk
, Text
sigRst :: forall m. UnitEnv m -> Text
sigRst :: Text
sigRst
, Text
sigCycleBegin :: forall m. UnitEnv m -> Text
sigCycleBegin :: Text
sigCycleBegin
, Text
sigInCycle :: forall m. UnitEnv m -> Text
sigInCycle :: Text
sigInCycle
, Text
sigCycleEnd :: forall m. UnitEnv m -> Text
sigCycleEnd :: 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
$sel:stop:SimpleIOPorts :: forall i v x t. Ports (SimpleIO i v x t) -> String
$sel:oe:SimpleIOPorts :: forall i v x t. Ports (SimpleIO i v x t) -> SignalTag
$sel:wr:SimpleIOPorts :: forall i v x t. Ports (SimpleIO i v x t) -> SignalTag
stop :: String
oe :: SignalTag
wr :: 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_cs :: InputPortTag
slave_sclk :: InputPortTag
slave_miso :: OutputPortTag
slave_mosi :: InputPortTag
$sel:slave_cs:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
$sel:slave_sclk:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
$sel:slave_miso:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
$sel:slave_mosi:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
..} =
[__i|
, .mosi( #{ slave_mosi } )
, .miso( #{ slave_miso } )
, .sclk( #{ slave_sclk } )
, .cs( #{ slave_cs } )
|] ::
Verilog
extIO SPIMaster{OutputPortTag
InputPortTag
master_cs :: OutputPortTag
master_sclk :: OutputPortTag
master_miso :: InputPortTag
master_mosi :: OutputPortTag
$sel:master_cs:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
$sel:master_sclk:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
$sel:master_miso:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
$sel:master_mosi:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> 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 = 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 = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Text
tag 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_ :: Process t (StepInfo v x t)
$sel:process_:SimpleIO :: forall i v x t. SimpleIO i v x t -> Process t (StepInfo v x t)
process_, Int
bounceFilter :: Int
$sel:bounceFilter:SimpleIO :: forall i v x t. SimpleIO i v x t -> Int
bounceFilter}
UnitEnv
{ Text
sigClk :: Text
sigClk :: forall m. UnitEnv m -> Text
sigClk
, Text
sigRst :: Text
sigRst :: forall m. UnitEnv m -> 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 :: forall v x. Cntx v x -> Int
cntxCycleNumber :: Int
cntxCycleNumber, [CycleCntx v x]
cntxProcess :: forall v x. Cntx v x -> [CycleCntx v x]
cntxProcess :: [CycleCntx v x]
cntxProcess}, Int
teComputationDuration :: forall v x. TestEnvironment v x -> Int
teComputationDuration :: Int
teComputationDuration} =
let receivedVariablesSeq :: [v]
receivedVariablesSeq =
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe
( \F v x
f -> case 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{} -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall {c}. Set c -> c
oneOf forall a b. (a -> b) -> a -> b
$ forall a v. Variables a v => a -> Set v
variables F v x
f
Maybe (Receive v x)
_ -> forall a. Maybe a
Nothing
)
forall a b. (a -> b) -> a -> b
$ forall a f. WithFunctions a f => a -> [f]
functions Process t (StepInfo v x t)
process_
receivedVarsValues :: [Map v x]
receivedVarsValues = forall a. Int -> [a] -> [a]
take Int
cntxCycleNumber forall a b. (a -> b) -> a -> b
$ forall v x. Ord v => Cntx v x -> [Map v x]
cntxReceivedBySlice Cntx v x
cntx
sendedVariableSeq :: [v]
sendedVariableSeq =
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe
( \case
(Target v
v) -> forall a. a -> Maybe a
Just v
v
EndpointRole v
_ -> forall a. Maybe a
Nothing
)
forall a b. (a -> b) -> a -> b
$ 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 = forall a. Int -> [a] -> [a]
take Int
cntxCycleNumber forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map forall v x. CycleCntx v x -> HashMap v x
cycleCntx [CycleCntx v x]
cntxProcess
wordWidth :: Int
wordWidth = forall x. Val x => x -> Int
dataWidth (forall a. Default a => a
def :: x)
frameWordCount :: Int
frameWordCount = forall a. Ord a => a -> a -> a
max (forall (t :: * -> *) a. Foldable t => t a -> Int
length [v]
receivedVariablesSeq) forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t a -> Int
length [v]
sendedVariableSeq
frameWidth :: Int
frameWidth = Int
frameWordCount forall a. Num a => a -> a -> a
* Int
wordWidth
timeLag :: Int
timeLag = Int
10 :: Int
sendingDuration :: Int
sendingDuration =
forall a. Ord a => a -> a -> a
max
(Int
teComputationDuration forall a. Num a => a -> a -> a
+ Int
2)
(Int
frameWidth forall a. Num a => a -> a -> a
* Int
2 forall a. Num a => a -> a -> a
+ Int
bounceFilter forall a. Num a => a -> a -> a
+ Int
2)
toVerilogLiteral :: [x] -> Doc Any
toVerilogLiteral [x]
xs =
let xs' :: [Doc Any]
xs' = forall a b. (a -> b) -> [a] -> [b]
map x -> Doc Any
toVerilogLiteral' [x]
xs
placeholder :: [Doc Any]
placeholder = forall a. Int -> a -> [a]
replicate (Int
frameWordCount forall a. Num a => a -> a -> a
- forall (t :: * -> *) a. Foldable t => t a -> Int
length [x]
xs) [i|#{ wordWidth }'d00|]
in forall ann. [Doc ann] -> Doc ann
hsep forall a b. (a -> b) -> a -> b
$ forall ann. Doc ann -> [Doc ann] -> [Doc ann]
punctuate Doc Any
", " ([Doc Any]
xs' forall a. Semigroup a => a -> a -> a
<> [Doc Any]
placeholder)
toVerilogLiteral' :: x -> Doc Any
toVerilogLiteral' x
x
| forall a. Num a => a -> a
abs x
x 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 =
forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => String -> a
error String
"SPI: testEnvironment: internal error") forall a b. (a -> b) -> a -> b
$
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_cs :: InputPortTag
slave_sclk :: InputPortTag
slave_miso :: OutputPortTag
slave_mosi :: InputPortTag
$sel:slave_cs:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
$sel:slave_sclk:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
$sel:slave_miso:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
$sel:slave_mosi:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
..} ->
let receiveCycle :: Map v x -> Doc Any
receiveCycle Map v x
transmit =
let xs :: [x]
xs = forall a b. (a -> b) -> [a] -> [b]
map (\v
v -> forall a. a -> Maybe a -> a
fromMaybe forall a. Default a => a
def forall a b. (a -> b) -> a -> b
$ Map v x
transmit 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 = forall a b. (a -> b) -> [a] -> [b]
map (\v
v -> forall a. a -> Maybe a -> a
fromMaybe forall a. Default a => a
def forall a b. (a -> b) -> a -> b
$ 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
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_cs :: OutputPortTag
master_sclk :: OutputPortTag
master_miso :: InputPortTag
master_mosi :: OutputPortTag
$sel:master_cs:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
$sel:master_sclk:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
$sel:master_miso:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> InputPortTag
$sel:master_mosi:SPIMaster :: forall v x t. IOPorts (SPI v x t) -> OutputPortTag
..} ->
let receiveCycle :: Map v x -> Doc Any
receiveCycle Map v x
transmit =
let xs :: [x]
xs = forall a b. (a -> b) -> [a] -> [b]
map (\v
v -> forall a. a -> Maybe a -> a
fromMaybe forall a. Default a => a
def forall a b. (a -> b) -> a -> b
$ Map v x
transmit 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 = forall a b. (a -> b) -> [a] -> [b]
map (\v
v -> forall a. a -> Maybe a -> a
fromMaybe forall a. Default a => a
def forall a b. (a -> b) -> a -> b
$ 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 forall a. a -> Maybe a
Just (Verilog
envInstance forall a. Semigroup a => a -> a -> a
<> forall ann. Doc ann
line forall a. Semigroup a => a -> a -> a
<> forall ann. Doc ann
line forall a. Semigroup a => a -> a -> a
<> if Int
frameWordCount 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 = forall a. HasCallStack => String -> a
error String
"internal error"