{-# OPTIONS --safe --cubical #-}
module Spartan6.Netlist.NormalizeRegister where
open import Spartan6.Prelude
import Spartan6.Netlist.Checked as Checked
import Spartan6.Netlist.Raw as Raw
open import Spartan6.Netlist.RegisterMode public
using
( lookupInputIndex
; RegisterPorts; registerPorts; registerD; registerC; registerCE
; registerControl; registerQ; parseRegisterPorts; outputNet
; RegisterMode; fdreMode; fdseMode; modeInitial; modeForcedValue
; normaliseFDREMode; normaliseFDSEMode; normaliseRegisterMode
)
import Spartan6.Netlist.TopInterface as TopInterface
import Spartan6.Validation.Diagnostic as Diagnostic
import Spartan6.Validation.Raw as Validation
open import Cubical.Data.Nat using (_≡ᵇ_)
open import Agda.Builtin.String using (primShowNat)
singleton : Diagnostic.Diagnostic → Diagnostic.Diagnostics
singleton item = item ∷ᴸ []ᴸ
issue : Diagnostic.DiagnosticCode → String → String → String → String
→ Diagnostic.Diagnostic
issue code subject expected observed detail =
Diagnostic.diagnostic code Diagnostic.reject subject expected observed detail
resolveBaseConnection : (input-nets : List Raw.NetId)
→ Raw.NetId
→ Raw.Connection
→ Maybe
(Checked.Wire
(lengthList input-nets) 1 0)
resolveBaseConnection input-nets q-net (Raw.constant bit) =
just (Checked.literalWire bit)
resolveBaseConnection input-nets q-net Raw.disconnected = nothing
resolveBaseConnection input-nets q-net (Raw.net net-id) =
if net-id ≡ᵇ q-net
then just (Checked.storedWire fzero)
else external (lookupInputIndex net-id input-nets)
where
external : Maybe (Fin (lengthList input-nets))
→ Maybe (Checked.Wire (lengthList input-nets) 1 0)
external nothing = nothing
external (just index) = just (Checked.externalWire index)
unresolved : String → Raw.Connection → Diagnostic.Diagnostics
unresolved subject (Raw.net net-id) =
singleton
(issue Diagnostic.undrivenInput subject
"the register Q net, a top-level input net, or a constant"
(primShowNat net-id)
"The single-register normaliser does not invent a source for an unresolved net.")
unresolved subject (Raw.constant bit) =
singleton
(issue Diagnostic.undrivenInput subject "a resolvable connection"
"an internal resolution failure"
"Constants are normally resolvable; this total branch records an impossible internal mismatch.")
unresolved subject Raw.disconnected =
singleton
(issue Diagnostic.undrivenInput subject "a connected semantic input"
"an explicit disconnection"
"Required register data/control inputs may not be discarded.")
resolveBasePort : (input-nets : List Raw.NetId)
→ Raw.NetId
→ String
→ Raw.RawPort
→ Diagnostic.CheckResult
(Checked.Wire (lengthList input-nets) 1 0)
resolveBasePort input-nets q-net subject port
with Raw.rawPortConnections port
... | []ᴸ =
Diagnostic.rejected
(singleton
(issue Diagnostic.widthMismatch subject "one scalar connection"
"an empty connection list" "The checked register interface is scalar."))
... | connection ∷ᴸ []ᴸ =
resolve-one connection
where
resolve-one : Raw.Connection
→ Diagnostic.CheckResult
(Checked.Wire (lengthList input-nets) 1 0)
resolve-one connection with
resolveBaseConnection input-nets q-net connection
... | nothing = Diagnostic.rejected (unresolved subject connection)
... | just wire = Diagnostic.accepted wire
... | first ∷ᴸ second ∷ᴸ rest =
Diagnostic.rejected
(singleton
(issue Diagnostic.widthMismatch subject "one scalar connection"
"multiple connections" "The checked register interface is scalar."))
clockNetInput : (input-nets : List Raw.NetId)
→ Raw.RawPort
→ Raw.NetId
→ Diagnostic.CheckResult (Fin (lengthList input-nets))
clockNetInput input-nets port net-id with lookupInputIndex net-id input-nets
... | nothing =
Diagnostic.rejected
(singleton
(issue Diagnostic.unsupportedEvent (Raw.rawPortName port)
"a retained top-level input net used as the abstract clock"
(primShowNat net-id)
"Clock must be exposed at the raw boundary; generated/multiple clock handling is not yet admitted."))
... | just index = Diagnostic.accepted index
clockInput : (input-nets : List Raw.NetId)
→ Raw.RawPort
→ Diagnostic.CheckResult (Fin (lengthList input-nets))
clockInput input-nets port with Raw.rawPortConnections port
... | Raw.net net-id ∷ᴸ []ᴸ = clockNetInput input-nets port net-id
... | Raw.constant bit ∷ᴸ []ᴸ =
Diagnostic.rejected
(singleton
(issue Diagnostic.unsupportedEvent (Raw.rawPortName port)
"a retained top-level clock input" "a constant clock binding"
"The rising-edge Event cannot be justified by a constant raw clock."))
... | Raw.disconnected ∷ᴸ []ᴸ =
Diagnostic.rejected
(singleton
(issue Diagnostic.unsupportedEvent (Raw.rawPortName port)
"a retained top-level clock input" "a disconnected clock"
"A missing raw clock cannot justify abstract rising-edge events."))
... | connections =
Diagnostic.rejected
(singleton
(issue Diagnostic.widthMismatch (Raw.rawPortName port)
"one scalar clock connection" "a non-scalar clock connection list"
"The initial event model has one scalar abstract clock."))
liftBaseOne : ∀ {inputCount}
→ Checked.Wire inputCount 1 0
→ Checked.Wire inputCount 1 1
liftBaseOne (Checked.externalWire index) = Checked.externalWire index
liftBaseOne (Checked.storedWire index) = Checked.storedWire index
liftBaseOne (Checked.localWire ())
liftBaseOne (Checked.literalWire bit) = Checked.literalWire bit
liftBaseTwo : ∀ {inputCount}
→ Checked.Wire inputCount 1 0
→ Checked.Wire inputCount 1 2
liftBaseTwo (Checked.externalWire index) = Checked.externalWire index
liftBaseTwo (Checked.storedWire index) = Checked.storedWire index
liftBaseTwo (Checked.localWire ())
liftBaseTwo (Checked.literalWire bit) = Checked.literalWire bit
registerNodes : ∀ {inputCount}
→ RegisterMode
→ Checked.Wire inputCount 1 0
→ Checked.Wire inputCount 1 0
→ Checked.Wire inputCount 1 0
→ Checked.Nodes inputCount 1 2
registerNodes mode data-wire enable-wire control-wire =
(Checked.noNodes Checked.▻
Checked.muxNode
enable-wire
(Checked.storedWire fzero)
data-wire)
Checked.▻
Checked.muxNode
(liftBaseOne control-wire)
(Checked.localWire fzero)
(Checked.literalWire (modeForcedValue mode))
resolveTopOutputConnections : (input-nets : List Raw.NetId)
→ Raw.NetId
→ String
→ List Raw.Connection
→ Diagnostic.CheckResult
(List (Checked.Wire (lengthList input-nets) 1 0))
resolveTopOutputConnections input-nets q-net subject []ᴸ =
Diagnostic.accepted []ᴸ
resolveTopOutputConnections input-nets q-net subject
(connection ∷ᴸ connections)
with resolveBaseConnection input-nets q-net connection
... | nothing = Diagnostic.rejected (unresolved subject connection)
... | just wire
with resolveTopOutputConnections input-nets q-net subject connections
... | Diagnostic.rejected diagnostics = Diagnostic.rejected diagnostics
... | Diagnostic.accepted wires = Diagnostic.accepted (wire ∷ᴸ wires)
collectTopOutputs : (input-nets : List Raw.NetId)
→ Raw.NetId
→ List Raw.RawTopPort
→ Diagnostic.CheckResult
(List
(Checked.Wire (lengthList input-nets) 1 0))
collectTopOutputs input-nets q-net []ᴸ = Diagnostic.accepted []ᴸ
collectTopOutputs input-nets q-net (port ∷ᴸ ports)
with Raw.rawTopPortDirection port
... | Raw.bidirectionalPort =
Diagnostic.rejected
(singleton
(issue Diagnostic.unsupportedMode (Raw.rawTopPortName port)
"input or output" "bidirectional"
"Resolved bidirectional behavior is outside the checked two-valued core."))
... | Raw.inputPort = collectTopOutputs input-nets q-net ports
... | Raw.outputPort
with resolveTopOutputConnections
input-nets q-net (Raw.rawTopPortName port)
(Raw.rawTopPortConnections port)
... | Diagnostic.rejected diagnostics = Diagnostic.rejected diagnostics
... | Diagnostic.accepted here
with collectTopOutputs input-nets q-net ports
... | Diagnostic.rejected diagnostics = Diagnostic.rejected diagnostics
... | Diagnostic.accepted later = Diagnostic.accepted (here ++ᴸ later)
liftOutputWires : ∀ {inputCount}
→ List (Checked.Wire inputCount 1 0)
→ List (Checked.Wire inputCount 1 2)
liftOutputWires []ᴸ = []ᴸ
liftOutputWires (wire ∷ᴸ wires) =
liftBaseTwo wire ∷ᴸ liftOutputWires wires
liftOutputVec : ∀ {inputCount}
→ (wires : List (Checked.Wire inputCount 1 0))
→ Vec (Checked.Wire inputCount 1 2) (lengthList wires)
liftOutputVec []ᴸ = []
liftOutputVec (wire ∷ᴸ wires) = liftBaseTwo wire ∷ liftOutputVec wires
record CheckedRegisterCandidate : Type₀ where
constructor checkedRegisterCandidate
field
candidateSource : Raw.RawDesign
candidateStructuralProof : Validation.StructurallyValid candidateSource
candidateInputCount : ℕ
candidateOutputCount : ℕ
candidateClockInput : Fin candidateInputCount
candidateNetlist :
Checked.CheckedNetlist candidateInputCount candidateOutputCount 1 2
open CheckedRegisterCandidate public
buildCandidate :
(design : Raw.RawDesign)
→ Validation.StructurallyValid design
→ (item : Raw.RawInstance)
→ (ports : RegisterPorts)
→ (mode : RegisterMode)
→ (input-nets : List Raw.NetId)
→ (q-net : Raw.NetId)
→ (clock-index : Fin (lengthList input-nets))
→ Checked.Wire (lengthList input-nets) 1 0
→ Checked.Wire (lengthList input-nets) 1 0
→ Checked.Wire (lengthList input-nets) 1 0
→ List (Checked.Wire (lengthList input-nets) 1 0)
→ CheckedRegisterCandidate
buildCandidate design structural-proof item ports mode input-nets q-net
clock-index data-wire enable-wire control-wire outputs =
checkedRegisterCandidate
design structural-proof
(lengthList input-nets)
(lengthList outputs)
clock-index
(Checked.checkedNetlist
(modeInitial mode ∷ [])
(registerNodes mode data-wire enable-wire control-wire)
(liftOutputVec outputs)
(Checked.localWire fzero ∷ []))
normaliseParsedRegister :
(design : Raw.RawDesign)
→ Validation.StructurallyValid design
→ Raw.RawInstance
→ RegisterPorts
→ RegisterMode
→ Diagnostic.CheckResult CheckedRegisterCandidate
normaliseParsedRegister design structural-proof item ports mode
with TopInterface.collectInputNets (Raw.rawTopPorts design)
... | Diagnostic.rejected diagnostics = Diagnostic.rejected diagnostics
... | Diagnostic.accepted input-nets with outputNet item ports
... | Diagnostic.rejected diagnostics = Diagnostic.rejected diagnostics
... | Diagnostic.accepted q-net
with clockInput input-nets (registerC ports)
... | Diagnostic.rejected diagnostics = Diagnostic.rejected diagnostics
... | Diagnostic.accepted clock-index
with resolveBasePort input-nets q-net "register.D" (registerD ports)
... | Diagnostic.rejected diagnostics = Diagnostic.rejected diagnostics
... | Diagnostic.accepted data-wire
with resolveBasePort input-nets q-net "register.CE" (registerCE ports)
... | Diagnostic.rejected diagnostics = Diagnostic.rejected diagnostics
... | Diagnostic.accepted enable-wire
with resolveBasePort
input-nets q-net "register.control" (registerControl ports)
... | Diagnostic.rejected diagnostics = Diagnostic.rejected diagnostics
... | Diagnostic.accepted control-wire
with collectTopOutputs input-nets q-net (Raw.rawTopPorts design)
... | Diagnostic.rejected diagnostics = Diagnostic.rejected diagnostics
... | Diagnostic.accepted outputs =
Diagnostic.accepted
(buildCandidate
design structural-proof item ports mode input-nets q-net clock-index
data-wire enable-wire control-wire outputs)
normaliseRegisterItem :
(design : Raw.RawDesign)
→ Validation.StructurallyValid design
→ Raw.RawInstance
→ Diagnostic.CheckResult CheckedRegisterCandidate
normaliseRegisterItem design structural-proof item
with parseRegisterPorts (Raw.rawInstancePorts item)
... | nothing =
Diagnostic.rejected
(singleton
(issue Diagnostic.widthMismatch (Raw.rawInstanceName item)
"canonical D, C, CE, control, and Q scalar ports"
"a different raw port list"
"StructurallyValid should make this branch unreachable for FDRE/FDSE."))
... | just ports with normaliseRegisterMode item
... | Diagnostic.rejected diagnostics = Diagnostic.rejected diagnostics
... | Diagnostic.accepted mode =
normaliseParsedRegister design structural-proof item ports mode
wrong-count : Diagnostic.CheckResult CheckedRegisterCandidate
wrong-count =
Diagnostic.rejected
(singleton
(issue Diagnostic.unsupportedMode "raw instance list"
"exactly one FDRE or FDSE instance"
"zero or multiple instances"
"Multi-register and mixed combinational/state translation remains a later admission layer."))
normaliseTargetedRegister :
(design : Raw.RawDesign)
→ Validation.StructurallyValid design
→ Raw.RawInstance
→ Diagnostic.CheckResult CheckedRegisterCandidate
normaliseTargetedRegister design structural-proof item
with TopInterface.checkDevelopmentTarget design
... | Diagnostic.rejected diagnostics = Diagnostic.rejected diagnostics
... | Diagnostic.accepted tt =
normaliseRegisterItem design structural-proof item
normaliseSingleRegister : Validation.StructurallyChecked
→ Diagnostic.CheckResult CheckedRegisterCandidate
normaliseSingleRegister
(Raw.rawDesign target top-ports (item ∷ᴸ []ᴸ) , structural-proof) =
normaliseTargetedRegister
(Raw.rawDesign target top-ports (item ∷ᴸ []ᴸ)) structural-proof item
normaliseSingleRegister
(Raw.rawDesign target top-ports []ᴸ , structural-proof) =
wrong-count
normaliseSingleRegister
(Raw.rawDesign target top-ports (first ∷ᴸ second ∷ᴸ rest) ,
structural-proof) =
wrong-count