packages feed

ice40-prim (empty) → 0.1.0.0

raw patch · 14 files changed

+1573/−0 lines, 14 filesdep +Cabaldep +basedep +clash-preludesetup-changed

Dependencies added: Cabal, base, clash-prelude, ghc-typelits-extra, ghc-typelits-knownnat, ghc-typelits-natnormalise, interpolate

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for ice40-prim++## 0.1.0.0 -- 2021-02-15++* First version. 
+ LICENSE view
@@ -0,0 +1,29 @@+BSD 3-Clause License++Copyright (c) 2020, dopamane+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice, this+   list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright notice,+   this list of conditions and the following disclaimer in the documentation+   and/or other materials provided with the distribution.++3. Neither the name of the copyright holder nor the names of its+   contributors may be used to endorse or promote products derived from+   this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,74 @@+# ice40-prim+![Haskell CI](https://github.com/standardsemiconductor/ice40-prim/workflows/Haskell%20CI/badge.svg)++Lattice iCE40 Primitive IP+## Supported IP Modules+* [Ice40.Spram](https://github.com/standardsemiconductor/ice40-prim/blob/main/src/Ice40/Spram.hs) - For more information see the [iCE40 SPRAM Usage Guide](https://github.com/standardsemiconductor/VELDT-info/blob/master/FPGA-TN-02022-1-2-iCE40-SPRAM-Usage-Guide.pdf)+  * sysMem Single Port RAM Memory (SPRAM)+  * Each block of SPRAM is 16k x 16 (256 kbits)+  * 16-bit data width with nibble mast control+  * Cascadable design for deeper/wider SPRAM+  * Three power modes, standby, sleep, and power off++* [Ice40.Mac](https://github.com/standardsemiconductor/ice40-prim/blob/main/src/Ice40/Mac.hs) - For more information see the [DSP Function Usage Guide PDF](https://github.com/standardsemiconductor/VELDT-info/blob/master/DSPFunctionUsageGuideforICE40Devices.pdf)+  * 16-bit x 16-bit Multiplier, or two independent 8-bit x 8-bit multipliers+  * Optional independent pipeline control on input Register, Output Register, and Intermediate Register for faster clock performance+  * 32-bit accumulator, or two independent 16-bit accumulators+  * 32-bit, or two independent 16-bit adder/subtractor functions, registered or asynchronous+  * Cascadable to create wider accumulator blocks++* [Ice40.Osc](https://github.com/standardsemiconductor/ice40-prim/blob/main/src/Ice40/Osc.hs)+  * on-chip oscillator+  * Low-power low frequency oscillator of 10 kHz+  * High frequency oscillator configurable to 48 Mhz, 24 Mhz, 12 Mhz, or 6 Mhz+  * See also [Ice40.Clock](https://github.com/standardsemiconductor/ice40-prim/blob/main/src/Ice40/Clock.hs) for clock domains and reset++* [Ice40.Rgb](https://github.com/standardsemiconductor/ice40-prim/blob/main/src/Ice40/Rgb.hs) - For more information see the [iCE40 LED Driver Usage Guide](https://github.com/standardsemiconductor/VELDT-info/blob/master/ICE40LEDDriverUsageGuide.pdf)+  * RGB High Current Drive I/O Pins+  * Provides sinking current to an LED connecting to the positive supply+  * Three outputs designed to drive the RGB LEDs+  * RGB drive current is user programmable from 4mA to 24mA, in increments of 4mA++* [Ice40.Led](https://github.com/standardsemiconductor/ice40-prim/blob/main/src/Ice40/Led.hs) - For more information see the [iCE40 LED Driver Usage Guide PDF](https://github.com/standardsemiconductor/VELDT-info/blob/master/ICE40LEDDriverUsageGuide.pdf)+  * LED PWM IP+  * Provide easier usage of RGB high current drivers+  * Provides flexibility for user to dynamically change the modulation width of each of the RGB LED driver+  * User can dynamically change ON and OFF-time durations+  * Ability to turn LEDs on and off gradually with breath-on and breath-off time++* [Ice40.Spi](https://github.com/standardsemiconductor/ice40-prim/blob/main/src/Ice40/Spi.hs) - For more information see the [Advanced SPI and I2C Usage Guide PDF](https://github.com/standardsemiconductor/VELDT-info/blob/master/AdvancediCE40SPII2CHardenedIPUsageGuide.pdf)+  * User SPI IP+  * Configurable Boss and Worker modes+  * Full-Duplex data transfer+  * Mode fault error flag with CPU interrupt capability+  * Double-buffered data register+  * Serial clock with programmable polarity and phase+  * LSB First or MSB First data transfer++* [Ice40.IO](https://github.com/standardsemiconductor/ice40-prim/blob/main/src/Ice40/IO.hs)+  * sysIO++* [Ice40.I2c](https://github.com/standardsemiconductor/ice40-prim/blob/main/src/Ice40/I2c.hs) - For more information see the [Advanced SPI and I2C Usage Guide PDF](https://github.com/standardsemiconductor/VELDT-info/blob/master/AdvancediCE40SPII2CHardenedIPUsageGuide.pdf)+  * User I2C IP+  * Boss and Worker operation+  * 7-bit and 10-bit addressing+  * Multi-master arbitration support+  * Clock stretching+  * Up to 400 kHz data transfer speed+  * General Call support+  * Optionally delaying input or output data, or both+  * Optional filter on SCL input++## Lattice Documentation++[iCE40 UltraPlus Family Data Sheet PDF](https://github.com/standardsemiconductor/VELDT-info/blob/master/FPGA-DS-02008-1-9-iCE40-UltraPlus-Family-Data-Sheet.pdf)++[iCE Technology Library PDF](https://github.com/standardsemiconductor/VELDT-info/blob/master/SBTICETechnologyLibrary201708.pdf)++[Advanced SPI and I2C Usage Guide PDF](https://github.com/standardsemiconductor/VELDT-info/blob/master/AdvancediCE40SPII2CHardenedIPUsageGuide.pdf)++[iCE40 LED Driver Usage Guide PDF](https://github.com/standardsemiconductor/VELDT-info/blob/master/ICE40LEDDriverUsageGuide.pdf)++[iCE40 SPRAM Usage Guide](https://github.com/standardsemiconductor/VELDT-info/blob/master/FPGA-TN-02022-1-2-iCE40-SPRAM-Usage-Guide.pdf)++[DSP Function Usage Guide PDF](https://github.com/standardsemiconductor/VELDT-info/blob/master/DSPFunctionUsageGuideforICE40Devices.pdf)
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ ice40-prim.cabal view
@@ -0,0 +1,89 @@+cabal-version:       >=1.10+name:                ice40-prim+version:             0.1.0.0+synopsis:            Lattice iCE40 Primitive IP+description:         Clash primitives to instantiate Lattice Semiconductor's iCE40 FPGA hard IP+bug-reports:         https://github.com/standardsemiconductor/ice40-prim/issues+license:             BSD3+license-file:        LICENSE+author:              dopamane+maintainer:          dopamane <standard.semiconductor@gmail.com>+copyright:           Copyright (c) 2020-2021 David Cox+category:            Hardware+build-type:          Simple+extra-source-files:  CHANGELOG.md, README.md++source-repository head+  type: git+  location: git://github.com/standardsemiconductor/ice40-prim.git+                     +library+        exposed-modules: Ice40.Clock,+                         Ice40.Led,+                         Ice40.Mac,+                         Ice40.Osc,+                         Ice40.Spram,+                         Ice40.Rgb,+                         Ice40.Spi,+                         Ice40.I2c,+                         Ice40.IO+        hs-source-dirs: src+        build-depends: base >=4.12 && <4.15,+                       Cabal,+                       interpolate,+                       clash-prelude >=1.2.5 && <1.4,+                       ghc-typelits-natnormalise,+                       ghc-typelits-extra,+                       ghc-typelits-knownnat+        ghc-options:+          -Wall -Wcompat+          -haddock++          -- Plugins to support type-level constraint solving on naturals+          -fplugin GHC.TypeLits.Extra.Solver+          -fplugin GHC.TypeLits.Normalise+          -fplugin GHC.TypeLits.KnownNat.Solver++          -- Worker wrappers introduce unstable names for functions that might+          -- have blackboxes attached for them. You can disable this,+          -- but be sure to add a no-specialize pragma to every function+          -- with a blackbox.+          -fno-worker-wrapper+        default-language: Haskell2010+        default-extensions:+          BangPatterns+          BinaryLiterals+          ConstraintKinds+          DataKinds+          DefaultSignatures+          DeriveAnyClass+          DeriveDataTypeable+          DeriveFoldable+          DeriveFunctor+          DeriveGeneric+          DeriveLift+          DeriveTraversable+          DerivingStrategies+          InstanceSigs+          KindSignatures+          LambdaCase+          NoStarIsType+          MagicHash+          PolyKinds+          RankNTypes+          RecordWildCards+          ScopedTypeVariables+          StandaloneDeriving+          TupleSections+          TypeApplications+          TypeFamilies+          TypeOperators+          ViewPatterns+          +          -- TemplateHaskell is used to support convenience functions such as+          -- 'listToVecTH' and 'bLit'.+          TemplateHaskell+          QuasiQuotes++          -- Prelude isn't imported by default as Clash offers Clash.Prelude+          NoImplicitPrelude
+ src/Ice40/Clock.hs view
@@ -0,0 +1,36 @@+{-|+Module      : Ice40.Clock+Description : Ice40 Clock domains+Copyright   : (c) David Cox, 2021+License     : BSD 3-Clause+Maintainer  : standardsemiconductor@gmail.com++Commonly used clock domains with ice40 IP+-}++{-# OPTIONS_GHC -fno-warn-orphans #-}+module Ice40.Clock+  ( vLattice10kHz+  , Lattice10kHz+  , vLattice48Mhz+  , vLattice24Mhz+  , vLattice12Mhz+  , vLattice6Mhz+  , Lattice48Mhz+  , Lattice24Mhz+  , Lattice12Mhz+  , Lattice6Mhz+  , latticeRst+  ) where++import Clash.Prelude++createDomain vXilinxSystem{vName="Lattice10kHz", vPeriod=100000000}+createDomain vXilinxSystem{vName="Lattice48Mhz", vPeriod=20833}+createDomain vXilinxSystem{vName="Lattice24Mhz", vPeriod=41666}+createDomain vXilinxSystem{vName="Lattice12Mhz", vPeriod=83333}+createDomain vXilinxSystem{vName="Lattice6Mhz",  vPeriod=166660}++-- | Lattice reset signal, always inactive+latticeRst :: KnownDomain dom => Reset dom+latticeRst = unsafeFromHighPolarity $ pure False
+ src/Ice40/I2c.hs view
@@ -0,0 +1,231 @@+{-|+Module      : Ice40.I2c+Description : Ice40 I2C hard IP primitive+Copyright   : (c) David Cox, 2021+License     : BSD 3-Clause+Maintainer  : standardsemiconductor@gmail.com++I2C hard IP primitive from Lattice Ice Technology Library https://github.com/standardsemiconductor/VELDT-info/blob/master/SBTICETechnologyLibrary201708.pdf+-}+module Ice40.I2c ( i2c ) where++import Clash.Prelude+import Clash.Annotations.Primitive+import Data.String.Interpolate (i)+import Data.String.Interpolate.Util (unindent)++{-# ANN i2cPrim (InlinePrimitive [Verilog] $ unindent [i|+  [  { "BlackBox" :+       { "name" : "Ice40.I2c.i2cPrim"+       , "kind" : "Declaration"+       , "type" :+  "i2cPrim+    :: String          -- ARG[0]  initAddr+    -> String          -- ARG[1]  busAddr+    -> Clock dom       -- ARG[2]  sbclki+    -> Signal dom Bool -- ARG[3]  sbrwi+    -> Signal dom Bool -- ARG[4]  sbstbi+    -> Signal dom Bit  -- ARG[5]  sbadri7+    -> Signal dom Bit  -- ARG[6]  sbadri6+    -> Signal dom Bit  -- ARG[7]  sbadri5+    -> Signal dom Bit  -- ARG[8]  sbadri4+    -> Signal dom Bit  -- ARG[9]  sbadri3+    -> Signal dom Bit  -- ARG[10] sbadri2+    -> Signal dom Bit  -- ARG[11] sbadri1+    -> Signal dom Bit  -- ARG[12] sbadri0+    -> Signal dom Bit  -- ARG[13] sbdati7+    -> Signal dom Bit  -- ARG[14] sbdati6+    -> Signal dom Bit  -- ARG[15] sbdati5+    -> Signal dom Bit  -- ARG[16] sbdati4+    -> Signal dom Bit  -- ARG[17] sbdati3+    -> Signal dom Bit  -- ARG[18] sbdati2+    -> Signal dom Bit  -- ARG[19] sbdati1+    -> Signal dom Bit  -- ARG[20] sbdati0+    -> Signal dom Bit  -- ARG[21] scli+    -> Signal dom Bit  -- ARG[22] sdai+    -> Unbundled dom+         ( BitVector 8 -- sbdato+         , Bool        -- sbacko+         , Bit         -- i2cirq+         , Bit         -- i2cwkup+         , Bit         -- sclo+         , Bit         -- scloe+         , Bit         -- sdao+         , Bit         -- sdaoe+         )"+       , "template" :+  "//SB_I2C begin+  wire ~GENSYM[sbdato7][0];+  wire ~GENSYM[sbdato6][1];+  wire ~GENSYM[sbdato5][2];+  wire ~GENSYM[sbdato4][3];+  wire ~GENSYM[sbdato3][4];+  wire ~GENSYM[sbdato2][5];+  wire ~GENSYM[sbdato1][6];+  wire ~GENSYM[sbdato0][7];+  wire ~GENSYM[sbacko][8];+  wire ~GENSYM[i2cirq][9];+  wire ~GENSYM[i2cwkup][10];+  wire ~GENSYM[sclo][11];+  wire ~GENSYM[scloe][12];+  wire ~GENSYM[sdao][13];+  wire ~GENSYM[sdaoe][14];++  SB_I2C #(+    .I2C_SLAVE_INIT_ADDR ( ~ARG[0] ),+    .BUS_ADDR74          ( ~ARG[1] )+  ) ~GENSYM[sb_i2c_inst][15] (+    .SBCLKI  ( ~ARG[2]  ),+    .SBRWI   ( ~ARG[3]  ),+    .SBSTBI  ( ~ARG[4]  ),+    .SBADRI7 ( ~ARG[5]  ),+    .SBADRI6 ( ~ARG[6]  ),+    .SBADRI5 ( ~ARG[7]  ),+    .SBADRI4 ( ~ARG[8]  ),+    .SBADRI3 ( ~ARG[9]  ),+    .SBADRI2 ( ~ARG[10] ),+    .SBADRI1 ( ~ARG[11] ),+    .SBADRI0 ( ~ARG[12] ),+    .SBDATI7 ( ~ARG[13] ),+    .SBDATI6 ( ~ARG[14] ),+    .SBDATI5 ( ~ARG[15] ),+    .SBDATI4 ( ~ARG[16] ),+    .SBDATI3 ( ~ARG[17] ),+    .SBDATI2 ( ~ARG[18] ),+    .SBDATI1 ( ~ARG[19] ),+    .SBDATI0 ( ~ARG[20] ),+    .SCLI    ( ~ARG[21] ),+    .SDAI    ( ~ARG[22] ),+    .SBDATO7 ( ~SYM[0]  ),+    .SBDATO6 ( ~SYM[1]  ),+    .SBDATO5 ( ~SYM[2]  ),+    .SBDATO4 ( ~SYM[3]  ),+    .SBDATO3 ( ~SYM[4]  ),+    .SBDATO2 ( ~SYM[5]  ),+    .SBDATO1 ( ~SYM[6]  ),+    .SBDATO0 ( ~SYM[7]  ),+    .SBACKO  ( ~SYM[8]  ),+    .I2CIRQ  ( ~SYM[9]  ),+    .I2CWKUP ( ~SYM[10] ),+    .SCLO    ( ~SYM[11] ),+    .SCLOE   ( ~SYM[12] ),+    .SDAO    ( ~SYM[13] ),+    .SDAOE   ( ~SYM[14] )+  );++  assign ~RESULT = { ~SYM[0]  // sbdato7+                   , ~SYM[1]  // sbdato6+                   , ~SYM[2]  // sbdato5+                   , ~SYM[3]  // sbdato4+                   , ~SYM[4]  // sbdato3+                   , ~SYM[5]  // sbdato2+                   , ~SYM[6]  // sbdato1+                   , ~SYM[7]  // sbdato0+                   , ~SYM[8]  // sbacko+                   , ~SYM[9]  // i2cirq+                   , ~SYM[10] // i2cwkup+                   , ~SYM[11] // sclo+                   , ~SYM[12] // scloe+                   , ~SYM[13] // sdao+                   , ~SYM[14] // sdaoe+                   };+  //SB_I2C end"+       }+     }+  ]+  |]) #-}++{-# NOINLINE i2cPrim #-}+i2cPrim+  :: String          -- ARG[0]  initAddr+  -> String          -- ARG[1]  busAddr+  -> Clock dom       -- ARG[2]  sbclki+  -> Signal dom Bool -- ARG[3]  sbrwi+  -> Signal dom Bool -- ARG[4]  sbstbi+  -> Signal dom Bit  -- ARG[5]  sbadri7+  -> Signal dom Bit  -- ARG[6]  sbadri6+  -> Signal dom Bit  -- ARG[7]  sbadri5+  -> Signal dom Bit  -- ARG[8]  sbadri4+  -> Signal dom Bit  -- ARG[9]  sbadri3+  -> Signal dom Bit  -- ARG[10] sbadri2+  -> Signal dom Bit  -- ARG[11] sbadri1+  -> Signal dom Bit  -- ARG[12] sbadri0+  -> Signal dom Bit  -- ARG[13] sbdati7+  -> Signal dom Bit  -- ARG[14] sbdati6+  -> Signal dom Bit  -- ARG[15] sbdati5+  -> Signal dom Bit  -- ARG[16] sbdati4+  -> Signal dom Bit  -- ARG[17] sbdati3+  -> Signal dom Bit  -- ARG[18] sbdati2+  -> Signal dom Bit  -- ARG[19] sbdati1+  -> Signal dom Bit  -- ARG[20] sbdati0+  -> Signal dom Bit  -- ARG[21] scli+  -> Signal dom Bit  -- ARG[22] sdai+  -> Unbundled dom+       ( BitVector 8 -- sbdato+       , Bool        -- sbacko+       , Bit         -- i2cirq+       , Bit         -- i2cwkup+       , Bit         -- sclo+       , Bit         -- scloe+       , Bit         -- sdao+       , Bit         -- sdaoe+       )+i2cPrim !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_+  = unbundle $ pure ( 0+                    , False+                    , 0+                    , 0+                    , 0+                    , 0+                    , 0+                    , 0+                    )++-- | I2C primitive wrapper+i2c+  :: HiddenClock dom+  => String                   -- ^ initAddr+  -> String                   -- ^ busAddr+  -> Signal dom Bool          -- ^ sbrwi+  -> Signal dom Bool          -- ^ sbstbi+  -> Signal dom (BitVector 8) -- ^ sbadri+  -> Signal dom (BitVector 8) -- ^ sbdati+  -> Signal dom Bit           -- ^ scli+  -> Signal dom Bit           -- ^ sdai+  -> Unbundled dom+       ( BitVector 8 -- sbdato+       , Bool        -- sbacko+       , Bit         -- i2cirq+       , Bit         -- i2cwkup+       , Bit         -- sclo+       , Bit         -- scloe+       , Bit         -- sdao+       , Bit         -- sdaoe+       ) -- ^ (sbdato, sbacko, i2cirq, i2cwkup, sclo, scloe, sdao, sdaoe)+i2c initAddr busAddr sbrwi sbstbi sbadri sbdati scli sdai =+  i2cPrim initAddr+          busAddr+          hasClock+          sbrwi+          sbstbi+          (bitAt 7 sbadri)+          (bitAt 6 sbadri)+          (bitAt 5 sbadri)+          (bitAt 4 sbadri)+          (bitAt 3 sbadri)+          (bitAt 2 sbadri)+          (bitAt 1 sbadri)+          (bitAt 0 sbadri)+          (bitAt 7 sbdati)+          (bitAt 6 sbdati)+          (bitAt 5 sbdati)+          (bitAt 4 sbdati)+          (bitAt 3 sbdati)+          (bitAt 2 sbdati)+          (bitAt 1 sbdati)+          (bitAt 0 sbdati)+          scli+          sdai++bitAt :: KnownNat n => Index n -> Signal dom (BitVector n) -> Signal dom Bit+bitAt n = fmap (!n)
+ src/Ice40/IO.hs view
@@ -0,0 +1,173 @@+{-|+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++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++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)++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)+
+ src/Ice40/Led.hs view
@@ -0,0 +1,140 @@+{-|+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+-}+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. The IP contains registers that are programmed in byte the SCI bus interface signals.+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)
+ src/Ice40/Mac.hs view
@@ -0,0 +1,187 @@+{-|+Module      : Ice40.Mac+Description : Ice40 Multiply-Accumulate (DSP) hard IP primitive+Copyright   : (c) David Cox, 2021+License     : BSD 3-Clause+Maintainer  : standardsemiconductor@gmail.com++Mac hard IP primitive from Lattice Ice Technology Library https://github.com/standardsemiconductor/VELDT-info/blob/master/SBTICETechnologyLibrary201708.pdf+-}+module Ice40.Mac ( macPrim ) where++import Clash.Prelude+import Clash.Annotations.Primitive+import Data.String.Interpolate (i)+import Data.String.Interpolate.Util (unindent)++{-# ANN macPrim (InlinePrimitive [Verilog] $ unindent [i|+  [  { "BlackBox" :+       { "name" : "Ice40.Mac.macPrim"+       , "kind" : "Declaration"+       , "type" :+  "macPrim+  :: Bit                         -- ARG[0]  negTrigger+  -> Bit                         -- ARG[1]  aReg+  -> Bit                         -- ARG[2]  bReg+  -> Bit                         -- ARG[3]  cReg+  -> Bit                         -- ARG[4]  dReg+  -> Bit                         -- ARG[5]  top8x8MultReg+  -> Bit                         -- ARG[6]  bot8x8MultReg+  -> Bit                         -- ARG[7]  pipeline16x16MultReg1+  -> Bit                         -- ARG[8]  pipeline16x16MultReg2+  -> BitVector 2                 -- ARG[9]  topOutputSelect+  -> BitVector 2                 -- ARG[10] topAddSubLowerInput+  -> Bit                         -- ARG[11] topAddSubUpperInput+  -> BitVector 2                 -- ARG[12] topAddSubCarrySelect+  -> BitVector 2                 -- ARG[13] botOutputSelect+  -> BitVector 2                 -- ARG[14] botAddSubLowerInput+  -> Bit                         -- ARG[15] botAddSubUpperInput+  -> BitVector 2                 -- ARG[16] botAddSubCarrySelect+  -> Bit                         -- ARG[17] mode8x8+  -> Bit                         -- ARG[18] aSigned+  -> Bit                         -- ARG[19] bSigned+  -> Clock dom                   -- ARG[20] clk+  -> Signal dom Bit              -- ARG[21] ce+  -> Signal dom (BitVector 16)   -- ARG[22] c+  -> Signal dom (BitVector 16)   -- ARG[23] a+  -> Signal dom (BitVector 16)   -- ARG[24] b+  -> Signal dom (BitVector 16)   -- ARG[25] d+  -> Signal dom Bit              -- ARG[26] irsttop+  -> Signal dom Bit              -- ARG[27] irstbot+  -> Signal dom Bit              -- ARG[28] orsttop+  -> Signal dom Bit              -- ARG[29] orstbot+  -> Signal dom Bit              -- ARG[30] ahold+  -> Signal dom Bit              -- ARG[31] bhold+  -> Signal dom Bit              -- ARG[32] chold+  -> Signal dom Bit              -- ARG[33] dhold+  -> Signal dom Bit              -- ARG[34] oholdtop+  -> Signal dom Bit              -- ARG[35] oholdbot+  -> Signal dom Bit              -- ARG[36] addsubtop+  -> Signal dom Bit              -- ARG[37] addsubbot+  -> Signal dom Bit              -- ARG[38] oloadtop+  -> Signal dom Bit              -- ARG[39] oloadbot+  -> Signal dom Bit              -- ARG[40] accumci+  -> Signal dom Bit              -- ARG[41] signextin+  -> Signal dom Bit              -- ARG[42] ci+  -> ( Signal dom (BitVector 32) -- o[31:0]+     , Signal dom Bit            -- co+     , Signal dom Bit            -- accumco+     , Signal dom Bit            -- signextout+     )"+       , "template" :+  "//SB_MAC16 begin+  wire [31:0]  ~GENSYM[o][0];+  wire         ~GENSYM[co][1];+  wire         ~GENSYM[accumco][2];+  wire         ~GENSYM[signextout][3];++  SB_MAC16 #(+    .NEG_TRIGGER(~ARG[0]),+    .C_REG(~ARG[3]),+    .A_REG(~ARG[1]),+    .B_REG(~ARG[2]),+    .D_REG(~ARG[4]),+    .TOP_8x8_MULT_REG(~ARG[5]),+    .BOT_8x8_MULT_REG(~ARG[6]),+    .PIPELINE_16x16_MULT_REG1(~ARG[7]),+    .PIPELINE_16x16_MULT_REG2(~ARG[8]),+    .TOPOUTPUT_SELECT(~ARG[9]),+    .TOPADDSUB_LOWERINPUT(~ARG[10]),+    .TOPADDSUB_UPPERINPUT(~ARG[11]),+    .TOPADDSUB_CARRYSELECT(~ARG[12]),+    .BOTOUTPUT_SELECT(~ARG[13]),+    .BOTADDSUB_LOWERINPUT(~ARG[14]),+    .BOTADDSUB_UPPERINPUT(~ARG[15]),+    .BOTADDSUB_CARRYSELECT(~ARG[16]),+    .MODE_8x8(~ARG[17]),+    .A_SIGNED(~ARG[18]),+    .B_SIGNED(~ARG[19])+  ) ~GENSYM[sb_mac16_inst][4] (+    .CLK(~ARG[20]),+    .CE(~ARG[21]),+    .C(~ARG[22]),+    .A(~ARG[23]),+    .B(~ARG[24]),+    .D(~ARG[25]),+    .AHOLD(~ARG[30]),+    .BHOLD(~ARG[31]),+    .CHOLD(~ARG[32]),+    .DHOLD(~ARG[33]),+    .IRSTTOP(~ARG[26]),+    .IRSTBOT(~ARG[27]),+    .ORSTTOP(~ARG[28]),+    .ORSTBOT(~ARG[29]),+    .OLOADTOP(~ARG[38]),+    .OLOADBOT(~ARG[39]),+    .ADDSUBTOP(~ARG[36]),+    .ADDSUBBOT(~ARG[37]),+    .OHOLDTOP(~ARG[34]),+    .OHOLDBOT(~ARG[35]),+    .CI(~ARG[42]),+    .ACCUMCI(~ARG[40]),+    .SIGNEXTIN(~ARG[41]),+    .O(~SYM[0]),+    .CO(~SYM[1]),+    .ACCUMCO(~SYM[2]),+    .SIGNEXTOUT(~SYM[3])+  );++  assign ~RESULT = { ~SYM[0], ~SYM[1], ~SYM[2], ~SYM[3] };+  // SB_MAC16 end"+       }+     }+  ]+  |]) #-}++-- | Multiply-Accumulate primitive+{-# NOINLINE macPrim #-}+macPrim+  :: Bit                         -- ^ negTrigger+  -> Bit                         -- ^ aReg+  -> Bit                         -- ^ bReg+  -> Bit                         -- ^ cReg+  -> Bit                         -- ^ dReg+  -> Bit                         -- ^ top8x8MultReg+  -> Bit                         -- ^ bot8x8MultReg+  -> Bit                         -- ^ pipeline16x16MultReg1+  -> Bit                         -- ^ pipeline16x16MultReg2+  -> BitVector 2                 -- ^ topOutputSelect+  -> BitVector 2                 -- ^ topAddSubLowerInput+  -> Bit                         -- ^ topAddSubUpperInput+  -> BitVector 2                 -- ^ topAddSubCarrySelect+  -> BitVector 2                 -- ^ botOutputSelect+  -> BitVector 2                 -- ^ botAddSubLowerInput+  -> Bit                         -- ^ botAddSubUpperInput+  -> BitVector 2                 -- ^ botAddSubCarrySelect+  -> Bit                         -- ^ mode8x8+  -> Bit                         -- ^ aSigned+  -> Bit                         -- ^ bSigned+  -> Clock dom                   -- ^ clk+  -> Signal dom Bit              -- ^ ce+  -> Signal dom (BitVector 16)   -- ^ c+  -> Signal dom (BitVector 16)   -- ^ a+  -> Signal dom (BitVector 16)   -- ^ b+  -> Signal dom (BitVector 16)   -- ^ d+  -> Signal dom Bit              -- ^ irsttop+  -> Signal dom Bit              -- ^ irstbot+  -> Signal dom Bit              -- ^ orsttop+  -> Signal dom Bit              -- ^ orstbot+  -> Signal dom Bit              -- ^ ahold+  -> Signal dom Bit              -- ^ bhold+  -> Signal dom Bit              -- ^ chold+  -> Signal dom Bit              -- ^ dhold+  -> Signal dom Bit              -- ^ oholdtop+  -> Signal dom Bit              -- ^ oholdbot+  -> Signal dom Bit              -- ^ addsubtop+  -> Signal dom Bit              -- ^ addsubbot+  -> Signal dom Bit              -- ^ oloadtop+  -> Signal dom Bit              -- ^ oloadbot+  -> Signal dom Bit              -- ^ accumci+  -> Signal dom Bit              -- ^ signextin+  -> Signal dom Bit              -- ^ ci+  -> ( Signal dom (BitVector 32) -- o[31:0]+     , Signal dom Bit            -- co+     , Signal dom Bit            -- accumco+     , Signal dom Bit            -- signextout+     )                           -- ^ (o[31:0], co, accumco, signextout)+macPrim !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ = (0, 0, 0, 0)
+ src/Ice40/Osc.hs view
@@ -0,0 +1,130 @@+{-|+Module      : Ice40.Osc+Description : Ice40 oscillator hard IP primitives+Copyright   : (c) David Cox, 2021+License     : BSD 3-Clause+Maintainer  : standardsemiconductor@gmail.com++LFOSC and HFOSC hard IP primitive from Lattice Ice Technology Library https://github.com/standardsemiconductor/VELDT-info/blob/master/SBTICETechnologyLibrary201708.pdf+-}+module Ice40.Osc+  ( lf10kHz+  , hf48Mhz+  , hf24Mhz+  , hf12Mhz+  , hf6Mhz+  ) where++import Clash.Prelude+import Clash.Signal.Internal+import Clash.Annotations.Primitive+import Data.String.Interpolate (i)+import Data.String.Interpolate.Util (unindent)+import Ice40.Clock++------------------------------+-- Low Frequency Oscillator --+------------------------------++{-# ANN lf10kHz (InlinePrimitive [Verilog] $ unindent [i|+  [  { "BlackBox" :+       { "name" : "Ice40.Osc.lf10kHz"+       , "kind" : "Declaration"+       , "type" :+  "lf10kHz+  :: Signal dom Bool -- ARG[0] clkLfPu+  -> Signal dom Bool -- ARG[1] clkLfEn+  -> Clock Lattice10kHz"+       , "template" :+  "//SB_LFOSC begin+  SB_LFOSC ~GENSYM[sb_lfosc_inst][0] (   +  .CLKLFEN (~ARG[0]),+  .CLKLFPU (~ARG[1]), +  .CLKLF   (~RESULT)+  );+  //SB_LFOSC end"+      }+    }+  ]+  |]) #-}++-- | Low frequency oscillator 10 kHz+{-# NOINLINE lf10kHz #-}+lf10kHz+  :: Signal dom Bool -- ^ CLKLFPU - Power up the LFOSC circuit. After power up, oscillator output will be stable after 100us. Active High.+  -> Signal dom Bool -- ^ CLKLFEN - Enable the clock output. Enable should be low for the 100us power up period. Active High.+  -> Clock Lattice10kHz -- ^ LF Oscillator output+lf10kHz !_ !_ = Clock SSymbol++-------------------------------+-- High Frequency Oscillator --+-------------------------------+-- | SB_HFOSC primitive generates 48MHz nominal clock frequency within +/-10% variation, with user programmable divider value of 1, 2, 4, and 8. the HFOSC can drive either the global clock network or fabric routes directly based on the clock network selection.++{-# ANN hfPrim (InlinePrimitive [Verilog] $ unindent [i|+  [  { "BlackBox" :+       { "name" : "Ice40.Osc.hfPrim"+       , "kind" : "Declaration"+       , "type" :+  "hfPrim+  :: KnownDomain dom            -- ARG[0]+  => KnownDomain dom'           -- ARG[1]+  => String                     -- ARG[2]  clkhfdiv+  -> Signal dom Bool            -- ARG[3]  clkhfen+  -> Signal dom Bool            -- ARG[4]  clkhfpu+  -> Clock dom'                 -- clkhf"+       , "template" :+  "//SB_HFOSC begin+  SB_HFOSC #( .CLKHF_DIV(~ARG[2]) ) sb_hfosc_inst (+    .CLKHFEN (~ARG[3]),+    .CLKHFPU (~ARG[4]),+    .CLKHF   (~RESULT)+  );                                                                                          +  //SB_HFOSC end"+      }+    }+  ]+  |]) #-}++{-# NOINLINE hfPrim #-}+hfPrim+  :: KnownDomain dom            -- ARG[0]+  => KnownDomain dom'           -- ARG[1]+  => String                     -- ARG[2]  clkhfdiv+  -> Signal dom Bool            -- ARG[3]  clkhfen+  -> Signal dom Bool            -- ARG[4]  clkhfpu+  -> Clock dom'                 -- clkhf"+hfPrim !_ !_ !_ = Clock SSymbol++-- | High frequency oscillator 48 Mhz+hf48Mhz+  :: KnownDomain dom+  => Signal dom Bool -- ^ CLKHFEN Enable the clock output. Enable should be low for the 100us power up period. Active High.+  -> Signal dom Bool -- ^ CLKHFPU Power up the HFOSC circuit. After power up, oscillator output will be stable after 100us. Active High.+  -> Clock Lattice48Mhz -- ^ HF Oscillator output+hf48Mhz = hfPrim "0b00"++-- | High frequency oscillator 24 Mhz+hf24Mhz+  :: KnownDomain dom+  => Signal dom Bool -- ^ CLKHFEN Enable the clock output. Enable should be low for the 100us power up period. Active High.+  -> Signal dom Bool -- ^ CLKHFPU Power up the HFOSC circuit. After power up, oscillator output will be stable after 100us. Active High.+  -> Clock Lattice24Mhz -- ^ HF Oscillator output+hf24Mhz = hfPrim "0b01"++-- | High frequency oscillator 12 Mhz+hf12Mhz+  :: KnownDomain dom+  => Signal dom Bool -- ^ CLKHFEN Enable the clock output. Enable should be low for the 100us power up period. Active High.+  -> Signal dom Bool -- ^ CLKHFPU Power up the HFOSC circuit. After power up, oscillator output will be stable after 100us. Active High.+  -> Clock Lattice12Mhz -- ^ HF Oscillator output+hf12Mhz = hfPrim "0b10"++-- | High frequency oscillator 6 Mhz+hf6Mhz+  :: KnownDomain dom+  => Signal dom Bool -- ^ CLKHFEN Enable the clock output. Enable should be low for the 100us power up period. Active High.+  -> Signal dom Bool -- ^ CLKHFPU Power up the HFOSC circuit. After power up, oscillator output will be stable after 100us. Active High.+  -> Clock Lattice6Mhz -- ^ HF Oscillator output+hf6Mhz = hfPrim "0b11"+  
+ src/Ice40/Rgb.hs view
@@ -0,0 +1,95 @@+{-|+Module : Ice40.Rgb+Description : Ice40 RGB hard IP primitive+Copyright : (c) David Cox, 2021+License : BSD 3-Clause+Maintainer : standardsemiconductor@gmail.com++RGB hard IP primitive from Lattice Ice Technology Library https://github.com/standardsemiconductor/VELDT-info/blob/master/SBTICETechnologyLibrary201708.pdf+-}+module Ice40.Rgb where++import Clash.Prelude+import Clash.Annotations.Primitive+import Data.String.Interpolate (i)+import Data.String.Interpolate.Util (unindent)++{-# ANN rgbPrim (InlinePrimitive [Verilog] $ unindent [i|+  [ { "BlackBox" :+      { "name" : "Ice40.Rgb.rgbPrim"+      , "kind" : "Declaration"+      , "type" :+  "rgbPrim+  :: String           -- currentMode ARG[0]+  -> String           -- rgb0Current ARG[1]+  -> String           -- rgb1Current ARG[2]+  -> String           -- rgb2Current ARG[3]+  -> Signal dom Bit   -- curren      ARG[4]+  -> Signal dom Bit   -- rgbleden    ARG[5]+  -> Signal dom Bit   -- rgb0Pwm     ARG[6]+  -> Signal dom Bit   -- rgb1Pwm     ARG[7]+  -> Signal dom Bit   -- rgb2Pwm     ARG[8]+  -> Signal dom ( Bit -- rgb0+                , Bit -- rgb1+                , Bit -- rgb2+                )"+      , "template" :+  "//SB_RGBA_DRV begin+  wire ~GENSYM[rgb0][0];+  wire ~GENSYM[rgb1][1];+  wire ~GENSYM[rgb2][2];++  SB_RGBA_DRV #(+     .CURRENT_MODE ( ~ARG[0] ),+     .RGB0_CURRENT ( ~ARG[1] ),+     .RGB1_CURRENT ( ~ARG[2] ),+     .RGB2_CURRENT ( ~ARG[3] )+  ) ~GENSYM[rgba_drv_inst][3] (+     .CURREN       ( ~ARG[4] ),+     .RGBLEDEN     ( ~ARG[5] ),+     .RGB0PWM      ( ~ARG[6] ),+     .RGB1PWM      ( ~ARG[7] ),+     .RGB2PWM      ( ~ARG[8] ),+     .RGB0         ( ~SYM[0] ),+     .RGB1         ( ~SYM[1] ),+     .RGB2         ( ~SYM[2] )+  );+ +  assign ~RESULT = {~SYM[0], ~SYM[1], ~SYM[2]};+  //SB_RGBA_DRV end"+      }+    } +  ]+  |]) #-}++-- | SB_RGBA_DRV primitive is the RGB LED drive module which contains 3 +--   dedicated open drain I/O pins for RGB LED outputs. Each of the RGB LED +--   output is bonded out together with an SB_IO_OD primitive to +--   the package pin. User can either use SB_RGB_DRV primitive or the +--   SB_IO_OD primitive to drive the package pin, but not both.+-- +--   The primitive allows configuration of each of the 3 RGB LED +--   outputs individually. When the RGBx_CURRENT parameter of RGBx output is +--   set to "0b000000", then SB_IO_OD can be used to drive +--   the package pin. "0b000001" = 4mA for Full Mode; 2mA for +--   Half Mode. "0b000011" = 8mA for Full Mode; 4mA for Half Mode. +--   "0b000111" = 12mA for Full Mode; 6mA for Half Mode. +--   "0b001111" = 16mA for Full Mode; 8mA for Half Mode. +--   "0b011111" = 20mA for Full Mode; 10mA for Half Mode. +--   "0b111111" = 24mA for Full Mode; 12mA for Half Mode.+{-# NOINLINE rgbPrim #-}+rgbPrim+  :: String           -- ^ currentMode - Parameter values: "0b0" = Full Current Mode (Default), "0b1" = Half Current Mode.+  -> String           -- ^ rgb0Current+  -> String           -- ^ rgb1Current+  -> String           -- ^ rgb2Current+  -> Signal dom Bit   -- ^ curren - enable the mixed signal control block to supply reference current to the IR drivers. When it is not enabled (CURREN=0), no current is supplied, and the IR drivers are powered down. Enabling the mixed signal control block takes 100us to reach a stable reference current value.+  -> Signal dom Bit   -- ^ rgbleden - enable the SB_RGB_DRV primitive. Active High.+  -> Signal dom Bit   -- ^ rgb0Pwm - input data to drive RGB0 LED pin. This input is usually driven from the SB_LEDD_IP.+  -> Signal dom Bit   -- ^ rgb1Pwm - input data to drive RGB1 LED pin. This input is usually driven from the SB_LEDD_IP.+  -> Signal dom Bit   -- ^ rgb2Pwm - input data to drive RGB2 LED pin. This input is usually driven from teh SB_LEDD_IP.+  -> Signal dom ( Bit+                , Bit+                , Bit+                ) -- ^ (RGB0 LED output, RGB1 LED output, RGB2 LED output)+rgbPrim !_ !_ !_ !_ !_ !_ !_ !_ !_ = pure (0, 0, 0)
+ src/Ice40/Spi.hs view
@@ -0,0 +1,285 @@+{-|+Module      : Ice40.Spi+Description : Ice40 SPI hard IP primitive+Copyright   : (c) David Cox, 2021+License     : BSD 3-Clause+Maintainer  : standardsemiconductor@gmail.com++SPI hard IP primitive from Lattice Ice Technology Library https://github.com/standardsemiconductor/VELDT-info/blob/master/SBTICETechnologyLibrary201708.pdf+-}+module Ice40.Spi ( spi ) where++import Clash.Prelude+import Clash.Annotations.Primitive+import Data.String.Interpolate (i)+import Data.String.Interpolate.Util (unindent)+                    +-- | spi primitive wrapper+spi+  :: HiddenClock dom+  => String                   -- ^ busAddr+  -> Signal dom Bool          -- ^ sbrwi+  -> Signal dom Bool          -- ^ sbstbi+  -> Signal dom (BitVector 8) -- ^ sbadri+  -> Signal dom (BitVector 8) -- ^ sbdati+  -> Signal dom Bit           -- ^ bi+  -> Signal dom Bit           -- ^ wi+  -> Signal dom Bit           -- ^ wcki+  -> Signal dom Bit           -- ^ wcsni+  -> Unbundled dom +       ( BitVector 8 -- sbdato+       , Bool        -- sbacko+       , Bit         -- spiirq+       , Bit         -- spiwkup+       , Bit         -- wo+       , Bit         -- woe+       , Bit         -- bo+       , Bit         -- boe+       , Bit         -- wcko+       , Bit         -- wckoe+       , BitVector 4 -- bcsno+       , BitVector 4 -- bcsnoe+       ) -- ^ (sbdato, sbacko, spiirq, spiwkup, wo, woe, bo, boe, wcko, wckoe, bcsno, bcsnoe)+spi busAddr sbrwi sbstbi sbadri sbdati bi wi wcki wcsni =+  spiPrim busAddr+          hasClock+          sbrwi+          sbstbi+          (bitAt 7 sbadri)+          (bitAt 6 sbadri)+          (bitAt 5 sbadri)+          (bitAt 4 sbadri)+          (bitAt 3 sbadri)+          (bitAt 2 sbadri)+          (bitAt 1 sbadri)+          (bitAt 0 sbadri)+          (bitAt 7 sbdati)+          (bitAt 6 sbdati)+          (bitAt 5 sbdati)+          (bitAt 4 sbdati)+          (bitAt 3 sbdati)+          (bitAt 2 sbdati)+          (bitAt 1 sbdati)+          (bitAt 0 sbdati)+          bi+          wi+          wcki+          wcsni++bitAt :: KnownNat n => Index n -> Signal dom (BitVector n) -> Signal dom Bit+bitAt n = fmap (!n)++{-# ANN spiPrim (InlinePrimitive [Verilog] $ unindent [i|+  [  { "BlackBox" :+       { "name" : "Ice40.Spi.spiPrim"+       , "kind" : "Declaration"+       , "type" :+  "spiPrim+    :: String          -- ARG[0]  busAddr+    -> Clock dom       -- ARG[1]  sbclki+    -> Signal dom Bool -- ARG[2]  sbrwi+    -> Signal dom Bool -- ARG[3]  sbstbi+    -> Signal dom Bit  -- ARG[4]  sbadri7+    -> Signal dom Bit  -- ARG[5]  sbadri6+    -> Signal dom Bit  -- ARG[6]  sbadri5+    -> Signal dom Bit  -- ARG[7]  sbadri4+    -> Signal dom Bit  -- ARG[8]  sbadri3+    -> Signal dom Bit  -- ARG[9]  sbadri2+    -> Signal dom Bit  -- ARG[10] sbadri1+    -> Signal dom Bit  -- ARG[11] sbadri0+    -> Signal dom Bit  -- ARG[12] sbdati7+    -> Signal dom Bit  -- ARG[13] sbdati6+    -> Signal dom Bit  -- ARG[14] sbdati5+    -> Signal dom Bit  -- ARG[15] sbdati4+    -> Signal dom Bit  -- ARG[16] sbdati3+    -> Signal dom Bit  -- ARG[17] sbdati2+    -> Signal dom Bit  -- ARG[18] sbdati1+    -> Signal dom Bit  -- ARG[19] sbdati0+    -> Signal dom Bit  -- ARG[20] bi+    -> Signal dom Bit  -- ARG[21] wi+    -> Signal dom Bit  -- ARG[22] wcki+    -> Signal dom Bit  -- ARG[23] wcsni+    -> Unbundled dom +         ( BitVector 8 -- sbdato+         , Bool        -- sbacko+         , Bit         -- spiirq+         , Bit         -- spiwkup+         , Bit         -- wo+         , Bit         -- woe+         , Bit         -- bo+         , Bit         -- boe+         , Bit         -- wcko+         , Bit         -- wckoe+         , BitVector 4 -- bcsno+         , BitVector 4 -- bcsnoe+         )"+        , "template" :+  "//SB_SPI begin+  wire ~GENSYM[sbdato7][0];+  wire ~GENSYM[sbdato6][1];+  wire ~GENSYM[sbdato5][2];+  wire ~GENSYM[sbdato4][3];+  wire ~GENSYM[sbdato3][4];+  wire ~GENSYM[sbdato2][5];+  wire ~GENSYM[sbdato1][6];+  wire ~GENSYM[sbdato0][7];+  wire ~GENSYM[sbacko][8];+  wire ~GENSYM[irq][9];+  wire ~GENSYM[wkup][10];+  wire ~GENSYM[wo][11];+  wire ~GENSYM[woe][12];+  wire ~GENSYM[bo][13];+  wire ~GENSYM[boe][14];+  wire ~GENSYM[wcko][15];+  wire ~GENSYM[wckoe][16];+  wire ~GENSYM[bcsno3][17];+  wire ~GENSYM[bcsno2][18];+  wire ~GENSYM[bcsno1][19];+  wire ~GENSYM[bcsno0][20];+  wire ~GENSYM[bcsnoe3][21];+  wire ~GENSYM[bcsnoe2][22];+  wire ~GENSYM[bcsnoe1][23];+  wire ~GENSYM[bcsnoe0][24];++  SB_SPI #(+    .BUS_ADDR74( ~ARG[0] )+  ) ~GENSYM[sb_spi_inst][25] (+    .SBCLKI  ( ~ARG[1]  ),+    .SBRWI   ( ~ARG[2]  ),+    .SBSTBI  ( ~ARG[3]  ),+    .SBADRI7 ( ~ARG[4]  ),+    .SBADRI6 ( ~ARG[5]  ),+    .SBADRI5 ( ~ARG[6]  ),+    .SBADRI4 ( ~ARG[7]  ),+    .SBADRI3 ( ~ARG[8]  ),+    .SBADRI2 ( ~ARG[9]  ),+    .SBADRI1 ( ~ARG[10] ),+    .SBADRI0 ( ~ARG[11] ),+    .SBDATI7 ( ~ARG[12] ),+    .SBDATI6 ( ~ARG[13] ),+    .SBDATI5 ( ~ARG[14] ),+    .SBDATI4 ( ~ARG[15] ),+    .SBDATI3 ( ~ARG[16] ),+    .SBDATI2 ( ~ARG[17] ),+    .SBDATI1 ( ~ARG[18] ),+    .SBDATI0 ( ~ARG[19] ),+    .MI      ( ~ARG[20] ),+    .SI      ( ~ARG[21] ),+    .SCKI    ( ~ARG[22] ),+    .SCSNI   ( ~ARG[23] ),++    .SBDATO7 ( ~SYM[0]  ),+    .SBDATO6 ( ~SYM[1]  ),+    .SBDATO5 ( ~SYM[2]  ),+    .SBDATO4 ( ~SYM[3]  ),+    .SBDATO3 ( ~SYM[4]  ),+    .SBDATO2 ( ~SYM[5]  ),+    .SBDATO1 ( ~SYM[6] ),+    .SBDATO0 ( ~SYM[7] ),+    .SBACKO  ( ~SYM[8] ),+    .SPIIRQ  ( ~SYM[9] ),+    .SPIWKUP ( ~SYM[10] ),+    .SO      ( ~SYM[11] ),+    .SOE     ( ~SYM[12] ),+    .MO      ( ~SYM[13] ),+    .MOE     ( ~SYM[14] ),+    .SCKO    ( ~SYM[15] ),+    .SCKOE   ( ~SYM[16] ),+    .MCSNO3  ( ~SYM[17] ),+    .MCSNO2  ( ~SYM[18] ),+    .MCSNO1  ( ~SYM[19] ),+    .MCSNO0  ( ~SYM[20] ),+    .MCSNOE3 ( ~SYM[21] ),+    .MCSNOE2 ( ~SYM[22] ),+    .MCSNOE1 ( ~SYM[23] ),+    .MCSNOE0 ( ~SYM[24] )+  );++  assign ~RESULT = { ~SYM[0]  // sbdato7+                   , ~SYM[1]  // sbdato6+                   , ~SYM[2]  // sbdato5+                   , ~SYM[3]  // sbdato4+                   , ~SYM[4]  // sbdato3+                   , ~SYM[5]  // sbdato2+                   , ~SYM[6]  // sbdato1+                   , ~SYM[7]  // sbdato0+                   , ~SYM[8]  // sbacko+                   , ~SYM[9]  // spiirq+                   , ~SYM[10] // spiwkup+                   , ~SYM[11] // wo+                   , ~SYM[12] // woe+                   , ~SYM[13] // bo+                   , ~SYM[14] // boe+                   , ~SYM[15] // wcko+                   , ~SYM[16] // wckoe+                   , ~SYM[17] // bcsno3+                   , ~SYM[18] // bcsno2+                   , ~SYM[19] // bcsno1+                   , ~SYM[20] // bcsno0+                   , ~SYM[21] // bcsnoe3+                   , ~SYM[22] // bcsnoe2+                   , ~SYM[23] // bcsnoe1+                   , ~SYM[24] // bcsnoe0+                   };+  // SB_SPI end"+       }+     }+  ]+  |]) #-}++{-# NOINLINE spiPrim #-}+spiPrim+  :: String          -- ARG[0]  busAddr+  -> Clock dom       -- ARG[1]  sbclki+  -> Signal dom Bool -- ARG[2]  sbrwi+  -> Signal dom Bool -- ARG[3]  sbstbi+  -> Signal dom Bit  -- ARG[4]  sbadri7+  -> Signal dom Bit  -- ARG[5]  sbadri6+  -> Signal dom Bit  -- ARG[6]  sbadri5+  -> Signal dom Bit  -- ARG[7]  sbadri4+  -> Signal dom Bit  -- ARG[8]  sbadri3+  -> Signal dom Bit  -- ARG[9]  sbadri2+  -> Signal dom Bit  -- ARG[10] sbadri1+  -> Signal dom Bit  -- ARG[11] sbadri0+  -> Signal dom Bit  -- ARG[12] sbdati7+  -> Signal dom Bit  -- ARG[13] sbdati6+  -> Signal dom Bit  -- ARG[14] sbdati5+  -> Signal dom Bit  -- ARG[15] sbdati4+  -> Signal dom Bit  -- ARG[16] sbdati3+  -> Signal dom Bit  -- ARG[17] sbdati2+  -> Signal dom Bit  -- ARG[18] sbdati1+  -> Signal dom Bit  -- ARG[19] sbdati0+  -> Signal dom Bit  -- ARG[20] bi+  -> Signal dom Bit  -- ARG[21] wi+  -> Signal dom Bit  -- ARG[22] wcki+  -> Signal dom Bit  -- ARG[23] wcsni+  -> Unbundled dom +       ( BitVector 8 -- sbdato+       , Bool        -- sbacko+       , Bit         -- spiirq+       , Bit         -- spiwkup+       , Bit         -- wo+       , Bit         -- woe+       , Bit         -- bo+       , Bit         -- boe+       , Bit         -- wcko+       , Bit         -- wckoe+       , BitVector 4 -- bcsno+       , BitVector 4 -- bcsnoe+       )+spiPrim !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_ !_+  = unbundle $ pure ( 0     -- sbdato+                    , False -- sbacko+                    , 0     -- spiirq+                    , 0     -- spiwkup+                    , 0     -- wo+                    , 0     -- woe+                    , 0     -- bo+                    , 0     -- boe+                    , 0     -- wcko+                    , 0     -- wckoe+                    , 0     -- bcsno+                    , 0     -- bcsnoe+                    )++
+ src/Ice40/Spram.hs view
@@ -0,0 +1,97 @@+{-|+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 address dataIn maskWrEn wrEn chipSelect !_ !_ !_+  = concat4 <$> nyb3 <*> nyb2 <*> nyb1 <*> nyb0+  where+    addressU = unpack <$> address+    concat4 a b c d = a ++# b ++# c ++# d+    ramEn = toEnable $ bitToBool <$> chipSelect+    nybRam = withClock clock $ withEnable ramEn (blockRamPow2 (repeat 0) addressU)+    nyb3 = nybRam wrM3+    nyb2 = nybRam wrM2+    nyb1 = nybRam wrM1+    nyb0 = nybRam wrM0+    wrM3 = writeGuard Nyb3 <$> dataIn <*> addressU <*> wrEn <*> maskWrEn+    wrM2 = writeGuard Nyb2 <$> dataIn <*> addressU <*> wrEn <*> maskWrEn+    wrM1 = writeGuard Nyb1 <$> dataIn <*> addressU <*> wrEn <*> maskWrEn+    wrM0 = writeGuard Nyb0 <$> dataIn <*> addressU <*> wrEn <*> maskWrEn+    nybSlice = \case+      Nyb3 -> slice d15 d12+      Nyb2 -> slice d11 d8+      Nyb1 -> slice d7  d4+      Nyb0 -> slice d3  d0+    nybMask = \case+      Nyb3 -> (!(3 :: Index 4))+      Nyb2 -> (!(2 :: Index 4))+      Nyb1 -> (!(1 :: Index 4))+      Nyb0 -> (!(0 :: Index 4))+    writeGuard n dIn addr en mask+      | bitToBool en && (not.bitToBool) (nybMask n mask) = Just (addr, nybSlice n dIn)+      | otherwise = Nothing