{-|
Module      : Ice40.Spram
Description : Ice40 single-port RAM hard IP primitive
Copyright   : (c) David Cox, 2021
License     : BSD 3-Clause
Maintainer  : standardsemiconductor@gmail.com

SPRAM hard IP primitive from [Lattice Ice Technology Library](https://github.com/standardsemiconductor/VELDT-info/blob/master/SBTICETechnologyLibrary201708.pdf)
-}
module Ice40.Spram ( spramPrim ) where

import Clash.Prelude
import Clash.Annotations.Primitive
import Data.String.Interpolate (i)
import Data.String.Interpolate.Util (unindent)

{-# ANN spramPrim (InlinePrimitive [Verilog] $ unindent [i|
  [  { "BlackBox" :
       { "name" : "Ice40.Spram.spramPrim"
       , "kind" : "Declaration"
       , "type" :
  "spramPrim
  :: KnownDomain dom            -- ARG[0] 
  => Clock dom                  -- ARG[1]  clock
  -> Signal dom (BitVector 14)  -- ARG[2]  address
  -> Signal dom (BitVector 16)  -- ARG[3]  dataIn
  -> Signal dom (BitVector 4)   -- ARG[4]  maskWrEn
  -> Signal dom Bit             -- ARG[5]  wrEN
  -> Signal dom Bit             -- ARG[6]  chipSelect
  -> Signal dom Bit             -- ARG[7]  standBy
  -> Signal dom Bit             -- ARG[8]  sleep
  -> Signal dom Bit             -- ARG[9] powerOff
  -> Signal dom (BitVector 16)  -- dataOut"
       , "template" :
  "//SB_SPRAM begin
  SB_SPRAM256KA ~GENSYM[sb_spram_inst][0] (
    .ADDRESS   (~ARG[2]),
    .DATAIN    (~ARG[3]),
    .MASKWREN  (~ARG[4]),
    .WREN      (~ARG[5]),
    .CHIPSELECT(~ARG[6]),
    .CLOCK     (~ARG[1]),
    .STANDBY   (~ARG[7]),
    .SLEEP     (~ARG[8]),
    .POWEROFF  (~ARG[9]),
    .DATAOUT   (~RESULT)
  );
  //SB_SPRAM end"
       }
    }
  ]
  |]) #-}

data Nyb = Nyb3 | Nyb2 | Nyb1 | Nyb0

-- | Single port RAM primitive
{-# NOINLINE spramPrim #-}
spramPrim
  :: KnownDomain dom            -- ARG[0] 
  => Clock dom                  -- ^ clock
  -> Signal dom (BitVector 14)  -- ^ address
  -> Signal dom (BitVector 16)  -- ^ dataIn
  -> Signal dom (BitVector 4)   -- ^ maskWrEn
  -> Signal dom Bit             -- ^ wrEN
  -> Signal dom Bit             -- ^ chipSelect
  -> Signal dom Bit             -- ^ standBy
  -> Signal dom Bit             -- ^ sleep
  -> Signal dom Bit             -- ^ powerOff
  -> Signal dom (BitVector 16)  -- ^ dataOut
spramPrim :: Clock dom
-> Signal dom (BitVector 14)
-> Signal dom (BitVector 16)
-> Signal dom (BitVector 4)
-> Signal dom Bit
-> Signal dom Bit
-> Signal dom Bit
-> Signal dom Bit
-> Signal dom Bit
-> Signal dom (BitVector 16)
spramPrim Clock dom
clock Signal dom (BitVector 14)
address Signal dom (BitVector 16)
dataIn Signal dom (BitVector 4)
maskWrEn Signal dom Bit
wrEn Signal dom Bit
chipSelect !Signal dom Bit
_ !Signal dom Bit
_ !Signal dom Bit
_
  = BitVector 4
-> BitVector 4 -> BitVector 4 -> BitVector 4 -> BitVector 16
forall (m :: Nat) (m :: Nat) (m :: Nat) (n :: Nat).
(KnownNat m, KnownNat m, KnownNat m) =>
BitVector n
-> BitVector m
-> BitVector m
-> BitVector m
-> BitVector (((n + m) + m) + m)
concat4 (BitVector 4
 -> BitVector 4 -> BitVector 4 -> BitVector 4 -> BitVector 16)
-> Signal dom (BitVector 4)
-> Signal
     dom (BitVector 4 -> BitVector 4 -> BitVector 4 -> BitVector 16)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (BitVector 4)
nyb3 Signal
  dom (BitVector 4 -> BitVector 4 -> BitVector 4 -> BitVector 16)
-> Signal dom (BitVector 4)
-> Signal dom (BitVector 4 -> BitVector 4 -> BitVector 16)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom (BitVector 4)
nyb2 Signal dom (BitVector 4 -> BitVector 4 -> BitVector 16)
-> Signal dom (BitVector 4)
-> Signal dom (BitVector 4 -> BitVector 16)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom (BitVector 4)
nyb1 Signal dom (BitVector 4 -> BitVector 16)
-> Signal dom (BitVector 4) -> Signal dom (BitVector 16)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom (BitVector 4)
nyb0
  where
    addressU :: Signal dom (Unsigned 14)
addressU = BitVector 14 -> Unsigned 14
forall a. BitPack a => BitVector (BitSize a) -> a
unpack (BitVector 14 -> Unsigned 14)
-> Signal dom (BitVector 14) -> Signal dom (Unsigned 14)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (BitVector 14)
address
    concat4 :: BitVector n
-> BitVector m
-> BitVector m
-> BitVector m
-> BitVector (((n + m) + m) + m)
concat4 BitVector n
a BitVector m
b BitVector m
c BitVector m
d = BitVector n
a BitVector n -> BitVector m -> BitVector (n + m)
forall (m :: Nat) (n :: Nat).
KnownNat m =>
BitVector n -> BitVector m -> BitVector (n + m)
++# BitVector m
b BitVector (n + m) -> BitVector m -> BitVector ((n + m) + m)
forall (m :: Nat) (n :: Nat).
KnownNat m =>
BitVector n -> BitVector m -> BitVector (n + m)
++# BitVector m
c BitVector ((n + m) + m)
-> BitVector m -> BitVector (((n + m) + m) + m)
forall (m :: Nat) (n :: Nat).
KnownNat m =>
BitVector n -> BitVector m -> BitVector (n + m)
++# BitVector m
d
    ramEn :: Enable dom
ramEn = Signal dom Bool -> Enable dom
forall (dom :: Domain). Signal dom Bool -> Enable dom
toEnable (Signal dom Bool -> Enable dom) -> Signal dom Bool -> Enable dom
forall a b. (a -> b) -> a -> b
$ Bit -> Bool
bitToBool (Bit -> Bool) -> Signal dom Bit -> Signal dom Bool
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom Bit
chipSelect
    nybRam :: Signal dom (Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 4)
nybRam = Clock dom
-> (HiddenClock dom =>
    Signal dom (Maybe (Unsigned 14, BitVector 4))
    -> Signal dom (BitVector 4))
-> Signal dom (Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 4)
forall (dom :: Domain) r.
KnownDomain dom =>
Clock dom -> (HiddenClock dom => r) -> r
withClock Clock dom
clock ((HiddenClock dom =>
  Signal dom (Maybe (Unsigned 14, BitVector 4))
  -> Signal dom (BitVector 4))
 -> Signal dom (Maybe (Unsigned 14, BitVector 4))
 -> Signal dom (BitVector 4))
-> (HiddenClock dom =>
    Signal dom (Maybe (Unsigned 14, BitVector 4))
    -> Signal dom (BitVector 4))
-> Signal dom (Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 4)
forall a b. (a -> b) -> a -> b
$ Enable dom
-> (HiddenEnable dom =>
    Signal dom (Maybe (Unsigned 14, BitVector 4))
    -> Signal dom (BitVector 4))
-> Signal dom (Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 4)
forall (dom :: Domain) r.
KnownDomain dom =>
Enable dom -> (HiddenEnable dom => r) -> r
withEnable Enable dom
ramEn (Vec (2 ^ 14) (BitVector 4)
-> Signal dom (Unsigned 14)
-> Signal dom (Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 4)
forall (dom :: Domain) a (n :: Nat).
(HasCallStack, HiddenClock dom, HiddenEnable dom, NFDataX a,
 KnownNat n) =>
Vec (2 ^ n) a
-> Signal dom (Unsigned n)
-> Signal dom (Maybe (Unsigned n, a))
-> Signal dom a
blockRamPow2 (BitVector 4 -> Vec (2 ^ 14) (BitVector 4)
forall (n :: Nat) a. KnownNat n => a -> Vec n a
repeat BitVector 4
0) Signal dom (Unsigned 14)
addressU)
    nyb3 :: Signal dom (BitVector 4)
nyb3 = Signal dom (Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 4)
nybRam Signal dom (Maybe (Unsigned 14, BitVector 4))
wrM3
    nyb2 :: Signal dom (BitVector 4)
nyb2 = Signal dom (Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 4)
nybRam Signal dom (Maybe (Unsigned 14, BitVector 4))
wrM2
    nyb1 :: Signal dom (BitVector 4)
nyb1 = Signal dom (Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 4)
nybRam Signal dom (Maybe (Unsigned 14, BitVector 4))
wrM1
    nyb0 :: Signal dom (BitVector 4)
nyb0 = Signal dom (Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 4)
nybRam Signal dom (Maybe (Unsigned 14, BitVector 4))
wrM0
    wrM3 :: Signal dom (Maybe (Unsigned 14, BitVector 4))
wrM3 = Nyb
-> BitVector 16
-> Unsigned 14
-> Bit
-> BitVector 4
-> Maybe (Unsigned 14, BitVector 4)
writeGuard Nyb
Nyb3 (BitVector 16
 -> Unsigned 14
 -> Bit
 -> BitVector 4
 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 16)
-> Signal
     dom
     (Unsigned 14
      -> Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (BitVector 16)
dataIn Signal
  dom
  (Unsigned 14
   -> Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom (Unsigned 14)
-> Signal
     dom (Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom (Unsigned 14)
addressU Signal dom (Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom Bit
-> Signal dom (BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom Bit
wrEn Signal dom (BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 4)
-> Signal dom (Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom (BitVector 4)
maskWrEn
    wrM2 :: Signal dom (Maybe (Unsigned 14, BitVector 4))
wrM2 = Nyb
-> BitVector 16
-> Unsigned 14
-> Bit
-> BitVector 4
-> Maybe (Unsigned 14, BitVector 4)
writeGuard Nyb
Nyb2 (BitVector 16
 -> Unsigned 14
 -> Bit
 -> BitVector 4
 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 16)
-> Signal
     dom
     (Unsigned 14
      -> Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (BitVector 16)
dataIn Signal
  dom
  (Unsigned 14
   -> Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom (Unsigned 14)
-> Signal
     dom (Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom (Unsigned 14)
addressU Signal dom (Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom Bit
-> Signal dom (BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom Bit
wrEn Signal dom (BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 4)
-> Signal dom (Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom (BitVector 4)
maskWrEn
    wrM1 :: Signal dom (Maybe (Unsigned 14, BitVector 4))
wrM1 = Nyb
-> BitVector 16
-> Unsigned 14
-> Bit
-> BitVector 4
-> Maybe (Unsigned 14, BitVector 4)
writeGuard Nyb
Nyb1 (BitVector 16
 -> Unsigned 14
 -> Bit
 -> BitVector 4
 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 16)
-> Signal
     dom
     (Unsigned 14
      -> Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (BitVector 16)
dataIn Signal
  dom
  (Unsigned 14
   -> Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom (Unsigned 14)
-> Signal
     dom (Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom (Unsigned 14)
addressU Signal dom (Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom Bit
-> Signal dom (BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom Bit
wrEn Signal dom (BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 4)
-> Signal dom (Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom (BitVector 4)
maskWrEn
    wrM0 :: Signal dom (Maybe (Unsigned 14, BitVector 4))
wrM0 = Nyb
-> BitVector 16
-> Unsigned 14
-> Bit
-> BitVector 4
-> Maybe (Unsigned 14, BitVector 4)
writeGuard Nyb
Nyb0 (BitVector 16
 -> Unsigned 14
 -> Bit
 -> BitVector 4
 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 16)
-> Signal
     dom
     (Unsigned 14
      -> Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (BitVector 16)
dataIn Signal
  dom
  (Unsigned 14
   -> Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom (Unsigned 14)
-> Signal
     dom (Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom (Unsigned 14)
addressU Signal dom (Bit -> BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom Bit
-> Signal dom (BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom Bit
wrEn Signal dom (BitVector 4 -> Maybe (Unsigned 14, BitVector 4))
-> Signal dom (BitVector 4)
-> Signal dom (Maybe (Unsigned 14, BitVector 4))
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom (BitVector 4)
maskWrEn
    nybSlice :: Nyb -> BitVector 16 -> BitVector 4
nybSlice = \case
      Nyb
Nyb3 -> SNat 15 -> SNat 12 -> BitVector 16 -> BitVector ((15 + 1) - 12)
forall a (m :: Nat) (i :: Nat) (n :: Nat).
(BitPack a, BitSize a ~ ((m + 1) + i)) =>
SNat m -> SNat n -> a -> BitVector ((m + 1) - n)
slice SNat 15
d15 SNat 12
d12
      Nyb
Nyb2 -> SNat 11 -> SNat 8 -> BitVector 16 -> BitVector ((11 + 1) - 8)
forall a (m :: Nat) (i :: Nat) (n :: Nat).
(BitPack a, BitSize a ~ ((m + 1) + i)) =>
SNat m -> SNat n -> a -> BitVector ((m + 1) - n)
slice SNat 11
d11 SNat 8
d8
      Nyb
Nyb1 -> SNat 7 -> SNat 4 -> BitVector 16 -> BitVector ((7 + 1) - 4)
forall a (m :: Nat) (i :: Nat) (n :: Nat).
(BitPack a, BitSize a ~ ((m + 1) + i)) =>
SNat m -> SNat n -> a -> BitVector ((m + 1) - n)
slice SNat 7
d7  SNat 4
d4
      Nyb
Nyb0 -> SNat 3 -> SNat 0 -> BitVector 16 -> BitVector ((3 + 1) - 0)
forall a (m :: Nat) (i :: Nat) (n :: Nat).
(BitPack a, BitSize a ~ ((m + 1) + i)) =>
SNat m -> SNat n -> a -> BitVector ((m + 1) - n)
slice SNat 3
d3  SNat 0
d0
    nybMask :: Nyb -> BitVector 4 -> Bit
nybMask = \case
      Nyb
Nyb3 -> (BitVector 4 -> Index 4 -> Bit
forall a i. (BitPack a, Enum i) => a -> i -> Bit
!(Index 4
3 :: Index 4))
      Nyb
Nyb2 -> (BitVector 4 -> Index 4 -> Bit
forall a i. (BitPack a, Enum i) => a -> i -> Bit
!(Index 4
2 :: Index 4))
      Nyb
Nyb1 -> (BitVector 4 -> Index 4 -> Bit
forall a i. (BitPack a, Enum i) => a -> i -> Bit
!(Index 4
1 :: Index 4))
      Nyb
Nyb0 -> (BitVector 4 -> Index 4 -> Bit
forall a i. (BitPack a, Enum i) => a -> i -> Bit
!(Index 4
0 :: Index 4))
    writeGuard :: Nyb
-> BitVector 16
-> Unsigned 14
-> Bit
-> BitVector 4
-> Maybe (Unsigned 14, BitVector 4)
writeGuard Nyb
n BitVector 16
dIn Unsigned 14
addr Bit
en BitVector 4
mask
      | Bit -> Bool
bitToBool Bit
en Bool -> Bool -> Bool
&& (Bool -> Bool
not(Bool -> Bool) -> (Bit -> Bool) -> Bit -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Bit -> Bool
bitToBool) (Nyb -> BitVector 4 -> Bit
nybMask Nyb
n BitVector 4
mask) = (Unsigned 14, BitVector 4) -> Maybe (Unsigned 14, BitVector 4)
forall a. a -> Maybe a
Just (Unsigned 14
addr, Nyb -> BitVector 16 -> BitVector 4
nybSlice Nyb
n BitVector 16
dIn)
      | Bool
otherwise = Maybe (Unsigned 14, BitVector 4)
forall a. Maybe a
Nothing