access to circuit generators in embedded hdls gordon pace christian tabone university of malta march...

Post on 12-Jan-2016

228 Views

Category:

Documents

6 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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…

top related