Wired: Low-level hardware design in Haskell Hardware Description - - PowerPoint PPT Presentation
Wired: Low-level hardware design in Haskell Hardware Description - - PowerPoint PPT Presentation
Wired: Low-level hardware design in Haskell Hardware Description and Verification Emil Axelsson, May 2007 Goal (example) bitMult = row andBitM where andBitM = and2 *=* ((cro *||* wireT0) *||* wireX) Help to reach the goal Logic
Goal (example)
bitMult = row andBitM where andBitM = and2 *=* ((cro *||* wireT0) *||* wireX)
Help to reach the goal
- Logic programming library (LP) in Haskell
- Relational Lava (uses LP)
exArith = do (res,x) <- free res <== x |-| 3 x <== 5 |*| 2 return res *Main> runLP exArith [7]
Setup constraints Solve constraints
Lava
- A Lava “circuit”:
A Haskell program that generates a netlist (directed graph with simple boolean gates as nodes)
- Feels like functional programming
inv :: Signal Bool -> Signal Bool *Main> simulate (inv ->- inv) low low *Main> (not . not) False False
Recursive generators
*Main> simulate (map (inv->-inv)) [low,high,low] [low,high,low]
Simple, compact descriptions for complicated structures
Relational Lava (RLava)
- Lava circuits have predefined signal-flow
direction
- Reason: Circuits are functions
- Ideally, connection patterns should abstract
away from signal flow (think about real electrical wires)
Relational Lava (RLava)
- RLava models circuits as relations instead:
- Relations implemented using the LP library
- RLava's combinator library mimics Lava's
- Simulation, verification, synthesis, etc. is done
through Lava (using convert)
*Main> L.simulate (convert (inv <> inv)) L.low low
Signal flow abstraction
exRLava = mapM ((inv <> wire 1)
- |-
(converse inv <> wire 1) ) wire :: Term Int -> Signal -> LP Signal
Wired background
- Netlists are lacking geometrical information
- Cell placement and wire routing needed before
fabrication
- Pre-layout performance estimation very hard!!
– Main reason: hard to predict wire properties
- Automatic tools are often not good enough
– Evidence: Large parts of Intel's chips are designed manually
- Can Haskell make manual design easier?
Basic idea
- Use connection patterns as in Lava, but let
them also represent layout
- Example, row:
- This has been done before (e.g. in Lava), but
we want a more direct connection to standard cell layout, including wiring:
Wired circuits
- Wired circuit: A rectangular tile characterized by
its four ports (w, n, s and e)
w e n s
and2 :: Circ Ins ((Sig, Sig), Ins) (Ins, Sig) Ins
Wired example
(*||*) :: ( Port wL, Port nL, Port sL, Port x , Port nR, Port sR, Port eR ) => Circ wL nL sL x -> Circ x nR sR eR
- > Circ wL (nL,nR) (sL,sR) eR
and2 :: Circ Ins ((Sig, Sig), Ins) (Ins, Sig) Ins
wL eR (nL,nR) (sL,sR)
Wired example
(*||*) :: ( Port wL, Port nL, Port sL, Port x , Port nR, Port sR, Port eR ) => Circ wL nL sL x -> Circ x nR sR eR
- > Circ wL (nL,nR) (sL,sR) eR
and2 :: Circ Ins ((Sig, Sig), Ins) (Ins, Sig) Ins and2 *||* and2 :: Circ Ins (((Sig, Sig), Ins), ((Sig, Sig), Ins)) ((Ins, Sig), (Ins, Sig)) Ins renderCircuit "circ" (and2 *||* and2)
wL eR (nL,nR) (sL,sR)
Wires
wireX :: Circ Sig Ins Ins Sig wireY :: Circ Ins Sig Sig Ins wireL0 :: Circ Ins Sig Ins Sig wireT0 :: Circ Sig Ins Sig Sig cro :: Circ Sig Sig Sig Sig
Wires
wireX :: Circ Sig Ins Ins Sig wireY :: Circ Ins Sig Sig Ins wireL0 :: Circ Ins Sig Ins Sig wireT0 :: Circ Sig Ins Sig Sig cro :: Circ Sig Sig Sig Sig bitMult = row andBitM where andBitM = and2 *=* ((cro *||* wireT0) *||* wireX) renderCircuit "circ" (bitMult `ofLengthX` 3)
Size inference
- Haskell type system checks that interfaces of
connected circuits match, but not sizes
- Sizes are checked using logical constraints in
the LP library
- By solving size constraints we also get size
inference for free!
Size inference
bitMult `ofLengthX` 3 64 x
*=*
length 3 Unifies intermediate ports
Combinators
(*=*) :: ( Port wL, Port x, Port sL, Port eL , Port wH, Port nH, Port eH ) => Circ wL x sL eL -> Circ wH nH x eH
- > Circ (wL,wH) nH sL (eL,eH)
(*||~) :: (Port w, Port n, Port s, Port e, Port x) => Circ w n s x
- > Circ x [n] [s] e
- > Circ w [n] [s] e
(*=~) :: (Port w, Port n, Port s, Port e, Port x) => Circ w x s e
- > Circ [w] n x [e]
- > Circ [w] n s [e]
Patterns
rowN :: (Port x, Port n, Port s) => Term Int -> Circ x n s x -> Circ x [n] [s] x rowN n circ = unintR n rowN' where rowN' 0 = nilY rowN' n = circ *||~ rowN' (n-1) row :: (Port y, Port n, Port s) => Circ y n s y -> Circ y [n] [s] y row circ = do cR <- free l <- lengthR $ north cR l <== (lengthR $ south cR) cR <== rowN l circ n
nilY
circ
Softening
bitMultR :: (RLava.Signal, [RLava.Signal]) -> LP [RLava.Signal] bitMultR (x,as) = do ys <- sequence [free | _ <- as] -- Outputs (w,n,s,e) <- soften (bitMult `ofLengthX` term (length as)) w =:= ((),x) n =:= term [((a,()), ()) | a <- as] s =:= term [((),y) | y <- ys] return ys *Main> L.simulate (convert bitMultR) (L.high, [L.low, L.high]) [low,high]
Output
- Simulation, verification, synthesis:
Wired → RLava → Lava
- Timing estimation:
Wired → RLava
- Visualization:
Wired → Postscript
- Real layout (not yet):
Wired → ?? → GDS2
Case study: Prefix circuits
Given inputs x1, x2, … xn compute y1 = x1 y2 = x1 ○ x2 … yn = x1 ○ x2 ○ … ○ xn for ○, an associative (but not necessarily commutative) operator
Prefix circuits (2)
- Very central component in microprocessors
- Most common use: Computing carries in fast
adders
- Trying different operators
– Addition:
prefix (+) [1,2,3,4]
Prefix circuits (2)
- Very central component in microprocessors
- Most common use: Computing carries in fast
adders
- Trying different operators
– Addition:
prefix (+) [1,2,3,4] = [1, 1+2, 1+2+3, 1+2+3+4] = [1,3,6,10]
Prefix circuits (2)
- Very central component in microprocessors
- Most common use: Computing carries in fast
adders
- Trying different operators
– Addition:
prefix (+) [1,2,3,4] = [1, 1+2, 1+2+3, 1+2+3+4] = [1,3,6,10]
– Boolean OR:
prefix (||) [F,F,F,T,F,T,T,F]
Prefix circuits (2)
- Very central component in microprocessors
- Most common use: Computing carries in fast
adders
- Trying different operators
– Addition:
prefix (+) [1,2,3,4] = [1, 1+2, 1+2+3, 1+2+3+4] = [1,3,6,10]
– Boolean OR:
prefix (||) [F,F,F,T,F,T,T,F] = [F,F,F,T,T,T,T,T]
Prefix circuits (3)
Implementation choices (relying on associativity): prefix (○) [x1,x2,x3,x4] = [y1,y2,y3,y4]
– Serial:
y4 = ((x1○x2) ○ x3) ○ x4
– Parallel:
y4 = (x1○x2) ○ (x3○x4)
– Sharing:
y4 = y3 ○ x4
Serial prefix (standard diagram)
- perator
8 inputs depth 7 size 7
1 2
… 7 8
1 1:2
… 1:7 1:8
Parallel prefix (Sklansky)
- Serial: Fewer operators, linear logical depth
- Parallel: More operators, logarithmic depth
Sklansky in Lava
sklansky op [a] = [a] sklansky op as = ls' ++ [op (last ls', r) | r <- rs'] where k = (length as + 1) `div` 2 (ls,rs) = splitAt k as ls' = sklansky op ls rs' = sklansky op rs
Sklansky in Lava
sklansky op [a] = [a] sklansky op as = ls' ++ [op (last ls', r) | r <- rs'] where k = (length as + 1) `div` 2 (ls,rs) = splitAt k as ls' = sklansky op ls rs' = sklansky op rs
Abstract wires
- Need a notion of abstract wires in Wired
- These are called buses
sklansky :: ((a,a) -> a) -> [a] -> [a]
Can contain lots of concrete wires
Buses
- Generalization of wireX, wireY, wireLX,
wireTX, cro
- Shape determined by context
wireT0 busT0 Example instance
Bus example
bus :: Circ (Sig, Ins, (Sig,Sig)) Ins (Sig, Ins, (Sig,Sig)) (Sig, Ins, (Sig,Sig)) bus = busT0 `withConstraint` \cct -> do [a,b,c,d,e,f] <- replicateM 6 free west cct === tup3 (sig1 a) (Ins 60) (sig2 b c) south cct === tup3 (sig1 d) (Ins 90) (sig2 e f)
Sklansky in Wired
sklansky 0 op opFO = rowN 1 $ nilX `withConstraint` \circ -> north circ <== (structure =<< asLP south =<< op) sklansky d op opFO = (joinL ~||~ joinR) *=~ (skl~||~skl) where skl = sklansky (d-1) op opFO n = term (2^(d-1) - 1)
- p' = op *=* alignLeft 4
- pFO' = opFO *=* alignLeft 4
joinL = rowN n (busY*=*busY) ~||* (busT1*=*busY) joinR = rowN n opFO' ~||* op'
Sklansky with single-bit operator
renderCircuit "circ" $ sklansky 3 dot1 dot1FO
Sklansky with pair operator
renderCircuit "circ" $ sklansky 3 dot dotFO
Summary
- Haskell can alleviate manual design
- Being built on top of other libraries, Wired itself
is quite a small library
- LP is the perfect foundation for RLava/Wired
- Read about LP and Wired:
Matthew Naylor, Emil Axelsson and Colin Runciman.
A Functional-Logic Library for Wired. HFL'07
http://www.cs.chalmers.se/~emax/wired/documents/LP_HFL07.pdf
Future work
- Clever generators
- Connection to realistic design flow
- More performance analyses
– Power, cross-talk, etc.