{-# OPTIONS --safe --cubical #-}

module Spartan6.Examples.RawLUT where

open import Spartan6.Prelude

import Spartan6.Architecture.Primitive as Architecture
import Spartan6.Netlist.Checked as Checked
import Spartan6.Netlist.NormalizeCombinational as Normalize
import Spartan6.Netlist.Raw as Raw
import Spartan6.Primitive.LUT as LUT
import Spartan6.Semantics.Design as Semantics
import Spartan6.Validation.Diagnostic as Diagnostic
import Spartan6.Validation.Raw as Validation

inputPort : String → Raw.Connection → Raw.RawPort
inputPort name connection =
  Raw.rawPort name Raw.inputPort 1 (connection ∷ᴸ []ᴸ)

outputPort : String → Raw.Connection → Raw.RawPort
outputPort name connection =
  Raw.rawPort name Raw.outputPort 1 (connection ∷ᴸ []ᴸ)

-- INIT 0xAAAA... has vendor-index bits 0,1,0,1,... and therefore implements
-- O=I0 independently of I1..I5 under the documented LUT address ordering.

rawIdentityLUT : Raw.RawInstance
rawIdentityLUT =
  Raw.rawInstance
    "identity"
    (Raw.knownPrimitive Architecture.LUT6)
    (inputPort "I0" (Raw.net 0)
     ∷ᴸ inputPort "I1" (Raw.constant low)
     ∷ᴸ inputPort "I2" (Raw.constant low)
     ∷ᴸ inputPort "I3" (Raw.constant low)
     ∷ᴸ inputPort "I4" (Raw.constant low)
     ∷ᴸ inputPort "I5" (Raw.constant low)
     ∷ᴸ outputPort "O" (Raw.net 1)
     ∷ᴸ []ᴸ)
    (Raw.rawParameter "INIT" "AAAAAAAAAAAAAAAA" ∷ᴸ []ᴸ)
    nothing

rawIdentityDesign : Raw.RawDesign
rawIdentityDesign =
  Raw.rawDesign nothing
    (Raw.rawTopPort "input" Raw.inputPort 1 (Raw.net 0 ∷ᴸ []ᴸ)
     ∷ᴸ Raw.rawTopPort "output" Raw.outputPort 1 (Raw.net 1 ∷ᴸ []ᴸ)
     ∷ᴸ []ᴸ)
    (rawIdentityLUT ∷ᴸ []ᴸ)

raw-identity-is-structurally-valid :
  Validation.StructurallyValid rawIdentityDesign
raw-identity-is-structurally-valid = refl

alternatingPairs : (count : ℕ) → Vec Bit (count · 2)
alternatingPairs zero = []
alternatingPairs (suc count) = low ∷ high ∷ alternatingPairs count

identityTable : LUT.LUT6Table
identityTable = alternatingPairs 32

identityNetlist : Checked.CheckedNetlist 1 1 0 1
identityNetlist =
  Checked.checkedNetlist
    []
    (Checked.noNodes Checked.▻
      Checked.lutNode identityTable
        (Checked.externalWire fzero
         ∷ Checked.literalWire low
         ∷ Checked.literalWire low
         ∷ Checked.literalWire low
         ∷ Checked.literalWire low
         ∷ Checked.literalWire low
         ∷ []))
    (Checked.localWire fzero ∷ [])
    []

identityCandidate : Normalize.CheckedCombinationalCandidate
identityCandidate =
  Normalize.checkedCombinationalCandidate
    rawIdentityDesign
    raw-identity-is-structurally-valid
    1 1 1
    identityNetlist

raw-identity-normalises :
  Normalize.normaliseCombinational
    (rawIdentityDesign , raw-identity-is-structurally-valid)
  ≡ Diagnostic.accepted identityCandidate
raw-identity-normalises = refl

compiledIdentity : Semantics.Design 1 1 0
compiledIdentity = Checked.compileNetlist identityNetlist

compiled-identity-low :
  Semantics.observe compiledIdentity (low ∷ []) [] ≡ low ∷ []
compiled-identity-low = refl

compiled-identity-high :
  Semantics.observe compiledIdentity (high ∷ []) [] ≡ high ∷ []
compiled-identity-high = refl

rawIdentityStage : String → Raw.NetId → Raw.NetId → Raw.RawInstance
rawIdentityStage name input-net output-net =
  Raw.rawInstance
    name
    (Raw.knownPrimitive Architecture.LUT6)
    (inputPort "I0" (Raw.net input-net)
     ∷ᴸ inputPort "I1" (Raw.constant low)
     ∷ᴸ inputPort "I2" (Raw.constant low)
     ∷ᴸ inputPort "I3" (Raw.constant low)
     ∷ᴸ inputPort "I4" (Raw.constant low)
     ∷ᴸ inputPort "I5" (Raw.constant low)
     ∷ᴸ outputPort "O" (Raw.net output-net)
     ∷ᴸ []ᴸ)
    (Raw.rawParameter "INIT" "AAAAAAAAAAAAAAAA" ∷ᴸ []ᴸ)
    nothing

forwardReferenceDesign : Raw.RawDesign
forwardReferenceDesign =
  Raw.rawDesign nothing
    (Raw.rawTopPort "input" Raw.inputPort 1 (Raw.net 0 ∷ᴸ []ᴸ)
     ∷ᴸ Raw.rawTopPort "output" Raw.outputPort 1 (Raw.net 2 ∷ᴸ []ᴸ)
     ∷ᴸ []ᴸ)
    (rawIdentityStage "consumer" 1 2
     ∷ᴸ rawIdentityStage "producer" 0 1
     ∷ᴸ []ᴸ)

forward-reference-design-is-acyclic-and-structurally-valid :
  Validation.StructurallyValid forwardReferenceDesign
forward-reference-design-is-acyclic-and-structurally-valid = refl

forward-reference-needs-topological-order :
  Normalize.normaliseCombinational
    (forwardReferenceDesign ,
     forward-reference-design-is-acyclic-and-structurally-valid)
  ≡ Diagnostic.rejected
      (Normalize.unresolvedConnection "LUT6.I0" (Raw.net 1))
forward-reference-needs-topological-order = refl

rawIdentityLUT2 : Raw.RawInstance
rawIdentityLUT2 =
  Raw.rawInstance
    "identity2"
    (Raw.knownPrimitive Architecture.LUT2)
    (inputPort "I0" (Raw.net 20)
     ∷ᴸ inputPort "I1" (Raw.constant low)
     ∷ᴸ outputPort "O" (Raw.net 21)
     ∷ᴸ []ᴸ)
    (Raw.rawParameter "INIT" "A" ∷ᴸ []ᴸ)
    nothing

rawIdentityLUT2Design : Raw.RawDesign
rawIdentityLUT2Design =
  Raw.rawDesign nothing
    (Raw.rawTopPort "input" Raw.inputPort 1 (Raw.net 20 ∷ᴸ []ᴸ)
     ∷ᴸ Raw.rawTopPort "output" Raw.outputPort 1 (Raw.net 21 ∷ᴸ []ᴸ)
     ∷ᴸ []ᴸ)
    (rawIdentityLUT2 ∷ᴸ []ᴸ)

raw-lut2-is-structurally-valid :
  Validation.StructurallyValid rawIdentityLUT2Design
raw-lut2-is-structurally-valid = refl

identityLUT2Netlist : Checked.CheckedNetlist 1 1 0 1
identityLUT2Netlist =
  Checked.checkedNetlist
    []
    (Checked.noNodes Checked.▻
      Checked.lutNode
        (low ∷ high ∷ low ∷ high ∷ [])
        (Checked.externalWire fzero ∷ Checked.literalWire low ∷ []))
    (Checked.localWire fzero ∷ [])
    []

identityLUT2Candidate : Normalize.CheckedCombinationalCandidate
identityLUT2Candidate =
  Normalize.checkedCombinationalCandidate
    rawIdentityLUT2Design raw-lut2-is-structurally-valid
    1 1 1 identityLUT2Netlist

raw-lut2-normalises :
  Normalize.normaliseCombinational
    (rawIdentityLUT2Design , raw-lut2-is-structurally-valid)
  ≡ Diagnostic.accepted identityLUT2Candidate
raw-lut2-normalises = refl

compiledLUT2 : Semantics.Design 1 1 0
compiledLUT2 = Checked.compileNetlist identityLUT2Netlist

compiled-lut2-passes-high :
  Semantics.observe compiledLUT2 (high ∷ []) [] ≡ high ∷ []
compiled-lut2-passes-high = refl

rawInvertingLUT1 : Raw.RawInstance
rawInvertingLUT1 =
  Raw.rawInstance
    "not1"
    (Raw.knownPrimitive Architecture.LUT1)
    (inputPort "I0" (Raw.net 30)
     ∷ᴸ outputPort "O" (Raw.net 31)
     ∷ᴸ []ᴸ)
    (Raw.rawParameter "INIT" "1" ∷ᴸ []ᴸ)
    nothing

rawInvertingLUT1Design : Raw.RawDesign
rawInvertingLUT1Design =
  Raw.rawDesign nothing
    (Raw.rawTopPort "input" Raw.inputPort 1 (Raw.net 30 ∷ᴸ []ᴸ)
     ∷ᴸ Raw.rawTopPort "output" Raw.outputPort 1 (Raw.net 31 ∷ᴸ []ᴸ)
     ∷ᴸ []ᴸ)
    (rawInvertingLUT1 ∷ᴸ []ᴸ)

raw-lut1-is-structurally-valid :
  Validation.StructurallyValid rawInvertingLUT1Design
raw-lut1-is-structurally-valid = refl

invertingLUT1Netlist : Checked.CheckedNetlist 1 1 0 1
invertingLUT1Netlist =
  Checked.checkedNetlist
    []
    (Checked.noNodes Checked.▻
      Checked.lutNode
        (high ∷ low ∷ [])
        (Checked.externalWire fzero ∷ []))
    (Checked.localWire fzero ∷ [])
    []

invertingLUT1Candidate : Normalize.CheckedCombinationalCandidate
invertingLUT1Candidate =
  Normalize.checkedCombinationalCandidate
    rawInvertingLUT1Design raw-lut1-is-structurally-valid
    1 1 1 invertingLUT1Netlist

raw-lut1-normalises :
  Normalize.normaliseCombinational
    (rawInvertingLUT1Design , raw-lut1-is-structurally-valid)
  ≡ Diagnostic.accepted invertingLUT1Candidate
raw-lut1-normalises = refl

compiledLUT1 : Semantics.Design 1 1 0
compiledLUT1 = Checked.compileNetlist invertingLUT1Netlist

compiled-lut1-inverts-low :
  Semantics.observe compiledLUT1 (low ∷ []) [] ≡ high ∷ []
compiled-lut1-inverts-low = refl

compiled-lut1-inverts-high :
  Semantics.observe compiledLUT1 (high ∷ []) [] ≡ low ∷ []
compiled-lut1-inverts-high = refl