1 / 37

A Functional-Logic Library for Wired

A Functional-Logic Library for Wired. Matthew Naylor and Collin Runciman – University of York Emil Axelsson – Chalmers University Haskell Workshop 2007. Acknowledgement. This project recieves Intel-custom funding from the Semiconductor Research Corporation. Overview.

isleen
Download Presentation

A Functional-Logic Library for Wired

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. A Functional-Logic Library for Wired Matthew Naylor and Collin Runciman – University of York Emil Axelsson – Chalmers University Haskell Workshop 2007

  2. Acknowledgement This project recieves Intel-custom funding from the Semiconductor Research Corporation

  3. Overview • Background: Digital circuit design • Wired: Low-level hardware design in Haskell • LP: Logic programming in Haskell • Wired implemented using LP

  4. Circuit abstraction levels Just like software, digital circuits can be described at various levels of abstraction: • Netlist: Directed graph with simple Boolean gates as nodes • Placed netlist: Netlist where every gate has been assigned a unique position on the chip • Final layout: Placed netlist where every connection has been assigned a unique route in the metal layers • Netlist-to-layout is normally done by automatic tools

  5. The problem… • Integrated circuit performance is largely determined by wire properties • Long wire  longer signal delay, more power dissipation • Many long wires  bigger chip area • The abstract netlist view leaves wires implicit! • Conclusion: Hard to reason about performance at the netlist level • Evidence: Large parts of Intel’s chips are designed through manual layout editing

  6. Can Haskell help? • Haskell has already proven to be useful for hardware description at the (placed) netlist level (Lava, Hydra) • Idea: Take the Lava approach further and describe the full layout, including wiring in Haskell • Result: Wired

  7. Wired example Wires and gates are conceptually the same thing! bitMult = row (and2 *=* wiring) where wiring = (wire *||* wireT0 *||* wire) `withConstraintW` (<== sigStruct) Netlist and layout described simultaneously

  8. Functional circuit model • Lava represents circuits as functions • Inputs and outputs are determined syntactically • But where is the input here?

  9. Relational circuit model One relational combinator captures a whole family of functional ones (signal-flow abstraction)

  10. Relational circuit model One relational wire captures a whole family of functional ones (signal-flow abstraction)

  11. Relational circuit model Size inference x 64

  12. LP: Logic programming in Haskell • Old Wired implementation very ad-hoc and inefficient • Matthew Naylor spotted that Curry was better suited for implementing Wired • This led to the birth of the library LP • Inspired by Curry and Typed logical variables in Haskell. Claessen and Ljunglöf (HW’2000) • Easy construction/deconstruction of logical terms • Supports residuation (heavily used in Wired) • Supports non-determinism

  13. Logical terms • Definition • Constructors data Uni = Var VarID | Ctr Int [Uni] | Int Int newtype Term a = Term { uni :: Uni } type VarID = Int nil :: Term [a] nil = Term (Ctr 0 []) (|>) :: Term a -> Term [a] -> Term [a] a |> as = Term (Ctr 1 [uni a, uni as]) int :: Int -> Term Int int n = Term (Int n) ...

  14. Automating data type creation (nil ::: (|>)) = datatype (cons0 [] \/ cons2 (:)) (true ::: false) = datatype (cons0 True \/ cons0 False)

  15. Logic programs Non-determinism + state data LP a = LP { runLP :: State -> [(a, State)] } type State = (Map VarID Val, VarID) type Residual = Uni -> LP () data Val = Bound Uni | Unbound [Residual] Current variable mapping, and a fresh ID Possibly bound to a term Actual implementation uses Hinze’s two-continuation monad transformer and IORef’s

  16. Basic LP interface (>>) interpreted as conjunction instance Monad LP ... instance MonadPlus LP ... (?) :: LP a -> LP a -> LP a (?) = mplus newVar :: Val -> LP VarID readVar :: VarID -> LP Val writeVar :: VarID -> Val -> LP () Disjunction + failure

  17. Unification unify :: Uni -> Uni -> LP () unify a b = do ra <- root a; rb <- root b unif ra rb where unif (Var v) (Var w) | v == w = return () unif (Var v) b = bindVar v b unif a (Var w) = bindVar w a unif (Int a) (Int b) | a == b = return () unif (Ctr n as) (Ctr m bs) | n == m = unif' as bs unif _ _ = mzero unif' [] [] = return () unif' (a:as) (b:bs) = unify a b >> unif' as bs

  18. Logical class class Logical a where free :: LP a (===) :: a -> a -> LP () instance Logical (Term a) where free = return . Term . Var =<< unboundVar a === b = unify (uni a) (uni b) instance (Logical a, Logical b) => Logical (a,b) where free = liftM2 (,) free free (a0,a1) === (b0,b1) = a0 === b0 >> a1 === b1

  19. Example: Append app :: Term [a] -> Term [a] -> Term [a] -> LP () app as bs cs = do as===nil bs===cs ? do ((a,as'),cs’) <- free a|>as' === as a|>cs' === cs app as' bs cs' testApp = run $ do as' <- free let as = 1|>2|>3|> as' cs = 1|>2|>3|>4|>5|> nil bs <- free app as bs cs return bs *Main> testApp [[4,5],[5],[]]

  20. Pattern matching pat --> rhs = return (pat,rhs) caseOf a as = do (pat,rhs) <- free >>= as pat === a rhs app as bs cs = caseOf (as,cs) alts where alts ((a,as'),cs') = (nil,cs') --> (bs===cs) ? (a|>as', a|>cs') --> app as' bs cs'

  21. Residuation rigid :: Logical b => (Uni -> LP b) -> (Uni -> LP b) ... Accepts variables Does not accept variables (pure function)

  22. Residuation rigid :: Logical b => (Uni -> LP b) -> (Uni -> LP b) ... data Val = Bound Uni | Unbound [Residual] type Residual = Uni -> LP () bindVar :: VarID -> Uni -> LP () bindVar v a = do Unbound rs <- readVar v writeVar v (Bound a) rs `resumeOn` a Used by unify to instantiate a variable

  23. Rigid deconstruction/arithmetic unint :: Logical b => Term Int -> (Int -> LP b) -> LP b unint a f = rigid (\(Int a) -> f a) (uni a) liftInt2 f a b = unint a (\a -> unint b (\b -> return (int (f a b)))) (|+|), (|-|), (|*|) :: Term Int -> Term Int -> LP (Term Int) (|+|) = liftInt2 (+) (|-|) = liftInt2 (-) (|*|) = liftInt2 (*)

  24. Residuation example (<==) :: Logical a => a -> LP a -> LP () a <== m = (a===) =<< m testResid = run $ do (res,x) <- free res <== x |-| 3 x <== 5 |*| 2 return res *Main> testResid [7]

  25. Determistic relations If any two of a, b and c are known, the third one will be inferred a <+> b = do c <- a |+| b b <== c |-| a a <== c |-| b return c testPlus = run $ do a <- free 20 <== ((1<+>) =<< (2<+>) =<< (3<+>a)) return a *Main> testPlus [14] • Completely deterministic • Abstract information flow • Exactly what Wired needs!

  26. n w e s Wired data Circuit w n s e = Circ { west :: w , north :: n , south :: s , east :: e , sizeX :: Term Size , sizeY :: Term Size , layout :: Term Layout } type Circ w n s e = LP (Circuit w n s e) Ports : Contain geometry and signals of each side

  27. nH (wL,wH) (eL,eH) nL nH wL wH eL eH sL sL sL Wired: Below composition (*=*) :: (...) => Circ wL x sL eL -> Circ wH nH x eH -> Circ (wL,wH) nH sL (eL,eH) circL *=* circH = do Circ wL nL sL eL szxL szyL layL <- circL Circ wH nH sH eH szxH szyH layH <- circH nL === sH szy <- szyL <+> szyH let lay = (term (layL :=: layH)) return $ Circ (wL,wH) nH sL (eL,eH) szxL szy lay *=* Connects netlists and exchanges geometrical info

  28. Size inference revisited x 64

  29. Connection pattern: row rowN :: (...) => Term Int -> Circ x n s x -> Circ x [n] [s] x rowN n circ = unint n rowNN where rowNN 0 = nilY rowNN n = circ *||~ rowNN (n-1) row :: (...) => 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 return cR Length determined by context. lengthR is a rigid version of length.

  30. Bit multiplier revisited bitMult = row (and2 *=* wiring) where wiring = (wire *||* wireT0 *||* wire) `withConstraintW` (<== sigStruct) *Main> renderCircuit "circ" (bitMult `ofLengthX` 6)

  31. Example: Sklansky sklansky 0 op opFO = rowN 1 $ nilX `withConstraint` \c -> north c <== (structure =<< asLP south =<< op) sklansky d op opFO = consW (joinL *=* skl) ~||~ consE (joinR *=* skl) where skl = sklansky (d-1) op opFO op' = op *=*alignLeft opFO' = opFO*=*alignLeft joinL = row (busY*=*busY) ~||* (busT1*=*busY) joinR = row opFO' ~||* op'

  32. Example: Sklansky *Main> renderCircuit "circ" $ sklansky 3 dot dotFO

  33. Related work • Lava: • Claessen, Sheeran, Singh. CHARME’2001. • Logic programming in Haskell: • Typed logical variables in Haskell. Claessen and Ljunglöf, HW’2000. • Backtracking, interleaving and terminating monad transformers. Kiselyov, Shan, Friedman and Sabry, ICFP’2005. • SparseCheck (Matthew Naylor 2007)

  34. Future work • LP: • More forms of non-determinism (breadth-first, fair backtracking…) • Lazy narrowing • Wired: • Working on new much simplified version (might not need LP…) • Producing real layout for evaluation • Examples…

  35. Unification unboundVar :: LP VarID unboundVar = newVar (Unbound []) bindVar :: VarID -> Uni -> LP () bindVar v a = writeVar v (Bound a) ifBound :: VarID -> (Uni -> LP b) -> LP b -> LP b ifBound v t f = readVar v >>= decons where decons (Bound a) = t a decons (Unbound _) = f root :: Uni -> LP Uni root (Var v) = ifBound v root (return (Var v)) root a = return a

  36. Residuation rigid' :: Logical b => (Uni -> LP b) -> (Uni -> LP b) ... data Val = Bound Uni | Unbound [Residual] type Residual = Uni -> LP () bindVar :: VarID -> Uni -> LP () bindVar v a = do Unbound rs <- readVar v writeVar v (Bound a) rs `resumeOn` a resumeOn :: [Residual] -> Uni -> LP () resumeOn rs (Var v) = do Unbound ss <- readVar v writeVar v (Unbound (rs ++ ss)) resumeOn rs a = mapM_ (resume a) rs where resume a g = g a Used by unify to instantiate a variable

  37. Residuation rigid' :: Logical b => (Uni -> LP b) -> (Uni -> LP b) rigid' f a = do ar <- root a b <- free let g x = f x >>= (===b) [g] `resumeOn` ar return b rigid :: Logical b => (Term a -> LP b) -> (Term a -> LP b) rigid f a = rigid' (f . Term) (uni a) b gives access to the (future) result of the computation

More Related