Skip to content

Commit

Permalink
add / and % operators
Browse files Browse the repository at this point in the history
caveats:
behavior is undefined when divisor = 0
c++ only supports up to 64b operands for now
  • Loading branch information
aswaterman committed Nov 15, 2012
1 parent b9218d2 commit ef08a0e
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 23 deletions.
6 changes: 6 additions & 0 deletions csrc/emulator.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef __IS_EMULATOR__
#define __IS_EMULATOR__

#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <limits.h>
Expand Down Expand Up @@ -225,6 +226,11 @@ static inline val_t mask_val(int n) {
return res;
}

static void div_n (val_t d[], val_t s0[], val_t s1[], int nb0, int nb1) {
assert(nb0 <= val_n_bits() && nb1 <= val_n_bits()); // TODO: generalize
d[0] = s1[0] == 0 ? mask_val(nb0) : s0[0] / s1[0];
}

static inline void mask_n (val_t d[], int nw, int nb) {
int n_full_words = val_n_full_words(nb);
int n_word_bits = val_n_word_bits(nb);
Expand Down
3 changes: 3 additions & 0 deletions src/main/scala/Cpp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ class CppBackend extends Backend {
res += emitWordRef(o, i) + " = " + emitWordRef(o.inputs(0), i) + o.op + emitWordRef(o.inputs(1), i) + o.op + "__c"
}
block(res) + trunc(o)
} else if (o.op == "/") {
val cmd = "div_n(__d, __x, __y, " + o.inputs(0).width + ", " + o.inputs(1).width + ")"
block(makeArray("__d", o) ++ toArray("__x", o.inputs(0)) ++ toArray("__y", o.inputs(1)) ++ List(cmd) ++ fromArray("__d", o))
} else if (o.op == "*") {
if (o.width <= bpw)
" " + emitLoWordRef(o) + " = " + emitLoWordRef(o.inputs(0)) + " * " + emitLoWordRef(o.inputs(1)) + ";\n"
Expand Down
4 changes: 4 additions & 0 deletions src/main/scala/Fix.scala
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class Fix extends Num {
//Fix to Fix arithmetic
def + (b: Fix): Fix = BinaryOp(this, b, "+"){Fix()};
def * (b: Fix): Fix = BinaryOp(this, b, "s*s"){Fix()};
def / (b: Fix): Fix = BinaryOp(this, b, "s/s"){Fix()};
def % (b: Fix): Fix = BinaryOp(this, b, "s%s"){Fix()};
def ===(b: Fix): Bool = LogicalOp(this, b, "==="){Fix()};
def - (b: Fix): Fix = BinaryOp(this, b, "-"){Fix()};
def != (b: Fix): Bool = LogicalOp(this, b, "!="){Fix()};
Expand All @@ -102,6 +104,8 @@ class Fix extends Num {
//Fix to UFix arithmetic
def + (b: UFix): Fix = this + Cat(Bits(0, 1), b).toFix;
def * (b: UFix): Fix = BinaryOp(this, b, "s*u"){Fix()}.toFix;
def / (b: UFix): Fix = BinaryOp(this, b, "s/u"){Fix()}.toFix;
def % (b: UFix): Fix = BinaryOp(this, b, "s%u"){Fix()}.toFix;
def - (b: UFix): Fix = this - Cat(Bits(0, 1), b).toFix;
def === (b: UFix): Bool = this === Cat(Bits(0, 1), b).toFix;
def != (b: UFix): Bool = this != Cat(Bits(0, 1), b).toFix;
Expand Down
12 changes: 6 additions & 6 deletions src/main/scala/Node.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package Chisel
import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.Stack

import scala.math.max;
import Node._;
import Component._;
import ChiselError._;
Expand Down Expand Up @@ -41,14 +40,15 @@ object Node {
}}}

def maxWidth(m: Node): Int = {
var res = 0;
var w = 0
for (i <- m.inputs)
if(!(i == null) && !(i == m)){
res = max(res, i.width);
}
res
if (!(i == null || i == m))
w = w.max(i.width)
w
}

def minWidth(m: Node): Int = m.inputs.map(_.width).min

def maxWidthPlusOne(m: Node): Int = maxWidth(m) + 1;

def sumWidth(m: Node): Int = {
Expand Down
56 changes: 45 additions & 11 deletions src/main/scala/Op.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ object BinaryOp {
case "s*s" => Op("s*s", 0, sumWidth _, x, y );
case "s*u" => Op("s*u", 0, sumWidth _, x, y );
case "u*s" => Op("u*s", 0, sumWidth _, x, y );
case "/" => Op("/", 0, widthOf(0), x, y );
case "s/s" => Op("s/s", 0, widthOf(0), x, y );
case "s/u" => Op("s/u", 0, widthOf(0), x, y );
case "u/s" => Op("u/s", 0, widthOf(0), x, y );
case "%" => Op("%", 0, minWidth _, x, y );
case "s%s" => Op("s%s", 0, minWidth _, x, y );
case "s%u" => Op("s%u", 0, minWidth _, x, y );
case "u%s" => Op("u%s", 0, minWidth _, x, y );
case "^" => Op("^", 2, maxWidth _, x, y );
case "?" => Multiplex(x, y, null);
case "-" => Op("-", 2, maxWidth _, x, y );
Expand Down Expand Up @@ -184,6 +192,11 @@ object Op {
}
}
if (backend.isInstanceOf[CppBackend]) {
def signAbs(x: Node) = {
val f = x.asInstanceOf[Fix]
val s = f < Fix(0)
(s, Mux(s, -f, f).toUFix)
}
name match {
case ">" | "<" | ">=" | "<=" =>
if (a.isInstanceOf[Fix] && b.isInstanceOf[Fix]) {
Expand All @@ -204,22 +217,43 @@ object Op {
if (a.litOf != null && a.litOf.isZ)
return Op(name, nGrow, widthInfer, b, a)
case "s*s" =>
val fixA = a.asInstanceOf[Fix]
val signA = fixA < Fix(0)
val absA = Mux(signA, -fixA, fixA)
val fixB = b.asInstanceOf[Fix]
val signB = fixB < Fix(0)
val absB = Mux(signB, -fixB, fixB)
val prod = absA.toUFix * absB.toUFix
val (signA, absA) = signAbs(a)
val (signB, absB) = signAbs(b)
val prod = absA * absB
return Mux(signA ^ signB, -prod, prod)
case "s*u" =>
val fixA = a.asInstanceOf[Fix]
val signA = fixA < Fix(0)
val absA = Mux(signA, -fixA, fixA)
val prod = absA.toUFix * b.asInstanceOf[UFix]
val (signA, absA) = signAbs(a)
val prod = absA * b.asInstanceOf[UFix]
return Mux(signA, -prod, prod)
case "u*s" =>
return Op("s*u", nGrow, widthInfer, b, a)
case "s/s" =>
val (signA, absA) = signAbs(a)
val (signB, absB) = signAbs(b)
val quo = absA / absB
return Mux(signA != signB, -quo, quo)
case "s/u" =>
val (signA, absA) = signAbs(a)
val quo = absA / b.asInstanceOf[UFix]
return Mux(signA, -quo, quo)
case "u/s" =>
val (signB, absB) = signAbs(b)
val quo = a.asInstanceOf[UFix] / absB
return Mux(signB, -quo, quo)
case "s%s" =>
val (signA, absA) = signAbs(a)
val (signB, absB) = signAbs(b)
val rem = absA % absB
return Mux(signA, -rem, rem)
case "u%s" =>
return a.asInstanceOf[UFix] / signAbs(b)._2
case "s%u" =>
val (signA, absA) = signAbs(a)
val rem = absA % b.asInstanceOf[UFix]
return Mux(signA, -rem, rem)
case "%" =>
val (au, bu) = (a.asInstanceOf[UFix], b.asInstanceOf[UFix])
return Op("-", nGrow, widthInfer, au, au/bu*bu)
case _ =>
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/scala/UFix.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class UFix extends Num {
override def >> (b: UFix): UFix = BinaryOp(this, b, ">>"){UFix()};
def + (b: UFix): UFix = BinaryOp(this, b, "+"){UFix()};
def * (b: UFix): UFix = BinaryOp(this, b, "*"){UFix()};
def / (b: UFix): UFix = BinaryOp(this, b, "/"){UFix()};
def % (b: UFix): UFix = BinaryOp(this, b, "%"){UFix()};
def ^ (b: UFix): UFix = BinaryOp(this, b, "^"){UFix()};
def ? (b: UFix): UFix = BinaryOp(this, b, "?"){UFix()};
def - (b: UFix): UFix = BinaryOp(this, b, "-"){UFix()};
Expand All @@ -74,6 +76,8 @@ class UFix extends Num {

//UFix op Fix arithmetic
def * (b: Fix): Fix = BinaryOp(this, b, "u*s"){Fix()}.toFix;
def % (b: Fix): Fix = BinaryOp(this, b, "u/s"){Fix()}.toFix;
def / (b: Fix): Fix = BinaryOp(this, b, "u%s"){Fix()}.toFix;
}

class Eyum extends UFix { };
Expand Down
12 changes: 6 additions & 6 deletions src/main/scala/Verilog.scala
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,12 @@ class VerilogBackend extends Backend {
"{" + emitRef(node.inputs(0)) + ", " + emitRef(node.inputs(1)) + "}"
else if (node.inputs.length == 1)
o.op + " " + emitRef(node.inputs(0))
else if (o.op == "s*s")
"$signed(" + emitRef(node.inputs(0)) + ") * $signed(" + emitRef(node.inputs(1)) + ")"
else if (o.op == "s*u")
"$signed(" + emitRef(node.inputs(0)) + ") * " + emitRef(node.inputs(1))
else if (o.op == "u*s")
emitRef(node.inputs(0)) + " * $signed(" + emitRef(node.inputs(1)) + ")"
else if (o.op == "s*s" || o.op == "s%s" || o.op == "s/s")
"$signed(" + emitRef(node.inputs(0)) + ") " + o.op(1) + " $signed(" + emitRef(node.inputs(1)) + ")"
else if (o.op == "s*u" || o.op == "s%u" || o.op == "s/u")
"$signed(" + emitRef(node.inputs(0)) + ") " + o.op(1) + " " + emitRef(node.inputs(1))
else if (o.op == "u*s" || o.op == "u%s" || o.op == "u/s")
emitRef(node.inputs(0)) + " " + o.op(1) + " $signed(" + emitRef(node.inputs(1)) + ")"
else if(node.isSigned) {
if (o.op == ">>")
"$signed(" + emitRef(node.inputs(0)) +") " + ">>>" + " " + emitRef(node.inputs(1))
Expand Down

0 comments on commit ef08a0e

Please sign in to comment.