aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--TODO120
-rw-r--r--notes/female-node.txt13
-rw-r--r--notes/flo.txt2
-rw-r--r--spec/spec.tex1
-rw-r--r--src/main/stanza/firrtl-ir.stanza4
-rw-r--r--src/main/stanza/ir-parser.stanza1
-rw-r--r--src/main/stanza/passes.stanza235
-rw-r--r--test/passes/to-flo/gcd.fir45
9 files changed, 344 insertions, 80 deletions
diff --git a/Makefile b/Makefile
index acdda20c..51d30ae1 100644
--- a/Makefile
+++ b/Makefile
@@ -23,6 +23,9 @@ build:
check:
cd $(test_dir)/passes && lit -v . --path=$(root_dir)/utils/bin/
+chisel3:
+ cd $(test_dir)/chisel3 && lit -v . --path=$(root_dir)/utils/bin/
+
clean:
rm -f $(test_dir)/*/*/*.out
rm -f $(test_dir)/*/*.out
diff --git a/TODO b/TODO
index 7be956ea..28e40327 100644
--- a/TODO
+++ b/TODO
@@ -1,67 +1,65 @@
-Passes:
-- To-Real-IR
-+ Inline Modules
-+ Remove Nested Expressions
-+ Flo
+================================================
+========== ADAM's BIG ASS TODO LIST ============
+================================================
-TODO
- Change all primops to be strict on data widths
- Change parser to use <> syntax (and update all tests) (patrick)
- Think about on-reset, add it
- Think about expanding mems, more complicated than first glance! Change DefMem to be size, and element type
- Make instances always male, flip the bundles on declaration
- Talk to palmer/patrick about how writing passes is going to be supported
- Add asserts, printf to spec
- Write lowering step for primops
- Figure out how widths propogate for all updated primops (Adam)
- Add bit-reduce-and etc to primops (Jonathan)
- //HANDLED IN FRONT END// Write pass to rename identifiers (alpha-transform) (Adam)
- Add partial bulk connect (Scott, Stephen)
- Add FIFOs to the IR (Palmer)
- Multi-streams for print statements/asserts (Jack)
- Consider def female node. (Patrick)
- Think about supporting generic primops on bundles and vecs (Adam) (wait until front-end more completed)
+Important things:
+ Include new parser
+
+======== Update Core ==========
+Change all primops to be strict on data widths
+Merge pull request and update tests
+on-reset
+Write lowering step for primops
+Add bit-reduce-and etc to primops (Jonathan)
+Add source locaters
- Update spec
- add assertions
- cannot connect directly to a mem (loc can never contain a mem)
- Front-end needs to guarantee unique names per module.
- FIRRTL rule: No name can be a prefix of any other name.
- Future questions to address in spec:
- Introduction – motivation, and intended usage
- Philosophical justifications for all constructs
- More introduction for types, e.g. what is a ground type?
- What is a statement? What is an expression? What is a memory? Difference between vector type and memory? What are accessors for?
- Why would I ever write an empty statement? Mainly for use by compiler/passes
- What is a structural element? Duplication?
- Subtracting two unsigned numbers… Should talk to a math guy to figure it out
- What are shift left and shift right operations? HW doesn’t have these concepts. Need justification.
- What is lowered form? What is it for?
-
-
-Checks:
+======== Check Passes ==========
+Parser
+ Error if incorrectly assign stuff, like use = instead of :=
+Well-formed high firrtl
+ Unique names per module
+ No name can be a prefix of any other name.
+ No nested modules
+ Only modules in circuit (no statements or expressions)
+ Cannot connect directly to a mem ever
Subfields are only on bundles, before type inference
- After adding dynamic assertions, insert bounds check with accessor expansion
+ Can only connect to a Ref or Subfield or Index
+ UInt only has positive ints
+After adding dynamic assertions, insert bounds check with accessor expansion
+Well-formed low firrtl
All things only assigned to once
- Front-end needs to guarantee unique names per module.
- FIRRTL rule: No name can be a prefix of any other name.
-
-Tests:
- Error if declare anything other than module in circuit
- Error if incorrectly assign stuff, like use = instead of :=
- Error: Node not parsed for stmts
-
-Male node:
-defnode n = e
-==>
-wire n
-n := e
-
-Female node:
-defnode n = e
-==>
-wire n
-e := n
-
+======== Other Passes ========
+Flo backend
+PrimOp lowering
+======== Think About ========
+annotation system
+zero-width wires
+on-reset
+expanding mems (consider changing defmem to be size, and element type)
+Make instances always male, flip the bundles on declaration
+Multi-streams for print statements/asserts (Jack)
+Consider def female node. (Patrick)
+Talk to palmer/patrick about how writing passes is going to be supported
+Figure out how widths propogate for all updated primops (Adam)
+Add partial bulk connect (Scott, Stephen)
+Add FIFOs to the IR (Palmer)
+Think about supporting generic primops on bundles and vecs (Adam) (wait until front-end more completed)
+
+======== Update Spec ========
+Add Not to spec
+add assertions and printfs
+cannot connect directly to a mem (loc can never contain a mem)
+Front-end needs to guarantee unique names per module.
+FIRRTL rule: No name can be a prefix of any other name.
+Future questions to address in spec:
+ Introduction – motivation, and intended usage
+ Philosophical justifications for all constructs
+ More introduction for types, e.g. what is a ground type?
+ What is a statement? What is an expression? What is a memory? Difference between vector type and memory? What are accessors for?
+ Why would I ever write an empty statement? Mainly for use by compiler/passes
+ What is a structural element? Duplication?
+ Subtracting two unsigned numbers… Should talk to a math guy to figure it out
+ What are shift left and shift right operations? HW doesn’t have these concepts. Need justification.
+ What is lowered form? What is it for?
diff --git a/notes/female-node.txt b/notes/female-node.txt
new file mode 100644
index 00000000..5125e8df
--- /dev/null
+++ b/notes/female-node.txt
@@ -0,0 +1,13 @@
+Male node:
+male defnode n = e
+==>
+wire n
+n := e
+
+Female node:
+female defnode n = e
+==>
+wire n
+e := n
+
+
diff --git a/notes/flo.txt b/notes/flo.txt
new file mode 100644
index 00000000..70fed3cf
--- /dev/null
+++ b/notes/flo.txt
@@ -0,0 +1,2 @@
+Questions:
+ WritePort(
diff --git a/spec/spec.tex b/spec/spec.tex
index a246b663..f7f1a2ee 100644
--- a/spec/spec.tex
+++ b/spec/spec.tex
@@ -100,6 +100,7 @@
\vert &\kws{shl} \vert \kws{shl-u} \vert \kws{shl-s} &\text{Unsigned/Signed Shift Left}\\
\vert &\kws{shr} \vert \kws{shr-u} \vert \kws{shr-s} &\text{Unsigned/Signed Shift Right}\\
\vert &\kws{convert} \vert \kws{convert-u} \vert \kws{convert-s} &\text{Unsigned to Signed Conversion}\\
+\vert &\kws{not} &\text{Unsigned Not}\\
\vert &\kws{and} &\text{Unsigned And}\\
\vert &\kws{or} &\text{Unsigned Or}\\
\vert &\kws{xor} &\text{Unsigned Xor}\\
diff --git a/src/main/stanza/firrtl-ir.stanza b/src/main/stanza/firrtl-ir.stanza
index f10dba0c..358ad9aa 100644
--- a/src/main/stanza/firrtl-ir.stanza
+++ b/src/main/stanza/firrtl-ir.stanza
@@ -81,6 +81,9 @@ public val GREATER-EQ-UU-OP = new PrimOp
public val GREATER-EQ-US-OP = new PrimOp
public val GREATER-EQ-SU-OP = new PrimOp
public val GREATER-EQ-SS-OP = new PrimOp
+public val NEQUAL-OP = new PrimOp
+public val NEQUAL-UU-OP = new PrimOp
+public val NEQUAL-SS-OP = new PrimOp
public val EQUAL-OP = new PrimOp
public val EQUAL-UU-OP = new PrimOp
public val EQUAL-SS-OP = new PrimOp
@@ -105,6 +108,7 @@ public val SHIFT-RIGHT-S-OP = new PrimOp
public val CONVERT-OP = new PrimOp
public val CONVERT-U-OP = new PrimOp
public val CONVERT-S-OP = new PrimOp
+public val BIT-NOT-OP = new PrimOp
public val BIT-AND-OP = new PrimOp
public val BIT-OR-OP = new PrimOp
public val BIT-XOR-OP = new PrimOp
diff --git a/src/main/stanza/ir-parser.stanza b/src/main/stanza/ir-parser.stanza
index 87458185..065aec34 100644
--- a/src/main/stanza/ir-parser.stanza
+++ b/src/main/stanza/ir-parser.stanza
@@ -239,6 +239,7 @@ rd.defsyntax firrtl :
operators[`convert] = CONVERT-OP
operators[`convert-u] = CONVERT-U-OP
operators[`convert-s] = CONVERT-S-OP
+ operators[`bit-not] = BIT-NOT-OP
operators[`bit-and] = BIT-AND-OP
operators[`bit-or] = BIT-OR-OP
operators[`bit-xor] = BIT-XOR-OP
diff --git a/src/main/stanza/passes.stanza b/src/main/stanza/passes.stanza
index b8059778..63c504a9 100644
--- a/src/main/stanza/passes.stanza
+++ b/src/main/stanza/passes.stanza
@@ -189,7 +189,6 @@ defn any-debug? (e:Expression|Stmt|Type|Port|Field) :
(hasGender(e) and PRINT-GENDERS) or
(hasType(e) and PRINT-TYPES) or
(hasWidth(e) and PRINT-WIDTHS) or
- (hasType(e) and PRINT-WIDTHS) or
(hasKind(e) and PRINT-KINDS)
defmethod print-debug (o:OutputStream, e:Expression|Stmt|Type|Port|Field) :
@@ -492,6 +491,7 @@ defn get-primop-rettype (e:DoPrim) -> Type :
CONVERT-OP : s()
CONVERT-U-OP : s()
CONVERT-S-OP : s()
+ BIT-NOT-OP : u()
BIT-AND-OP : u()
BIT-OR-OP : u()
BIT-XOR-OP : u()
@@ -1730,6 +1730,7 @@ defn gen-constraints (m:Module, h:HashTable<Symbol,Type>, v:Vector<WGeq>) -> Mod
SHIFT-RIGHT-S-OP : wmc(args(e),consts(e))
CONVERT-U-OP : add-c(PlusWidth(width!(args(e)[0]),IntWidth(1)))
CONVERT-S-OP : add-c(width!(args(e)[0]))
+ BIT-NOT-OP : maxw(args(e))
BIT-AND-OP : maxw(args(e))
BIT-OR-OP : maxw(args(e))
BIT-XOR-OP : maxw(args(e))
@@ -1762,11 +1763,17 @@ defn gen-constraints (m:Module, h:HashTable<Symbol,Type>, v:Vector<WGeq>) -> Mod
(e:Register) : Register(type(value(e)),value(e),enable(e))
(e:UIntValue) :
match(width(e)) :
- (w:UnknownWidth) : UIntValue(value(e),VarWidth(gensym(`w)))
+ (w:UnknownWidth) :
+ val w* = VarWidth(gensym(`w))
+ add(v,WGeq(w*,IntWidth(ceil-log2(value(e)))))
+ UIntValue(value(e),w*)
(w) : e
(e:SIntValue) :
match(width(e)) :
- (w:UnknownWidth) : SIntValue(value(e),VarWidth(gensym(`w)))
+ (w:UnknownWidth) :
+ val w* = VarWidth(gensym(`w))
+ add(v,WGeq(w*,IntWidth(1 + ceil-log2(abs(value(e))))))
+ SIntValue(value(e),w*)
(w) : e
(e) : e
@@ -1868,21 +1875,29 @@ defn inline-instances (c:Circuit) :
val h = HashTable<Symbol,Module>(symbol-hash)
val h-s = HashTable<Symbol,Stmt>(symbol-hash)
defn inline-inst (s:Stmt) -> Stmt :
- match(map(inline-inst,s)) :
- (s:DefInstance) :
- val n = name(module(s) as WRef)
- val m = h[n]
- val body* =
- if key?(h-s,n) : h-s[n]
- else :
- val v = Vector<Stmt>()
- for p in ports(m) do :
- add(v,DefWire(name(p),type(p)))
- add(v,inline-inst(body(m)))
- Begin(to-list(v))
- h-s[n] = body*
- rename-s(body*,name(s))
- (s) : s
+ match(map(inline-inst,s)) :
+ (s:DefInstance) :
+ val n = name(module(s) as WRef)
+ val m = h[n]
+ val body* =
+ if key?(h-s,n) : h-s[n]
+ else :
+ val v = Vector<Stmt>()
+ for p in ports(m) do :
+ add(v,DefWire(name(p),type(p)))
+ add(v,inline-inst(body(m)))
+ Begin(to-list(v))
+ h-s[n] = body*
+ rename-s(body*,name(s))
+ (s) : map(inline-inst-e,s)
+ defn inline-inst-e (e:Expression) -> Expression :
+ match(map(inline-inst-e,e)) :
+ (e:WSubfield) :
+ match(kind(exp(e) as WRef)) :
+ (k:InstanceKind) :
+ WRef(symbol-join([name(exp(e) as WRef) "$" name(e)]),type(e),k,gender(e))
+ (k:MemKind) : e
+ (e) : e
defn rename (ref:Symbol,n:Symbol) -> Symbol : symbol-join([n "$" ref])
defn rename-e (e:Expression,n:Symbol) -> Expression :
match(map(rename-e{_,n},e)) :
@@ -1955,6 +1970,188 @@ defn to-real-ir (c:Circuit) :
for m in modules(c) map :
Module(name(m), ports(m), to-stmt(body(m)))
+;============= FLO PRINTER ======================================
+; Emit
+
+defn flo-op-name (op:PrimOp) -> String :
+ switch {op == _ } :
+ ;NEG-OP : "neg"
+ ;NEG-OP : "neg"
+ ;NEG-OP : "neg"
+ ;NEG-OP : "neg"
+ ADD-UU-OP : "add"
+ ADD-US-OP : "add"
+ ADD-SU-OP : "add"
+ ADD-SS-OP : "add"
+ ADD-WRAP-UU-OP : "add"
+ ADD-WRAP-US-OP : "add"
+ ADD-WRAP-SU-OP : "add"
+ ADD-WRAP-SS-OP : "add"
+ SUB-UU-OP : "sub"
+ SUB-US-OP : "sub"
+ SUB-SU-OP : "sub"
+ SUB-SS-OP : "sub"
+ SUB-WRAP-UU-OP : "sub"
+ SUB-WRAP-US-OP : "sub"
+ SUB-WRAP-SU-OP : "sub"
+ SUB-WRAP-SS-OP : "sub"
+ MUL-UU-OP : "mul" ;; todo: signed version
+ MUL-US-OP : "mul" ;; todo: signed version
+ MUL-SU-OP : "mul" ;; todo: signed version
+ MUL-SS-OP : "mul" ;; todo: signed version
+ DIV-UU-OP : "div" ;; todo: signed version
+ DIV-US-OP : "div" ;; todo: signed version
+ DIV-SU-OP : "div" ;; todo: signed version
+ DIV-SS-OP : "div" ;; todo: signed version
+ MOD-UU-OP : "mod" ;; todo: signed version
+ MOD-US-OP : "mod" ;; todo: signed version
+ MOD-SU-OP : "mod" ;; todo: signed version
+ MOD-SS-OP : "mod" ;; todo: signed version
+ LESS-UU-OP : "lt" ;; todo: signed version
+ LESS-US-OP : "lt" ;; todo: signed version
+ LESS-SU-OP : "lt" ;; todo: signed version
+ LESS-SS-OP : "lt" ;; todo: signed version
+ LESS-EQ-UU-OP : "lte" ;; todo: swap args
+ LESS-EQ-US-OP : "lte" ;; todo: swap args
+ LESS-EQ-SU-OP : "lte" ;; todo: swap args
+ LESS-EQ-SS-OP : "lte" ;; todo: swap args
+ GREATER-UU-OP : "lte" ;; todo: swap args BROKEN
+ GREATER-US-OP : "lte" ;; todo: swap args BROKEN
+ GREATER-SU-OP : "lte" ;; todo: swap args BROKEN
+ GREATER-SS-OP : "lte" ;; todo: swap args BROKEN
+ GREATER-EQ-UU-OP : "lt" ;; todo: signed version
+ GREATER-EQ-US-OP : "lt" ;; todo: signed version
+ GREATER-EQ-SU-OP : "lt" ;; todo: signed version
+ GREATER-EQ-SS-OP : "lt" ;; todo: signed version
+ NEQUAL-UU-OP : "neq"
+ NEQUAL-SS-OP : "neq"
+ EQUAL-UU-OP : "eq"
+ EQUAL-SS-OP : "eq"
+ MUX-UU-OP : "mux"
+ MUX-SS-OP : "mux"
+ PAD-U-OP : "rsh" ;; todo: signed version
+ PAD-S-OP : "rsh" ;; todo: signed version
+ ;AS-UINT-U-OP :
+ ;AS-UINT-S-OP :
+ ;AS-SINT-U-OP :
+ ;AS-SINT-S-OP :
+ SHIFT-LEFT-U-OP : "lsh" ;; todo: signed version
+ SHIFT-LEFT-S-OP : "lsh" ;; todo: signed version
+ SHIFT-RIGHT-U-OP : "rsh"
+ SHIFT-RIGHT-S-OP : "rsh"
+ ;CONVERT-U-OP :
+ ;CONVERT-S-OP :
+ BIT-AND-OP : "and"
+ BIT-NOT-OP : "not"
+ BIT-OR-OP : "or"
+ BIT-XOR-OP : "xor"
+ CONCAT-OP : "cat"
+ BIT-SELECT-OP : "rsh"
+ BITS-SELECT-OP : "rsh"
+ else : error $ string-join $ ["Unable to print Primop: " op]
+
+defn sane-width (wd:Width) -> Int :
+ match(wd) :
+ (w:IntWidth) : max(1, width(w))
+ (w) : error("Unknown width")
+
+defn prim-width (type:Type) -> Int :
+ match(type) :
+ (t:UIntType) : sane-width(width(t))
+ (t:SIntType) : sane-width(width(t))
+ (t) : error("Bad prim width type")
+
+defn sizeof (in: Int) -> Int :
+ ;; if in == 1: 1 else: to-int(ceil(log(in)/log(2)))
+ max(1, ceil-log2(in))
+
+defn emit-all (o:OutputStream, es:Streamable, top:Symbol) :
+ for e in es do :
+ match(e) :
+ (ex:Expression) : emit!(o,e,top)
+ (ex:String) : print(o, ex)
+ (ex:Symbol) : print(o, ex)
+ ;; (ex:Int) : print-all(o, [ex "'" sizeof(ex)])
+ (ex:Int) : print(o, ex)
+ (ex) : print(o, ex)
+
+defn emit! (o:OutputStream, e:Expression,top:Symbol) :
+ defn cmp-op? (op: PrimOp) -> True|False :
+ contains?([EQUAL-OP, NEQUAL-OP, GREATER-OP, LESS-EQ-OP, LESS-OP, GREATER-EQ-OP], op)
+ match(e) :
+ (e:Ref) : emit-all(o,[top "::" name(e)], top)
+ (e:UIntValue) : emit-all(o,[value(e) "'" sane-width(width(e))], top)
+ (e:SIntValue) : emit-all(o,[value(e) "'" sane-width(width(e))], top)
+ (e:Subfield) : emit-all(o,[exp(e) "/" name(e)], top)
+ (e:Index) : emit-all(o,[exp(e) "/" value(e)], top)
+ (e:Register) :
+ emit-all(o,["reg'" prim-width(type(e)) " " enable(e) " " value(e)], top)
+ (e:ReadPort) :
+ emit-all(o,["rd'" prim-width(type(e)) " " enable(e) " " mem(e) " " index(e)], top)
+ (e:DoPrim) :
+ if cmp-op?(op(e)) :
+ emit-all(o, [flo-op-name(op(e)) "'" prim-width(type(args(e)[0]))], top)
+ if op(e) == GREATER-OP or op(e) == LESS-EQ-OP :
+ emit-all(o, [" " args(e)[1] " " args(e)[0]], top)
+ else :
+ emit-all(o, [" " args(e)[0] " " args(e)[1]], top)
+ else if op(e) == BIT-SELECT-OP :
+ emit-all(o, [flo-op-name(op(e)) "'1 " args(e)[0] " " consts(e)[0]], top)
+ else if op(e) == BITS-SELECT-OP :
+ val w = consts(e)[0] - consts(e)[1] + 1
+ emit-all(o, [flo-op-name(op(e)) "'" w " " args(e)[0] " " consts(e)[1]], top)
+ ;; else if op(e) == CONCAT-OP :
+ ;; val w = consts(e)[0] - consts(e)[1] + 1
+ ;; emit-all(o, [flo-op-name(op(e)) "'" w " " args(e)[0] " " consts(e)[1]], top)
+ else :
+ emit-all(o, [flo-op-name(op(e)) "'" prim-width(type(e))], top)
+ if op(e) == PAD-OP :
+ emit-all(o, [" " args(e)[0] " 0"], top)
+ else :
+ for arg in args(e) do :
+ print(o, " ")
+ emit!(o, arg, top)
+ for const in consts(e) do :
+ print(o, " ")
+ print(o, const)
+ (e) : print-all(o, ["EMIT(" e ")"])
+ ;(e) : emit-all(o, ["mov'" prim-width(type(e)) " " e], top)
+
+defn emit-s (o:OutputStream, s:Stmt, v:List<Symbol>, top:Symbol) :
+ match(s) :
+ (s:DefWire) : ""
+ (s:DefInstance) : error("Shouldn't be here")
+ (s:DefMemory) :
+ val vtype = type(s) as VectorType
+ emit-all(o, [top "::" name(s) " = mem'" prim-width(type(vtype)) " " size(vtype) "\n"], top)
+ (s:DefNode) : emit-all(o, [top "::" name(s) " = " value(s) "\n"], top)
+ (s:Begin) : do(emit-s{o, _, v, top}, body(s))
+ (s:Connect) :
+ if loc(s) typeof WritePort :
+ val e = loc(s) as WritePort
+ val name = gensym("T")
+ emit-all(o, [top "::" name " = wr'" prim-width(type(e)) " " enable(e) " " top "::" mem(e) " " index(e) " " exp(s) "\n"], top)
+ else :
+ val n = name(loc(s) as Ref)
+ if contains?(v,n) :
+ emit-all(o, [n " = out'" prim-width(type(loc(s))) " " exp(s) "\n"], top)
+ else :
+ emit-all(o, [top "::" n " = " exp(s) "\n"], top)
+ (s) : s
+
+defn emit-module (o:OutputStream, m:Module) :
+ val v = Vector<Symbol>()
+ for port in ports(m) do :
+ if name(port) ==`reset :
+ emit-all(o, [name(m) "::" name(port) " = rst'1\n"], name(m))
+ else : switch {_ == direction(port)} :
+ INPUT : print-all(o, [name(m) "::" name(port) " = " "in'" prim-width(type(port)) "\n"])
+ OUTPUT : add(v,name(port))
+ emit-s(o, body(m), to-list(v), name(m))
+
+public defn emit-flo (o:OutputStream, c:Circuit) :
+ emit-module(o, modules(c)[0])
+ c
;============= DRIVER ======================================
public defn run-passes (c: Circuit, p: List<Char>) :
@@ -1984,7 +2181,7 @@ public defn run-passes (c: Circuit, p: List<Char>) :
if contains(p,'l') : do-stage("Inline Instances", inline-instances)
if contains(p,'m') : do-stage("Split Expressions", split-exp)
if contains(p,'n') : do-stage("Real IR", to-real-ir)
-
+ if contains(p,'o') : do-stage("To Flo", emit-flo{STANDARD-OUTPUT,_})
println("Done!")
diff --git a/test/passes/to-flo/gcd.fir b/test/passes/to-flo/gcd.fir
new file mode 100644
index 00000000..7a3179bf
--- /dev/null
+++ b/test/passes/to-flo/gcd.fir
@@ -0,0 +1,45 @@
+; RUN: firrtl %s abcefghipjklmno cw | tee %s.out | FileCheck %s
+
+;CHECK: Flo
+circuit top :
+ module subtracter :
+ input x : UInt
+ input y : UInt
+ output q : UInt
+ q := sub-wrap-uu(x, y)
+ module gcd :
+ input a : UInt(16)
+ input b : UInt(16)
+ input e : UInt(1)
+ output z : UInt(16)
+ output v : UInt(1)
+ reg x : UInt
+ reg y : UInt
+ x.init := UInt(0)
+ y.init := UInt(42)
+ when gt-uu(x, y) :
+ inst s of subtracter
+ s.x := x
+ s.y := y
+ x := s.q
+ else :
+ inst s2 of subtracter
+ s2.x := x
+ s2.y := y
+ y := s2.q
+ when e :
+ x := a
+ y := b
+ v := equal-uu(v, UInt(0))
+ z := x
+ module top :
+ input a : UInt(16)
+ input b : UInt(16)
+ output z : UInt
+ inst i of gcd
+ i.a := a
+ i.b := b
+ i.e := UInt(1)
+ z := i.z
+;CHECK: Done!
+