packages feed

ice40-prim-0.3.0.1: src/Ice40/Led.hs

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

LED hard IP primitive from [Lattice Ice Technology Library](https://github.com/standardsemiconductor/VELDT-info/blob/master/SBTICETechnologyLibrary201708.pdf). See [iCE40 LED Driver Usage Guide](https://github.com/standardsemiconductor/VELDT-info/blob/master/ICE40LEDDriverUsageGuide.pdf) for more information.
-}
module Ice40.Led ( led ) where

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

{-# ANN ledPrim (InlinePrimitive [Verilog] $ unindent [i|
  [  { "BlackBox" :
       { "name" : "Ice40.Led.ledPrim"
       , "kind" : "Declaration"
       , "type" :
  "ledPrim
  :: Signal dom Bit       -- ARG[0]  leddcs
  -> Clock dom            -- ARG[1]  leddclk
  -> Signal dom Bit       -- ARG[2]  ledddat7
  -> Signal dom Bit       -- ARG[3]  ledddat6
  -> Signal dom Bit       -- ARG[4]  ledddat5
  -> Signal dom Bit       -- ARG[5]  ledddat4
  -> Signal dom Bit       -- ARG[6]  ledddat3
  -> Signal dom Bit       -- ARG[7]  ledddat2
  -> Signal dom Bit       -- ARG[8]  ledddat1
  -> Signal dom Bit       -- ARG[9]  ledddat0
  -> Signal dom Bit       -- ARG[10] leddaddr3
  -> Signal dom Bit       -- ARG[11] leddaddr2
  -> Signal dom Bit       -- ARG[12] leddaddr1
  -> Signal dom Bit       -- ARG[13] leddaddr0
  -> Signal dom Bool      -- ARG[14] leddden
  -> Signal dom Bool      -- ARG[15] leddexe
  -> Unbundled dom ( Bit  -- pwmOut0
                   , Bit  -- pwmOut1
                   , Bit  -- pwmOut2
                   , Bool -- leddon
                   )"
      , "template" :
  "//SB_LEDDA_IP begin
  wire ~GENSYM[pwmOut0][0];
  wire ~GENSYM[pwmOut1][1];
  wire ~GENSYM[pwmOut2][2];
  wire ~GENSYM[leddon][3];

  SB_LEDDA_IP SB_LEDDA_IP_INST (
    .LEDDCS    ( ~ARG[0]  ),
    .LEDDCLK   ( ~ARG[1]  ),
    .LEDDDAT7  ( ~ARG[2]  ),
    .LEDDDAT6  ( ~ARG[3]  ),
    .LEDDDAT5  ( ~ARG[4]  ),
    .LEDDDAT4  ( ~ARG[5]  ),
    .LEDDDAT3  ( ~ARG[6]  ),
    .LEDDDAT2  ( ~ARG[7]  ),
    .LEDDDAT1  ( ~ARG[8]  ),
    .LEDDDAT0  ( ~ARG[9]  ),
    .LEDDADDR3 ( ~ARG[10] ),
    .LEDDADDR2 ( ~ARG[11] ),
    .LEDDADDR1 ( ~ARG[12] ),
    .LEDDADDR0 ( ~ARG[13] ),
    .LEDDDEN   ( ~ARG[14] ),
    .LEDDEXE   ( ~ARG[15] ),

    .PWMOUT0   ( ~SYM[0]  ),
    .PWMOUT1   ( ~SYM[1]  ),
    .PWMOUT2   ( ~SYM[2]  ),
    .LEDDON    ( ~SYM[3]  )
  );

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

{-# NOINLINE ledPrim #-}
ledPrim
  :: Signal dom Bit       -- ARG[0]  leddcs - CS to write LEDD IP registers
  -> Clock dom            -- ARG[1]  leddclk - Clock to write LEDD IP registers
  -> Signal dom Bit       -- ARG[2]  ledddat7 - bit 7 data to write into the LEDD IP registers
  -> Signal dom Bit       -- ARG[3]  ledddat6 - bit 6 data to write into the LEDD IP registers
  -> Signal dom Bit       -- ARG[4]  ledddat5 - bit 5 data to write into the LEDD IP registers
  -> Signal dom Bit       -- ARG[5]  ledddat4 - bit 4 data to write into the LEDD IP registers
  -> Signal dom Bit       -- ARG[6]  ledddat3 - bit 3 data to write into the LEDD IP registers
  -> Signal dom Bit       -- ARG[7]  ledddat2
  -> Signal dom Bit       -- ARG[8]  ledddat1
  -> Signal dom Bit       -- ARG[9]  ledddat0
  -> Signal dom Bit       -- ARG[10] leddaddr3
  -> Signal dom Bit       -- ARG[11] leddaddr2
  -> Signal dom Bit       -- ARG[12] leddaddr1
  -> Signal dom Bit       -- ARG[13] leddaddr0
  -> Signal dom Bool      -- ARG[14] leddden
  -> Signal dom Bool      -- ARG[15] leddexe
  -> Unbundled dom ( Bit  -- pwmOut0
                   , Bit  -- pwmOut1
                   , Bit  -- pwmOut2
                   , Bool -- leddon
                   )
ledPrim !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ = (pure 0, pure 0, pure 0, pure False)

-- | SB_LEDDA_IP primitive generates the RGB PWM outputs for the RGB LED drivers. 
-- 
-- LED Control Bus Addressable Registers
--
-- +---------------+----------+-------------------------------------------+--------+
-- | LEDD_ADR[3:0] | Name     | Usage                                     | Access |
-- +===============+==========+===========================================+========+
-- | 1000          | LEDDCR0  | LED Driver Control Register 0             | W      |
-- +---------------+----------+-------------------------------------------+--------+
-- | 1001          | LEDDBR   | LED Driver Pre-scale Register             | W      |
-- +---------------+----------+-------------------------------------------+--------+
-- | 1010          | LEDDONR  | LED Driver ON Time Register               | W      |
-- +---------------+----------+-------------------------------------------+--------+
-- | 1011          | LEDDOFR  | LED Driver OFF Time Register              | W      |
-- +---------------+----------+-------------------------------------------+--------+
-- | 0101          | LEDDBCRR | LED Driver Breathe On Control Register    | W      |
-- +---------------+----------+-------------------------------------------+--------+
-- | 0110          | LEDDBCFR | LED Driver Breate Off Control Register    | W      |
-- +---------------+----------+-------------------------------------------+--------+
-- | 0001          | LEDDPWRR | LED Driver Pulse Width Register for RED   | W      |
-- +---------------+----------+-------------------------------------------+--------+
-- | 0010          | LEDDPWRG | LED Driver Pulse Width Register for GREEN | W      |
-- +---------------+----------+-------------------------------------------+--------+
-- | 0011          | LEDDPWRB | LED Driver Pulse Width Register for BLUE  | W      |
-- +---------------+----------+-------------------------------------------+--------+
led
  :: HiddenClock dom
  => Signal dom Bit           -- ^ cs - CS to write LEDD IP registers
  -> Signal dom (BitVector 8) -- ^ dat - data to write into the LEDD IP registers
  -> Signal dom (BitVector 4) -- ^ addr - LEDD IP register address
  -> Signal dom Bool          -- ^ en - data enable input to indicate data and address are stable
  -> Signal dom Bool          -- ^ exe - enable to IP to run the blinking sequence. When it is LOW, the sequence stops at the nearest OFF state
  -> Unbundled dom ( Bit 
                   , Bit 
                   , Bit 
                   , Bool
                   ) -- ^ (pwmOut0, pwmOut1, pwmOut2, LED on indicator)
led cs dat addr en exe = (pwmOut0, pwmOut1, pwmOut2, on)
  where
    (pwmOut0, pwmOut1, pwmOut2, on) = ledPrim cs
                                              hasClock
                                              (bitAt 7 dat)
                                              (bitAt 6 dat)
                                              (bitAt 5 dat)
                                              (bitAt 4 dat)
                                              (bitAt 3 dat)
                                              (bitAt 2 dat)
                                              (bitAt 1 dat)
                                              (bitAt 0 dat)
                                              (bitAt 3 addr)
                                              (bitAt 2 addr)
                                              (bitAt 1 addr)
                                              (bitAt 0 addr)
                                              en
                                              exe

 
bitAt :: KnownNat n => Index n -> Signal dom (BitVector n) -> Signal dom Bit
bitAt n = fmap (!n)