packages feed

ice40-prim-0.3.1.0: src/Ice40/IO.hs

{-|
Module      : Ice40.IO
Description : Ice40 IO hard IP primitives
Copyright   : (c) David Cox, 2021
License     : BSD 3-Clause
Maintainer  : standardsemiconductor@gmail.com

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

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

{-# ANN ioPrim (InlinePrimitive [Verilog] $ unindent [i|
  [  { "BlackBox" :
       { "name" : "Ice40.IO.ioPrim"
       , "kind" : "Declaration"
       , "type" :
  "ioPrim
    :: BitVector 6         -- ARG[0]  pinType
    -> Bit                 -- ARG[1]  pullup
    -> Bit                 -- ARG[2]  negTrigger
    -> String              -- ARG[3]  ioStandard
    -> Signal domIn Bit    -- ARG[4]  latchInputValue
    -> Signal domEn Bit    -- ARG[5]  clockEnable
    -> Clock domIn         -- ARG[6]  inputClk
    -> Clock domOut        -- ARG[7]  outputClk
    -> Signal domOut Bit   -- ARG[8]  outputEnable
    -> Signal domOut Bit   -- ARG[9]  dOut0
    -> Signal domOut Bit   -- ARG[10] dOut1
    -> ( Signal domPin Bit -- packagePin
       , Signal domIn Bit  -- dIn0
       , Signal domIn Bit  -- dIn1
       )"
       , "template" :
  "//SB_IO begin
  wire ~GENSYM[package_pin][0];
  wire ~GENSYM[d_in_0][1];
  wire ~GENSYM[d_in_1][2];

  SB_IO #(
    .PIN_TYPE         ( ~ARG[0]  ),
    .PULLUP           ( ~ARG[1]  ),
    .NEG_TRIGGER      ( ~ARG[2]  ),
    .IO_STANDARD      ( ~ARG[3]  )
  ) ~GENSYM[sb_io_inst][3] (
    .PACKAGE_PIN      ( ~SYM[0]  ),
    .LATCH_INPUT_VALUE( ~ARG[4]  ),
    .CLOCK_ENABLE     ( ~ARG[5]  ),
    .INPUT_CLK        ( ~ARG[6]  ),
    .OUTPUT_CLK       ( ~ARG[7]  ),
    .OUTPUT_ENABLE    ( ~ARG[8]  ),
    .D_OUT_0          ( ~ARG[9]  ),
    .D_OUT_1          ( ~ARG[10] ),
    .D_IN_0           ( ~SYM[1]  ),
    .D_IN_1           ( ~SYM[2]  )
  );

  assign ~RESULT = { ~SYM[0], ~SYM[1], ~SYM[2] };
  //SB_IO end"
       }
     }
  ]
  |]) #-}

-- | IO primitive, see io for wrapper
{-# NOINLINE ioPrim #-}
ioPrim
  :: BitVector 6         -- ^ pinType
  -> Bit                 -- ^ pullup
  -> Bit                 -- ^ negTrigger
  -> String              -- ^ ioStandard
  -> Signal domIn Bit    -- ^ latchInputValue
  -> Signal domEn Bit    -- ^ clockEnable
  -> Clock domIn         -- ^ inputClk
  -> Clock domOut        -- ^ outputClk
  -> Signal domOut Bit   -- ^ outputEnable
  -> Signal domOut Bit   -- ^ dOut0
  -> Signal domOut Bit   -- ^ dOut1
  -> ( Signal domPin Bit -- packagePin
     , Signal domIn Bit  -- dIn0
     , Signal domIn Bit  -- dIn1
     ) -- ^ (packagePin, dIn0, dIn1)
ioPrim !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ = (pure 0, pure 0, pure 0)

-- | Input pin configuration parameter
data PinInput = PinInput -- ^ Simple Input pin dIn0
              | PinInputLatch -- ^ Disables Internal data changes on the physical input pin by latching the value
              | PinInputRegistered -- ^ Input data is registered in input cell
              | PinInputRegisteredLatch -- ^ Disables internal data changes on the physical input pin by latching the value on the input register
              | PinInputDDR -- ^ Input DDR data is clocked out on rising and falling clock edges. Use the dIn0 and dIn1 pins for DDR operation
  deriving stock (Generic, Show, Read, Eq)
  deriving anyclass NFDataX

-- | Convert `PinInput` to underlying `BitVector`
fromPinInput :: PinInput -> BitVector 2
fromPinInput = \case
  PinInput                -> 0b01
  PinInputLatch           -> 0b11
  PinInputRegistered      -> 0b00
  PinInputRegisteredLatch -> 0b10
  PinInputDDR             -> 0b00

-- | Output pin configuration parameter
data PinOutput = PinNoOutput -- ^Disables the output function
               | PinOutput -- ^ Simple output pin (no enable)
               | PinOutputTristate -- ^ The output pin may be tristated using the enable
               | PinOutputEnableRegistered -- ^ The output pin may be tristated using a registered enable signal
               | PinOutputRegistered -- ^ Output registered (no enable)
               | PinOutputRegisteredEnable -- ^ Output registered with enable (the enable is not registered)
               | PinOutputRegisteredEnableRegistered -- ^ Output registered and enable registered
               | PinOutputDDR -- ^ Output DDR data is clocked out on rising and falling clock edges
               | PinOutputDDREnable -- ^ Output data is clocked out on rising and falling clock edges
               | PinOutputDDREnableRegistered -- ^ Output DDR data with registered enable signal
               | PinOutputRegisteredInverted -- ^ Output registered signal is inverted
               | PinOutputRegisteredEnableInverted -- ^ Output signal is registered and inverted (no enable function)
               | PinOutputRegisteredEnableRegisteredInverted -- ^ Output signal is registered and inverted, the enable/tristate control is registered
  deriving stock (Generic, Show, Read, Eq)
  deriving anyclass NFDataX

-- | Convert `PinOutput` to underlying `BitVector`
fromPinOutput :: PinOutput -> BitVector 4
fromPinOutput = \case
  PinNoOutput                                 -> 0b0000
  PinOutput                                   -> 0b0110
  PinOutputTristate                           -> 0b1010
  PinOutputEnableRegistered                   -> 0b1110
  PinOutputRegistered                         -> 0b0101
  PinOutputRegisteredEnable                   -> 0b1001
  PinOutputRegisteredEnableRegistered         -> 0b1101
  PinOutputDDR                                -> 0b0100
  PinOutputDDREnable                          -> 0b1000
  PinOutputDDREnableRegistered                -> 0b1100
  PinOutputRegisteredInverted                 -> 0b0111
  PinOutputRegisteredEnableInverted           -> 0b1011
  PinOutputRegisteredEnableRegisteredInverted -> 0b1111

-- | Input-Output Standards
data IOStandard = SBLVCMOS
                | SBLVDSINPUT
  deriving (Generic, Show, Read, Eq)

-- | Convert `IOStandard` to underlying `String`
fromIOStandard :: IOStandard -> String
fromIOStandard = \case
  SBLVCMOS    -> "SB_LVCMOS"
  SBLVDSINPUT -> "SB_LVDS_INPUT"

-- | IO primitive
io
  :: PinInput
  -> PinOutput
  -> Bit                 -- ^ pullUp
  -> Bit                 -- ^ negTrigger
  -> IOStandard
  -> Signal domIn Bit    -- ^ latchInputValue
  -> Signal domEn Bit    -- ^ clockEnable
  -> Clock domIn         -- ^ inputClk
  -> Clock domOut        -- ^ outputClk
  -> Signal domOut Bit   -- ^ outputEnable
  -> Signal domOut Bit   -- ^ dOut0
  -> Signal domOut Bit   -- ^ dOut1
  -> ( Signal domPin Bit -- packagePin
     , Signal domIn Bit  -- dIn0
     , Signal domIn Bit  -- dIn1
     ) -- ^ (packagePin, dIn0, dIn1)
io pinInput pinOutput pullUp negTrigger ioStandard
  = ioPrim
      (fromPinOutput pinOutput ++# fromPinInput pinInput)
      pullUp
      negTrigger
      (fromIOStandard ioStandard)