Access to Circuit Generators in Embedded HDLs Gordon Pace Christian Tabone University of Malta March...
-
Upload
hortense-stone -
Category
Documents
-
view
227 -
download
6
Transcript of Access to Circuit Generators in Embedded HDLs Gordon Pace Christian Tabone University of Malta March...
Access to Circuit Generators in Embedded HDLsGordon PaceChristian Tabone
University of MaltaMarch 2008
Introduction•As circuits grow in size, we require more
abstract techniques for concise descriptions.•The circuits generated by these abstract
descriptions are then typically analysed.•But the circuits generators themselves
contain a lot of potentially useful information:▫Circuit structure▫‘Similar’ families of structured descriptions▫Circuit transformations
Embedded Languages for h/w Design•Embedding a HDL in a general-purpose language
provides a meta-language to the HDL.
Host Language
Embedded language
• Creating basic components
• Component composition
• Access to components
• etc
Embedded Languages for h/w Design•Embedding a HDL in a general-purpose language
provides a meta-language to the HDL.
Host Language
Embedded language
• Creating basic components
• Component composition
• Access to components
• etc
Circuit generators
Circuit analysis
Circuit transformations
Functional View of Circuits: Lava, Hydra, Hawk… •Circuits are described and used as
functions:adder 1 (cin, ([a],[b])) = ….adder n (cin, (as,bs)) = …. where n’ = n `div` 2 (ss1, cmid) = adder n’ (cin, (as1, bs1)) (ss20, cout0) = adder (n-n’) (low, (as2, bs2)) (ss21, cout1) = adder (n-n’) (high, (as2, bs2)) ss2 = mux (cmid, (ss20, ss21)) cout = mux (cmid, (cout0, cout1))
adder 1 (cin, ([a],[b])) = ….adder n (cin, (as,bs)) = …. where n’ = n `div` 2 (ss1, cmid) = adder n’ (cin, (as1, bs1)) (ss20, cout0) = adder (n-n’) (low, (as2, bs2)) (ss21, cout1) = adder (n-n’) (high, (as2, bs2)) ss2 = mux (cmid, (ss20, ss21)) cout = mux (cmid, (cout0, cout1))
Functional View of Circuits: Lava, Hydra, Hawk… •Circuits are described and used as
functions:adder 1 (cin, ([a],[b])) = ….adder n (cin, (as,bs)) = (ss1++ss2, cout) where n’ = n `div` 2 (ss1, cmid) = adder n’ (cin, (as1, bs1)) (ss20, cout0) = adder (n-n’) (low, (as2, bs2)) (ss21, cout1) = adder (n-n’) (high, (as2, bs2)) ss2 = mux (cmid, (ss20, ss21)) cout = mux (cmid, (cout0, cout1))
adder 1 (cin, ([a],[b])) = ….adder n (cin, (as,bs)) = (ss1++ss2, cout) where n’ = n `div` 2 (ss1, cmid) = adder n’ (cin, (as1, bs1)) (ss20, cout0) = adder (n-n’) (low, (as2, bs2)) (ss21, cout1) = adder (n-n’) (high, (as2, bs2)) ss2 = mux (cmid, (ss20, ss21)) cout = mux (cmid, (cout0, cout1))
The description induces a hierarchical structure, grouping
gates together (ones produced by the same call), which is lost
Functional View of Circuits: Lava, Hydra, Hawk… •Circuits are described and used as
functions:adder 1 (cin, ([a],[b])) = ….adder n (cin, (as,bs)) = …. where n’ = n `div` 2 (ss1, cmid) = adder n’ (cin, (as1, bs1)) (ss20, cout0) = adder (n-n’) (low, (as2, bs2)) (ss21, cout1) = adder (n-n’) (high, (as2, bs2)) ss2 = mux (cmid, (ss20, ss21)) cout = mux (cmid, (cout0, cout1))
adder 1 (cin, ([a],[b])) = ….adder n (cin, (as,bs)) = …. where n’ = n `div` 2 (ss1, cmid) = adder n’ (cin, (as1, bs1)) (ss20, cout0) = adder (n-n’) (low, (as2, bs2)) (ss21, cout1) = adder (n-n’) (high, (as2, bs2)) ss2 = mux (cmid, (ss20, ss21)) cout = mux (cmid, (cout0, cout1))
There is no way in which we can access information about the
parametrised circuit adder as a family of circuits to
analyse/reason about them as a single class
Block View of Circuits: Wired
•Circuits are viewed as objects, which can have their ports wired together explicitly or through combinators:
sklansky op 1 = idWiresklansky op k = left ~||~ right
wherehalf_k = k `div` 2left = forkLast (sklansky op half_k)right = extend op (sklansky op half_k)
sklansky op 1 = idWiresklansky op k = left ~||~ right
wherehalf_k = k `div` 2left = forkLast (sklansky op half_k)right = extend op (sklansky op half_k)
Block View of Circuits: Wired
•Circuits are viewed as objects, which can have their ports wired together explicitly or through combinators:
sklansky op 1 = idWiresklansky op k = left ~||~ right
wherehalf_k = k `div` 2left = forkLast (sklansky op half_k)right = extend op (sklansky op half_k)
sklansky op 1 = idWiresklansky op k = left ~||~ right
wherehalf_k = k `div` 2left = forkLast (sklansky op half_k)right = extend op (sklansky op half_k)
Information about blocks is kept thanks to the use of combinators
to glue circuits together.
This information can be useful for placement, delay analysis, etc.
Block View of Circuits: Wired
•Circuits are viewed as objects, which can have their ports wired together explicitly or through combinators:
sklansky op 1 = idWiresklansky op k = left ~||~ right
wherehalf_k = k `div` 2left = forkLast (sklansky op half_k)right = extend op (sklansky op half_k)
sklansky op 1 = idWiresklansky op k = left ~||~ right
wherehalf_k = k `div` 2left = forkLast (sklansky op half_k)right = extend op (sklansky op half_k)
The enforced use of combinators to keep placement information makes it more awkward to use than the functional approach
Block View of Circuits: Wired
•Circuits are viewed as objects, which can have their ports wired together explicitly or through combinators:
sklansky op 1 = idWiresklansky op k = left ~||~ right
wherehalf_k = k `div` 2left = forkLast (sklansky op half_k)right = extend op (sklansky op half_k)
sklansky op 1 = idWiresklansky op k = left ~||~ right
wherehalf_k = k `div` 2left = forkLast (sklansky op half_k)right = extend op (sklansky op half_k)
We still have no way of accessing the family of circuits encoded in the sklansky (or sklansky op n)
function.
HDLs Embedded in Meta-Languages•One possible solution is to use a meta-
language as a host language.▫ Circuit generators can be quoted and would
then be considered just like any other data object.
▫ Delaying circuit application gives us the structure induced by the description without losing the functional view of circuits.
•But at a cost: complexity of the host programming language.▫ Can the use of reflection features be limited to
(hidden) inside of the embedded language?
reFLect
•Developed by Intel specifically for applications in hardware design and verification.
•Strongly typed functional language with meta-programming features.
•reFLect programs are able to examine, modify or create other reFLect programs as data objects.
Composing Circuit Representations•Meta-constructs are used to provide a
structural representation of the circuits.
•Primitive gates decompose the input to obtain the required signals, and constructs the respective object program.
let inv (Signal {| `a |}) = Signal {| NOT `a |};
let and2 (Signal {| (`a, `b) |} = Signal {| `a AND `b |};
let inv (Signal {| `a |}) = Signal {| NOT `a |};
let and2 (Signal {| (`a, `b) |} = Signal {| `a AND `b |};
Representing Signals•The inputs and outputs can be modelled as:
▫A structure of signals each containing a single bit
▫A single signal consisting of a structure of bits•Current implementation uses a signal of
structures representation▫Simple design▫One common type▫Overhead code
Signal *a
Signal *b
Signal *a
*b
zipp
unzipp
Circuit Descriptions
let mux s_ab = val (s, ab) = unzipp s_ab in val (a, b) = unzipp ab in or2 (zipp (and2 (zipp (inv s, a)), and2 (zipp (s, b))));
let mux s_ab = val (s, ab) = unzipp s_ab in val (a, b) = unzipp ab in or2 (zipp (and2 (zipp (inv s, a)), and2 (zipp (s, b))));
: mux (zipp (low, zipp (low, high)));
Signal {| ((NOT low) AND low) OR (low AND high) |}
: mux (zipp (low, zipp (low, high)));
Signal {| ((NOT low) AND low) OR (low AND high) |}
Marking Circuit Blocks
•Circuit descriptions are defined as modular functions by the designer, but the internal structure discards the boundaries of sub-functions resulting in a netlist of interconnected gates.
c0
c1
c2
c3
c4
n0
n1
s
Marking Circuit Blocks
let makeBlock circuit = let vars = genInputVariables circuit in let fnct = circuit vars in \(Signal inp) . {| (\`vars . `fnct) `inp |};
let makeBlock circuit = let vars = genInputVariables circuit in let fnct = circuit vars in \(Signal inp) . {| (\`vars . `fnct) `inp |};
Marking Circuit Blocks
let muxBlk = makeBlock mux;let muxBlk = makeBlock mux;
: muxBlk (zipp (low, zipp (low, high)));
Signal {| (\(v1,(v2,v3)) . ((NOT v1) AND v2) OR (v1 AND v3)) (low, (low, high))
|}
: muxBlk (zipp (low, zipp (low, high)));
Signal {| (\(v1,(v2,v3)) . ((NOT v1) AND v2) OR (v1 AND v3)) (low, (low, high))
|}
(\(v1,(v2,v3)) . ((NOT v1) AND v2) OR (v1 AND v3))
Marking Circuit Blocks
let muxBlk = makeBlock mux;let muxBlk = makeBlock mux;
: muxBlk (zipp (low, zipp (low, high)));
Signal {| (\(v1,(v2,v3)) . ((NOT v1) AND v2) OR (v1 AND v3)) (low, (low, high))
|}
: muxBlk (zipp (low, zipp (low, high)));
Signal {| (\(v1,(v2,v3)) . ((NOT v1) AND v2) OR (v1 AND v3)) (low, (low, high))
|}
(\(v1,(v2,v3)) . ((NOT v1) AND v2) OR (v1 AND v3))
The structure of the described circuit is retained as a function,
and not simply as an unevaluated expression
Prefix Circuits: Sklansky
Prefix Circuits: Sklansky
letrec skl n op inp = let skl' 1 op inps = inps /\ skl' n op inps = val (lst,rst) = unzipp (splitSignalBus n inps) in let ls2 = skl (busLength lst) op lst in let rs2 = skl (busLength rst) op rst in let carry = lastSignal ls2 in let apply r = op (zipp (carry, r)) in zipp (ls2 @ map apply rs2) in makeBlock (skl' n op) inp;
letrec skl n op inp = let skl' 1 op inps = inps /\ skl' n op inps = val (lst,rst) = unzipp (splitSignalBus n inps) in let ls2 = skl (busLength lst) op lst in let rs2 = skl (busLength rst) op rst in let carry = lastSignal ls2 in let apply r = op (zipp (carry, r)) in zipp (ls2 @ map apply rs2) in makeBlock (skl' n op) inp;
Prefix Circuits: Sklansky
Related Work: reFLect HDL•An HDL embedded in reFLect similar to Lava.•The reflection features of reFLect are used to
provide access to the circuit structure.•The meta-programming constructs are not
concealed.•No relationship is maintained between the
generator and the circuit.▫No hierarchical structure of sub-functions
(blocks)▫No access to a single class of “family of circuits”
Related Work: DUAL-EVAL
•The Lisp quotation is used to mark module boundaries thus delaying the evaluation.
•Modules are a block representation.
(HALF-ADDER*) = `(HALF-ADDER (A B) (SUM CARRY) (( G0 (SUM) B-XOR (A B)) ( G1 (CARRY) B-AND (A B))) NIL)
(HALF-ADDER*) = `(HALF-ADDER (A B) (SUM CARRY) (( G0 (SUM) B-XOR (A B)) ( G1 (CARRY) B-AND (A B))) NIL)
Hardware Compilers•We are looking into the use of these
techniques for hardware compilers.•Access to structure enables:
▫ Generating placement hints▫ Post-compilation optimisations
•Access to the generator (compiler) gives us means of:▫ Analysing the generator in general▫ Proving compiler invariants automatically
using structural induction on the input program.
Placement Hints
•We are looking into means of introducing placement hints for blocks.
•Clustering/grouping of blocks is already possible, but we are looking into adding Ruby/Pebble/Wired-style placement information.
•Such hints will accompany, not replace, the functional descriptions.
Modular Verification
•Access to generators enabling:▫ Parametrised circuit verification.▫ Proving properties of circuit combinators
(eg commutativity of certain h/w compiler cases).
•Structural analysis:▫ Enables tagging of properties of
subcircuits.▫ Allow assume-guarantee style reasoning
for circuit analysis.
Conclusions•Techniques enabling abstract descriptions
of circuits should provide techniques to analyse:▫ not only the circuits,▫ but also the generation structrure, and▫ the abstract generators/transformers.
•Meta-programming seems to be providing the necessary infrastructure to enrich embedded languages with this.
•But we’d much rather keep as much of this hidden beneath the bonnet.
Questions…