package jazz.circuit.expr; ////////////////////////////////////////////////////////////////////////////// // // Imperative construction of circuits using boolean expressions // // Author: Francois.Bourdoncle@ensmp.fr // ////////////////////////////////////////////////////////////////////////////// import jazz.unsafe.Hashtable; import jazz.unsafe.Counter; var defs = Hashtable.create(); var inids = Hashtable.create(); var dummy = new _VarExpr(id = 0); var ids = Counter.create(1); BoolExpr.constant(v) = new BoolExpr(e = new _CstExpr(v = v)); BoolExpr.newLocal() = new BoolExpr(e = new _VarExpr(id = ids.next())); BoolExpr.newInput(n) = ( inids.put(id, n) ; new BoolExpr(e = new _VarExpr(id = id))) { id = ids.next(); } // Sets or update the definition of boolean variables setEq@BoolExpr(x) = (e.setEq(x.e) ; this); setEq@_BoolExpr(e) = error("setEq@_BoolExpr"); setEq@_VarExpr(e) = defs.put(id, e); setOr@BoolExpr(x) = (e.setOr(x.e) ; this); setOr@_BoolExpr(e) = error("setOr@_BoolExpr"); setOr@_VarExpr(e) = defs.put(id, setOr(e, defs.get(id, dummy))) { // Ignore "dummy" in the or fun setOr(e1: _BoolExpr, e2: _BoolExpr): _BoolExpr; setOr(e1, e2) = new _OrExpr(e1 = e1, e2 = e2); setOr(e1, e2@_VarExpr) = e2.id == 0 ? e1 : new _OrExpr(e1 = e1, e2 = e2); } setAnd@BoolExpr(x) = (e.setAnd(x.e) ; this); setAnd@_BoolExpr(e) = error("setAnd@_BoolExpr"); setAnd@_VarExpr(e) = defs.put(id, setAnd(e, defs.get(id, dummy))) { // Ignore "dummy" in the and fun setAnd(e1: _BoolExpr, e2: _BoolExpr): _BoolExpr; setAnd(e1, e2) = new _AndExpr(e1 = e1, e2 = e2); setAnd(e1, e2@_VarExpr) = e2.id == 0 ? e1 : new _AndExpr(e1 = e1, e2 = e2); } setXor@BoolExpr(x) = (e.setXor(x.e) ; this); setXor@_BoolExpr(e) = error("setXor@_BoolExpr"); setXor@_VarExpr(e) = defs.put(id, setXor(e, defs.get(id, dummy))) { // Ignore "dummy" in the xor fun setXor(e1: _BoolExpr, e2: _BoolExpr): _BoolExpr; setXor(e1, e2) = new _XorExpr(e1 = e1, e2 = e2); setXor(e1, e2@_VarExpr) = e2.id == 0 ? e1 : new _XorExpr(e1 = e1, e2 = e2); } // Returns the definition of a boolean expression getDefinition@BoolExpr() = new BoolExpr(e = e.getDefinition()); getDefinition@_BoolExpr() = this; getDefinition@_VarExpr() = defs.get(id, error("unassigned variable: %a", this)); // We create the lazy array "vars" of all boolean variables by a single // equation involving the two hashtables containing the input variables (vars) // and the definition of local variables (defs). This is the only way to // instanciate a circuit. If the circuit contains loops (without registers) // then the Jazz runtime will fail with unassigned variables (this is a bug in // the generated circuit, not in the code that follows). BoolExpr.instanciate(outputs)(inputs, reg, constant) = [i -> outputs[i].e.getValue(vars, reg, constant)] { // The "vars" array is the array of all the variables in the circuit vars = [id -> val(id)]; fun val(id) = (inids.containsKey(id) ? inputs[inids.get(id, error("internal error"))] : def(id).getValue(vars, reg, constant)); fun def(id) = (_BoolExpr) defs.get(id, error("undefined variable: $%d", id)); } getValue@_VarExpr(vars, reg, constant) = vars[id]; getValue@_CstExpr(vars, reg, constant) = constant(v); getValue@_NotExpr(vars, reg, constant) = ~e.getValue(vars, reg, constant); getValue@_RegExpr(vars, reg, constant) = reg(e.getValue(vars, reg, constant)); getValue@_AndExpr(vars, reg, constant) = e1.getValue(vars, reg, constant) & e2.getValue(vars, reg, constant); getValue@_OrExpr(vars, reg, constant) = e1.getValue(vars, reg, constant) | e2.getValue(vars, reg, constant); getValue@_XorExpr(vars, reg, constant) = e1.getValue(vars, reg, constant) ^ e2.getValue(vars, reg, constant); getValue@_MuxExpr(vars, reg, constant) = cond(e0.getValue(vars, reg, constant), e1.getValue(vars, reg, constant), e2.getValue(vars, reg, constant));