From b208bfb5691c7b5921dd47d0b599726872acd1cd Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 11 May 2015 10:04:01 -0700 Subject: move source files under Chisel folder - eclipse compatibility --- src/main/scala/Backend.scala | 10 - src/main/scala/Chisel/Backend.scala | 10 + src/main/scala/Chisel/Core.scala | 1248 ++++++++++++++++++++++++++++++++ src/main/scala/Chisel/Driver.scala | 420 +++++++++++ src/main/scala/Chisel/Enum.scala | 44 ++ src/main/scala/Chisel/Error.scala | 167 +++++ src/main/scala/Chisel/FP.scala | 321 ++++++++ src/main/scala/Chisel/JHFormat.scala | 105 +++ src/main/scala/Chisel/Literal.scala | 199 +++++ src/main/scala/Chisel/Parameters.scala | 644 ++++++++++++++++ src/main/scala/Chisel/Params.scala | 195 +++++ src/main/scala/Chisel/Tester.scala | 417 +++++++++++ src/main/scala/Chisel/utils.scala | 561 ++++++++++++++ src/main/scala/Core.scala | 1248 -------------------------------- src/main/scala/Driver.scala | 420 ----------- src/main/scala/Enum.scala | 44 -- src/main/scala/Error.scala | 167 ----- src/main/scala/FP.scala | 321 -------- src/main/scala/JHFormat.scala | 105 --- src/main/scala/Literal.scala | 199 ----- src/main/scala/Parameters.scala | 644 ---------------- src/main/scala/Params.scala | 195 ----- src/main/scala/Tester.scala | 417 ----------- src/main/scala/utils.scala | 561 -------------- 24 files changed, 4331 insertions(+), 4331 deletions(-) delete mode 100644 src/main/scala/Backend.scala create mode 100644 src/main/scala/Chisel/Backend.scala create mode 100644 src/main/scala/Chisel/Core.scala create mode 100644 src/main/scala/Chisel/Driver.scala create mode 100644 src/main/scala/Chisel/Enum.scala create mode 100644 src/main/scala/Chisel/Error.scala create mode 100644 src/main/scala/Chisel/FP.scala create mode 100644 src/main/scala/Chisel/JHFormat.scala create mode 100644 src/main/scala/Chisel/Literal.scala create mode 100644 src/main/scala/Chisel/Parameters.scala create mode 100644 src/main/scala/Chisel/Params.scala create mode 100644 src/main/scala/Chisel/Tester.scala create mode 100644 src/main/scala/Chisel/utils.scala delete mode 100644 src/main/scala/Core.scala delete mode 100644 src/main/scala/Driver.scala delete mode 100644 src/main/scala/Enum.scala delete mode 100644 src/main/scala/Error.scala delete mode 100644 src/main/scala/FP.scala delete mode 100644 src/main/scala/JHFormat.scala delete mode 100644 src/main/scala/Literal.scala delete mode 100644 src/main/scala/Parameters.scala delete mode 100644 src/main/scala/Params.scala delete mode 100644 src/main/scala/Tester.scala delete mode 100644 src/main/scala/utils.scala (limited to 'src') diff --git a/src/main/scala/Backend.scala b/src/main/scala/Backend.scala deleted file mode 100644 index 9b8bfb6d..00000000 --- a/src/main/scala/Backend.scala +++ /dev/null @@ -1,10 +0,0 @@ -package Chisel -import Chisel._ - -class Backend; -class FloBackend extends Backend; -class CppBackend extends Backend; -class VerilogBackend extends Backend; -class FPGABackend extends Backend; -class DotBackend extends Backend; -class SysCBackend extends Backend; diff --git a/src/main/scala/Chisel/Backend.scala b/src/main/scala/Chisel/Backend.scala new file mode 100644 index 00000000..9b8bfb6d --- /dev/null +++ b/src/main/scala/Chisel/Backend.scala @@ -0,0 +1,10 @@ +package Chisel +import Chisel._ + +class Backend; +class FloBackend extends Backend; +class CppBackend extends Backend; +class VerilogBackend extends Backend; +class FPGABackend extends Backend; +class DotBackend extends Backend; +class SysCBackend extends Backend; diff --git a/src/main/scala/Chisel/Core.scala b/src/main/scala/Chisel/Core.scala new file mode 100644 index 00000000..8236c154 --- /dev/null +++ b/src/main/scala/Chisel/Core.scala @@ -0,0 +1,1248 @@ +package Chisel +import scala.collection.mutable.{ArrayBuffer, Stack, HashSet, HashMap, LinkedHashMap} +import java.lang.reflect.Modifier._ +import java.lang.Double.longBitsToDouble +import java.lang.Float.intBitsToFloat + +class GenSym { + private var counter = -1 + def nextInt: Int = { + counter += 1 + counter + } + def next(name: String): String = + name + "_" + nextInt +} + +object Builder { + val components = new ArrayBuffer[Component]() + val genSym = new GenSym() + val scopes = new Stack[HashSet[String]]() + def scope = scopes.top + val switchKeyz = new Stack[Stack[Bits]]() + def switchKeys = switchKeyz.top + def pushScope = { + scopes.push(new HashSet[String]()) + switchKeyz.push(new Stack[Bits]()) + } + def popScope = { + scopes.pop() + switchKeyz.pop() + } + val modules = new HashMap[String,Module]() + def addModule(mod: Module) { + modules(mod.cid) = mod + } + val modulez = new Stack[Module]() + def pushModule(mod: Module) { + modulez.push(mod) + } + def getComponent(): Module = if (modulez.length > 0) modulez.head else null + def popModule() { + modulez.pop + } + val componentNames = new HashSet[String]() + def UniqueComponent(name: String, ports: Array[Port], body: Command) = { + val res = Component(if (componentNames.contains(name)) genSym.next(name) else name, ports, body) + componentNames += name + res + } + val commandz = new Stack[ArrayBuffer[Command]]() + def commands = commandz.top + def pushCommand(cmd: Command) = commands += cmd + def commandify(cmds: ArrayBuffer[Command]): Command = { + if (cmds.length == 0) + EmptyCommand() + else if (cmds.length == 1) + cmds(0) + else + Begin(cmds.toList) + } + def pushCommands = + commandz.push(new ArrayBuffer[Command]()) + def popCommands: Command = { + val newCommands = commands + commandz.pop() + commandify(newCommands) + } + def collectCommands[T <: Module](f: => T): (Command, T) = { + pushCommands + val mod = f + // mod.setRefs + (popCommands, mod) + } + + private val refmap = new HashMap[String,Immediate]() + + def legalizeName (name: String) = { + if (name == "mem" || name == "node" || name == "wire" || + name == "reg" || name == "inst") + // genSym.next(name) + name + "__" + else + name + } + + def setRefForId(id: String, name: String, overwrite: Boolean = false) { + if (overwrite || !refmap.contains(id)) { + refmap(id) = Ref(legalizeName(name)) + } + } + + def setFieldForId(parentid: String, id: String, name: String) { + refmap(id) = Slot(Alias(parentid), legalizeName(name)) + } + + def setIndexForId(parentid: String, id: String, index: Int) { + refmap(id) = Index(Alias(parentid), index) + } + + def getRefForId(id: String): Immediate = { + if (refmap.contains(id)) { + refmap(id) + } else { + val ref = Ref(genSym.next("T")) + refmap(id) = ref + ref + } + } + + def build[T <: Module](f: => T): (Circuit, T) = { + val (cmd, mod) = collectCommands(f) + setRefForId(mod.cid, mod.name) + (Circuit(components.toArray, components.last.name), mod) + } + +} + +import Builder._ + +/// CHISEL IR + +case class PrimOp(val name: String) { + override def toString = name +} + +object PrimOp { + val AddOp = PrimOp("add") + val AddModOp = PrimOp("add-wrap") + val SubOp = PrimOp("sub") + val SubModOp = PrimOp("sub-wrap") + val TimesOp = PrimOp("mul") + val DivideOp = PrimOp("div") + val ModOp = PrimOp("mod") + val ShiftLeftOp = PrimOp("shl") + val ShiftRightOp = PrimOp("shr") + val DynamicShiftLeftOp = PrimOp("dshl") + val DynamicShiftRightOp = PrimOp("dshr") + val BitAndOp = PrimOp("bit-and") + val BitOrOp = PrimOp("bit-or") + val BitXorOp = PrimOp("bit-xor") + val BitNotOp = PrimOp("bit-not") + val ConcatOp = PrimOp("cat") + val BitSelectOp = PrimOp("bit") + val BitsExtractOp = PrimOp("bits") + val LessOp = PrimOp("lt") + val LessEqOp = PrimOp("leq") + val GreaterOp = PrimOp("gt") + val GreaterEqOp = PrimOp("geq") + val EqualOp = PrimOp("eq") + val PatternEqualOp = PrimOp("pattern-equal") + val PadOp = PrimOp("pad") + val NotEqualOp = PrimOp("neq") + val NegOp = PrimOp("neg") + val MultiplexOp = PrimOp("mux") + val XorReduceOp = PrimOp("xorr") + val ConvertOp = PrimOp("convert") + val AsUIntOp = PrimOp("as-UInt") + val AsSIntOp = PrimOp("as-SInt") +} +import PrimOp._ + +abstract class Immediate { + def fullname: String + def name: String + def debugName = fullname +} + +abstract class Arg extends Immediate { + def fullname: String + def name: String +} + +case class Alias(val id: String) extends Arg { + def fullname = getRefForId(id).fullname + def name = getRefForId(id).name + override def debugName = getRefForId(id).debugName + def emit: String = "Alias(" + id + ")" +} + +abstract class LitArg (val num: BigInt, val width: Int) extends Arg { +} + +case class ULit(n: BigInt, w: Int = -1) extends LitArg(n, w) { + def fullname = name + def name = "UInt<" + width + ">(" + num + ")" +} + +case class SLit(n: BigInt, w: Int = -1) extends LitArg(n, w) { + def fullname = name + def name = "SInt<" + width + ">(" + num + ")" +} + +case class Ref(val name: String) extends Immediate { + def fullname = name +} +case class Slot(val imm: Immediate, val name: String) extends Immediate { + def fullname = { + val imm_fullname = imm.fullname + if (imm_fullname == "this") name else imm_fullname + "." + name + } + override def debugName = { + val imm_debugName = imm.debugName + if (imm_debugName == "this") name else imm_debugName + "." + name + } +} +case class Index(val imm: Immediate, val value: Int) extends Immediate { + def name = "[" + value + "]" + def fullname = imm.fullname + "[" + value + "]" + override def debugName = imm.debugName + "." + value +} + +case class Port(val id: String, val dir: Direction, val kind: Kind); + +abstract class Width; +case class UnknownWidth() extends Width; +case class IntWidth(val value: Int) extends Width; + +abstract class Kind(val isFlip: Boolean); +case class UnknownType(flip: Boolean) extends Kind(flip); +case class UIntType(val width: Width, flip: Boolean) extends Kind(flip); +case class SIntType(val width: Width, flip: Boolean) extends Kind(flip); +case class FloType(flip: Boolean) extends Kind(flip); +case class DblType(flip: Boolean) extends Kind(flip); +case class BundleType(val ports: Array[Port], flip: Boolean) extends Kind(flip); +case class VectorType(val size: Int, val kind: Kind, flip: Boolean) extends Kind(flip); + +abstract class Command; +abstract class Definition extends Command { + def id: String + def name = getRefForId(id).name +} +case class DefUInt(val id: String, val value: BigInt, val width: Int) extends Definition; +case class DefSInt(val id: String, val value: BigInt, val width: Int) extends Definition; +case class DefFlo(val id: String, val value: Float) extends Definition; +case class DefDbl(val id: String, val value: Double) extends Definition; +case class DefPrim(val id: String, val kind: Kind, val op: PrimOp, val args: Array[Arg], val lits: Array[BigInt]) extends Definition; +case class DefWire(val id: String, val kind: Kind) extends Definition; +case class DefRegister(val id: String, val kind: Kind) extends Definition; +case class DefMemory(val id: String, val kind: Kind, val size: Int) extends Definition; +case class DefSeqMemory(val id: String, val kind: Kind, val size: Int) extends Definition; +case class DefAccessor(val id: String, val source: Alias, val direction: Direction, val index: Arg) extends Definition; +case class DefInstance(val id: String, val module: String) extends Definition; +case class Conditionally(val prep: Command, val pred: Arg, val conseq: Command, var alt: Command) extends Command; +case class Begin(val body: List[Command]) extends Command(); +case class Connect(val loc: Alias, val exp: Arg) extends Command; +case class BulkConnect(val loc1: Alias, val loc2: Alias) extends Command; +case class ConnectInit(val loc: Alias, val exp: Arg) extends Command; +case class ConnectInitIndex(val loc: Alias, val index: Int, val exp: Arg) extends Command; +case class EmptyCommand() extends Command; + +case class Component(val name: String, val ports: Array[Port], val body: Command); +case class Circuit(val components: Array[Component], val main: String); + +object Commands { + val NoLits = Array[BigInt]() +} + +import Commands._ + +/// COMPONENTS + +sealed abstract class Direction(val name: String) { + override def toString = name +} +object INPUT extends Direction("input") +object OUTPUT extends Direction("output") +object NO_DIR extends Direction("?") + +object Direction { + def flipDirection(dir: Direction) = { + dir match { + case INPUT => OUTPUT + case OUTPUT => INPUT + case NO_DIR => NO_DIR + } + } +} +import Direction._ + +/// CHISEL FRONT-END + +abstract class Id { + protected[Chisel] val _id = genSym.nextInt + protected[Chisel] val cid = "id_" + _id + + var isDef_ = false + def defd: this.type = { + isDef_ = true + this + } + def isDef = isDef_ +} + +object debug { + // TODO: + def apply (arg: Data) = arg +} + +abstract class Data(dirArg: Direction) extends Id { + val mod = getComponent() + def toType: Kind + var isFlipVar = dirArg == INPUT + def isFlip = isFlipVar + def dir: Direction = if (isFlip) INPUT else OUTPUT + def setDir(dir: Direction) { + isFlipVar = (dir == INPUT) + } + def init(dummy:Int = 0) = { } + def asInput: this.type = { + setDir(INPUT) + this + } + def asOutput: this.type = { + setDir(OUTPUT) + this + } + def flip(): this.type = { + isFlipVar = !isFlipVar + this + } + def :=(other: Data) = + pushCommand(Connect(this.lref, other.ref)) + def <>(other: Data) = + pushCommand(BulkConnect(this.lref, other.lref)) + final def cloneType: this.type = { + val res = doCloneType + collectElts + res + } + def collectElts = { } + def doCloneType: this.type + def cloneTypeWidth(width: Int): this.type + def lref: Alias = + Alias(cid) + def ref: Arg = + if (isLitValue) litArg() else Alias(cid) + def name = getRefForId(cid).name + def debugName = mod.debugName + "." + getRefForId(cid).debugName + def litArg(): LitArg = null + def litValue(): BigInt = -1 + def isLitValue(): Boolean = false + def setLitValue(x: LitArg) { } + def floLitValue: Float = intBitsToFloat(litValue().toInt) + def dblLitValue: Double = longBitsToDouble(litValue().toLong) + def getWidth: Int = flatten.map(_.getWidth).reduce(_ + _) + def maxWidth(other: Data, amt: BigInt): Int = -1 + def sumWidth(amt: BigInt): Int = -1 + def sumWidth(other: Data, amt: BigInt): Int = -1 + def flatten: IndexedSeq[Bits] + def fromBits(n: Bits): this.type = { + var i = 0 + val wire = Wire(this.cloneType) + for (x <- wire.flatten.reverse) { + x := n(i + x.getWidth-1, i) + i += x.getWidth + } + wire.asInstanceOf[this.type] + } + def toBits: UInt = { + val elts = this.flatten.reverse + Cat(elts.head, elts.tail:_*).asUInt + } + def makeLit(value: BigInt, width: Int): this.type = + this.fromBits(Bits(value, width)) + + def toPort: Port = Port(cid, dir, toType) + var isReg_ = false + def isReg = isReg_ + def params = if(Driver.parStack.isEmpty) Parameters.empty else Driver.parStack.top +} + +object Wire { + def apply[T <: Data](t: T = null, init: T = null): T = { + val mType = if (t == null) init else t + if(mType == null) + throw new Exception("cannot infer type of Init.") + val x = mType.cloneType + // TODO: COME UP WITH MORE ROBUST WAY TO HANDLE THIS + pushCommand(DefWire(x.defd.cid, x.toType)) + if (init != null) + pushCommand(Connect(x.lref, init.ref)) + x + } +} + +object Reg { + def apply[T <: Data](t: T = null, next: T = null, init: T = null): T = { + var mType = t + if(mType == null) + mType = next + if(mType == null) + mType = init + if(mType == null) + throw new Exception("cannot infer type of Reg.") + val x = mType.cloneType + x.isReg_ = true + pushCommand(DefRegister(x.defd.cid, x.toType)) + if (init != null) + pushCommand(ConnectInit(x.lref, init.ref)) + if (next != null) + x := next + x + } + def apply[T <: Data](outType: T): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T]) +} + +object Mem { + def apply[T <: Data](t: T, size: Int): Mem[T] = { + val mt = t.cloneType + val mem = new Mem(mt, size) + pushCommand(DefMemory(mt.defd.cid, mt.toType, size)) + mem + } +} + +class Mem[T <: Data](protected[Chisel] val t: T, n: Int) extends VecLike[T] { + def length: Int = n + def apply(idx: Int): T = apply(UInt(idx)) + def apply(idx: UInt): T = { + val x = t.cloneType + pushCommand(DefAccessor(x.defd.cid, Alias(t.cid), NO_DIR, idx.ref)) + x + } + + def read(idx: UInt): T = apply(idx) + def write(idx: UInt, data: T): Unit = apply(idx) := data + def write(idx: UInt, data: T, mask: T): Unit = { + // This is totally fucked, but there's no true write mask support yet + val mask1 = mask.toBits + write(idx, t.fromBits((read(idx).toBits & ~mask1) | (data.toBits & mask1))) + } + + def name = getRefForId(t.cid).name + def debugName = t.mod.debugName + "." + getRefForId(t.cid).debugName +} + +object SeqMem { + def apply[T <: Data](t: T, size: Int): SeqMem[T] = + new SeqMem(t, size) +} + +// For now, implement SeqMem in terms of Mem +class SeqMem[T <: Data](t: T, n: Int) { + private val mem = Mem(t, n) + + def read(addr: UInt): T = mem.read(Reg(next = addr)) + def read(addr: UInt, enable: Bool): T = mem.read(RegEnable(addr, enable)) + + def write(addr: UInt, data: T): Unit = mem.write(addr, data) + def write(addr: UInt, data: T, mask: T): Unit = mem.write(addr, data, mask) +} + +object Vec { + def apply[T <: Data](gen: => T, n: Int): Vec[T] = + new Vec((0 until n).map(i => gen.cloneType)) + def apply[T <: Data](elts: Iterable[T]): Vec[T] = { + val vec = new Vec[T](elts.map(e => elts.head.cloneType)) + val isDef = true || elts.head.isDef + if (vec.isReg) + throw new Exception("Vec of Reg Deprecated.") + if (isDef) { + pushCommand(DefWire(vec.defd.cid, vec.toType)) + var i = 0 + for (elt <- elts) { + vec(i) := elt + i += 1 + } + } + vec + } + def apply[T <: Data](elt0: T, elts: T*): Vec[T] = + apply(elt0 +: elts.toSeq) + def tabulate[T <: Data](n: Int)(gen: (Int) => T): Vec[T] = + apply((0 until n).map(i => gen(i))) + def fill[T <: Data](n: Int)(gen: => T): Vec[T] = + Vec.tabulate(n){ i => gen } +} + +abstract class Aggregate(dirArg: Direction) extends Data(dirArg) { + def cloneTypeWidth(width: Int): this.type = cloneType +} + +class Vec[T <: Data](elts: Iterable[T], dirArg: Direction = NO_DIR) extends Aggregate(dirArg) with VecLike[T] { + private val self = elts.toIndexedSeq + private val elt0 = elts.head + + // println("BEGIN VEC NAMING " + this) + for ((e, i) <- self zipWithIndex) { + // println(" NAME " + i + " -> " + cid) + e.collectElts + setIndexForId(cid, e.cid, i) + } + // println("DONE VEC NAMING " + this) + + def <> (that: Iterable[T]): Unit = + this <> Vec(that).asInstanceOf[Data] + + override def isReg = elt0.isReg + override def isFlip = { + val isSubFlip = elt0.isFlip + if (isFlipVar) !isSubFlip else isSubFlip + } + + def apply(idx: UInt): T = { + val x = elt0.cloneType + pushCommand(DefAccessor(x.defd.cid, Alias(cid), NO_DIR, idx.ref)) + x + } + def apply(idx: Int): T = + self(idx) + def toPorts: Array[Port] = + self.map(d => d.toPort).toArray + def toType: Kind = + VectorType(self.size, elt0.toType, isFlipVar) + override def doCloneType: this.type = + Vec(elt0.cloneType, self.size).asInstanceOf[this.type] + override def init(dummy:Int = 0) = + for (e <- self) e.init() + def inits (f: (Int, T, (Int, T, T) => Unit) => Unit) = { + var i = 0 + def doInit (index: Int, elt: T, init: T) = + pushCommand(ConnectInitIndex(elt.lref, index, init.ref)) + for (d <- self) { + f(i, d, doInit) + i += 1; + } + } + override def flatten: IndexedSeq[Bits] = + self.map(_.flatten).reduce(_ ++ _) + + def length: Int = self.size + + def read(idx: UInt): T = apply(idx) + def write(idx: UInt, data: T): Unit = apply(idx) := data +} + +trait VecLike[T <: Data] extends collection.IndexedSeq[T] { + def read(idx: UInt): T + def write(idx: UInt, data: T): Unit + def apply(idx: UInt): T + + def forall(p: T => Bool): Bool = (this map p).fold(Bool(true))(_&&_) + def exists(p: T => Bool): Bool = (this map p).fold(Bool(false))(_||_) + def contains(x: T) (implicit evidence: T <:< Bits): Bool = this.exists(_ === x) + def count(p: T => Bool): UInt = PopCount((this map p).toSeq) + + private def indexWhereHelper(p: T => Bool) = this map p zip (0 until length).map(i => UInt(i)) + def indexWhere(p: T => Bool): UInt = PriorityMux(indexWhereHelper(p)) + def lastIndexWhere(p: T => Bool): UInt = PriorityMux(indexWhereHelper(p).reverse) + def onlyIndexWhere(p: T => Bool): UInt = Mux1H(indexWhereHelper(p)) +} + +// object chiselCast { +// def apply[S <: Data, T <: Bits](i: S)(gen: Int => T): T = { +// val b = i.toBits +// val x = gen(b.getWidth) +// pushCommand(DefPrim(x.defd.id, x.toType, ConvertOp, Array(b.ref), NoLits)) +// x +// } +// } + +import Literal._ + +class BitPat(val value: String, val width: Int) extends Data(NO_DIR) { + def cloneTypeWidth(width: Int): this.type = cloneType + override def dir: Direction = NO_DIR + override def setDir(dir: Direction): Unit = { } + override def toType: Kind = UIntType(UnknownWidth(), isFlip) + override def getWidth: Int = width + override def flatten: IndexedSeq[Bits] = throw new Exception("BitPat.flatten") + override def doCloneType: this.type = + new BitPat(value, width).asInstanceOf[this.type] + def fromInt(x: BigInt): BitPat = BitPat(x.toString(2), -1).asInstanceOf[this.type] + val (bits, mask, swidth) = parseLit(value) + def zEquals(other: Bits): Bool = + (Bits(toLitVal(mask, 2)) & other) === Bits(toLitVal(bits, 2)) + def === (other: Bits): Bool = zEquals(other) + def != (other: Bits): Bool = !zEquals(other) +} + +object BitPat { + def mintLit(n: String, width: Int) = { + assert(n(0) == 'b', "BINARY MINTS ONLY") + new BitPat(n.substring(1, n.length), width) + } + def apply(value: String, width: Int): BitPat = mintLit(value, width) + def apply(value: String): BitPat = apply(value, -1) +} + +abstract class Element(dirArg: Direction, val width: Int) extends Data(dirArg) { + override def getWidth: Int = width +} + +abstract class Bits(dirArg: Direction, width: Int) extends Element(dirArg, width) { + private var litValueVar: Option[LitArg] = None + + override def litArg(): LitArg = litValueVar.get + override def isLitValue(): Boolean = litValueVar.isDefined + override def litValue(): BigInt = if (isLitValue) litValueVar.get.num else -1 + override def setLitValue(x: LitArg) { litValueVar = Some(x) } + override def doCloneType : this.type = cloneTypeWidth(width) + def fromInt(x: BigInt): this.type = makeLit(x, -1) + + override def flatten: IndexedSeq[Bits] = IndexedSeq(this) + + final def apply(x: BigInt): Bool = { + val d = new Bool(dir) + if (isLitValue()) + d.setLitValue(ULit((litValue() >> x.toInt) & 1, 1)) + else + pushCommand(DefPrim(d.defd.cid, d.toType, BitSelectOp, Array(this.ref), Array(x))) + d + } + final def apply(x: Int): Bool = + apply(BigInt(x)) + final def apply(x: UInt): Bool = + apply(x.litValue()) + + final def apply(x: BigInt, y: BigInt): UInt = { + val w = (x - y + 1).toInt + val d = UInt(width = w) + if (isLitValue()) { + val mask = (BigInt(1)<> y.toInt) & mask, w)) + } else + pushCommand(DefPrim(d.defd.cid, d.toType, BitsExtractOp, Array(this.ref), Array(x, y))) + d + } + final def apply(x: Int, y: Int): UInt = + apply(BigInt(x), BigInt(y)) + final def apply(x: UInt, y: UInt): UInt = + apply(x.litValue(), y.litValue()) + + def maxWidth(other: Bits, amt: Int): Int = + if (getWidth >= 0 && other.getWidth >= 0) ((getWidth max other.getWidth) + amt) else -1 + override def sumWidth(amt: BigInt): Int = if (getWidth >= 0) (getWidth + amt).toInt else -1 + def sumWidth(other: Bits, amt: BigInt): Int = + if (getWidth >= 0 && other.getWidth >= 0) (getWidth + other.getWidth + amt).toInt else -1 + def sumLog2Width(other: Bits): Int = + if (getWidth >= 0 && other.getWidth >= 0) (getWidth + (1<> (other: BigInt): Bits = binop(ShiftRightOp, other, sumWidth(-other)) + def >> (other: Int): Bits = this >> BigInt(other) + def >> (other: Bits): Bits = binop(DynamicShiftRightOp, other, sumWidth(0)) + def unary_~ : Bits = unop(BitNotOp, sumWidth(0)) + def pad (other: BigInt): Bits = binop(PadOp, other, other.toInt) + + def & (other: Bits): Bits = binop(BitAndOp, other, maxWidth(other, 0)) + def | (other: Bits): Bits = binop(BitOrOp, other, maxWidth(other, 0)) + def ^ (other: Bits): Bits = binop(BitXorOp, other, maxWidth(other, 0)) + def ## (other: Bits): Bits = Cat(this, other) + + def < (other: Bits): Bool = compop(LessOp, other) + def > (other: Bits): Bool = compop(GreaterOp, other) + def === (other: Bits): Bool = compop(EqualOp, other) + def != (other: Bits): Bool = compop(NotEqualOp, other) + def <= (other: Bits): Bool = compop(LessEqOp, other) + def >= (other: Bits): Bool = compop(GreaterEqOp, other) + def unary_! : Bool = this === Bits(0) + + private def bits_redop(op: PrimOp): Bool = { + val d = new Bool(dir) + pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref), NoLits)) + d + } + + def orR = !(this === Bits(0)) + def andR = (this === Bits(-1)) + def xorR = bits_redop(XorReduceOp) + + def bitSet(off: UInt, dat: Bits): Bits = { + val bit = UInt(1, 1) << off + this & ~bit | dat.toSInt & bit + } + + def toBools: Vec[Bool] = Vec.tabulate(this.getWidth)(i => this(i)) + + def asSInt(): SInt + def asUInt(): UInt + def toSInt(): SInt + def toUInt(): UInt + def toBool(): Bool = this(0) +} + +abstract trait Num[T <: Data] { + // def << (b: T): T; + // def >> (b: T): T; + //def unary_-(): T; + def + (b: T): T; + def * (b: T): T; + def / (b: T): T; + def % (b: T): T; + def - (b: T): T; + def < (b: T): Bool; + def <= (b: T): Bool; + def > (b: T): Bool; + def >= (b: T): Bool; + + def min(b: T): T = Mux(this < b, this.asInstanceOf[T], b) + def max(b: T): T = Mux(this < b, b, this.asInstanceOf[T]) +} + +class UInt(dir: Direction, width: Int) extends Bits(dir, width) with Num[UInt] { + override def cloneTypeWidth(w: Int): this.type = + new UInt(dir, w).asInstanceOf[this.type] + + def toType: Kind = + UIntType(if (width == -1) UnknownWidth() else IntWidth(width), isFlipVar) + + override def makeLit(value: BigInt, width: Int): this.type = + UInt(value, width).asInstanceOf[this.type] + + override def unary_- = UInt(0) - this + override def unary_-% = UInt(0) -% this + def +& (other: UInt): UInt = binop(AddOp, other, maxWidth(other, 1)) + def + (other: UInt): UInt = this +% other + def +% (other: UInt): UInt = binop(AddModOp, other, maxWidth(other, 0)) + def -& (other: UInt): UInt = binop(SubOp, other, maxWidth(other, 1)) + def - (other: UInt): UInt = this -% other + def -% (other: UInt): UInt = binop(SubModOp, other, maxWidth(other, 0)) + def * (other: UInt): UInt = binop(TimesOp, other, sumWidth(other, 0)) + def / (other: UInt): UInt = binop(DivideOp, other, sumWidth(0)) + def % (other: UInt): UInt = binop(ModOp, other, sumWidth(0)) + override def << (other: BigInt): UInt = binop(ShiftLeftOp, other, sumWidth(other)) + override def << (other: Int): UInt = this << BigInt(other) + def << (other: UInt): UInt = binop(DynamicShiftLeftOp, other, sumLog2Width(other)) + override def >> (other: BigInt): UInt = binop(ShiftRightOp, other, sumWidth(-other)) + override def >> (other: Int): UInt = this >> BigInt(other) + def >> (other: UInt): UInt = binop(DynamicShiftRightOp, other, sumWidth(0)) + + override def unary_~ : UInt = unop(BitNotOp, sumWidth(0)) + def & (other: UInt): UInt = binop(BitAndOp, other, maxWidth(other, 0)) + def | (other: UInt): UInt = binop(BitOrOp, other, maxWidth(other, 0)) + def ^ (other: UInt): UInt = binop(BitXorOp, other, maxWidth(other, 0)) + def ## (other: UInt): UInt = Cat(this, other) + + def < (other: UInt): Bool = compop(LessOp, other) + def > (other: UInt): Bool = compop(GreaterOp, other) + def === (other: UInt): Bool = compop(EqualOp, other) + def != (other: UInt): Bool = compop(NotEqualOp, other) + def <= (other: UInt): Bool = compop(LessEqOp, other) + def >= (other: UInt): Bool = compop(GreaterEqOp, other) + + override def pad (other: BigInt): UInt = binop(PadOp, other, other.toInt) + + def zext(): SInt = { + val x = SInt(width = getWidth + 1) + pushCommand(DefPrim(x.defd.cid, x.toType, ConvertOp, Array(ref), NoLits)) + x + } + + def asSInt(): SInt = { + val x = SInt(width = getWidth) + pushCommand(DefPrim(x.defd.cid, x.toType, AsSIntOp, Array(ref), NoLits)) + x + } + + def toSInt(): SInt = asSInt() + def toUInt(): UInt = this + def asUInt(): UInt = this +} + +trait UIntFactory { + def apply(dir: Direction = OUTPUT, width: Int = -1) = + new UInt(dir, width) + def uintLit(value: BigInt, width: Int) = { + val w = if (width == -1) (1 max bitLength(value)) else width + // println("UINT-LIT VALUE = " + value + "(b" + value.toString(2) + ") WIDTH " + w) + val b = new UInt(NO_DIR, w) + b.setLitValue(ULit(value, w)) + // pushCommand(DefUInt(b.defd.id, value, w)) + b + } + def apply(value: BigInt, width: Int): UInt = uintLit(value, width) + def apply(value: BigInt): UInt = apply(value, -1) + def apply(n: String, width: Int): UInt = { + val bitsPerDigit = if (n(0) == 'b') 1 else if (n(0) == 'h') 4 else -1 + apply(stringToVal(n(0), n.substring(1, n.length)), + if (width == -1) (bitsPerDigit * (n.length-1)) else width) + } + def apply(n: String): UInt = apply(n, -1) +} + +// Bits constructors are identical to UInt constructors. +object Bits extends UIntFactory +object UInt extends UIntFactory + +class SInt(dir: Direction, width: Int) extends Bits(dir, width) with Num[SInt] { + override def cloneTypeWidth(w: Int): this.type = + new SInt(dir, w).asInstanceOf[this.type] + def toType: Kind = + SIntType(if (width == -1) UnknownWidth() else IntWidth(width), isFlipVar) + + override def makeLit(value: BigInt, width: Int): this.type = + SInt(value, width).asInstanceOf[this.type] + + override def unary_- : SInt = SInt(0, getWidth) - this + override def unary_-% : SInt = SInt(0, getWidth) -% this + def +& (other: SInt): SInt = binop(AddOp, other, maxWidth(other, 1)) + def +% (other: SInt): SInt = binop(AddModOp, other, maxWidth(other, 0)) + def + (other: SInt): SInt = this +% other + def -& (other: SInt): SInt = binop(SubOp, other, maxWidth(other, 1)) + def -% (other: SInt): SInt = binop(SubModOp, other, maxWidth(other, 0)) + def - (other: SInt): SInt = this -% other + def * (other: SInt): SInt = binop(TimesOp, other, sumWidth(other, 0)) + def / (other: SInt): SInt = binop(DivideOp, other, sumWidth(0)) + def % (other: SInt): SInt = binop(ModOp, other, sumWidth(0)) + override def << (other: BigInt): SInt = binop(ShiftLeftOp, other, sumWidth(other)) + override def << (other: Int): SInt = this << BigInt(other) + def << (other: UInt): SInt = binop(DynamicShiftLeftOp, other, sumLog2Width(other)) + override def >> (other: BigInt): SInt = binop(ShiftRightOp, other, sumWidth(-other)) + override def >> (other: Int): SInt = this >> BigInt(other) + def >> (other: UInt): SInt = binop(DynamicShiftRightOp, other, sumWidth(0)) + + override def unary_~ : SInt = unop(BitNotOp, sumWidth(0)) + def & (other: SInt): SInt = binop(BitAndOp, other, maxWidth(other, 0)) + def | (other: SInt): SInt = binop(BitOrOp, other, maxWidth(other, 0)) + def ^ (other: SInt): SInt = binop(BitXorOp, other, maxWidth(other, 0)) + + def < (other: SInt): Bool = compop(LessOp, other) + def > (other: SInt): Bool = compop(GreaterOp, other) + def === (other: SInt): Bool = compop(EqualOp, other) + def != (other: SInt): Bool = compop(NotEqualOp, other) + def <= (other: SInt): Bool = compop(LessEqOp, other) + def >= (other: SInt): Bool = compop(GreaterEqOp, other) + def abs: UInt = Mux(this < SInt(0), (-this).toUInt, this.toUInt) + + override def pad (other: BigInt): SInt = binop(PadOp, other, other.toInt) + + def asUInt(): UInt = { + val x = UInt(width = getWidth) + pushCommand(DefPrim(x.defd.cid, x.toType, AsUIntOp, Array(ref), NoLits)) + x + } + def toUInt(): UInt = asUInt() + def asSInt(): SInt = this + def toSInt(): SInt = this +} + +object SInt { + def apply(dir: Direction = OUTPUT, width: Int = -1) = + new SInt(dir, width) + def sintLit(value: BigInt, width: Int) = { + val w = if (width == -1) bitLength(value) + 1 else width + val b = new SInt(NO_DIR, w) + b.setLitValue(SLit(value, w)) + // pushCommand(DefSInt(b.defd.id, value, w)) + b + } + def apply(value: BigInt, width: Int): SInt = sintLit(value, width) + def apply(value: BigInt): SInt = apply(value, -1) + def apply(n: String, width: Int): SInt = + apply(stringToVal(n(0), n.substring(1, n.length)), width) + def apply(n: String): SInt = apply(n, -1) +} + +class Bool(dir: Direction) extends UInt(dir, 1) { + override def cloneTypeWidth(w: Int): this.type = new Bool(dir).asInstanceOf[this.type] + + override def makeLit(value: BigInt, width: Int): this.type = + Bool(value).asInstanceOf[this.type] + + def & (other: Bool): Bool = super.&(other).asInstanceOf[Bool] + def | (other: Bool): Bool = super.|(other).asInstanceOf[Bool] + def ^ (other: Bool): Bool = super.^(other).asInstanceOf[Bool] + override def unary_~ : Bool = super.unary_~.asInstanceOf[Bool] + + def || (that: Bool): Bool = this | that + def && (that: Bool): Bool = this & that +} +object Bool { + def apply(dir: Direction) : Bool = + new Bool(dir) + def apply() : Bool = + apply(NO_DIR) + def boolLit(value: BigInt) = { + val b = new Bool(NO_DIR) + b.setLitValue(ULit(value, 1)) + b + } + def apply(value: BigInt) : Bool = boolLit(value) + def apply(value: Boolean) : Bool = apply(if (value) 1 else 0) +} + +object Mux { + def apply[T <: Data](cond: Bool, con: T, alt: T): T = { + val w = Wire(alt, init = alt) + when (cond) { + w := con + } + w + } +} + +object Cat { + def apply[T <: Bits](a: T, r: T*): T = apply(a :: r.toList) + def apply[T <: Bits](r: Seq[T]): T = doCat(r) + private def doCat[T <: Data](r: Seq[T]): T = { + if (r.tail.isEmpty) + r.head + else { + val l = doCat(r.slice(0, r.length/2)) + val h = doCat(r.slice(r.length/2, r.length)) + val isConst = (l.isLitValue() && h.isLitValue()) + val w = if (isConst) l.getWidth + h.getWidth else if (l.getWidth >= 0 && h.getWidth >= 0) l.getWidth + h.getWidth else -1 + val d = l.cloneTypeWidth(w) + if (isConst) { + val c = (l.litValue() << h.getWidth) | h.litValue() + // println("DO-CAT L = " + l.litValue() + " LW = " + l.getWidth + " H = " + h.litValue() + " -> " + c) + + d.setLitValue(ULit(c, w)) + } else + pushCommand(DefPrim(d.cid, d.toType, ConcatOp, Array(l.ref, h.ref), NoLits)) + d + } + } +} + +object Bundle { + val keywords = HashSet[String]("elements", "flip", "toString", + "flatten", "binding", "asInput", "asOutput", "unary_$tilde", + "unary_$bang", "unary_$minus", "cloneType", "doCloneType", + "toUInt", "toBits", + "toBool", "toSInt", "asDirectionless") + def apply[T <: Bundle](b: => T)(implicit p: Parameters): T = { + Driver.parStack.push(p.push) + val res = b + Driver.parStack.pop + res + } + def apply[T <: Bundle](b: => T, f: PartialFunction[Any,Any]): T = { + val q = params.alterPartial(f) + apply(b)(q) + } + private def params = if(Driver.parStack.isEmpty) Parameters.empty else Driver.parStack.top +} + +class Bundle(dirArg: Direction = NO_DIR) extends Aggregate(dirArg) { + def toPorts: Array[Port] = + elements.map(_._2.toPort).toArray + def toType: BundleType = + BundleType(this.toPorts, isFlipVar) + + override def flatten: IndexedSeq[Bits] = { + val sortedElts = elements.values.toIndexedSeq sortWith (_._id < _._id) + sortedElts.map(_.flatten).reduce(_ ++ _) + } + + override def init(dummy:Int = 0) = + for ((s, e) <- elements) e.init() + lazy val elements: LinkedHashMap[String, Data] = { + val elts = LinkedHashMap[String, Data]() + // println("BEGIN BUNDLE NAMING " + cid) + for (m <- getClass.getMethods) { + val name = m.getName + // println("NAME = " + name) + val rtype = m.getReturnType + val isInterface = classOf[Data].isAssignableFrom(rtype) + if (m.getParameterTypes.isEmpty && + !isStatic(m.getModifiers) && + isInterface && + !(Bundle.keywords contains name)) { + val obj = m.invoke(this) + obj match { + case data: Data => + // println(" NAMING " + name + " -> " + cid) + setFieldForId(cid, data.cid, name) + elts(name) = data + case _ => () + } + } + } + // println("DONE BUNDLE NAMING " + cid) + elts + } + override def collectElts = elements + + override def doCloneType : this.type = { + try { + val constructor = this.getClass.getConstructors.head + val res = constructor.newInstance(Array.fill(constructor.getParameterTypes.size)(null):_*) + res.asInstanceOf[this.type] + } catch { + case npe: java.lang.reflect.InvocationTargetException if npe.getCause.isInstanceOf[java.lang.NullPointerException] => + // throwException("Parameterized Bundle " + this.getClass + " needs cloneType method. You are probably using an anonymous Bundle object that captures external state and hence is un-cloneTypeable", npe) + val s = "CLONE INVOCATION EXCEPTION " + this.getClass + error(s) + case e: java.lang.Exception => + val s = "CLONE ANY EXCEPTION " + this.getClass + error(s) + // throwException("Parameterized Bundle " + this.getClass + " needs cloneType method", e) + } + } +} + +object Module { + def apply[T <: Module](bc: => T)(implicit p: Parameters = params): T = { + Driver.modStackPushed = true + Driver.parStack.push(p.push) + val m = bc + val cmd = popCommands + popScope + popModule + m.setRefs + val ports = m.io.toPorts + val component = UniqueComponent(m.name, ports, cmd) + components += component + pushCommand(DefInstance(m.defd.cid, component.name)) + Driver.parStack.pop + m + } + def apply[T <: Module](m: => T, f: PartialFunction[Any,Any]): T = { + val q = params.alterPartial(f) + apply(m)(q) + } + private def params = if(Driver.parStack.isEmpty) Parameters.empty else Driver.parStack.top +} + +abstract class Module(private[Chisel] _reset: Bool = null) extends Id { + val parent = modulez.headOption + pushModule(this) + pushScope + pushCommands + addModule(this) + + lazy val params = Module.params + params.path = this.getClass :: params.path + + def io: Bundle + def ref = getRefForId(cid) + def lref = ref + val reset = if (_reset == null) Bool().defd else _reset + setRefForId(reset.cid, "reset") + + def name = { + // getClass.getName.replace('.', '_') + getClass.getName.split('.').last + } + def debugName: String = { + val p = parent.getOrElse(null) + val pname = if (p == null) "" else (p.debugName + ".") + pname + getRefForId(cid).debugName + } + + def setRefs { + setRefForId(io.cid, "this") + + for (m <- getClass.getDeclaredMethods) { + val name = m.getName() + val types = m.getParameterTypes() + if (types.length == 0) { + val obj = m.invoke(this) + obj match { + case module: Module => + setRefForId(module.cid, name) + module.setRefs + case bundle: Bundle => + if (name != "io") { + setRefForId(bundle.cid, name) + } + case mem: Mem[_] => + setRefForId(mem.t.cid, name) + case vec: Vec[_] => + setRefForId(vec.cid, name) + case data: Data => + setRefForId(data.cid, name) + // ignore anything not of those types + case _ => null + } + } + } + } + + // TODO: actually implement assert + def assert(cond: Bool, msg: String): Unit = {} +} + +// TODO: actually implement BlackBox (this hack just allows them to compile) +abstract class BlackBox(private[Chisel] _reset: Bool = null) extends Module(_reset) { + def setVerilogParameters(s: String): Unit = {} +} + +object when { + def execBlock(block: => Unit): Command = { + pushScope + pushCommands + block + val cmd = popCommands + popScope + cmd + } + def apply(cond: => Bool)(block: => Unit): when = { + new when(cond)( block ) + } +} + +import when._ + +class when(cond: => Bool)(block: => Unit) { + def elsewhen (cond: => Bool)(block: => Unit): when = { + pushCommands + val res = new when(cond) ( block ) + this.cmd.alt = popCommands + res + } + + def otherwise (block: => Unit) { + this.cmd.alt = execBlock(block) + } + + // Capture any commands we need to set up the conditional test. + pushCommands + val pred = cond.ref + val prep = popCommands + val conseq = execBlock(block) + // Assume we have an empty alternate clause. + // elsewhen and otherwise will update it if that isn't the case. + val cmd = Conditionally(prep, pred, conseq, EmptyCommand()) + pushCommand(cmd) +} + + +/// CHISEL IR EMITTER + +class Emitter { + var indenting = 0 + def withIndent(f: => String) = { + indenting += 1; + val res = f + indenting -= 1; + res + } + def join(parts: Array[String], sep: String) = + parts.foldLeft("")((s, p) => if (s == "") p else s + sep + p) + def join0(parts: Array[String], sep: String) = + parts.foldLeft("")((s, p) => s + sep + p) + def join0(parts: List[String], sep: String) = + parts.foldLeft("")((s, p) => s + sep + p) + def newline = + "\n" + join((0 until indenting).map(x => " ").toArray, "") + def emitDir(e: Direction, isTop: Boolean): String = + if (isTop) (e.name + " ") else if (e == INPUT) "flip " else "" + def emit(e: PrimOp): String = e.name + def emit(e: Arg): String = e.fullname + def emitPort(e: Port, isTop: Boolean): String = + emitDir(e.dir, isTop) + getRefForId(e.id).name + " : " + emitType(e.kind) + def emit(e: Width): String = { + e match { + case e: UnknownWidth => "" + case e: IntWidth => "<" + e.value.toString + ">" + } + } + def emitType(e: Kind): String = { + e match { + case e: UnknownType => "?" + case e: UIntType => "UInt" + emit(e.width) + case e: SIntType => "SInt" + emit(e.width) + case e: BundleType => "{" + join(e.ports.map(x => emitPort(x, false)), ", ") + "}" + case e: VectorType => emitType(e.kind) + "[" + e.size + "]" + } + } + def emit(e: Command): String = { + def maybeWidth (w: Int) = if (w == -1) "" else ("<" + w + ">") + e match { + case e: DefUInt => "node " + e.name + " = UInt" + maybeWidth(e.width) + "(" + e.value + ")" + case e: DefSInt => "node " + e.name + " = SInt" + maybeWidth(e.width) + "(" + e.value + ")" + case e: DefFlo => "node " + e.name + " = Flo(" + e.value + ")" + case e: DefDbl => "node " + e.name + " = Dbl(" + e.value + ")" + case e: DefPrim => + "node " + e.name + " = " + emit(e.op) + "(" + join(e.args.map(x => emit(x)) ++ e.lits.map(x => x.toString), ", ") + ")" + case e: DefWire => "wire " + e.name + " : " + emitType(e.kind) + case e: DefRegister => "reg " + e.name + " : " + emitType(e.kind) + case e: DefMemory => "cmem " + e.name + " : " + emitType(e.kind) + "[" + e.size + "]"; + case e: DefSeqMemory => "smem " + e.name + " : " + emitType(e.kind) + "[" + e.size + "]"; + case e: DefAccessor => "accessor " + e.name + " = " + emit(e.source) + "[" + emit(e.index) + "]" + case e: DefInstance => { + val mod = modules(e.id) + // update all references to the modules ports + setRefForId(mod.io.cid, e.name, true) + "inst " + e.name + " of " + e.module + } + case e: Conditionally => { + val prefix = if (!e.prep.isInstanceOf[EmptyCommand]) { + newline + emit(e.prep) + newline + } else { + "" + } + val suffix = if (!e.alt.isInstanceOf[EmptyCommand]) { + newline + "else : " + withIndent{ newline + emit(e.alt) } + } else { + "" + } + prefix + "when " + emit(e.pred) + " : " + withIndent{ emit(e.conseq) } + suffix + } + case e: Begin => join0(e.body.map(x => emit(x)), newline) + case e: Connect => emit(e.loc) + " := " + emit(e.exp) + case e: BulkConnect => emit(e.loc1) + " <> " + emit(e.loc2) + case e: ConnectInit => "on-reset " + emit(e.loc) + " := " + emit(e.exp) + case e: ConnectInitIndex => "on-reset " + emit(e.loc) + "[" + e.index + "] := " + emit(e.exp) + case e: EmptyCommand => "skip" + } + } + def emit(e: Component): String = { + withIndent{ "module " + e.name + " : " + + join0(e.ports.map(x => emitPort(x, true)), newline) + + newline + emit(e.body) } + } + def emit(e: Circuit): String = + withIndent{ "circuit " + e.main + " : " + join0(e.components.map(x => emit(x)), newline) } +} diff --git a/src/main/scala/Chisel/Driver.scala b/src/main/scala/Chisel/Driver.scala new file mode 100644 index 00000000..c4a26221 --- /dev/null +++ b/src/main/scala/Chisel/Driver.scala @@ -0,0 +1,420 @@ +/* + Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of + California (Regents). All Rights Reserved. Redistribution and use in + source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of the Regents nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF + ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION + TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + MODIFICATIONS. +*/ + +package Chisel +import Builder._ +import Direction._ +import ChiselError._ + +import collection.mutable.{ArrayBuffer, HashSet, HashMap, Stack, LinkedHashSet, Queue => ScalaQueue} +import scala.math.min +import java.io.File +import java.io.InputStream +import java.io.OutputStream +import java.io.PrintStream + +trait FileSystemUtilities { + /** Ensures a directory *dir* exists on the filesystem. */ + def ensureDir(dir: String): String = { + val d = dir + (if (dir == "" || dir(dir.length-1) == '/') "" else "/") + new File(d).mkdirs() + d + } + + def createOutputFile(name: String): java.io.FileWriter = { + val baseDir = ensureDir(Driver.targetDir) + new java.io.FileWriter(baseDir + name) + } +} + +class ChiselException(message: String, cause: Throwable) extends Exception(message, cause) + +object throwException { + def apply(s: String, t: Throwable = null) = { + val xcpt = new ChiselException(s, t) + findFirstUserLine(xcpt.getStackTrace) foreach { u => xcpt.setStackTrace(Array(u)) } + throw xcpt + } +} + +object chiselMain { + val wrapped = true + val unwrapped = false + + def apply[T <: Module](args: Array[String], gen: () => T): (Circuit, T) = + Driver(args, gen, wrapped) + + def apply[T <: Module](args: Array[String], gen: () => T, ftester: T => Tester[T]): (Circuit, T) = + Driver(args, gen, ftester, wrapped) + + // Assumes gen needs to be wrapped in Module() + def run[T <: Module] (args: Array[String], gen: () => T): (Circuit, T) = + Driver(args, gen, unwrapped) + + def run[T <: Module] (args: Array[String], gen: () => T, ftester: T => Tester[T]): (Circuit, T) = + Driver(args, gen, ftester, unwrapped) +} + +//Is this antiquated? +object chiselMainTest { + def apply[T <: Module](args: Array[String], gen: () => T)(tester: T => Tester[T]): (Circuit, T) = { + chiselMain(args, gen, tester) + } +} + +object Driver extends FileSystemUtilities{ + def apply[T <: Module](args: Array[String], gen: () => T, wrapped:Boolean = true): (Circuit, T) = { + initChisel(args) + try { + if(wrapped) execute(gen) else executeUnwrapped(gen) + } finally { + ChiselError.report + if (ChiselError.hasErrors && !getLineNumbers) { + println("Re-running Chisel in debug mode to obtain erroneous line numbers...") + // apply(args :+ "--lineNumbers", gen, wrapped) + } + } + } + + def apply[T <: Module](args: Array[String], gen: () => T, + ftester: T => Tester[T], wrapped:Boolean): (Circuit, T) = { + val (circuit, mod) = apply(args, gen, wrapped) + if (isTesting) test(mod, ftester) + (circuit, mod) + } + + private def executeUnwrapped[T <: Module](gen: () => T): (Circuit, T) = { + if (!chiselConfigMode.isEmpty && !chiselConfigClassName.isEmpty) { + println("CHISEL PARAMS") + val name = appendString(chiselProjectName,chiselConfigClassName) + val config = try { + Class.forName(name).newInstance.asInstanceOf[ChiselConfig] + } catch { + case e: java.lang.ClassNotFoundException => + throwException("Could not find the ChiselConfig subclass you asked for (\"" + + name + "\"), did you misspell it?", e) + } + val world = if(chiselConfigMode.get == "collect") { + new Collector(config.topDefinitions,config.knobValues) + } else { new Instance(config.topDefinitions,config.knobValues) } + val p = Parameters.root(world) + config.topConstraints.foreach(c => p.constrain(c)) + val (circuit, mod) = execute(() => Module(gen())(p)) + if(chiselConfigMode.get == "collect") { + val v = createOutputFile(chiselConfigClassName.get + ".knb") + v.write(world.getKnobs) + v.close + val w = createOutputFile(chiselConfigClassName.get + ".cst") + w.write(world.getConstraints) + w.close + } + (circuit, mod) + } + else { + execute(() => Module(gen())) + } + } + + private def execute[T <: Module](gen: () => T): (Circuit, T) = { + val emitter = new Emitter + val (c, mod) = build{ gen() } + // setTopComponent(c) + if (!isTesting) { + val s = emitter.emit( c ) + // println(c.components(0)) + val filename = c.main + ".fir" + // println("FILENAME " + filename) + // println("S = " + s) + val out = createOutputFile(filename) + out.write(s) + /* Params - If dumping design, dump space to pDir*/ + if (chiselConfigMode == None || chiselConfigMode.get == "instance") { + if(chiselConfigDump && !Dump.dump.isEmpty) { + val w = createOutputFile(appendString(Some(topComponent.name),chiselConfigClassName) + ".prm") + w.write(Dump.getDump); w.close + } + } + out.close() + } + (c, mod) + } + + private def test[T <: Module](mod: T, ftester: T => Tester[T]): Unit = { + var res = false + var tester: Tester[T] = null + try { + tester = ftester(mod) + } finally { + if (tester != null && tester.process != null) + res = tester.finish() + } + println(if (res) "PASSED" else "*** FAILED ***") + if(!res) throwException("Module under test FAILED at least one test vector.") + } + + def elapsedTime: Long = System.currentTimeMillis - startTime + + def initChisel(args: Array[String]): Unit = { + ChiselError.clear() + warnInputs = false + warnOutputs = false + saveConnectionWarnings = false + saveComponentTrace = false + dontFindCombLoop = false + isGenHarness = false + isDebug = false + getLineNumbers = false + isCSE = false + isIoDebug = true + isVCD = false + isVCDMem = false + isReportDims = false + targetDir = "." + components.clear() + sortedComps.clear() + compStack.clear() + stackIndent = 0 + printStackStruct.clear() + // blackboxes.clear() + chiselOneHotMap.clear() + chiselOneHotBitMap.clear() + isCompiling = false + isCheckingPorts = false + isTesting = false + isDebugMem = false + isSupportW0W = false + partitionIslands = false + lineLimitFunctions = 0 + minimumLinesPerFile = 0 + shadowRegisterInObject = false + allocateOnlyNeededShadowRegisters = false + compileInitializationUnoptimized = false + useSimpleQueue = false + parallelMakeJobs = 0 + isVCDinline = false + isSupportW0W = false + hasMem = false + hasSRAM = false + sramMaxSize = 0 + topComponent = null + // clocks.clear() + // implicitReset.isIo = true + // implicitReset.setName("reset") + // implicitClock = new Clock() + // implicitClock.setName("clk") + isInGetWidth = false + startTime = System.currentTimeMillis + modStackPushed = false + + readArgs(args) + } + + private def readArgs(args: Array[String]): Unit = { + var i = 0 + var backendName = "c" // Default backend is Cpp. + while (i < args.length) { + val arg = args(i) + arg match { + case "--Wall" => { + saveConnectionWarnings = true + saveComponentTrace = true + isCheckingPorts = true + } + case "--wi" => warnInputs = true + case "--wo" => warnOutputs = true + case "--wio" => {warnInputs = true; warnOutputs = true} + case "--Wconnection" => saveConnectionWarnings = true + case "--Wcomponent" => saveComponentTrace = true + case "--W0W" => isSupportW0W = true + case "--noW0W" => isSupportW0W = false + case "--noCombLoop" => dontFindCombLoop = true + case "--genHarness" => isGenHarness = true + case "--debug" => isDebug = true + case "--lineNumbers" => getLineNumbers = true + case "--cse" => isCSE = true + case "--ioDebug" => isIoDebug = true + case "--noIoDebug" => isIoDebug = false + case "--vcd" => isVCD = true + case "--vcdMem" => isVCDMem = true + case "--v" => backendName = "v" + // case "--moduleNamePrefix" => Backend.moduleNamePrefix = args(i + 1); i += 1 + case "--inlineMem" => isInlineMem = true + case "--noInlineMem" => isInlineMem = false + case "--assert" => isAssert = true + case "--noAssert" => isAssert = false + case "--debugMem" => isDebugMem = true + case "--partitionIslands" => partitionIslands = true + case "--lineLimitFunctions" => lineLimitFunctions = args(i + 1).toInt; i += 1 + case "--minimumLinesPerFile" => minimumLinesPerFile = args(i + 1).toInt; i += 1 + case "--shadowRegisterInObject" => shadowRegisterInObject = true + case "--allocateOnlyNeededShadowRegisters" => allocateOnlyNeededShadowRegisters = true + case "--compileInitializationUnoptimized" => compileInitializationUnoptimized = true + case "--useSimpleQueue" => useSimpleQueue = true + case "--parallelMakeJobs" => parallelMakeJobs = args(i + 1).toInt; i += 1 + case "--isVCDinline" => isVCDinline = true + case "--backend" => backendName = args(i + 1); i += 1 + case "--compile" => isCompiling = true + case "--test" => isTesting = true + case "--targetDir" => targetDir = args(i + 1); i += 1 + case "--include" => includeArgs = args(i + 1).split(' ').toList; i += 1 + case "--checkPorts" => isCheckingPorts = true + case "--reportDims" => isReportDims = true + //Jackhammer Flags + case "--configCollect" => chiselConfigMode = Some("collect"); chiselConfigClassName = Some(getArg(args(i+1),1)); chiselProjectName = Some(getArg(args(i+1),0)); i+=1; //dump constraints in dse dir + case "--configInstance" => chiselConfigMode = Some("instance"); chiselConfigClassName = Some(getArg(args(i+1),1)); chiselProjectName = Some(getArg(args(i+1),0)); i+=1; //use ChiselConfig to supply parameters + case "--configDump" => chiselConfigDump = true; //when using --configInstance, write Dump parameters to .prm file in targetDir + case "--dumpTestInput" => dumpTestInput = true + case "--testerSeed" => { + testerSeedValid = true + testerSeed = args(i+1).toLong + i += 1 + } + case "--emitTempNodes" => { + isDebug = true + emitTempNodes = true + } + /* + // Dreamer configuration flags + case "--numRows" => { + if (backend.isInstanceOf[FloBackend]) { + backend.asInstanceOf[FloBackend].DreamerConfiguration.numRows = args(i+1).toInt + } + i += 1 + } + case "--numCols" => { + if (backend.isInstanceOf[FloBackend]) { + backend.asInstanceOf[FloBackend].DreamerConfiguration.numCols = args(i+1).toInt + } + i += 1 + } + */ + case any => ChiselError.warning("'" + arg + "' is an unknown argument.") + } + i += 1 + } + // Check for bogus flags + if (!isVCD) { + isVCDinline = false + } + // Set the backend after we've interpreted all the arguments. + // (The backend may want to configure itself based on the arguments.) + backend = backendName match { + case "v" => new VerilogBackend + case "c" => new CppBackend + case "flo" => new FloBackend + case "dot" => new DotBackend + case "fpga" => new FPGABackend + case "sysc" => new SysCBackend + case _ => Class.forName(backendName).newInstance.asInstanceOf[Backend] + } + } + + var warnInputs = false + var warnOutputs = false + var saveConnectionWarnings = false + var saveComponentTrace = false + var dontFindCombLoop = false + var isDebug = false + var getLineNumbers = false + var isCSE = false + var isIoDebug = true + var isVCD = false + var isVCDMem = false + var isInlineMem = true + var isGenHarness = false + var isReportDims = false + var includeArgs: List[String] = Nil + var targetDir: String = null + var isCompiling = false + var isCheckingPorts = false + var isTesting = false + var isAssert = true + var isDebugMem = false + var partitionIslands = false + var lineLimitFunctions = 0 + var minimumLinesPerFile = 0 + var shadowRegisterInObject = false + var allocateOnlyNeededShadowRegisters = false + var compileInitializationUnoptimized = false + var useSimpleQueue = false + var parallelMakeJobs = 0 + var isVCDinline = false + var isSupportW0W = false + var hasMem = false + var hasSRAM = false + var sramMaxSize = 0 + var backend: Backend = null + var topComponent: Module = null + val components = ArrayBuffer[Module]() + val sortedComps = ArrayBuffer[Module]() + // val blackboxes = ArrayBuffer[BlackBox]() + val chiselOneHotMap = HashMap[(UInt, Int), UInt]() + val chiselOneHotBitMap = HashMap[(Bits, Int), Bool]() + val compStack = Stack[Module]() + val parStack = new Stack[Parameters] + var stackIndent = 0 + val printStackStruct = ArrayBuffer[(Int, Module)]() + // val clocks = ArrayBuffer[Clock]() + // val implicitReset = Bool(INPUT) + // var implicitClock: Clock = null + var isInGetWidth: Boolean = false + var modStackPushed: Boolean = false + var modAdded: Boolean = false + var startTime = 0L + /* ChiselConfig flags */ + var chiselConfigClassName: Option[String] = None + var chiselProjectName: Option[String] = None + var chiselConfigMode: Option[String] = None + var chiselConfigDump: Boolean = false + + def appendString(s1:Option[String],s2:Option[String]):String = { + if(s1.isEmpty && s2.isEmpty) "" else { + if(!s1.isEmpty) { + s1.get + (if(!s2.isEmpty) "." + s2.get else "") + } else { + if(!s2.isEmpty) s2.get else "" + } + } + } + def getArg(s:String,i:Int):String = s.split('.')(i) + + // Setting this to TRUE will case the test harness to print its + // standard input stream to a file. + var dumpTestInput = false + + // Setting this to TRUE will initialize the tester's RNG with the + // seed below. + var testerSeedValid = false + var testerSeed = System.currentTimeMillis() + + // Setting this to TRUE will result in temporary values (ie, nodes + // named "T*") to be emited to the VCD file. + var emitTempNodes = false +} diff --git a/src/main/scala/Chisel/Enum.scala b/src/main/scala/Chisel/Enum.scala new file mode 100644 index 00000000..3bc24220 --- /dev/null +++ b/src/main/scala/Chisel/Enum.scala @@ -0,0 +1,44 @@ +/* + Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of + California (Regents). All Rights Reserved. Redistribution and use in + source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of the Regents nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF + ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION + TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + MODIFICATIONS. +*/ + +package Chisel +import Literal._ + +object Enum { + /** create n enum values of given type */ + def apply[T <: Bits](nodeType: T, n: Int): List[T] = (Range(0, n, 1).map(x => (Lit(x, sizeof(n-1))(nodeType)))).toList; + + /** create enum values of given type and names */ + def apply[T <: Bits](nodeType: T, l: Symbol *): Map[Symbol, T] = (l.toList zip (Range(0, l.length, 1).map(x => Lit(x, sizeof(l.length-1))(nodeType)))).toMap; + + /** create enum values of given type and names */ + def apply[T <: Bits](nodeType: T, l: List[Symbol]): Map[Symbol, T] = (l zip (Range(0, l.length, 1).map(x => Lit(x, sizeof(l.length-1))(nodeType)))).toMap; + +} diff --git a/src/main/scala/Chisel/Error.scala b/src/main/scala/Chisel/Error.scala new file mode 100644 index 00000000..1ad5414d --- /dev/null +++ b/src/main/scala/Chisel/Error.scala @@ -0,0 +1,167 @@ +/* + Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of + California (Regents). All Rights Reserved. Redistribution and use in + source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of the Regents nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF + ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION + TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + MODIFICATIONS. +*/ + +package Chisel +import scala.collection.mutable.ArrayBuffer + +/** This Singleton implements a log4j compatible interface. + It is used through out the Chisel package to report errors and warnings + detected at runtime. + */ +object ChiselError { + var hasErrors: Boolean = false; + val ChiselErrors = new ArrayBuffer[ChiselError]; + + def clear() { + ChiselErrors.clear() + hasErrors = false + } + + /** emit an error message */ + def error(mf: => String, line: StackTraceElement) { + hasErrors = true + ChiselErrors += new ChiselError(() => mf, line) + } + + def error(m: String) { + val stack = Thread.currentThread().getStackTrace + error(m, findFirstUserLine(stack) getOrElse stack(0)) + } + + /** Emit an informational message + (useful to track long running passes) */ + def info(m: String): Unit = + println(tag("info", Console.MAGENTA) + " [%2.3f] ".format(Driver.elapsedTime/1e3) + m) + + /** emit a warning message */ + def warning(m: => String) { + val stack = Thread.currentThread().getStackTrace + ChiselErrors += new ChiselError(() => m, + findFirstUserLine(stack) getOrElse stack(0), 1) + } + + def findFirstUserLine(stack: Array[StackTraceElement]): Option[StackTraceElement] = { + findFirstUserInd(stack) map { stack(_) } + } + + def findFirstUserInd(stack: Array[StackTraceElement]): Option[Int] = { + def isUserCode(ste: StackTraceElement): Boolean = { + val className = ste.getClassName() + try { + val cls = Class.forName(className) + if( cls.getSuperclass() == classOf[Module] ) { + true + } else { + /* XXX Do it the old way until we figure if it is safe + to remove from Node.scala + var line: StackTraceElement = findFirstUserLine(Thread.currentThread().getStackTrace) + */ + val dotPos = className.lastIndexOf('.') + if( dotPos > 0 ) { + (className.subSequence(0, dotPos) != "Chisel") && !className.contains("scala") && + !className.contains("java") && !className.contains("$$") + } else { + false + } + } + } catch { + case e: java.lang.ClassNotFoundException => false + } + } + val idx = stack.indexWhere(isUserCode) + if(idx < 0) { + println("COULDN'T FIND LINE NUMBER (" + stack(1) + ")") + None + } else { + Some(idx) + } + } + + // Print stack frames up to and including the "user" stack frame. + def printChiselStackTrace() { + val stack = Thread.currentThread().getStackTrace + val idx = ChiselError.findFirstUserInd(stack) + idx match { + case None => {} + case Some(x) => for (i <- 0 to x) println(stack(i)) + } + } + + /** Prints error messages generated by Chisel at runtime. */ + def report() { + if (!ChiselErrors.isEmpty) { + for(err <- ChiselErrors) err.print; + } + } + + /** Throws an exception if there has been any error recorded + before this point. */ + def checkpoint() { + if(hasErrors) { + throw new IllegalStateException( + Console.UNDERLINED + "CODE HAS " + + Console.UNDERLINED + Console.BOLD + ChiselErrors.filter(_.isError).length + Console.RESET + + Console.UNDERLINED + " " + + Console.UNDERLINED + Console.RED + "ERRORS" + Console.RESET + + Console.UNDERLINED + " and " + + Console.UNDERLINED + Console.BOLD + ChiselErrors.filter(_.isWarning).length + Console.RESET + + Console.UNDERLINED + " " + + Console.UNDERLINED + Console.YELLOW + "WARNINGS" + Console.RESET) + } + } + + def tag(name: String, color: String): String = + s"[${color}${name}${Console.RESET}]" +} + +class ChiselError(val errmsgFun: () => String, val errline: StackTraceElement, +val errlevel: Int = 0) { + + val level = errlevel + val line = errline + val msgFun = errmsgFun + + def isError = (level == 0) + def isWarning = (level == 1) + + def print() { + /* Following conventions for error formatting */ + val levelstr = + if (isError) ChiselError.tag("error", Console.RED) + else ChiselError.tag("warn", Console.YELLOW) + if( line != null ) { + println(levelstr + " " + line.getFileName + ":" + + line.getLineNumber + ": " + msgFun() + + " in class " + line.getClassName) + } else { + println(levelstr + ": " + msgFun()) + } + } +} diff --git a/src/main/scala/Chisel/FP.scala b/src/main/scala/Chisel/FP.scala new file mode 100644 index 00000000..c22ee475 --- /dev/null +++ b/src/main/scala/Chisel/FP.scala @@ -0,0 +1,321 @@ +/* + Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of + California (Regents). All Rights Reserved. Redistribution and use in + source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of the Regents nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF + ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION + TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + MODIFICATIONS. +*/ + +package Chisel +import Chisel._ +import Builder._ +import ChiselError._ +import Commands.NoLits + +/// FLO + +object Flo { + def apply(x: Float): Flo = floLit(x) + def apply(x: Double): Flo = Flo(x.toFloat) + def floLit(value: Float): Flo = { + val b = new Flo(NO_DIR, Some(value)) + pushCommand(DefFlo(b.defd.cid, value)) + b + } + def apply(dir: Direction = null): Flo = + new Flo(dir) +} + +object FloPrimOp { + val FloNeg = PrimOp("flo-neg") + val FloAdd = PrimOp("flo-add") + val FloSub = PrimOp("flo-sub") + val FloMul = PrimOp("flo-mul") + val FloDiv = PrimOp("flo-div") + val FloMod = PrimOp("flo-mod") + val FloEqual = PrimOp("flo-equal") + val FloNotEqual = PrimOp("flo-not-equal") + val FloGreater = PrimOp("flo-greater") + val FloLess = PrimOp("flo-less") + val FloLessEqual = PrimOp("flo-less-equal") + val FloGreaterEqual = PrimOp("flo-greater-equal") + val FloPow = PrimOp("flo-pow") + val FloSin = PrimOp("flo-sin") + val FloCos = PrimOp("flo-cos") + val FloTan = PrimOp("flo-tan") + val FloAsin = PrimOp("flo-asin") + val FloAcos = PrimOp("flo-acos") + val FloAtan = PrimOp("flo-atan") + val FloSqrt = PrimOp("flo-sqrt") + val FloFloor = PrimOp("flo-floor") + val FloCeil = PrimOp("flo-ceil") + val FloRound = PrimOp("flo-round") + val FloLog = PrimOp("flo-log") + val FloToBits = PrimOp("flo-to-bits") + val BitsToFlo = PrimOp("bits-to-flo") +} +import FloPrimOp._ + +class Flo(dir: Direction = NO_DIR, val value:Option[Float] = None) extends Element(dir, 32) with Num[Flo] { + type T = Flo; + override def floLitValue: Float = value.get + def cloneTypeWidth(width: Int): this.type = cloneType + override def fromBits(n: Bits): this.type = { + val d = cloneType + pushCommand(DefPrim(d.defd.cid, d.toType, BitsToFlo, Array(this.ref), NoLits)) + d + } + override def toBits: UInt = { + val d = new UInt(dir, 32) + pushCommand(DefPrim(d.defd.cid, d.toType, FloToBits, Array(this.ref), NoLits)) + d + } + def toType: Kind = FloType(isFlip) + def doCloneType: this.type = new Flo(dir).asInstanceOf[this.type] + def flatten: IndexedSeq[Bits] = IndexedSeq(toBits) + + def fromInt(x: Int): Flo = + Flo(x.toFloat).asInstanceOf[this.type] + + private def flo_unop(op: PrimOp): Flo = { + val d = cloneType + pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref), NoLits)) + d + } + private def flo_binop(op: PrimOp, other: Flo): Flo = { + val d = cloneType + pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits)) + d + } + private def flo_compop(op: PrimOp, other: Flo): Bool = { + val d = new Bool(dir) + pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits)) + d + } + + def unary_-() = flo_unop(FloNeg) + def + (b: Flo) = flo_binop(FloAdd, b) + def - (b: Flo) = flo_binop(FloSub, b) + def * (b: Flo) = flo_binop(FloMul, b) + def / (b: Flo) = flo_binop(FloDiv, b) + def % (b: Flo) = flo_binop(FloMod, b) + def ===(b: Flo) = flo_compop(FloEqual, b) + def != (b: Flo) = flo_compop(FloNotEqual, b) + def > (b: Flo) = flo_compop(FloGreater, b) + def < (b: Flo) = flo_compop(FloLess, b) + def <= (b: Flo) = flo_compop(FloLessEqual, b) + def >= (b: Flo) = flo_compop(FloGreaterEqual, b) + def pow (b: Flo) = flo_binop(FloPow, b) + def sin = flo_unop(FloSin) + def cos = flo_unop(FloCos) + def tan = flo_unop(FloTan) + def asin = flo_unop(FloAsin) + def acos = flo_unop(FloAcos) + def atan = flo_unop(FloAtan) + def sqrt = flo_unop(FloSqrt) + def floor = flo_unop(FloFloor) + def ceil = flo_unop(FloCeil) + def round = flo_unop(FloRound) + def log = flo_unop(FloLog) + def toSInt () = SInt(OUTPUT).fromBits(toBits) + def toUInt () = UInt(OUTPUT).fromBits(toBits) +} + +/// DBL + +import java.lang.Double.doubleToLongBits + +object Dbl { + def apply(x: Float): Dbl = Dbl(x.toDouble); + def apply(x: Double): Dbl = dblLit(x) + def dblLit(value: Double): Dbl = { + val b = new Dbl(NO_DIR, Some(value)) + pushCommand(DefDbl(b.defd.cid, value)) + b + } + def apply(dir: Direction = NO_DIR): Dbl = + new Dbl(dir) +} + +object DblPrimOp { + val DblNeg = PrimOp("dbl-neg") + val DblAdd = PrimOp("dbl-add") + val DblSub = PrimOp("dbl-sub") + val DblMul = PrimOp("dbl-mul") + val DblDiv = PrimOp("dbl-div") + val DblMod = PrimOp("dbl-mod") + val DblEqual = PrimOp("dbl-equal") + val DblNotEqual = PrimOp("dbl-not-equal") + val DblGreater = PrimOp("dbl-greater") + val DblLess = PrimOp("dbl-less") + val DblLessEqual = PrimOp("dbl-less-equal") + val DblGreaterEqual = PrimOp("dbl-greater-equal") + val DblPow = PrimOp("dbl-pow") + val DblSin = PrimOp("dbl-sin") + val DblCos = PrimOp("dbl-cos") + val DblTan = PrimOp("dbl-tan") + val DblAsin = PrimOp("dbl-asin") + val DblAcos = PrimOp("dbl-acos") + val DblAtan = PrimOp("dbl-atan") + val DblSqrt = PrimOp("dbl-sqrt") + val DblFloor = PrimOp("dbl-floor") + val DblCeil = PrimOp("dbl-ceil") + val DblRound = PrimOp("dbl-round") + val DblLog = PrimOp("dbl-log") + val DblToBits = PrimOp("dbl-to-bits") + val BitsToDbl = PrimOp("bits-to-dbl") +} +import DblPrimOp._ + +class Dbl(dir: Direction, val value: Option[Double] = None) extends Element(dir, 64) with Num[Dbl] { + // setIsSigned + + // override def setIsTypeNode = {inputs(0).setIsSigned; super.setIsTypeNode} + + type T = Dbl; + override def dblLitValue: Double = value.get + def cloneTypeWidth(width: Int): this.type = cloneType + override def fromBits(n: Bits): this.type = { + val d = cloneType + pushCommand(DefPrim(d.defd.cid, d.toType, BitsToDbl, Array(this.ref), NoLits)) + d + } + override def toBits: UInt = { + val d = new UInt(dir, 64) + pushCommand(DefPrim(d.defd.cid, d.toType, DblToBits, Array(this.ref), NoLits)) + d + } + def toType: Kind = DblType(isFlip) + def doCloneType: this.type = new Dbl(dir).asInstanceOf[this.type] + def flatten: IndexedSeq[Bits] = IndexedSeq(toBits) + + def fromInt(x: Int): this.type = + Dbl(x.toDouble).asInstanceOf[this.type] + + private def dbl_unop(op: PrimOp): Dbl = { + val d = cloneType + pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref), NoLits)) + d + } + private def dbl_binop(op: PrimOp, other: Dbl): Dbl = { + val d = cloneType + pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits)) + d + } + private def dbl_compop(op: PrimOp, other: Dbl): Bool = { + val d = new Bool(dir) + pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits)) + d + } + + def unary_-() = dbl_unop(DblNeg) + def + (b: Dbl) = dbl_binop(DblAdd, b) + def - (b: Dbl) = dbl_binop(DblSub, b) + def * (b: Dbl) = dbl_binop(DblMul, b) + def / (b: Dbl) = dbl_binop(DblDiv, b) + def % (b: Dbl) = dbl_binop(DblMod, b) + def ===(b: Dbl) = dbl_compop(DblEqual, b) + def != (b: Dbl) = dbl_compop(DblNotEqual, b) + def > (b: Dbl) = dbl_compop(DblGreater, b) + def < (b: Dbl) = dbl_compop(DblLess, b) + def <= (b: Dbl) = dbl_compop(DblLessEqual, b) + def >= (b: Dbl) = dbl_compop(DblGreaterEqual, b) + def pow (b: Dbl) = dbl_binop(DblPow, b) + def sin = dbl_unop(DblSin) + def cos = dbl_unop(DblCos) + def tan = dbl_unop(DblTan) + def asin = dbl_unop(DblAsin) + def acos = dbl_unop(DblAcos) + def atan = dbl_unop(DblAtan) + def sqrt = dbl_unop(DblSqrt) + def floor = dbl_unop(DblFloor) + def ceil = dbl_unop(DblCeil) + def round = dbl_unop(DblRound) + def log = dbl_unop(DblLog) + def toSInt () = SInt(OUTPUT).fromBits(toBits) + def toUInt () = UInt(OUTPUT).fromBits(toBits) +} + +object Sin { + def apply (x: Flo): Flo = x.sin + def apply (x: Dbl): Dbl = x.sin +} + +object Cos { + def apply (x: Flo): Flo = x.cos + def apply (x: Dbl): Dbl = x.cos +} + +object Tan { + def apply (x: Flo): Flo = x.tan + def apply (x: Dbl): Dbl = x.tan +} + +object ASin { + def apply (x: Flo): Flo = x.asin + def apply (x: Dbl): Dbl = x.asin +} + +object ACos { + def apply (x: Flo): Flo = x.acos + def apply (x: Dbl): Dbl = x.acos +} + +object ATan { + def apply (x: Flo): Flo = x.atan + def apply (x: Dbl): Dbl = x.atan +} + +object Sqrt { + def apply (x: Flo): Flo = x.sqrt + def apply (x: Dbl): Dbl = x.sqrt +} + +object Floor { + def apply (x: Flo): Flo = x.floor + def apply (x: Dbl): Dbl = x.floor +} + +object Ceil { + def apply (x: Flo): Flo = x.ceil + def apply (x: Dbl): Dbl = x.ceil +} + +object Round { + def apply (x: Flo): Flo = x.round + def apply (x: Dbl): Dbl = x.round +} + +object Log { + def apply (x: Flo): Flo = x.log + def apply (x: Dbl): Dbl = x.log + def apply (x: Flo, p: Flo): Flo = Log(x)/Log(p) + def apply (x: Dbl, p: Dbl): Dbl = Log(x)/Log(p) +} + +object Pow { + def apply (x: Flo, y: Flo): Flo = x.pow(y) + def apply (x: Dbl, y: Dbl): Dbl = x.pow(y) +} diff --git a/src/main/scala/Chisel/JHFormat.scala b/src/main/scala/Chisel/JHFormat.scala new file mode 100644 index 00000000..e177835e --- /dev/null +++ b/src/main/scala/Chisel/JHFormat.scala @@ -0,0 +1,105 @@ +/* + Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of + California (Regents). All Rights Reserved. Redistribution and use in + source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of the Regents nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF + ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION + TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + MODIFICATIONS. +*/ + +package Chisel +import scala.collection.mutable.HashMap +import scala.collection.mutable.ArrayBuffer +import scala.io.Source +import java.io._ + +object JHFormat { + type Space = ArrayBuffer[(String,Param[Any],Int)] + def serialize[T<:Param[Any]](space: Space) : String = { + var string = new StringBuilder("") + for ((mname, p, gID) <- space) { + string ++= mname + "," + toStringParam(p) + "\n" + } + string.toString + } + + def deserialize(filename: String):Space = { + var lines = io.Source.fromFile(filename).getLines + var space = new Space + while(lines.hasNext) { + val line = lines.next() + val args = line.split(",") + val mname = args(0) + val ptype = args(1) + val gID = args(2).toInt + val pname = args(3) + val param = ptype match { + case "value" => { val p = new ValueParam(pname,args(4).toInt) + p.gID = gID; p } + case "range" => { val p = new RangeParam(pname,args(4).toInt,args(5).toInt,args(6).toInt) + p.gID = gID; p } + case "less" => { val p = new LessParam(pname,args(4).toInt,args(5).toInt,space.find(i => i._3 == args(6).toInt).get._2) + p.gID = gID; p } + case "lesseq" => { val p = new LessEqParam(pname,args(4).toInt,args(5).toInt,space.find(i => i._3 == args(6).toInt).get._2) + p.gID = gID; p } + case "great" => { val p = new GreaterParam(pname,args(4).toInt,space.find(i => i._3 == args(5).toInt).get._2,args(6).toInt) + p.gID = gID; p } + case "greateq" => { val p = new GreaterEqParam(pname,args(4).toInt,space.find(i => i._3 == args(5).toInt).get._2,args(6).toInt) + p.gID = gID; p } + case "divisor" => { val p = new DivisorParam(pname,args(4).toInt,args(5).toInt,args(6).toInt,space.find(i => i._3 == args(7).toInt).get._2) + p.gID = gID; p } + case "enum" => { val p = new EnumParam(pname,args(4),args.slice(5,args.length).toList) + p.gID = gID; p } + case _ => { throw new ParamInvalidException("Unknown parameter"); new ValueParam("error",0) } + } + space += ((mname,param,gID.toInt)) + } + space + } + + def toStringParam(param: Param[Any]):String = { + param match { + case ValueParam(pname, init) => + "value," + param.gID + "," + pname + "," + init + case RangeParam(pname, init, min, max) => + "range," + param.gID + "," + pname + "," + init + "," + min + "," + max + case LessParam(pname, init, min, par) => + "less," + param.gID + "," + pname + "," + init + "," + min + "," + par.gID + case LessEqParam(pname, init, min, par) => + "lesseq," + param.gID + "," + pname + "," + init + "," + min + "," + par.gID + case GreaterParam(pname, init, par, max) => + "great," + param.gID + "," + pname + "," + init + "," + par.gID + "," + max + case GreaterEqParam(pname, init, par, max) => + "greateq," + param.gID + "," + pname + "," + init + "," + par.gID + "," + max + case DivisorParam(pname, init, min, max, par) => + "divisor," + param.gID + "," + pname + "," + init + "," + min + "," + max + "," + par.gID + case EnumParam(pname, init, values) => + "enum," + param.gID + "," + pname + "," + init + "," + values.mkString(",") + case _ => + throw new ParamInvalidException("Unknown parameter class!"); "" + } + } + + val spaceName = "space.prm" +} diff --git a/src/main/scala/Chisel/Literal.scala b/src/main/scala/Chisel/Literal.scala new file mode 100644 index 00000000..fff2780b --- /dev/null +++ b/src/main/scala/Chisel/Literal.scala @@ -0,0 +1,199 @@ +package Chisel +import scala.math.log +import scala.math.abs +import scala.math.ceil +import scala.math.max +import scala.math.min +import Literal._ +import ChiselError._ + +/* Factory for literal values to be used by Bits and SInt factories. */ +object Lit { + def apply[T <: Bits](n: String)(gen: => T): T = { + makeLit(Literal(n, -1))(gen) + } + + def apply[T <: Bits](n: String, width: Int)(gen: => T): T = { + makeLit(Literal(n, width))(gen) + } + + def apply[T <: Bits](n: String, base: Char)(gen: => T): T = { + makeLit(Literal(-1, base, n))(gen) + } + + def apply[T <: Bits](n: String, base: Char, width: Int)(gen: => T): T = { + makeLit(Literal(width, base, n))(gen) + } + + def apply[T <: Bits](n: BigInt)(gen: => T): T = { + makeLit(Literal(n, signed = gen.isInstanceOf[SInt]))(gen) + } + + def apply[T <: Bits](n: BigInt, width: Int)(gen: => T): T = { + val lit = Literal(n, width, signed = gen.isInstanceOf[SInt]) + makeLit(lit)(gen) + } + + def makeLit[T <: Bits](x: Literal)(gen: => T): T = { + gen.makeLit(x.value, x.width) + } +} + +class Literal(val value: BigInt, val width: Int) { } + +object Literal { + + private def bigMax(x: BigInt, y: BigInt): BigInt = if (x > y) x else y; + def sizeof(x: BigInt): Int = { + val y = bigMax(BigInt(1), x.abs).toDouble; + val res = max(1, (ceil(log(y + 1)/log(2.0))).toInt); + res + } + + private def sizeof(base: Char, x: String): Int = { + var res = 0; + var first = true; + val size = + if(base == 'b') { + 1 + } else if(base == 'h') { + 4 + } else if(base == 'o') { + 3 + } else { + -1 + } + for(c <- x) + if (c == '_') { + + } else if(first) { + first = false; + res += sizeof(c.asDigit); + } else if (c != '_') { + res += size; + } + res + } + val hexNibbles = "0123456789abcdef"; + def toHexNibble(x: String, off: Int): Char = { + var res = 0; + for (i <- 0 until 4) { + val idx = off + i; + val c = if (idx < 0) '0' else x(idx); + res = 2 * res + (if (c == '1') 1 else 0); + } + hexNibbles(res) + } + val pads = Vector(0, 3, 2, 1); + def toHex(x: String): String = { + var res = ""; + val numNibbles = (x.length-1) / 4 + 1; + val pad = pads(x.length % 4); + for (i <- 0 until numNibbles) { + res += toHexNibble(x, i*4 - pad); + } + res + } + def toLitVal(x: String): BigInt = { + BigInt(x.substring(2, x.length), 16) + } + + def toLitVal(x: String, shamt: Int): BigInt = { + var res = BigInt(0); + for(c <- x) + if(c != '_'){ + if(!(hexNibbles + "?").contains(c.toLower)) ChiselError.error({"Literal: " + x + " contains illegal character: " + c}); + res = res * shamt + c.asDigit; + } + res + } + + def removeUnderscore(x: String): String = { + var res = "" + for(c <- x){ + if(c != '_'){ + res = res + c + } + } + res + } + + def parseLit(x: String): (String, String, Int) = { + var bits = ""; + var mask = ""; + var width = 0; + for (d <- x) { + if (d != '_') { + if(!"01?".contains(d)) ChiselError.error({"Literal: " + x + " contains illegal character: " + d}); + width += 1; + mask = mask + (if (d == '?') "0" else "1"); + bits = bits + (if (d == '?') "0" else d.toString); + } + } + (bits, mask, width) + } + def stringToVal(base: Char, x: String): BigInt = { + if(base == 'x') { + toLitVal(x, 16); + } else if(base == 'd') { + BigInt(x.toInt) + } else if(base == 'h') { + toLitVal(x, 16) + } else if(base == 'b') { + toLitVal(x, 2) + } else if(base == 'o') { + toLitVal(x, 8) + } else { + BigInt(-1) + } + } + + /** Derive the bit length for a Literal + * + */ + def bitLength(b: BigInt): Int = { + // Check for signedness + // We have seen unexpected values (one too small) when using .bitLength on negative BigInts, + // so use the positive value instead. + val usePositiveValueForBitLength = false + (if (usePositiveValueForBitLength && b < 0) { + -b + } else { + b + }).bitLength + } + /** Creates a *Literal* instance from a scala integer. + */ + def apply(x: BigInt, width: Int = -1, signed: Boolean = false): Literal = { + // Check for signedness + // We get unexpected values (one too small) when using .bitLength on negative BigInts, + // so use the positive value instead. + val bl = bitLength(x) + val xWidth = if (signed) { + bl + 1 + } else { + max(bl, 1) + } + val w = if(width == -1) xWidth else width + val xString = (if (x >= 0) x else (BigInt(1) << w) + x).toString(16) + + if(xWidth > width && width != -1) { + // Is this a zero-width wire with value 0 + if (!(x == 0 && width == 0 && Driver.isSupportW0W)) { + ChiselError.error({"width " + width + " is too small for literal " + x + ". Smallest allowed width is " + xWidth}); + } + } + apply("h" + xString, w) + } + def apply(n: String, width: Int): Literal = + apply(width, n(0), n.substring(1, n.length)); + + def apply(width: Int, base: Char, literal: String): Literal = { + if (!"dhbo".contains(base)) { + ChiselError.error("no base specified"); + } + new Literal(stringToVal(base, literal), width) + } +} + + diff --git a/src/main/scala/Chisel/Parameters.scala b/src/main/scala/Chisel/Parameters.scala new file mode 100644 index 00000000..9a117ee0 --- /dev/null +++ b/src/main/scala/Chisel/Parameters.scala @@ -0,0 +1,644 @@ +/* + Constructing Hardware in a Scala Embedded Language, Copyright (c) 2014, The + Regents of the University of California, through Lawrence Berkeley National + Laboratory (subject to receipt of any required approvals from the U.S. Dept. + of Energy). All rights reserved. + + If you have questions about your rights to use or distribute this software, + please contact Berkeley Lab's Technology Transfer Department at TTD@lbl.gov. + + NOTICE. This software is owned by the U.S. Department of Energy. As such, + the U.S. Government has been granted for itself and others acting on its + behalf a paid-up, nonexclusive, irrevocable, worldwide license in the Software + to reproduce, prepare derivative works, and perform publicly and display + publicly. Beginning five (5) years after the date permission to assert + copyright is obtained from the U.S. Department of Energy, and subject to any + subsequent five (5) year renewals, the U.S. Government is granted for itself + and others acting on its behalf a paid-up, nonexclusive, irrevocable, + worldwide license in the Software to reproduce, prepare derivative works, + distribute copies to the public, perform publicly and display publicly, and to + permit others to do so. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + (1) Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + (3) Neither the name of the University of California, Lawrence Berkeley + National Laboratory, U.S. Dept. of Energy nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You are under no obligation whatsoever to provide any bug fixes, patches, or + upgrades to the features, functionality or performance of the source code + ("Enhancements") to anyone; however, if you choose to make your Enhancements + available either publicly, or directly to Lawrence Berkeley National + Laboratory, without imposing a separate written license agreement for such + Enhancements, then you hereby grant the following license: a non-exclusive, + royalty-free perpetual license to install, use, modify, prepare derivative + works, incorporate into other computer software, distribute, and sublicense + such enhancements or derivative works thereof, in binary and source code form. + + Authors: J. Bachan, A. Izraelevitz, H. Cook +*/ + +package Chisel + +import scala.collection.immutable.{Seq=>Seq, Iterable=>Iterable} +import scala.{collection=>readonly} +import scala.collection.mutable + +// Convention: leading _'s on names means private to the outside world +// but accessible to anything in this file. + +abstract trait UsesParameters { + def params: Parameters +} + +class ParameterUndefinedException(field:Any, cause:Throwable=null) + extends RuntimeException("Parameter " + field + " undefined.", cause) +class KnobUndefinedException(field:Any, cause:Throwable=null) + extends RuntimeException("Knob " + field + " undefined.", cause) + +// Knobs are top level free variables that go into the constraint solver. +final case class Knob[T](name:Any) + + +class ChiselConfig( + val topDefinitions: World.TopDefs = { (a,b,c) => {throw new scala.MatchError(a)}}, + val topConstraints: List[ViewSym=>Ex[Boolean]] = List( ex => ExLit[Boolean](true) ), + val knobValues: Any=>Any = { case x => {throw new scala.MatchError(x)}} +) { + import Implicits._ + type Constraint = ViewSym=>Ex[Boolean] + + def this(that: ChiselConfig) = this(that.topDefinitions, + that.topConstraints, + that.knobValues) + + def ++(that: ChiselConfig) = { + new ChiselConfig(this.addDefinitions(that.topDefinitions), + this.addConstraints(that.topConstraints), + this.addKnobValues(that.knobValues)) + } + + def addDefinitions(that: World.TopDefs): World.TopDefs = { + (pname,site,here) => { + try this.topDefinitions(pname, site, here) + catch { + case e: scala.MatchError => that(pname, site, here) + } + } + } + + def addConstraints(that: List[Constraint]):List[Constraint] = { + this.topConstraints ++ that + } + + + def addKnobValues(that: Any=>Any): Any=>Any = { case x => + try this.knobValues(x) + catch { + case e: scala.MatchError => that(x) + } + } + +} + +object Dump { + val dump = mutable.Set[Tuple2[Any,Any]]() + val knobList = mutable.ListBuffer[Any]() + def apply[T](key:Any,value:T):T = {addToDump(key,value); value} + def apply[T](knob:Knob[T]):Knob[T] = {knobList += knob.name; knob} + def addToDump(key:Any,value:Any) = dump += ((key,value)) + def getDump:String = dump.map(_.toString).reduce(_+"\n"+_) + "\n" +} + +// objects given to the user in mask functions (site,here,up) +abstract class View { + // the list of classes in our current path down the heirarchy + def path: List[Class[_]] + + protected val deftSite: View // when views are queried without a specifying a site this is the default + + // use `this` view's behavior to query for a parameters value as if + // the original site were `site` + def apply[T](pname:Any, site:View):T + def sym[T](pname:Any, site:View):Ex[T] + + // query for a parameters value using the default site + final def apply[T](pname:Any):T = apply[T](pname, deftSite) + final def apply[T](field:Field[T]):T = apply[T](field.asInstanceOf[Any], deftSite) + + final def sym[T](pname:Any):Ex[T] = sym[T](pname, deftSite) + final def sym[T](field:Field[T]):Ex[T] = sym[T](field.asInstanceOf[Any], deftSite) +} + +/* Wrap a View to make the application return the symbolic expression, + * basically a shorthand to save typing '.sym' + * before: + * val v: View + * v.sym[Int]("x") // returns Ex[_] + * now: + * val vs = ViewSym(v) + * vs[Int]("xs") // Ex[_] +*/ +final case class ViewSym(view:View) { + def apply[T](f:Any):Ex[T] = view.sym[T](f) + def apply[T](f:Field[T]):Ex[T] = view.sym[T](f) + def apply[T](f:Any, site:View):Ex[T] = view.sym[T](f, site) + def apply[T](f:Field[T], site:View):Ex[T] = view.sym[T](f, site) +} + + +// internal type to represent functions that evaluate parameter values +abstract class _Lookup { + var path:List[Class[_]] = null + + def apply[T](pname:Any, site:View):Ex[T] + + // build a new Lookup that just defers to this one + final def push() = { + val me = this + new _Lookup { + this.path = me.path + def apply[T](pname:Any, site:View) = me.apply(pname, site) + } + } +} + +// Internal type used as name in all ExVar[T]'s +sealed abstract class _Var[T] + +// Variables which are 'free' parameters when seen from the top level. +final case class _VarKnob[T](kname:Any) extends _Var[T] { + override def toString = kname.toString +} +// Variables whose values are computed by `expr`. The term 'let' comes +// from the idea of 'let' bindings in functional languages i.e.: +final case class _VarLet[T](pname:Any,expr:Ex[T]) extends _Var[T] { + override def toString = pname.toString + "{" + expr.toString + "}" +} + + +object World { + // An alias for the type of function provided by user to describe parameters that + // reach the top level. The return of this function can be either: + // Knob(k): this parameter maps to the constraint variable `k` + // Ex: this parameter is computed using the expression + // Any(thing else): variable takes a literal value + type TopDefs = (/*pname:*/Any,/*site:*/View,/*here:*/View) => Any/*Knob[_] | Ex[_] | Any*/ +} + +// Worlds collect the variable definitions and constraints seen when building hardware. +abstract class World( + topDefs: World.TopDefs + ) { + + val _knobs = new mutable.HashSet[Any] + abstract class _View extends View { + val look: _Lookup + def path = look.path + + def apply[T](pname:Any, site:View):T = { + _eval(look(pname, site).asInstanceOf[Ex[T]]) + } + def sym[T](pname:Any, site:View):Ex[T] = { + _bindLet[T](pname,look(pname, site).asInstanceOf[Ex[T]]) + } + } + + // evaluate an expression against this world + def _eval[T](e:Ex[T]):T = { + Ex.eval(e, { + case v:_VarKnob[_] => { + _knobs += v.kname + val e = _knobValue(v.kname) + if(Dump.knobList.contains(v.kname)) {Dump.addToDump(v.kname,e);e} else e + } + case v:_VarLet[_] => _eval(v.expr.asInstanceOf[Ex[T]]) + }) + } + + // create a view whose default site is itself + def _siteView(look:_Lookup):View = { + val _look = look + new _View { + val look = _look + val deftSite = this + } + } + + // create a View which with a supplied default site + def _otherView(look:_Lookup, deftSite:View):View = { + val _look = look + val _deft = deftSite + new _View { + val look = _look + val deftSite = _deft + } + } + + // the top level lookup + def _topLook():_Lookup = { + class TopLookup extends _Lookup { + this.path = Nil + + def apply[T](pname:Any, site:View):Ex[T] = { + val here = _otherView(this, site) + ( + try topDefs(pname, site, here) + catch { + case e:scala.MatchError => throw new ParameterUndefinedException(pname, e) + } + ) match { + case k:Knob[T] => ExVar[T](_VarKnob[T](k.name)) + case ex:Ex[T] => _bindLet[T](pname,ex) + case lit => ExLit(lit.asInstanceOf[T]) + } + } + } + new TopLookup + } + + def _bindLet[T](pname:Any,expr:Ex[T]):Ex[T] + + def _constrain(e:Ex[Boolean]):Unit + + def _knobValue(kname:Any):Any + + def getConstraints:String = "" + + def getKnobs:String = "" +} + +// a world responsible for collecting all constraints in the first pass +class Collector( + topDefs: World.TopDefs, + knobVal: Any=>Any // maps knob names to default-values + ) + extends World(topDefs) { + + val _constraints = new mutable.HashSet[Ex[Boolean]] + + def knobs():List[Any] = { + _knobs.toList + } + + def constraints():List[Ex[Boolean]] = { + _constraints.toList + } + + def _bindLet[T](pname:Any,expr:Ex[T]):Ex[T] = { + expr match { + case e:ExVar[T] => expr + case e:ExLit[T] => expr + case _ => ExVar[T](_VarLet[T](pname,expr)) + } + } + + def _constrain(c:Ex[Boolean]) = { + _constraints += c // add the constraint + + // Also add all equality constraints for all bound variables in the + // constraint expression and do it recursively for all expressions + // being bound to. + var q = List[Ex[_]](c) + while(!q.isEmpty) { + val e = q.head // pop an expression + q = q.tail + // walk over the variables in `e` + for(e <- Ex.unfurl(e)) { + e match { + case ExVar(_VarLet(p,e1)) => { + // form the equality constraint + val c1 = ExEq[Any](e.asInstanceOf[Ex[Any]], e1.asInstanceOf[Ex[Any]]) + // recurse into the expression if its never been seen before + if(!_constraints.contains(c1)) { + _constraints += c1 + q ::= e1 // push + } + } + case _ => {} + } + } + } + } + + def _knobValue(kname:Any) = { + try knobVal(kname) + catch { + case e:scala.MatchError => throw new KnobUndefinedException(kname, e) + } + } + + override def getConstraints:String = if(constraints.isEmpty) "" else constraints.map("( " + _.toString + " )").reduce(_ +"\n" + _) + "\n" + + override def getKnobs:String = if(knobs.isEmpty) "" else { + knobs.map(_.toString).reduce(_ + "\n" + _) + "\n" + } +} + +// a world instantianted to a specific mapping of knobs to values +class Instance( + topDefs: World.TopDefs, + knobVal: Any=>Any + ) + extends World(topDefs) { + + def _bindLet[T](pname:Any,expr:Ex[T]):Ex[T] = expr + def _constrain(e:Ex[Boolean]) = {} + def _knobValue(kname:Any) = { + try knobVal(kname) + catch { + case e:scala.MatchError => throw new KnobUndefinedException(kname, e) + } + } +} + +object Parameters { + def root(w:World) = { + new Parameters(w, w._topLook()) + } + def empty = Parameters.root(new Collector((a,b,c) => {throw new ParameterUndefinedException(a); a},(a:Any) => {throw new KnobUndefinedException(a); a})) + + // Mask making helpers + + // Lift a regular function into a mask by looking for MatchError's and + // interpreting those as calls to up + def makeMask(mask:(Any,View,View,View)=>Any) = { + (f:Any, site:View, here:View, up:View) => { + try mask(f,site,here,up) + catch {case e:MatchError => up.sym[Any](f, site)} + } + } + + // Lift a Map to be a mask. + def makeMask(mask:Map[Any,Any]) = { + (f:Any, site:View, here:View, up:View) => { + mask.get(f) match { + case Some(y) => y + case None => up.sym[Any](f, site) + } + } + } + + // Lift a PartialFunction to be a mask. + def makeMask(mask:PartialFunction[Any,Any]) = { + (f:Any, site:View, here:View, up:View) => { + + if(mask.isDefinedAt(f)) + mask.apply(f) + else { + up.sym[Any](f, site) + } + } + } +} + +class Field[T] + +final class Parameters( + private val _world: World, + private val _look: _Lookup + ) { + + private def _site() = _world._siteView(_look) + + // Create a new Parameters that just defers to this one. This is identical + // to doing an `alter` but not overriding any values. + def push():Parameters = + new Parameters(_world, _look.push()) + + // parameter's paths should be immutable but I foresee that not being sufficient + // when integrated into the chisel Module factory. + def path = _look.path + def path_=(x:List[Class[_]]) = + _look.path = x + + def apply[T](field:Any):T = + _world._eval(_look(field, _site())).asInstanceOf[T] + + def apply[T](field:Field[T]):T = + _world._eval(_look(field, _site())).asInstanceOf[T] + + def constrain(gen:ViewSym=>Ex[Boolean]) = { + val g = gen(new ViewSym(_site())) + if(!_world._eval(g)) ChiselError.error("Constraint failed: " + g.toString) + _world._constrain(g) + } + + private def _alter(mask:(/*field*/Any,/*site*/View,/*here*/View,/*up*/View)=>Any) = { + class KidLookup extends _Lookup { + this.path = _look.path + + def apply[T](f:Any, site:View):Ex[T] = { + val here = _world._otherView(this, site) + val up = _world._otherView(_look, site) + + mask(f, site, here, up) match { + case e:Ex[T] => e + case lit => ExLit(lit.asInstanceOf[T]) + } + } + } + + new Parameters(_world, new KidLookup) + } + + def alter(mask:(/*field*/Any,/*site*/View,/*here*/View,/*up*/View)=>Any) = + _alter(Parameters.makeMask(mask)) + + def alter[T](mask:Map[T,Any]) = + _alter(Parameters.makeMask(mask.asInstanceOf[Map[Any,Any]])) + + def alterPartial(mask:PartialFunction[Any,Any]) = + _alter(Parameters.makeMask(mask)) +} + + +/* + Expression Library +*/ +abstract class Ex[T] { + override def toString = Ex.pretty(this) +} + +case class IntEx (expr:Ex[Int]) { + def === (x:IntEx):Ex[Boolean] = (ExEq[Int](expr,x.expr)) + def + (x:IntEx):Ex[Int] = ExAdd(expr,x.expr) + def - (x:IntEx):Ex[Int] = ExSub(expr,x.expr) + def * (x:IntEx):Ex[Int] = ExMul(expr,x.expr) + def % (x:IntEx):Ex[Int] = ExMod(expr,x.expr) + def < (x:IntEx):Ex[Boolean] = ExLt(expr,x.expr) + def > (x:IntEx):Ex[Boolean] = ExGt(expr,x.expr) + def <= (x:IntEx):Ex[Boolean] = ExLte(expr,x.expr) + def >= (x:IntEx):Ex[Boolean] = ExGte(expr,x.expr) + def in (x:List[IntEx]):Ex[Boolean] = { + val canBound = x.map(_.expr match { + case e:ExVar[_] => false + case _ => true + }).reduce(_ && _) + if (canBound) { + val max = x.map(i => Ex.eval(i.expr,(x:Any)=>null)).max + val min = x.map(i => Ex.eval(i.expr,(x:Any)=>null)).min + ExAnd(IntEx(expr) in Range(min,max), IntEx(expr) _in x) + } else { + IntEx(expr) _in x + } + } + def in (x:Range):Ex[Boolean] = ExAnd(ExGte(expr,ExLit[Int](x.min)),ExLte(expr,ExLit[Int](x.max))) + private def _in (x:List[IntEx]):Ex[Boolean] = { + if (x.isEmpty) ExLit[Boolean](false) else { + ExOr(IntEx(expr) === x.head,IntEx(expr) _in x.tail) + } + } +} + +case class BoolEx (expr:Ex[Boolean]) { + def && (x:BoolEx):Ex[Boolean] = ExAnd(expr,x.expr) + def || (x:BoolEx):Ex[Boolean] = ExOr(expr,x.expr) + def ^ (x:BoolEx):Ex[Boolean] = ExXor(expr,x.expr) + def === (x:BoolEx):Ex[Boolean] = ExEq[Boolean](expr,x.expr) + def !== (x:BoolEx):Ex[Boolean] = ExEq[Boolean](expr,x.expr) +} + +object Implicits { + implicit def ExInt_IntEx(i:Ex[Int]):IntEx = IntEx(i) + implicit def Int_IntEx(i:Int):IntEx = IntEx(ExLit[Int](i)) + implicit def ExBool_BoolEx(b:Ex[Boolean]):BoolEx = BoolEx(b) + implicit def Bool_IntEx(b:Boolean):BoolEx = BoolEx(ExLit[Boolean](b)) + + implicit def ListInt_ListExInt(l:List[Int]):List[IntEx] = l.map((x:Int) => IntEx(ExLit[Int](x))) + implicit def ListExInt_ListExInt(l:List[Ex[Int]]):List[IntEx] = l.map((x:Ex[Int]) => IntEx(x)) +} + +final case class ExLit[T](value:T) extends Ex[T] +final case class ExVar[T](name:Any) extends Ex[T] + +final case class ExAnd(a:Ex[Boolean], b:Ex[Boolean]) extends Ex[Boolean] +final case class ExOr(a:Ex[Boolean], b:Ex[Boolean]) extends Ex[Boolean] +final case class ExXor(a:Ex[Boolean], b:Ex[Boolean]) extends Ex[Boolean] + +final case class ExEq[T](a:Ex[T], b:Ex[T]) extends Ex[Boolean] +final case class ExNeq[T](a:Ex[T], b:Ex[T]) extends Ex[Boolean] + +final case class ExLt(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean] +final case class ExLte(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean] +final case class ExGt(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean] +final case class ExGte(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean] +final case class ExAdd(a:Ex[Int], b:Ex[Int]) extends Ex[Int] +final case class ExSub(a:Ex[Int], b:Ex[Int]) extends Ex[Int] +final case class ExMul(a:Ex[Int], b:Ex[Int]) extends Ex[Int] +final case class ExMod(a:Ex[Int], b:Ex[Int]) extends Ex[Int] + +object Ex { + // evaluate an expression given a context that maps variable names to values + def eval[T](e:Ex[T], ctx:Any=>Any):T = e match { + case ExLit(v) => v.asInstanceOf[T] + case ExVar(nm) => ctx(nm).asInstanceOf[T] + case ExAnd(a,b) => eval(a,ctx) && eval(b,ctx) + case ExOr(a,b) => eval(a,ctx) || eval(b,ctx) + case ExXor(a,b) => eval(a,ctx) ^ eval(b,ctx) + case e:ExEq[u] => eval(e.a,ctx) == eval(e.b,ctx) + case e:ExNeq[u] => eval(e.a,ctx) != eval(e.b,ctx) + case ExLt(a,b) => eval(a,ctx) < eval(b,ctx) + case ExLte(a,b) => eval(a,ctx) <= eval(b,ctx) + case ExGt(a,b) => eval(a,ctx) > eval(b,ctx) + case ExGte(a,b) => eval(a,ctx) >= eval(b,ctx) + case ExAdd(a,b) => eval(a,ctx) + eval(b,ctx) + case ExSub(a,b) => eval(a,ctx) - eval(b,ctx) + case ExMul(a,b) => eval(a,ctx) * eval(b,ctx) + case ExMod(a,b) => eval(a,ctx) % eval(b,ctx) + } + + // get shallow list of subexpressions + def subExs(e:Ex[_]):List[Ex[_]] = e match { + case ExLit(_) => Nil + case ExVar(_) => Nil + case ExAnd(a,b) => List(a,b) + case ExOr(a,b) => List(a,b) + case ExXor(a,b) => List(a,b) + case ExEq(a,b) => List(a,b) + case ExNeq(a,b) => List(a,b) + case ExLt(a,b) => List(a,b) + case ExLte(a,b) => List(a,b) + case ExGt(a,b) => List(a,b) + case ExGte(a,b) => List(a,b) + case ExAdd(a,b) => List(a,b) + case ExSub(a,b) => List(a,b) + case ExMul(a,b) => List(a,b) + case ExMod(a,b) => List(a,b) + } + + // get all subexpressions including the expression given + def unfurl(e:Ex[_]):List[Ex[_]] = + e :: (subExs(e) flatMap unfurl) + + // pretty-print expression + def pretty(e:Ex[_]):String = { + // precedence rank for deciding where to put parentheses + def rank(e:Ex[_]):Int = e match { + case e:ExAnd => 40 + case e:ExOr => 50 + case e:ExXor => 50 + case e:ExEq[_] => 30 + case e:ExNeq[_] => 30 + case e:ExLt => 30 + case e:ExLte => 30 + case e:ExGt => 30 + case e:ExGte => 30 + case e:ExAdd => 20 + case e:ExSub => 20 + case e:ExMul => 20 + case e:ExMod => 20 + case e:ExLit[_] => 0 + case e:ExVar[_] => 0 + } + + val r = rank(e) + + def term(t:Ex[_]):String = { + val rt = rank(t) + //if(rt >= r) + "( " + t.toString + " )" + //else + //t.toString + } + + import Implicits._ + e match { + case ExLit(v) => v.toString + case e:ExVar[_]=> "$"+e.name + case ExAnd(a,b) => term(a)+" && "+term(b) + case ExOr(a,b) => term(a)+" || "+term(b) + case ExXor(a,b) => term(a)+" ^ "+term(b) + case ExEq(a,b) => term(a)+" = "+term(b) + case ExNeq(a,b) => term(a)+" != "+term(b) + case ExLt(a,b) => term(a)+" < "+term(b) + case ExLte(a,b) => term(a)+" <= "+term(b) + case ExGt(a,b) => term(a)+" > "+term(b) + case ExGte(a,b) => term(a)+" >= "+term(b) + case ExAdd(a,b) => term(a)+" + "+term(b) + case ExSub(a,b) => term(a)+" - "+term(b) + case ExMul(a,b) => term(a)+" * "+term(b) + case ExMod(a,b) => term(a)+" % "+term(b) + } + } +} diff --git a/src/main/scala/Chisel/Params.scala b/src/main/scala/Chisel/Params.scala new file mode 100644 index 00000000..9f98c336 --- /dev/null +++ b/src/main/scala/Chisel/Params.scala @@ -0,0 +1,195 @@ +/* + Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of + California (Regents). All Rights Reserved. Redistribution and use in + source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of the Regents nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF + ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION + TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + MODIFICATIONS. +*/ + +/* Unfinished. Has 3 basic parameters available */ +package Chisel + +import Builder._ +// import Node._ +import Module._ +import JHFormat._ + +import scala.collection.mutable.HashMap +import scala.collection.mutable.ArrayBuffer + +import java.lang.reflect.{Type, ParameterizedType} + +import scala.io.Source +import java.io._ + +//>Params.scala: Implementation of parameter framework. Defines case class + //containers for parameter types. Params object is what actually stores + //the data structures of parameters, whether they are generated from a Chisel + //design, or read from a json file + +case class ParamInvalidException(msg: String) extends Exception + +abstract class Param[+T] { + def init: T + def max: Int + def min: Int + def pname: String + var index: Int = -2 + var gID: Int = -1 + var register = Params.register(getComponent(), pname, this) + //def register(pName: String) = { pname = pName; Params.register(jack.getComponent(), pname, this)} + def getValue: T = Params.getValue(getComponent(),this.pname,this).asInstanceOf[T] +} + +case class ValueParam(pname:String, init: Any) extends Param[Any] { + val max = init.toString.toInt + val min = init.toString.toInt +} + +case class RangeParam(pname:String, init: Int, min: Int, max: Int) extends Param[Int] + +case class LessParam(pname:String, init: Int, min: Int, par: Param[Any]) extends Param[Int] { + val max = par.max +} + +case class LessEqParam(pname:String, init: Int, min: Int, par: Param[Any]) extends Param[Int] { + val max = par.max +} + +case class GreaterParam(pname:String, init: Int, par: Param[Any], max: Int) extends Param[Int] { + val min = par.min +} + +case class GreaterEqParam(pname:String, init: Int, par: Param[Any], max: Int) extends Param[Int] { + val min = par.min +} + +case class DivisorParam(pname:String, init: Int, min: Int, max: Int, par: Param[Any]) extends Param[Int] + +case class EnumParam(pname:String, init: String, values: List[String]) extends Param[String] { + val max = init.toString.toInt + val min = init.toString.toInt +} + +object IntParam { + def apply(name: String, init: Int) = RangeParam(name, init, init, init) +} + +object Params { + type Space = JHFormat.Space + var space = new Space + var design = new Space + var modules = new HashMap[String, Module] + var gID: Int = 0 + + var buildingSpace = true + + def getValue(module: Module, pname: String, p: Param[Any]) = { + val mname= if(module == null) "TOP" else {module.getClass.getName} + if(buildingSpace) p.init + else{ + val x = design.find(t => (t._3) == (p.gID)) + if(x.isEmpty){ + throw new ParamInvalidException("Missing parameter " + pname + " in Module " + mname) + } else { + x.get._2.init + } + } + } + + def register(module: Module, pname: String, p: Param[Any]) = { + val mname= if(module == null) "TOP" else {module.getClass.getName} + modules(mname) = module + if(buildingSpace) { + space += ((mname,p,gID)) + } + p.gID = gID + gID += 1 + p + } + + def dump_file(filename: String, design: Space) = { + val string = JHFormat.serialize(design) + val writer = new PrintWriter(new File(filename)) + println("Dumping to " + filename + ":\n" + string) + writer.write(string) + writer.close() + } + + def dump(dir: String) = { + buildingSpace = false + dump_file(dir + "/" + JHFormat.spaceName, Params.space) + } + def load(designName: String) = { + buildingSpace = false + design = JHFormat.deserialize(designName) + gID = 0 + } + + def toCxxStringParams : String = { + var string = new StringBuilder("") + for ((mname, p, gID) <- space) { + val rmname = if (mname == "TOP") "" else modules(mname).name + "__"; + string ++= "const int " + rmname + p.pname + " = " + toCxxStringParam(p) + ";\n" + } + string.toString + } + + def toDotpStringParams : String = { + var string = new StringBuilder("") + for ((mname, p, gID) <- space) { + val rmname = if (mname == "TOP") "" else modules(mname).name + ":"; + string ++= rmname + p.pname + " = " + toCxxStringParam(p) + "\n" + } + string.toString + } + + + def toCxxStringParam(param: Param[Any]) = { + param match { + // case EnumParam(init, list) => + //"(range," + init + "," + list + ")" + // "const int " + name + " = " + init + ";\n" + case ValueParam(pname, init) => + init.toString + case RangeParam(pname, init, min, max) => + init.toString + case LessParam(pname, init, min, par) => + init.toString + case LessEqParam(pname, init, min, par) => + init.toString + case GreaterParam(pname, init, min, par) => + init.toString + case GreaterEqParam(pname, init, min, par) => + init.toString + case DivisorParam(pname, init, min, max, par) => + init.toString + case EnumParam(pname, init, values) => + init.toString + case _ => + throw new ParamInvalidException("Unknown parameter class!"); "" + } + } +} diff --git a/src/main/scala/Chisel/Tester.scala b/src/main/scala/Chisel/Tester.scala new file mode 100644 index 00000000..bdeb0f68 --- /dev/null +++ b/src/main/scala/Chisel/Tester.scala @@ -0,0 +1,417 @@ +/* + Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of + California (Regents). All Rights Reserved. Redistribution and use in + source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + two paragraphs of disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of the Regents nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF + ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION + TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + MODIFICATIONS. +*/ + +package Chisel +import Chisel._ +import scala.math._ +import scala.collection.mutable.ArrayBuffer +import scala.collection.mutable.HashMap +import scala.util.Random +import java.io.{File, IOException, InputStream, OutputStream, PrintStream} +import java.lang.Double.longBitsToDouble +import java.lang.Float.intBitsToFloat +import java.lang.Double.doubleToLongBits +import java.lang.Float.floatToIntBits +import scala.sys.process._ +import scala.io.Source._ +import Literal._ + +case class Poke(val node: Data, val index: Int, val value: BigInt); + +class Snapshot(val t: Int) { + val pokes = new ArrayBuffer[Poke]() +} + +class ManualTester[+T <: Module] + (val c: T, val isT: Boolean = true) { + var testIn: InputStream = null + var testOut: OutputStream = null + var testErr: InputStream = null + val sb = new StringBuilder() + var delta = 0 + var t = 0 + var isTrace = isT + + /** + * Waits until the emulator streams are ready. This is a dirty hack related + * to the way Process works. TODO: FIXME. + */ + def waitForStreams() = { + var waited = 0 + while (testOut == null || testIn == null || testErr == null) { + Thread.sleep(100) + if (waited % 10 == 0 && waited > 30) { + println("waiting for emulator process treams to be valid ...") + } + } + } + + // TODO: MOVE TO SOMEWHERE COMMON TO BACKEND + def ensureDir(dir: String): String = { + val d = dir + (if (dir == "" || dir(dir.length-1) == '/') "" else "/") + new File(d).mkdirs() + d + } + def createOutputFile(name: String): java.io.FileWriter = { + val baseDir = ensureDir(Driver.targetDir) + new java.io.FileWriter(baseDir + name) + } + + def puts(str: String) = { + while (testOut == null) { Thread.sleep(100) } + for (e <- str) testOut.write(e); + } + + /** + * Sends a command to the emulator and returns the reply. + * The standard protocol treats a single line as a command, which always + * returns a single line of reply. + */ + def emulatorCmd(str: String): String = { + // validate cmd + if (str contains "\n") { + System.err.print(s"emulatorCmd($str): command should not contain newline") + return "error" + } + + waitForStreams() + + // send command to emulator + for (e <- str) testOut.write(e); + testOut.write('\n'); + testOut.flush() + + // read output from emulator + var c = testIn.read + sb.clear() + while (c != '\n' && c != -1) { + if (c == 0) { + Thread.sleep(100) + } + sb += c.toChar + // Look for a "PRINT" command. + if (sb.length == 6 && sb.startsWith("PRINT ")) { + do { + c = testIn.read + sb += c.toChar + } while (c != ' ') + // Get the PRINT character count. + val printCommand = """^PRINT (\d+) """.r + val printCommand(nChars) = sb.toString + sb.clear() + for (i <- 0 until nChars.toInt) { + c = testIn.read + sb += c.toChar + } + System.out.print(sb.toString()) + sb.clear() + } + c = testIn.read + } + + // drain errors + try { + while(testErr.available() > 0) { + System.err.print(Character.toChars(testErr.read())) + } + } catch { + case e : IOException => testErr = null; println("ERR EXCEPTION") + } + + if (sb == "error") { + System.err.print(s"FAILED: emulatorCmd($str): returned error") + ok = false + } + return sb.toString + } + + /* + def setClocks(clocks: HashMap[Clock, Int]) { + var cmd = "set_clocks" + for (clock <- Driver.clocks) { + if (clock.srcClock == null) { + val s = BigInt(clocks(clock)).toString(16) + cmd = cmd + " " + s + } + } + emulatorCmd(cmd) + // TODO: check for errors in return + } + */ + + def doPeekBits(name: String, off: Int = -1): BigInt = { + if (name == "") { + println("Unable to peek data " + name) // TODO: USE DATA + -1 + } else { + var cmd = "" + if (off != -1) { + cmd = "mem_peek " + name + " " + off; + } else { + cmd = "wire_peek " + name; + } + val s = emulatorCmd(cmd) + val rv = toLitVal(s) + if (isTrace) println(" PEEK " + name + " " + (if (off >= 0) (off + " ") else "") + "-> " + s) + rv + } + } + + def peekBits(data: Data, off: Int = -1): BigInt = { + doPeekBits(data.debugName, off) + } + + def signed_fix(dtype: Element, rv: BigInt): BigInt = { + val w = dtype.width + dtype match { + /* Any "signed" node */ + case _: SInt | _ : Flo | _: Dbl => (if(rv >= (BigInt(1) << w - 1)) (rv - (BigInt(1) << w)) else rv) + /* anything else (i.e., UInt) */ + case _ => (rv) + } + } + + def peekAt[T <: Bits](data: Mem[T], off: Int): BigInt = { + // signed_fix(data(1), peekBits(data, off)) + doPeekBits(data.debugName, off) + } + + def peek(data: Bits): BigInt = { + signed_fix(data, peekBits(data)) + } + + def peek(data: Flo): Float = { + intBitsToFloat(peekBits(data).toInt) + } + + def peek(data: Dbl): Double = { + longBitsToDouble(peekBits(data).toLong) + } + + def peek(data: Aggregate /*, off: Int = -1 */): IndexedSeq[BigInt] = { + data.flatten.map(peek(_)) + } + + def reset(n: Int = 1) = { + emulatorCmd("reset " + n) + // TODO: check for errors in return + if (isTrace) println("RESET " + n) + } + + def doPokeBits(name: String, x: BigInt, off: Int): Unit = { + if (name == "") { + println("Unable to poke data " + name) // TODO: data.toString + } else { + + var cmd = "" + if (off != -1) { + cmd = "mem_poke " + name + " " + off; + } else { + cmd = "wire_poke " + name; + } + // Don't prefix negative numbers with "0x" + val radixPrefix = if (x < 0) " -0x" else " 0x" + val xval = radixPrefix + x.abs.toString(16) + cmd = cmd + xval + if (isTrace) { + println(" POKE " + name + " " + (if (off >= 0) (off + " ") else "") + "<- " + xval) + } + val rtn = emulatorCmd(cmd) + if (rtn != "ok") { + System.err.print(s"FAILED: poke(${name}) returned false") + ok = false + } + } + } + + def pokeAt[T <: Bits](data: Mem[T], x: BigInt, off: Int): Unit = { + doPokeBits(data.debugName, x, off) + } + + def pokeBits(data: Data, x: BigInt, off: Int = -1): Unit = { + doPokeBits(data.debugName, x, off) + } + + def poke(data: Bits, x: BigInt): Unit = { + pokeBits(data, x) + } + + def poke(data: Flo, x: Float): Unit = { + pokeBits(data, BigInt(floatToIntBits(x))) + } + + def poke(data: Dbl, x: Double): Unit = { + pokeBits(data, BigInt(doubleToLongBits(x))) + } + + def poke(data: Aggregate, x: Array[BigInt]): Unit = { + val kv = (data.flatten, x.reverse).zipped; + for ((x, y) <- kv) + poke(x, y) + } + + def step(n: Int) = { + val target = t + n + val s = emulatorCmd("step " + n) + delta += s.toInt + if (isTrace) println("STEP " + n + " -> " + target) + t += n + } + + def int(x: Boolean): BigInt = if (x) 1 else 0 + def int(x: Int): BigInt = x + def int(x: Bits): BigInt = x.litValue() + + var ok = true; + var failureTime = -1 + + def expect (good: Boolean, msg: String): Boolean = { + if (isTrace) + println(msg + " " + (if (good) "PASS" else "FAIL")) + if (!good) { ok = false; if (failureTime == -1) failureTime = t; } + good + } + + def expect (data: Bits, expected: BigInt): Boolean = { + // val mask = (BigInt(1) << data) - 1 + val got = peek(data) + + // expect((got & mask) == (expected & mask), + expect(got == expected, + "EXPECT " + data.debugName + " <- 0x" + got.toString(16) + " == 0x" + expected.toString(16)) + } + + def expect (data: Aggregate, expected: Array[BigInt]): Boolean = { + val kv = (data.flatten, expected.reverse).zipped; + var allGood = true + for ((d, e) <- kv) + allGood = expect(d, e) && allGood + allGood + } + + /* We need the following so scala doesn't use our "tolerant" Float version of expect. + */ + def expect (data: Bits, expected: Int): Boolean = { + expect(data, BigInt(expected)) + } + def expect (data: Bits, expected: Long): Boolean = { + expect(data, BigInt(expected)) + } + def expect (data: Flo, expected: Double): Boolean = { + val got = peek(data) + expect(got == expected, "EXPECT " + data.debugName + " <- " + got + " == " + expected) + } + def expect (data: Dbl, expected: Double): Boolean = { + val got = peek(data) + expect(got == expected, "EXPECT " + data.debugName + " <- " + got + " == " + expected) + } + + /* Compare the floating point value of a node with an expected floating point value. + * We will tolerate differences in the bottom bit. + */ + def expect (data: Bits, expected: Float): Boolean = { + val gotBits = peek(data).toInt + val expectedBits = java.lang.Float.floatToIntBits(expected) + var gotFLoat = java.lang.Float.intBitsToFloat(gotBits) + var expectedFloat = expected + if (gotFLoat != expectedFloat) { + val gotDiff = gotBits - expectedBits + // Do we have a single bit difference? + if (abs(gotDiff) <= 1) { + expectedFloat = gotFLoat + } + } + expect(gotFLoat == expectedFloat, + "EXPECT " + data.debugName + " <- " + gotFLoat + " == " + expectedFloat) + } + + val rnd = if (Driver.testerSeedValid) new Random(Driver.testerSeed) else new Random() + var process: Process = null + + def start(): Process = { + val n = Driver.appendString(Some(c.name),Driver.chiselConfigClassName) + val target = Driver.targetDir + "/" + n + val cmd = target + println("OPENING " + cmd) + /* + (if (Driver.backend.isInstanceOf[FloBackend]) { + val dir = Driver.backend.asInstanceOf[FloBackend].floDir + val command = ArrayBuffer(dir + "fix-console", ":is-debug", "true", ":filename", target + ".hex", ":flo-filename", target + ".mwe.flo") + if (Driver.isVCD) { command ++= ArrayBuffer(":is-vcd-dump", "true") } + if (Driver.emitTempNodes) { command ++= ArrayBuffer(":emit-temp-nodes", "true") } + command ++= ArrayBuffer(":target-dir", Driver.targetDir) + command.mkString(" ") + } else { + target + (if (Driver.backend.isInstanceOf[VerilogBackend]) " -q +vcs+initreg+0 " else "") + }) + */ + println("SEED " + Driver.testerSeed) + println("STARTING " + cmd) + val processBuilder = Process(cmd) + val pio = new ProcessIO(in => testOut = in, out => testIn = out, err => testErr = err) + process = processBuilder.run(pio) + waitForStreams() + t = 0 + reset(5) + // Skip vpd message + if (Driver.backend.isInstanceOf[VerilogBackend] && Driver.isDebug) { + var vpdmsg = testIn.read + while (vpdmsg != '\n' && vpdmsg != -1) + vpdmsg = testIn.read + } + process + } + + def finish(): Boolean = { + if (process != null) { + emulatorCmd("quit") + + if (testOut != null) { + testOut.flush() + testOut.close() + } + if (testIn != null) { + testIn.close() + } + if (testErr != null) { + testErr.close() + } + + process.destroy() + } + println("RAN " + t + " CYCLES " + (if (ok) "PASSED" else { "FAILED FIRST AT CYCLE " + failureTime })) + ok + } +} + +class Tester[+T <: Module](c: T, isTrace: Boolean = true) extends ManualTester(c, isTrace) { + start() +} + diff --git a/src/main/scala/Chisel/utils.scala b/src/main/scala/Chisel/utils.scala new file mode 100644 index 00000000..3bbea34a --- /dev/null +++ b/src/main/scala/Chisel/utils.scala @@ -0,0 +1,561 @@ +package Chisel +import Builder._ +import scala.math._ + +object log2Up +{ + def apply(in: Int): Int = if(in == 1) 1 else ceil(log(in)/log(2)).toInt +} + +object log2Ceil +{ + def apply(in: Int): Int = ceil(log(in)/log(2)).toInt +} + + +object log2Down +{ + def apply(x : Int): Int = if (x == 1) 1 else floor(log(x)/log(2.0)).toInt +} + +object log2Floor +{ + def apply(x : Int): Int = floor(log(x)/log(2.0)).toInt +} + + +object isPow2 +{ + def apply(in: Int): Boolean = in > 0 && ((in & (in-1)) == 0) +} + +object FillInterleaved +{ + def apply(n: Int, in: UInt): UInt = apply(n, in.toBools) + def apply(n: Int, in: Seq[Bool]): UInt = Vec(in.map(Fill(n, _))).toBits +} + +/** Returns the number of bits set (i.e value is 1) in the input signal. + */ +object PopCount +{ + def apply(in: Iterable[Bool]): UInt = { + if (in.size == 0) { + UInt(0) + } else if (in.size == 1) { + in.head + } else { + apply(in.slice(0, in.size/2)) + Cat(UInt(0), apply(in.slice(in.size/2, in.size))) + } + } + def apply(in: Bits): UInt = apply((0 until in.getWidth).map(in(_))) +} + +object RegNext { + + def apply[T <: Data](next: T): T = Reg[T](next, next, null.asInstanceOf[T]) + + def apply[T <: Data](next: T, init: T): T = Reg[T](next, next, init) + +} + +object RegInit { + + def apply[T <: Data](init: T): T = Reg[T](init, null.asInstanceOf[T], init) + +} + +object RegEnable +{ + def apply[T <: Data](updateData: T, enable: Bool) = { + val r = Reg(updateData) + when (enable) { r := updateData } + r + } + def apply[T <: Data](updateData: T, resetData: T, enable: Bool) = { + val r = RegInit(resetData) + when (enable) { r := updateData } + r + } +} + +/** Builds a Mux tree out of the input signal vector using a one hot encoded + select signal. Returns the output of the Mux tree. + */ +object Mux1H +{ + def apply[T <: Data](sel: Iterable[Bool], in: Iterable[T]): T = { + if (in.tail.isEmpty) in.head + else { + val masked = (sel, in).zipped map ((s, i) => Mux(s, i.toBits, Bits(0))) + in.head.fromBits(masked.reduceLeft(_|_)) + } + } + def apply[T <: Data](in: Iterable[(Bool, T)]): T = { + val (sel, data) = in.unzip + apply(sel, data) + } + def apply[T <: Data](sel: Bits, in: Iterable[T]): T = + apply((0 until in.size).map(sel(_)), in) + def apply(sel: Bits, in: Bits): Bool = (sel & in).orR +} + +/** Builds a Mux tree under the assumption that multiple select signals + can be enabled. Priority is given to the first select signal. + + Returns the output of the Mux tree. + */ +object PriorityMux +{ + def apply[T <: Bits](in: Iterable[(Bool, T)]): T = { + if (in.size == 1) { + in.head._2 + } else { + Mux(in.head._1, in.head._2, apply(in.tail)) + } + } + def apply[T <: Bits](sel: Iterable[Bool], in: Iterable[T]): T = apply(sel zip in) + def apply[T <: Bits](sel: Bits, in: Iterable[T]): T = apply((0 until in.size).map(sel(_)), in) +} + +object unless { + def apply(c: Bool)(block: => Unit) { + when (!c) { block } + } +} + +object switch { + def apply(c: Bits)(block: => Unit) { + switchKeys.push(c) + block + switchKeys.pop() + } +} + +object is { + def apply(v: Bits)(block: => Unit): Unit = + apply(Seq(v))(block) + def apply(v: Bits, vr: Bits*)(block: => Unit): Unit = + apply(v :: vr.toList)(block) + def apply(v: Iterable[Bits])(block: => Unit): Unit = { + val keys = switchKeys + if (keys.isEmpty) ChiselError.error("The 'is' keyword may not be used outside of a switch.") + else if (!v.isEmpty) when (v.map(_ === keys.top).reduce(_||_)) { block } + } +} + +object MuxLookup { + def apply[S <: UInt, T <: Bits] (key: S, default: T, mapping: Seq[(S, T)]): T = { + var res = default; + for ((k, v) <- mapping.reverse) + res = Mux(k === key, v, res); + res + } + +} + +object Fill { + def apply(n: Int, x: Bool): UInt = n match { + case 0 => UInt(width=0) + case 1 => x + case x if n > 1 => UInt(0,n) - UInt(x) + case _ => throw new IllegalArgumentException(s"n (=$n) must be nonnegative integer.") + } + def apply(n: Int, y: UInt): UInt = { + n match { + case 0 => UInt(width=0) + case 1 => y + case x if n > 1 => + val p2 = Array.ofDim[UInt](log2Up(n+1)) + p2(0) = y + for (i <- 1 until p2.length) + p2(i) = Cat(p2(i-1), p2(i-1)) + Cat((0 until log2Up(x+1)).filter(i => (x & (1 << i)) != 0).map(p2(_))) + case _ => throw new IllegalArgumentException(s"n (=$n) must be nonnegative integer.") + } + } +} + +object MuxCase { + def apply[T <: Bits] (default: T, mapping: Seq[(Bool, T)]): T = { + var res = default; + for ((t, v) <- mapping.reverse){ + res = Mux(t, v, res); + } + res + } +} + +object ListLookup { + def apply[T <: Data](addr: UInt, default: List[T], mapping: Array[(BitPat, List[T])]): List[T] = { + val map = mapping.map(m => (m._1 === addr, m._2)) + default.zipWithIndex map { case (d, i) => + map.foldRight(d)((m, n) => Mux(m._1, m._2(i), n)) + } + } +} + +object Lookup { + def apply[T <: Bits](addr: UInt, default: T, mapping: Seq[(BitPat, T)]): T = + ListLookup(addr, List(default), mapping.map(m => (m._1, List(m._2))).toArray).head +} + +/** Litte/big bit endian convertion: reverse the order of the bits in a UInt. +*/ +object Reverse +{ + private def doit(in: UInt, length: Int): UInt = { + if (length == 1) { + in + } else if (isPow2(length) && length >= 8 && length <= 64) { + // Do it in logarithmic time to speed up C++. Neutral for real HW. + var res = in + var shift = length >> 1 + var mask = UInt((BigInt(1) << length) - 1, length) + do { + mask = mask ^ (mask(length-shift-1,0) << UInt(shift)) + res = ((res >> UInt(shift)) & mask) | (res(length-shift-1,0) << UInt(shift) & ~mask) + shift = shift >> 1 + } while (shift > 0) + res + } else { + val half = (1 << log2Up(length))/2 + Cat(doit(in(half-1,0), half), doit(in(length-1,half), length-half)) + } + } + def apply(in: UInt): UInt = doit(in, in.getWidth) +} + +/** Returns the n-cycle delayed version of the input signal. + */ +object ShiftRegister +{ + def apply[T <: Data](in: T, n: Int, en: Bool = Bool(true)): T = + { + // The order of tests reflects the expected use cases. + if (n == 1) { + RegEnable(in, en) + } else if (n != 0) { + RegNext(apply(in, n-1, en)) + } else { + in + } + } +} + +/** Returns the one hot encoding of the input UInt. + */ +object UIntToOH +{ + def apply(in: UInt, width: Int = -1): UInt = + if (width == -1) UInt(1) << in + else (UInt(1) << in(log2Up(width)-1,0))(width-1,0) +} + +class Counter(val n: Int) { + val value = if (n == 1) UInt(0) else Reg(init=UInt(0, log2Up(n))) + def inc(): Bool = { + if (n == 1) Bool(true) + else { + val wrap = value === UInt(n-1) + value := Mux(Bool(!isPow2(n)) && wrap, UInt(0), value + UInt(1)) + wrap + } + } +} + +object Counter +{ + def apply(n: Int): Counter = new Counter(n) + def apply(cond: Bool, n: Int): (UInt, Bool) = { + val c = new Counter(n) + var wrap: Bool = null + when (cond) { wrap = c.inc() } + (c.value, cond && wrap) + } +} + +class ValidIO[+T <: Data](gen2: T) extends Bundle +{ + val valid = Bool(OUTPUT) + val bits = gen2.cloneType.asOutput + def fire(dummy: Int = 0): Bool = valid + override def doCloneType: this.type = new ValidIO(gen2).asInstanceOf[this.type] +} + +/** Adds a valid protocol to any interface. The standard used is + that the consumer uses the flipped interface. +*/ +object Valid { + def apply[T <: Data](gen: T): ValidIO[T] = new ValidIO(gen) +} + +class DecoupledIO[+T <: Data](gen: T) extends Bundle +{ + val ready = Bool(INPUT) + val valid = Bool(OUTPUT) + val bits = gen.cloneType.asOutput + def fire(dummy: Int = 0): Bool = ready && valid + override def doCloneType: this.type = new DecoupledIO(gen).asInstanceOf[this.type] +} + +/** Adds a ready-valid handshaking protocol to any interface. + The standard used is that the consumer uses the flipped + interface. + */ +object Decoupled { + def apply[T <: Data](gen: T): DecoupledIO[T] = new DecoupledIO(gen) +} + +class EnqIO[T <: Data](gen: T) extends DecoupledIO(gen) +{ + def enq(dat: T): T = { valid := Bool(true); bits := dat; dat } + override def init(dummy: Int = 0) = { + valid := Bool(false); + for (io <- bits.flatten) + io := UInt(0) + } + override def doCloneType: this.type = { new EnqIO(gen).asInstanceOf[this.type]; } +} + +class DeqIO[T <: Data](gen: T) extends DecoupledIO(gen) +{ + flip() + override def init(dummy: Int = 0) = { + ready := Bool(false) + } + def deq(b: Boolean = false): T = { ready := Bool(true); bits } + override def doCloneType: this.type = { new DeqIO(gen).asInstanceOf[this.type]; } +} + + +class DecoupledIOC[+T <: Data](gen: T) extends Bundle +{ + val ready = Bool(INPUT) + val valid = Bool(OUTPUT) + val bits = gen.cloneType.asOutput +} + +class QueueIO[T <: Data](gen: T, entries: Int) extends Bundle +{ + val enq = Decoupled(gen.cloneType).flip + val deq = Decoupled(gen.cloneType) + val count = UInt(OUTPUT, log2Up(entries + 1)) +} + +class Queue[T <: Data](gen: T, val entries: Int, pipe: Boolean = false, flow: Boolean = false, _reset: Bool = null) extends Module(_reset=_reset) +{ + val io = new QueueIO(gen, entries) + + val ram = Mem(gen, entries) + val enq_ptr = Counter(entries) + val deq_ptr = Counter(entries) + val maybe_full = Reg(init=Bool(false)) + + val ptr_match = enq_ptr.value === deq_ptr.value + val empty = ptr_match && !maybe_full + val full = ptr_match && maybe_full + val maybe_flow = Bool(flow) && empty + val do_flow = maybe_flow && io.deq.ready + + val do_enq = io.enq.ready && io.enq.valid && !do_flow + val do_deq = io.deq.ready && io.deq.valid && !do_flow + when (do_enq) { + ram(enq_ptr.value) := io.enq.bits + enq_ptr.inc() + } + when (do_deq) { + deq_ptr.inc() + } + when (do_enq != do_deq) { + maybe_full := do_enq + } + + io.deq.valid := !empty || Bool(flow) && io.enq.valid + io.enq.ready := !full || Bool(pipe) && io.deq.ready + io.deq.bits := Mux(maybe_flow, io.enq.bits, ram(deq_ptr.value)) + + val ptr_diff = enq_ptr.value - deq_ptr.value + if (isPow2(entries)) { + io.count := Cat(maybe_full && ptr_match, ptr_diff) + } else { + io.count := Mux(ptr_match, Mux(maybe_full, UInt(entries), UInt(0)), Mux(deq_ptr.value > enq_ptr.value, UInt(entries) + ptr_diff, ptr_diff)) + } +} + +/** Generic hardware queue. Required parameter entries controls + the depth of the queues. The width of the queue is determined + from the inputs. + + Example usage: + val q = new Queue(UInt(), 16) + q.io.enq <> producer.io.out + consumer.io.in <> q.io.deq + */ +object Queue +{ + def apply[T <: Data](enq: DecoupledIO[T], entries: Int = 2, pipe: Boolean = false): DecoupledIO[T] = { + val q = Module(new Queue(enq.bits.cloneType, entries, pipe)) + q.io.enq.valid := enq.valid // not using <> so that override is allowed + q.io.enq.bits := enq.bits + enq.ready := q.io.enq.ready + q.io.deq + } +} + +object PriorityEncoderOH +{ + private def encode(in: Seq[Bool]): UInt = { + val outs = Vec.tabulate(in.size)(i => UInt(BigInt(1) << i, in.size)) + PriorityMux(in :+ Bool(true), outs :+ UInt(0, in.size)) + } + def apply(in: Seq[Bool]): Vec[Bool] = { + val enc = encode(in) + Vec.tabulate(in.size)(enc(_)) + } + def apply(in: Bits): UInt = encode((0 until in.getWidth).map(i => in(i))) +} + +class ArbiterIO[T <: Data](gen: T, n: Int) extends Bundle { + val in = Vec(Decoupled(gen), n).flip + val out = Decoupled(gen) + val chosen = UInt(OUTPUT, log2Up(n)) +} + +object ArbiterCtrl +{ + def apply(request: Seq[Bool]): Seq[Bool] = { + Bool(true) +: (1 until request.length).map(i => !request.slice(0, i).foldLeft(Bool(false))(_ || _)) + } +} + +abstract class LockingArbiterLike[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) extends Module { + require(isPow2(count)) + def grant: Seq[Bool] + val io = new ArbiterIO(gen, n) + val locked = if(count > 1) Reg(init=Bool(false)) else Bool(false) + val lockIdx = if(count > 1) Reg(init=UInt(n-1)) else UInt(n-1) + val chosen = Wire(UInt(width = log2Up(n))) + + for ((g, i) <- grant.zipWithIndex) + io.in(i).ready := Mux(locked, lockIdx === UInt(i), g) && io.out.ready + io.out.valid := io.in(chosen).valid + io.out.bits := io.in(chosen).bits + io.chosen := chosen + + if(count > 1){ + val cnt = Reg(init=UInt(0, width = log2Up(count))) + val cnt_next = cnt + UInt(1) + when(io.out.fire()) { + when(needsLock.map(_(io.out.bits)).getOrElse(Bool(true))) { + cnt := cnt_next + when(!locked) { + locked := Bool(true) + lockIdx := Vec(io.in.map{ in => in.fire()}).indexWhere{i: Bool => i} + } + } + when(cnt_next === UInt(0)) { + locked := Bool(false) + } + } + } +} + +class LockingRRArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) extends LockingArbiterLike[T](gen, n, count, needsLock) { + lazy val last_grant = Reg(init=UInt(0, log2Up(n))) + override def grant: Seq[Bool] = { + val ctrl = ArbiterCtrl((0 until n).map(i => io.in(i).valid && UInt(i) > last_grant) ++ io.in.map(_.valid)) + (0 until n).map(i => ctrl(i) && UInt(i) > last_grant || ctrl(i + n)) + } + + var choose = UInt(n-1) + for (i <- n-2 to 0 by -1) + choose = Mux(io.in(i).valid, UInt(i), choose) + for (i <- n-1 to 1 by -1) + choose = Mux(io.in(i).valid && UInt(i) > last_grant, UInt(i), choose) + chosen := Mux(locked, lockIdx, choose) + + when (io.out.fire()) { last_grant := chosen } +} + +class LockingArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) extends LockingArbiterLike[T](gen, n, count, needsLock) { + def grant: Seq[Bool] = ArbiterCtrl(io.in.map(_.valid)) + + var choose = UInt(n-1) + for (i <- n-2 to 0 by -1) { + choose = Mux(io.in(i).valid, UInt(i), choose) + } + chosen := Mux(locked, lockIdx, choose) +} + +/** Hardware module that is used to sequence n producers into 1 consumer. + Producers are chosen in round robin order. + + Example usage: + val arb = new RRArbiter(2, UInt()) + arb.io.in(0) <> producer0.io.out + arb.io.in(1) <> producer1.io.out + consumer.io.in <> arb.io.out + */ +class RRArbiter[T <: Data](gen:T, n: Int) extends LockingRRArbiter[T](gen, n, 1) + +/** Hardware module that is used to sequence n producers into 1 consumer. + Priority is given to lower producer + + Example usage: + val arb = Module(new Arbiter(2, UInt())) + arb.io.in(0) <> producer0.io.out + arb.io.in(1) <> producer1.io.out + consumer.io.in <> arb.io.out + */ +class Arbiter[T <: Data](gen: T, n: Int) extends LockingArbiter[T](gen, n, 1) + +/** linear feedback shift register + */ +object LFSR16 +{ + def apply(increment: Bool = Bool(true)): UInt = + { + val width = 16 + val lfsr = Reg(init=UInt(1, width)) + when (increment) { lfsr := Cat(lfsr(0)^lfsr(2)^lfsr(3)^lfsr(5), lfsr(width-1,1)) } + lfsr + } +} + +/** A hardware module that delays data coming down the pipeline + by the number of cycles set by the latency parameter. Functionality + is similar to ShiftRegister but this exposes a Pipe interface. + + Example usage: + val pipe = new Pipe(UInt()) + pipe.io.enq <> produce.io.out + consumer.io.in <> pipe.io.deq + */ +object Pipe +{ + def apply[T <: Data](enqValid: Bool, enqBits: T, latency: Int): ValidIO[T] = { + if (latency == 0) { + val out = Valid(enqBits) + out.valid <> enqValid + out.bits <> enqBits + out + } else { + val v = Reg(Bool(), next=enqValid, init=Bool(false)) + val b = RegEnable(enqBits, enqValid) + apply(v, b, latency-1) + } + } + def apply[T <: Data](enqValid: Bool, enqBits: T): ValidIO[T] = apply(enqValid, enqBits, 1) + def apply[T <: Data](enq: ValidIO[T], latency: Int = 1): ValidIO[T] = apply(enq.valid, enq.bits, latency) +} + +class Pipe[T <: Data](gen: T, latency: Int = 1) extends Module +{ + val io = new Bundle { + val enq = Valid(gen).flip + val deq = Valid(gen) + } + + io.deq <> Pipe(io.enq, latency) +} diff --git a/src/main/scala/Core.scala b/src/main/scala/Core.scala deleted file mode 100644 index 8236c154..00000000 --- a/src/main/scala/Core.scala +++ /dev/null @@ -1,1248 +0,0 @@ -package Chisel -import scala.collection.mutable.{ArrayBuffer, Stack, HashSet, HashMap, LinkedHashMap} -import java.lang.reflect.Modifier._ -import java.lang.Double.longBitsToDouble -import java.lang.Float.intBitsToFloat - -class GenSym { - private var counter = -1 - def nextInt: Int = { - counter += 1 - counter - } - def next(name: String): String = - name + "_" + nextInt -} - -object Builder { - val components = new ArrayBuffer[Component]() - val genSym = new GenSym() - val scopes = new Stack[HashSet[String]]() - def scope = scopes.top - val switchKeyz = new Stack[Stack[Bits]]() - def switchKeys = switchKeyz.top - def pushScope = { - scopes.push(new HashSet[String]()) - switchKeyz.push(new Stack[Bits]()) - } - def popScope = { - scopes.pop() - switchKeyz.pop() - } - val modules = new HashMap[String,Module]() - def addModule(mod: Module) { - modules(mod.cid) = mod - } - val modulez = new Stack[Module]() - def pushModule(mod: Module) { - modulez.push(mod) - } - def getComponent(): Module = if (modulez.length > 0) modulez.head else null - def popModule() { - modulez.pop - } - val componentNames = new HashSet[String]() - def UniqueComponent(name: String, ports: Array[Port], body: Command) = { - val res = Component(if (componentNames.contains(name)) genSym.next(name) else name, ports, body) - componentNames += name - res - } - val commandz = new Stack[ArrayBuffer[Command]]() - def commands = commandz.top - def pushCommand(cmd: Command) = commands += cmd - def commandify(cmds: ArrayBuffer[Command]): Command = { - if (cmds.length == 0) - EmptyCommand() - else if (cmds.length == 1) - cmds(0) - else - Begin(cmds.toList) - } - def pushCommands = - commandz.push(new ArrayBuffer[Command]()) - def popCommands: Command = { - val newCommands = commands - commandz.pop() - commandify(newCommands) - } - def collectCommands[T <: Module](f: => T): (Command, T) = { - pushCommands - val mod = f - // mod.setRefs - (popCommands, mod) - } - - private val refmap = new HashMap[String,Immediate]() - - def legalizeName (name: String) = { - if (name == "mem" || name == "node" || name == "wire" || - name == "reg" || name == "inst") - // genSym.next(name) - name + "__" - else - name - } - - def setRefForId(id: String, name: String, overwrite: Boolean = false) { - if (overwrite || !refmap.contains(id)) { - refmap(id) = Ref(legalizeName(name)) - } - } - - def setFieldForId(parentid: String, id: String, name: String) { - refmap(id) = Slot(Alias(parentid), legalizeName(name)) - } - - def setIndexForId(parentid: String, id: String, index: Int) { - refmap(id) = Index(Alias(parentid), index) - } - - def getRefForId(id: String): Immediate = { - if (refmap.contains(id)) { - refmap(id) - } else { - val ref = Ref(genSym.next("T")) - refmap(id) = ref - ref - } - } - - def build[T <: Module](f: => T): (Circuit, T) = { - val (cmd, mod) = collectCommands(f) - setRefForId(mod.cid, mod.name) - (Circuit(components.toArray, components.last.name), mod) - } - -} - -import Builder._ - -/// CHISEL IR - -case class PrimOp(val name: String) { - override def toString = name -} - -object PrimOp { - val AddOp = PrimOp("add") - val AddModOp = PrimOp("add-wrap") - val SubOp = PrimOp("sub") - val SubModOp = PrimOp("sub-wrap") - val TimesOp = PrimOp("mul") - val DivideOp = PrimOp("div") - val ModOp = PrimOp("mod") - val ShiftLeftOp = PrimOp("shl") - val ShiftRightOp = PrimOp("shr") - val DynamicShiftLeftOp = PrimOp("dshl") - val DynamicShiftRightOp = PrimOp("dshr") - val BitAndOp = PrimOp("bit-and") - val BitOrOp = PrimOp("bit-or") - val BitXorOp = PrimOp("bit-xor") - val BitNotOp = PrimOp("bit-not") - val ConcatOp = PrimOp("cat") - val BitSelectOp = PrimOp("bit") - val BitsExtractOp = PrimOp("bits") - val LessOp = PrimOp("lt") - val LessEqOp = PrimOp("leq") - val GreaterOp = PrimOp("gt") - val GreaterEqOp = PrimOp("geq") - val EqualOp = PrimOp("eq") - val PatternEqualOp = PrimOp("pattern-equal") - val PadOp = PrimOp("pad") - val NotEqualOp = PrimOp("neq") - val NegOp = PrimOp("neg") - val MultiplexOp = PrimOp("mux") - val XorReduceOp = PrimOp("xorr") - val ConvertOp = PrimOp("convert") - val AsUIntOp = PrimOp("as-UInt") - val AsSIntOp = PrimOp("as-SInt") -} -import PrimOp._ - -abstract class Immediate { - def fullname: String - def name: String - def debugName = fullname -} - -abstract class Arg extends Immediate { - def fullname: String - def name: String -} - -case class Alias(val id: String) extends Arg { - def fullname = getRefForId(id).fullname - def name = getRefForId(id).name - override def debugName = getRefForId(id).debugName - def emit: String = "Alias(" + id + ")" -} - -abstract class LitArg (val num: BigInt, val width: Int) extends Arg { -} - -case class ULit(n: BigInt, w: Int = -1) extends LitArg(n, w) { - def fullname = name - def name = "UInt<" + width + ">(" + num + ")" -} - -case class SLit(n: BigInt, w: Int = -1) extends LitArg(n, w) { - def fullname = name - def name = "SInt<" + width + ">(" + num + ")" -} - -case class Ref(val name: String) extends Immediate { - def fullname = name -} -case class Slot(val imm: Immediate, val name: String) extends Immediate { - def fullname = { - val imm_fullname = imm.fullname - if (imm_fullname == "this") name else imm_fullname + "." + name - } - override def debugName = { - val imm_debugName = imm.debugName - if (imm_debugName == "this") name else imm_debugName + "." + name - } -} -case class Index(val imm: Immediate, val value: Int) extends Immediate { - def name = "[" + value + "]" - def fullname = imm.fullname + "[" + value + "]" - override def debugName = imm.debugName + "." + value -} - -case class Port(val id: String, val dir: Direction, val kind: Kind); - -abstract class Width; -case class UnknownWidth() extends Width; -case class IntWidth(val value: Int) extends Width; - -abstract class Kind(val isFlip: Boolean); -case class UnknownType(flip: Boolean) extends Kind(flip); -case class UIntType(val width: Width, flip: Boolean) extends Kind(flip); -case class SIntType(val width: Width, flip: Boolean) extends Kind(flip); -case class FloType(flip: Boolean) extends Kind(flip); -case class DblType(flip: Boolean) extends Kind(flip); -case class BundleType(val ports: Array[Port], flip: Boolean) extends Kind(flip); -case class VectorType(val size: Int, val kind: Kind, flip: Boolean) extends Kind(flip); - -abstract class Command; -abstract class Definition extends Command { - def id: String - def name = getRefForId(id).name -} -case class DefUInt(val id: String, val value: BigInt, val width: Int) extends Definition; -case class DefSInt(val id: String, val value: BigInt, val width: Int) extends Definition; -case class DefFlo(val id: String, val value: Float) extends Definition; -case class DefDbl(val id: String, val value: Double) extends Definition; -case class DefPrim(val id: String, val kind: Kind, val op: PrimOp, val args: Array[Arg], val lits: Array[BigInt]) extends Definition; -case class DefWire(val id: String, val kind: Kind) extends Definition; -case class DefRegister(val id: String, val kind: Kind) extends Definition; -case class DefMemory(val id: String, val kind: Kind, val size: Int) extends Definition; -case class DefSeqMemory(val id: String, val kind: Kind, val size: Int) extends Definition; -case class DefAccessor(val id: String, val source: Alias, val direction: Direction, val index: Arg) extends Definition; -case class DefInstance(val id: String, val module: String) extends Definition; -case class Conditionally(val prep: Command, val pred: Arg, val conseq: Command, var alt: Command) extends Command; -case class Begin(val body: List[Command]) extends Command(); -case class Connect(val loc: Alias, val exp: Arg) extends Command; -case class BulkConnect(val loc1: Alias, val loc2: Alias) extends Command; -case class ConnectInit(val loc: Alias, val exp: Arg) extends Command; -case class ConnectInitIndex(val loc: Alias, val index: Int, val exp: Arg) extends Command; -case class EmptyCommand() extends Command; - -case class Component(val name: String, val ports: Array[Port], val body: Command); -case class Circuit(val components: Array[Component], val main: String); - -object Commands { - val NoLits = Array[BigInt]() -} - -import Commands._ - -/// COMPONENTS - -sealed abstract class Direction(val name: String) { - override def toString = name -} -object INPUT extends Direction("input") -object OUTPUT extends Direction("output") -object NO_DIR extends Direction("?") - -object Direction { - def flipDirection(dir: Direction) = { - dir match { - case INPUT => OUTPUT - case OUTPUT => INPUT - case NO_DIR => NO_DIR - } - } -} -import Direction._ - -/// CHISEL FRONT-END - -abstract class Id { - protected[Chisel] val _id = genSym.nextInt - protected[Chisel] val cid = "id_" + _id - - var isDef_ = false - def defd: this.type = { - isDef_ = true - this - } - def isDef = isDef_ -} - -object debug { - // TODO: - def apply (arg: Data) = arg -} - -abstract class Data(dirArg: Direction) extends Id { - val mod = getComponent() - def toType: Kind - var isFlipVar = dirArg == INPUT - def isFlip = isFlipVar - def dir: Direction = if (isFlip) INPUT else OUTPUT - def setDir(dir: Direction) { - isFlipVar = (dir == INPUT) - } - def init(dummy:Int = 0) = { } - def asInput: this.type = { - setDir(INPUT) - this - } - def asOutput: this.type = { - setDir(OUTPUT) - this - } - def flip(): this.type = { - isFlipVar = !isFlipVar - this - } - def :=(other: Data) = - pushCommand(Connect(this.lref, other.ref)) - def <>(other: Data) = - pushCommand(BulkConnect(this.lref, other.lref)) - final def cloneType: this.type = { - val res = doCloneType - collectElts - res - } - def collectElts = { } - def doCloneType: this.type - def cloneTypeWidth(width: Int): this.type - def lref: Alias = - Alias(cid) - def ref: Arg = - if (isLitValue) litArg() else Alias(cid) - def name = getRefForId(cid).name - def debugName = mod.debugName + "." + getRefForId(cid).debugName - def litArg(): LitArg = null - def litValue(): BigInt = -1 - def isLitValue(): Boolean = false - def setLitValue(x: LitArg) { } - def floLitValue: Float = intBitsToFloat(litValue().toInt) - def dblLitValue: Double = longBitsToDouble(litValue().toLong) - def getWidth: Int = flatten.map(_.getWidth).reduce(_ + _) - def maxWidth(other: Data, amt: BigInt): Int = -1 - def sumWidth(amt: BigInt): Int = -1 - def sumWidth(other: Data, amt: BigInt): Int = -1 - def flatten: IndexedSeq[Bits] - def fromBits(n: Bits): this.type = { - var i = 0 - val wire = Wire(this.cloneType) - for (x <- wire.flatten.reverse) { - x := n(i + x.getWidth-1, i) - i += x.getWidth - } - wire.asInstanceOf[this.type] - } - def toBits: UInt = { - val elts = this.flatten.reverse - Cat(elts.head, elts.tail:_*).asUInt - } - def makeLit(value: BigInt, width: Int): this.type = - this.fromBits(Bits(value, width)) - - def toPort: Port = Port(cid, dir, toType) - var isReg_ = false - def isReg = isReg_ - def params = if(Driver.parStack.isEmpty) Parameters.empty else Driver.parStack.top -} - -object Wire { - def apply[T <: Data](t: T = null, init: T = null): T = { - val mType = if (t == null) init else t - if(mType == null) - throw new Exception("cannot infer type of Init.") - val x = mType.cloneType - // TODO: COME UP WITH MORE ROBUST WAY TO HANDLE THIS - pushCommand(DefWire(x.defd.cid, x.toType)) - if (init != null) - pushCommand(Connect(x.lref, init.ref)) - x - } -} - -object Reg { - def apply[T <: Data](t: T = null, next: T = null, init: T = null): T = { - var mType = t - if(mType == null) - mType = next - if(mType == null) - mType = init - if(mType == null) - throw new Exception("cannot infer type of Reg.") - val x = mType.cloneType - x.isReg_ = true - pushCommand(DefRegister(x.defd.cid, x.toType)) - if (init != null) - pushCommand(ConnectInit(x.lref, init.ref)) - if (next != null) - x := next - x - } - def apply[T <: Data](outType: T): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T]) -} - -object Mem { - def apply[T <: Data](t: T, size: Int): Mem[T] = { - val mt = t.cloneType - val mem = new Mem(mt, size) - pushCommand(DefMemory(mt.defd.cid, mt.toType, size)) - mem - } -} - -class Mem[T <: Data](protected[Chisel] val t: T, n: Int) extends VecLike[T] { - def length: Int = n - def apply(idx: Int): T = apply(UInt(idx)) - def apply(idx: UInt): T = { - val x = t.cloneType - pushCommand(DefAccessor(x.defd.cid, Alias(t.cid), NO_DIR, idx.ref)) - x - } - - def read(idx: UInt): T = apply(idx) - def write(idx: UInt, data: T): Unit = apply(idx) := data - def write(idx: UInt, data: T, mask: T): Unit = { - // This is totally fucked, but there's no true write mask support yet - val mask1 = mask.toBits - write(idx, t.fromBits((read(idx).toBits & ~mask1) | (data.toBits & mask1))) - } - - def name = getRefForId(t.cid).name - def debugName = t.mod.debugName + "." + getRefForId(t.cid).debugName -} - -object SeqMem { - def apply[T <: Data](t: T, size: Int): SeqMem[T] = - new SeqMem(t, size) -} - -// For now, implement SeqMem in terms of Mem -class SeqMem[T <: Data](t: T, n: Int) { - private val mem = Mem(t, n) - - def read(addr: UInt): T = mem.read(Reg(next = addr)) - def read(addr: UInt, enable: Bool): T = mem.read(RegEnable(addr, enable)) - - def write(addr: UInt, data: T): Unit = mem.write(addr, data) - def write(addr: UInt, data: T, mask: T): Unit = mem.write(addr, data, mask) -} - -object Vec { - def apply[T <: Data](gen: => T, n: Int): Vec[T] = - new Vec((0 until n).map(i => gen.cloneType)) - def apply[T <: Data](elts: Iterable[T]): Vec[T] = { - val vec = new Vec[T](elts.map(e => elts.head.cloneType)) - val isDef = true || elts.head.isDef - if (vec.isReg) - throw new Exception("Vec of Reg Deprecated.") - if (isDef) { - pushCommand(DefWire(vec.defd.cid, vec.toType)) - var i = 0 - for (elt <- elts) { - vec(i) := elt - i += 1 - } - } - vec - } - def apply[T <: Data](elt0: T, elts: T*): Vec[T] = - apply(elt0 +: elts.toSeq) - def tabulate[T <: Data](n: Int)(gen: (Int) => T): Vec[T] = - apply((0 until n).map(i => gen(i))) - def fill[T <: Data](n: Int)(gen: => T): Vec[T] = - Vec.tabulate(n){ i => gen } -} - -abstract class Aggregate(dirArg: Direction) extends Data(dirArg) { - def cloneTypeWidth(width: Int): this.type = cloneType -} - -class Vec[T <: Data](elts: Iterable[T], dirArg: Direction = NO_DIR) extends Aggregate(dirArg) with VecLike[T] { - private val self = elts.toIndexedSeq - private val elt0 = elts.head - - // println("BEGIN VEC NAMING " + this) - for ((e, i) <- self zipWithIndex) { - // println(" NAME " + i + " -> " + cid) - e.collectElts - setIndexForId(cid, e.cid, i) - } - // println("DONE VEC NAMING " + this) - - def <> (that: Iterable[T]): Unit = - this <> Vec(that).asInstanceOf[Data] - - override def isReg = elt0.isReg - override def isFlip = { - val isSubFlip = elt0.isFlip - if (isFlipVar) !isSubFlip else isSubFlip - } - - def apply(idx: UInt): T = { - val x = elt0.cloneType - pushCommand(DefAccessor(x.defd.cid, Alias(cid), NO_DIR, idx.ref)) - x - } - def apply(idx: Int): T = - self(idx) - def toPorts: Array[Port] = - self.map(d => d.toPort).toArray - def toType: Kind = - VectorType(self.size, elt0.toType, isFlipVar) - override def doCloneType: this.type = - Vec(elt0.cloneType, self.size).asInstanceOf[this.type] - override def init(dummy:Int = 0) = - for (e <- self) e.init() - def inits (f: (Int, T, (Int, T, T) => Unit) => Unit) = { - var i = 0 - def doInit (index: Int, elt: T, init: T) = - pushCommand(ConnectInitIndex(elt.lref, index, init.ref)) - for (d <- self) { - f(i, d, doInit) - i += 1; - } - } - override def flatten: IndexedSeq[Bits] = - self.map(_.flatten).reduce(_ ++ _) - - def length: Int = self.size - - def read(idx: UInt): T = apply(idx) - def write(idx: UInt, data: T): Unit = apply(idx) := data -} - -trait VecLike[T <: Data] extends collection.IndexedSeq[T] { - def read(idx: UInt): T - def write(idx: UInt, data: T): Unit - def apply(idx: UInt): T - - def forall(p: T => Bool): Bool = (this map p).fold(Bool(true))(_&&_) - def exists(p: T => Bool): Bool = (this map p).fold(Bool(false))(_||_) - def contains(x: T) (implicit evidence: T <:< Bits): Bool = this.exists(_ === x) - def count(p: T => Bool): UInt = PopCount((this map p).toSeq) - - private def indexWhereHelper(p: T => Bool) = this map p zip (0 until length).map(i => UInt(i)) - def indexWhere(p: T => Bool): UInt = PriorityMux(indexWhereHelper(p)) - def lastIndexWhere(p: T => Bool): UInt = PriorityMux(indexWhereHelper(p).reverse) - def onlyIndexWhere(p: T => Bool): UInt = Mux1H(indexWhereHelper(p)) -} - -// object chiselCast { -// def apply[S <: Data, T <: Bits](i: S)(gen: Int => T): T = { -// val b = i.toBits -// val x = gen(b.getWidth) -// pushCommand(DefPrim(x.defd.id, x.toType, ConvertOp, Array(b.ref), NoLits)) -// x -// } -// } - -import Literal._ - -class BitPat(val value: String, val width: Int) extends Data(NO_DIR) { - def cloneTypeWidth(width: Int): this.type = cloneType - override def dir: Direction = NO_DIR - override def setDir(dir: Direction): Unit = { } - override def toType: Kind = UIntType(UnknownWidth(), isFlip) - override def getWidth: Int = width - override def flatten: IndexedSeq[Bits] = throw new Exception("BitPat.flatten") - override def doCloneType: this.type = - new BitPat(value, width).asInstanceOf[this.type] - def fromInt(x: BigInt): BitPat = BitPat(x.toString(2), -1).asInstanceOf[this.type] - val (bits, mask, swidth) = parseLit(value) - def zEquals(other: Bits): Bool = - (Bits(toLitVal(mask, 2)) & other) === Bits(toLitVal(bits, 2)) - def === (other: Bits): Bool = zEquals(other) - def != (other: Bits): Bool = !zEquals(other) -} - -object BitPat { - def mintLit(n: String, width: Int) = { - assert(n(0) == 'b', "BINARY MINTS ONLY") - new BitPat(n.substring(1, n.length), width) - } - def apply(value: String, width: Int): BitPat = mintLit(value, width) - def apply(value: String): BitPat = apply(value, -1) -} - -abstract class Element(dirArg: Direction, val width: Int) extends Data(dirArg) { - override def getWidth: Int = width -} - -abstract class Bits(dirArg: Direction, width: Int) extends Element(dirArg, width) { - private var litValueVar: Option[LitArg] = None - - override def litArg(): LitArg = litValueVar.get - override def isLitValue(): Boolean = litValueVar.isDefined - override def litValue(): BigInt = if (isLitValue) litValueVar.get.num else -1 - override def setLitValue(x: LitArg) { litValueVar = Some(x) } - override def doCloneType : this.type = cloneTypeWidth(width) - def fromInt(x: BigInt): this.type = makeLit(x, -1) - - override def flatten: IndexedSeq[Bits] = IndexedSeq(this) - - final def apply(x: BigInt): Bool = { - val d = new Bool(dir) - if (isLitValue()) - d.setLitValue(ULit((litValue() >> x.toInt) & 1, 1)) - else - pushCommand(DefPrim(d.defd.cid, d.toType, BitSelectOp, Array(this.ref), Array(x))) - d - } - final def apply(x: Int): Bool = - apply(BigInt(x)) - final def apply(x: UInt): Bool = - apply(x.litValue()) - - final def apply(x: BigInt, y: BigInt): UInt = { - val w = (x - y + 1).toInt - val d = UInt(width = w) - if (isLitValue()) { - val mask = (BigInt(1)<> y.toInt) & mask, w)) - } else - pushCommand(DefPrim(d.defd.cid, d.toType, BitsExtractOp, Array(this.ref), Array(x, y))) - d - } - final def apply(x: Int, y: Int): UInt = - apply(BigInt(x), BigInt(y)) - final def apply(x: UInt, y: UInt): UInt = - apply(x.litValue(), y.litValue()) - - def maxWidth(other: Bits, amt: Int): Int = - if (getWidth >= 0 && other.getWidth >= 0) ((getWidth max other.getWidth) + amt) else -1 - override def sumWidth(amt: BigInt): Int = if (getWidth >= 0) (getWidth + amt).toInt else -1 - def sumWidth(other: Bits, amt: BigInt): Int = - if (getWidth >= 0 && other.getWidth >= 0) (getWidth + other.getWidth + amt).toInt else -1 - def sumLog2Width(other: Bits): Int = - if (getWidth >= 0 && other.getWidth >= 0) (getWidth + (1<> (other: BigInt): Bits = binop(ShiftRightOp, other, sumWidth(-other)) - def >> (other: Int): Bits = this >> BigInt(other) - def >> (other: Bits): Bits = binop(DynamicShiftRightOp, other, sumWidth(0)) - def unary_~ : Bits = unop(BitNotOp, sumWidth(0)) - def pad (other: BigInt): Bits = binop(PadOp, other, other.toInt) - - def & (other: Bits): Bits = binop(BitAndOp, other, maxWidth(other, 0)) - def | (other: Bits): Bits = binop(BitOrOp, other, maxWidth(other, 0)) - def ^ (other: Bits): Bits = binop(BitXorOp, other, maxWidth(other, 0)) - def ## (other: Bits): Bits = Cat(this, other) - - def < (other: Bits): Bool = compop(LessOp, other) - def > (other: Bits): Bool = compop(GreaterOp, other) - def === (other: Bits): Bool = compop(EqualOp, other) - def != (other: Bits): Bool = compop(NotEqualOp, other) - def <= (other: Bits): Bool = compop(LessEqOp, other) - def >= (other: Bits): Bool = compop(GreaterEqOp, other) - def unary_! : Bool = this === Bits(0) - - private def bits_redop(op: PrimOp): Bool = { - val d = new Bool(dir) - pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref), NoLits)) - d - } - - def orR = !(this === Bits(0)) - def andR = (this === Bits(-1)) - def xorR = bits_redop(XorReduceOp) - - def bitSet(off: UInt, dat: Bits): Bits = { - val bit = UInt(1, 1) << off - this & ~bit | dat.toSInt & bit - } - - def toBools: Vec[Bool] = Vec.tabulate(this.getWidth)(i => this(i)) - - def asSInt(): SInt - def asUInt(): UInt - def toSInt(): SInt - def toUInt(): UInt - def toBool(): Bool = this(0) -} - -abstract trait Num[T <: Data] { - // def << (b: T): T; - // def >> (b: T): T; - //def unary_-(): T; - def + (b: T): T; - def * (b: T): T; - def / (b: T): T; - def % (b: T): T; - def - (b: T): T; - def < (b: T): Bool; - def <= (b: T): Bool; - def > (b: T): Bool; - def >= (b: T): Bool; - - def min(b: T): T = Mux(this < b, this.asInstanceOf[T], b) - def max(b: T): T = Mux(this < b, b, this.asInstanceOf[T]) -} - -class UInt(dir: Direction, width: Int) extends Bits(dir, width) with Num[UInt] { - override def cloneTypeWidth(w: Int): this.type = - new UInt(dir, w).asInstanceOf[this.type] - - def toType: Kind = - UIntType(if (width == -1) UnknownWidth() else IntWidth(width), isFlipVar) - - override def makeLit(value: BigInt, width: Int): this.type = - UInt(value, width).asInstanceOf[this.type] - - override def unary_- = UInt(0) - this - override def unary_-% = UInt(0) -% this - def +& (other: UInt): UInt = binop(AddOp, other, maxWidth(other, 1)) - def + (other: UInt): UInt = this +% other - def +% (other: UInt): UInt = binop(AddModOp, other, maxWidth(other, 0)) - def -& (other: UInt): UInt = binop(SubOp, other, maxWidth(other, 1)) - def - (other: UInt): UInt = this -% other - def -% (other: UInt): UInt = binop(SubModOp, other, maxWidth(other, 0)) - def * (other: UInt): UInt = binop(TimesOp, other, sumWidth(other, 0)) - def / (other: UInt): UInt = binop(DivideOp, other, sumWidth(0)) - def % (other: UInt): UInt = binop(ModOp, other, sumWidth(0)) - override def << (other: BigInt): UInt = binop(ShiftLeftOp, other, sumWidth(other)) - override def << (other: Int): UInt = this << BigInt(other) - def << (other: UInt): UInt = binop(DynamicShiftLeftOp, other, sumLog2Width(other)) - override def >> (other: BigInt): UInt = binop(ShiftRightOp, other, sumWidth(-other)) - override def >> (other: Int): UInt = this >> BigInt(other) - def >> (other: UInt): UInt = binop(DynamicShiftRightOp, other, sumWidth(0)) - - override def unary_~ : UInt = unop(BitNotOp, sumWidth(0)) - def & (other: UInt): UInt = binop(BitAndOp, other, maxWidth(other, 0)) - def | (other: UInt): UInt = binop(BitOrOp, other, maxWidth(other, 0)) - def ^ (other: UInt): UInt = binop(BitXorOp, other, maxWidth(other, 0)) - def ## (other: UInt): UInt = Cat(this, other) - - def < (other: UInt): Bool = compop(LessOp, other) - def > (other: UInt): Bool = compop(GreaterOp, other) - def === (other: UInt): Bool = compop(EqualOp, other) - def != (other: UInt): Bool = compop(NotEqualOp, other) - def <= (other: UInt): Bool = compop(LessEqOp, other) - def >= (other: UInt): Bool = compop(GreaterEqOp, other) - - override def pad (other: BigInt): UInt = binop(PadOp, other, other.toInt) - - def zext(): SInt = { - val x = SInt(width = getWidth + 1) - pushCommand(DefPrim(x.defd.cid, x.toType, ConvertOp, Array(ref), NoLits)) - x - } - - def asSInt(): SInt = { - val x = SInt(width = getWidth) - pushCommand(DefPrim(x.defd.cid, x.toType, AsSIntOp, Array(ref), NoLits)) - x - } - - def toSInt(): SInt = asSInt() - def toUInt(): UInt = this - def asUInt(): UInt = this -} - -trait UIntFactory { - def apply(dir: Direction = OUTPUT, width: Int = -1) = - new UInt(dir, width) - def uintLit(value: BigInt, width: Int) = { - val w = if (width == -1) (1 max bitLength(value)) else width - // println("UINT-LIT VALUE = " + value + "(b" + value.toString(2) + ") WIDTH " + w) - val b = new UInt(NO_DIR, w) - b.setLitValue(ULit(value, w)) - // pushCommand(DefUInt(b.defd.id, value, w)) - b - } - def apply(value: BigInt, width: Int): UInt = uintLit(value, width) - def apply(value: BigInt): UInt = apply(value, -1) - def apply(n: String, width: Int): UInt = { - val bitsPerDigit = if (n(0) == 'b') 1 else if (n(0) == 'h') 4 else -1 - apply(stringToVal(n(0), n.substring(1, n.length)), - if (width == -1) (bitsPerDigit * (n.length-1)) else width) - } - def apply(n: String): UInt = apply(n, -1) -} - -// Bits constructors are identical to UInt constructors. -object Bits extends UIntFactory -object UInt extends UIntFactory - -class SInt(dir: Direction, width: Int) extends Bits(dir, width) with Num[SInt] { - override def cloneTypeWidth(w: Int): this.type = - new SInt(dir, w).asInstanceOf[this.type] - def toType: Kind = - SIntType(if (width == -1) UnknownWidth() else IntWidth(width), isFlipVar) - - override def makeLit(value: BigInt, width: Int): this.type = - SInt(value, width).asInstanceOf[this.type] - - override def unary_- : SInt = SInt(0, getWidth) - this - override def unary_-% : SInt = SInt(0, getWidth) -% this - def +& (other: SInt): SInt = binop(AddOp, other, maxWidth(other, 1)) - def +% (other: SInt): SInt = binop(AddModOp, other, maxWidth(other, 0)) - def + (other: SInt): SInt = this +% other - def -& (other: SInt): SInt = binop(SubOp, other, maxWidth(other, 1)) - def -% (other: SInt): SInt = binop(SubModOp, other, maxWidth(other, 0)) - def - (other: SInt): SInt = this -% other - def * (other: SInt): SInt = binop(TimesOp, other, sumWidth(other, 0)) - def / (other: SInt): SInt = binop(DivideOp, other, sumWidth(0)) - def % (other: SInt): SInt = binop(ModOp, other, sumWidth(0)) - override def << (other: BigInt): SInt = binop(ShiftLeftOp, other, sumWidth(other)) - override def << (other: Int): SInt = this << BigInt(other) - def << (other: UInt): SInt = binop(DynamicShiftLeftOp, other, sumLog2Width(other)) - override def >> (other: BigInt): SInt = binop(ShiftRightOp, other, sumWidth(-other)) - override def >> (other: Int): SInt = this >> BigInt(other) - def >> (other: UInt): SInt = binop(DynamicShiftRightOp, other, sumWidth(0)) - - override def unary_~ : SInt = unop(BitNotOp, sumWidth(0)) - def & (other: SInt): SInt = binop(BitAndOp, other, maxWidth(other, 0)) - def | (other: SInt): SInt = binop(BitOrOp, other, maxWidth(other, 0)) - def ^ (other: SInt): SInt = binop(BitXorOp, other, maxWidth(other, 0)) - - def < (other: SInt): Bool = compop(LessOp, other) - def > (other: SInt): Bool = compop(GreaterOp, other) - def === (other: SInt): Bool = compop(EqualOp, other) - def != (other: SInt): Bool = compop(NotEqualOp, other) - def <= (other: SInt): Bool = compop(LessEqOp, other) - def >= (other: SInt): Bool = compop(GreaterEqOp, other) - def abs: UInt = Mux(this < SInt(0), (-this).toUInt, this.toUInt) - - override def pad (other: BigInt): SInt = binop(PadOp, other, other.toInt) - - def asUInt(): UInt = { - val x = UInt(width = getWidth) - pushCommand(DefPrim(x.defd.cid, x.toType, AsUIntOp, Array(ref), NoLits)) - x - } - def toUInt(): UInt = asUInt() - def asSInt(): SInt = this - def toSInt(): SInt = this -} - -object SInt { - def apply(dir: Direction = OUTPUT, width: Int = -1) = - new SInt(dir, width) - def sintLit(value: BigInt, width: Int) = { - val w = if (width == -1) bitLength(value) + 1 else width - val b = new SInt(NO_DIR, w) - b.setLitValue(SLit(value, w)) - // pushCommand(DefSInt(b.defd.id, value, w)) - b - } - def apply(value: BigInt, width: Int): SInt = sintLit(value, width) - def apply(value: BigInt): SInt = apply(value, -1) - def apply(n: String, width: Int): SInt = - apply(stringToVal(n(0), n.substring(1, n.length)), width) - def apply(n: String): SInt = apply(n, -1) -} - -class Bool(dir: Direction) extends UInt(dir, 1) { - override def cloneTypeWidth(w: Int): this.type = new Bool(dir).asInstanceOf[this.type] - - override def makeLit(value: BigInt, width: Int): this.type = - Bool(value).asInstanceOf[this.type] - - def & (other: Bool): Bool = super.&(other).asInstanceOf[Bool] - def | (other: Bool): Bool = super.|(other).asInstanceOf[Bool] - def ^ (other: Bool): Bool = super.^(other).asInstanceOf[Bool] - override def unary_~ : Bool = super.unary_~.asInstanceOf[Bool] - - def || (that: Bool): Bool = this | that - def && (that: Bool): Bool = this & that -} -object Bool { - def apply(dir: Direction) : Bool = - new Bool(dir) - def apply() : Bool = - apply(NO_DIR) - def boolLit(value: BigInt) = { - val b = new Bool(NO_DIR) - b.setLitValue(ULit(value, 1)) - b - } - def apply(value: BigInt) : Bool = boolLit(value) - def apply(value: Boolean) : Bool = apply(if (value) 1 else 0) -} - -object Mux { - def apply[T <: Data](cond: Bool, con: T, alt: T): T = { - val w = Wire(alt, init = alt) - when (cond) { - w := con - } - w - } -} - -object Cat { - def apply[T <: Bits](a: T, r: T*): T = apply(a :: r.toList) - def apply[T <: Bits](r: Seq[T]): T = doCat(r) - private def doCat[T <: Data](r: Seq[T]): T = { - if (r.tail.isEmpty) - r.head - else { - val l = doCat(r.slice(0, r.length/2)) - val h = doCat(r.slice(r.length/2, r.length)) - val isConst = (l.isLitValue() && h.isLitValue()) - val w = if (isConst) l.getWidth + h.getWidth else if (l.getWidth >= 0 && h.getWidth >= 0) l.getWidth + h.getWidth else -1 - val d = l.cloneTypeWidth(w) - if (isConst) { - val c = (l.litValue() << h.getWidth) | h.litValue() - // println("DO-CAT L = " + l.litValue() + " LW = " + l.getWidth + " H = " + h.litValue() + " -> " + c) - - d.setLitValue(ULit(c, w)) - } else - pushCommand(DefPrim(d.cid, d.toType, ConcatOp, Array(l.ref, h.ref), NoLits)) - d - } - } -} - -object Bundle { - val keywords = HashSet[String]("elements", "flip", "toString", - "flatten", "binding", "asInput", "asOutput", "unary_$tilde", - "unary_$bang", "unary_$minus", "cloneType", "doCloneType", - "toUInt", "toBits", - "toBool", "toSInt", "asDirectionless") - def apply[T <: Bundle](b: => T)(implicit p: Parameters): T = { - Driver.parStack.push(p.push) - val res = b - Driver.parStack.pop - res - } - def apply[T <: Bundle](b: => T, f: PartialFunction[Any,Any]): T = { - val q = params.alterPartial(f) - apply(b)(q) - } - private def params = if(Driver.parStack.isEmpty) Parameters.empty else Driver.parStack.top -} - -class Bundle(dirArg: Direction = NO_DIR) extends Aggregate(dirArg) { - def toPorts: Array[Port] = - elements.map(_._2.toPort).toArray - def toType: BundleType = - BundleType(this.toPorts, isFlipVar) - - override def flatten: IndexedSeq[Bits] = { - val sortedElts = elements.values.toIndexedSeq sortWith (_._id < _._id) - sortedElts.map(_.flatten).reduce(_ ++ _) - } - - override def init(dummy:Int = 0) = - for ((s, e) <- elements) e.init() - lazy val elements: LinkedHashMap[String, Data] = { - val elts = LinkedHashMap[String, Data]() - // println("BEGIN BUNDLE NAMING " + cid) - for (m <- getClass.getMethods) { - val name = m.getName - // println("NAME = " + name) - val rtype = m.getReturnType - val isInterface = classOf[Data].isAssignableFrom(rtype) - if (m.getParameterTypes.isEmpty && - !isStatic(m.getModifiers) && - isInterface && - !(Bundle.keywords contains name)) { - val obj = m.invoke(this) - obj match { - case data: Data => - // println(" NAMING " + name + " -> " + cid) - setFieldForId(cid, data.cid, name) - elts(name) = data - case _ => () - } - } - } - // println("DONE BUNDLE NAMING " + cid) - elts - } - override def collectElts = elements - - override def doCloneType : this.type = { - try { - val constructor = this.getClass.getConstructors.head - val res = constructor.newInstance(Array.fill(constructor.getParameterTypes.size)(null):_*) - res.asInstanceOf[this.type] - } catch { - case npe: java.lang.reflect.InvocationTargetException if npe.getCause.isInstanceOf[java.lang.NullPointerException] => - // throwException("Parameterized Bundle " + this.getClass + " needs cloneType method. You are probably using an anonymous Bundle object that captures external state and hence is un-cloneTypeable", npe) - val s = "CLONE INVOCATION EXCEPTION " + this.getClass - error(s) - case e: java.lang.Exception => - val s = "CLONE ANY EXCEPTION " + this.getClass - error(s) - // throwException("Parameterized Bundle " + this.getClass + " needs cloneType method", e) - } - } -} - -object Module { - def apply[T <: Module](bc: => T)(implicit p: Parameters = params): T = { - Driver.modStackPushed = true - Driver.parStack.push(p.push) - val m = bc - val cmd = popCommands - popScope - popModule - m.setRefs - val ports = m.io.toPorts - val component = UniqueComponent(m.name, ports, cmd) - components += component - pushCommand(DefInstance(m.defd.cid, component.name)) - Driver.parStack.pop - m - } - def apply[T <: Module](m: => T, f: PartialFunction[Any,Any]): T = { - val q = params.alterPartial(f) - apply(m)(q) - } - private def params = if(Driver.parStack.isEmpty) Parameters.empty else Driver.parStack.top -} - -abstract class Module(private[Chisel] _reset: Bool = null) extends Id { - val parent = modulez.headOption - pushModule(this) - pushScope - pushCommands - addModule(this) - - lazy val params = Module.params - params.path = this.getClass :: params.path - - def io: Bundle - def ref = getRefForId(cid) - def lref = ref - val reset = if (_reset == null) Bool().defd else _reset - setRefForId(reset.cid, "reset") - - def name = { - // getClass.getName.replace('.', '_') - getClass.getName.split('.').last - } - def debugName: String = { - val p = parent.getOrElse(null) - val pname = if (p == null) "" else (p.debugName + ".") - pname + getRefForId(cid).debugName - } - - def setRefs { - setRefForId(io.cid, "this") - - for (m <- getClass.getDeclaredMethods) { - val name = m.getName() - val types = m.getParameterTypes() - if (types.length == 0) { - val obj = m.invoke(this) - obj match { - case module: Module => - setRefForId(module.cid, name) - module.setRefs - case bundle: Bundle => - if (name != "io") { - setRefForId(bundle.cid, name) - } - case mem: Mem[_] => - setRefForId(mem.t.cid, name) - case vec: Vec[_] => - setRefForId(vec.cid, name) - case data: Data => - setRefForId(data.cid, name) - // ignore anything not of those types - case _ => null - } - } - } - } - - // TODO: actually implement assert - def assert(cond: Bool, msg: String): Unit = {} -} - -// TODO: actually implement BlackBox (this hack just allows them to compile) -abstract class BlackBox(private[Chisel] _reset: Bool = null) extends Module(_reset) { - def setVerilogParameters(s: String): Unit = {} -} - -object when { - def execBlock(block: => Unit): Command = { - pushScope - pushCommands - block - val cmd = popCommands - popScope - cmd - } - def apply(cond: => Bool)(block: => Unit): when = { - new when(cond)( block ) - } -} - -import when._ - -class when(cond: => Bool)(block: => Unit) { - def elsewhen (cond: => Bool)(block: => Unit): when = { - pushCommands - val res = new when(cond) ( block ) - this.cmd.alt = popCommands - res - } - - def otherwise (block: => Unit) { - this.cmd.alt = execBlock(block) - } - - // Capture any commands we need to set up the conditional test. - pushCommands - val pred = cond.ref - val prep = popCommands - val conseq = execBlock(block) - // Assume we have an empty alternate clause. - // elsewhen and otherwise will update it if that isn't the case. - val cmd = Conditionally(prep, pred, conseq, EmptyCommand()) - pushCommand(cmd) -} - - -/// CHISEL IR EMITTER - -class Emitter { - var indenting = 0 - def withIndent(f: => String) = { - indenting += 1; - val res = f - indenting -= 1; - res - } - def join(parts: Array[String], sep: String) = - parts.foldLeft("")((s, p) => if (s == "") p else s + sep + p) - def join0(parts: Array[String], sep: String) = - parts.foldLeft("")((s, p) => s + sep + p) - def join0(parts: List[String], sep: String) = - parts.foldLeft("")((s, p) => s + sep + p) - def newline = - "\n" + join((0 until indenting).map(x => " ").toArray, "") - def emitDir(e: Direction, isTop: Boolean): String = - if (isTop) (e.name + " ") else if (e == INPUT) "flip " else "" - def emit(e: PrimOp): String = e.name - def emit(e: Arg): String = e.fullname - def emitPort(e: Port, isTop: Boolean): String = - emitDir(e.dir, isTop) + getRefForId(e.id).name + " : " + emitType(e.kind) - def emit(e: Width): String = { - e match { - case e: UnknownWidth => "" - case e: IntWidth => "<" + e.value.toString + ">" - } - } - def emitType(e: Kind): String = { - e match { - case e: UnknownType => "?" - case e: UIntType => "UInt" + emit(e.width) - case e: SIntType => "SInt" + emit(e.width) - case e: BundleType => "{" + join(e.ports.map(x => emitPort(x, false)), ", ") + "}" - case e: VectorType => emitType(e.kind) + "[" + e.size + "]" - } - } - def emit(e: Command): String = { - def maybeWidth (w: Int) = if (w == -1) "" else ("<" + w + ">") - e match { - case e: DefUInt => "node " + e.name + " = UInt" + maybeWidth(e.width) + "(" + e.value + ")" - case e: DefSInt => "node " + e.name + " = SInt" + maybeWidth(e.width) + "(" + e.value + ")" - case e: DefFlo => "node " + e.name + " = Flo(" + e.value + ")" - case e: DefDbl => "node " + e.name + " = Dbl(" + e.value + ")" - case e: DefPrim => - "node " + e.name + " = " + emit(e.op) + "(" + join(e.args.map(x => emit(x)) ++ e.lits.map(x => x.toString), ", ") + ")" - case e: DefWire => "wire " + e.name + " : " + emitType(e.kind) - case e: DefRegister => "reg " + e.name + " : " + emitType(e.kind) - case e: DefMemory => "cmem " + e.name + " : " + emitType(e.kind) + "[" + e.size + "]"; - case e: DefSeqMemory => "smem " + e.name + " : " + emitType(e.kind) + "[" + e.size + "]"; - case e: DefAccessor => "accessor " + e.name + " = " + emit(e.source) + "[" + emit(e.index) + "]" - case e: DefInstance => { - val mod = modules(e.id) - // update all references to the modules ports - setRefForId(mod.io.cid, e.name, true) - "inst " + e.name + " of " + e.module - } - case e: Conditionally => { - val prefix = if (!e.prep.isInstanceOf[EmptyCommand]) { - newline + emit(e.prep) + newline - } else { - "" - } - val suffix = if (!e.alt.isInstanceOf[EmptyCommand]) { - newline + "else : " + withIndent{ newline + emit(e.alt) } - } else { - "" - } - prefix + "when " + emit(e.pred) + " : " + withIndent{ emit(e.conseq) } + suffix - } - case e: Begin => join0(e.body.map(x => emit(x)), newline) - case e: Connect => emit(e.loc) + " := " + emit(e.exp) - case e: BulkConnect => emit(e.loc1) + " <> " + emit(e.loc2) - case e: ConnectInit => "on-reset " + emit(e.loc) + " := " + emit(e.exp) - case e: ConnectInitIndex => "on-reset " + emit(e.loc) + "[" + e.index + "] := " + emit(e.exp) - case e: EmptyCommand => "skip" - } - } - def emit(e: Component): String = { - withIndent{ "module " + e.name + " : " + - join0(e.ports.map(x => emitPort(x, true)), newline) + - newline + emit(e.body) } - } - def emit(e: Circuit): String = - withIndent{ "circuit " + e.main + " : " + join0(e.components.map(x => emit(x)), newline) } -} diff --git a/src/main/scala/Driver.scala b/src/main/scala/Driver.scala deleted file mode 100644 index c4a26221..00000000 --- a/src/main/scala/Driver.scala +++ /dev/null @@ -1,420 +0,0 @@ -/* - Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of - California (Regents). All Rights Reserved. Redistribution and use in - source and binary forms, with or without modification, are permitted - provided that the following conditions are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer in the documentation and/or other materials - provided with the distribution. - * Neither the name of the Regents nor the names of its contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - - IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, - SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, - ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF - REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF - ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION - TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR - MODIFICATIONS. -*/ - -package Chisel -import Builder._ -import Direction._ -import ChiselError._ - -import collection.mutable.{ArrayBuffer, HashSet, HashMap, Stack, LinkedHashSet, Queue => ScalaQueue} -import scala.math.min -import java.io.File -import java.io.InputStream -import java.io.OutputStream -import java.io.PrintStream - -trait FileSystemUtilities { - /** Ensures a directory *dir* exists on the filesystem. */ - def ensureDir(dir: String): String = { - val d = dir + (if (dir == "" || dir(dir.length-1) == '/') "" else "/") - new File(d).mkdirs() - d - } - - def createOutputFile(name: String): java.io.FileWriter = { - val baseDir = ensureDir(Driver.targetDir) - new java.io.FileWriter(baseDir + name) - } -} - -class ChiselException(message: String, cause: Throwable) extends Exception(message, cause) - -object throwException { - def apply(s: String, t: Throwable = null) = { - val xcpt = new ChiselException(s, t) - findFirstUserLine(xcpt.getStackTrace) foreach { u => xcpt.setStackTrace(Array(u)) } - throw xcpt - } -} - -object chiselMain { - val wrapped = true - val unwrapped = false - - def apply[T <: Module](args: Array[String], gen: () => T): (Circuit, T) = - Driver(args, gen, wrapped) - - def apply[T <: Module](args: Array[String], gen: () => T, ftester: T => Tester[T]): (Circuit, T) = - Driver(args, gen, ftester, wrapped) - - // Assumes gen needs to be wrapped in Module() - def run[T <: Module] (args: Array[String], gen: () => T): (Circuit, T) = - Driver(args, gen, unwrapped) - - def run[T <: Module] (args: Array[String], gen: () => T, ftester: T => Tester[T]): (Circuit, T) = - Driver(args, gen, ftester, unwrapped) -} - -//Is this antiquated? -object chiselMainTest { - def apply[T <: Module](args: Array[String], gen: () => T)(tester: T => Tester[T]): (Circuit, T) = { - chiselMain(args, gen, tester) - } -} - -object Driver extends FileSystemUtilities{ - def apply[T <: Module](args: Array[String], gen: () => T, wrapped:Boolean = true): (Circuit, T) = { - initChisel(args) - try { - if(wrapped) execute(gen) else executeUnwrapped(gen) - } finally { - ChiselError.report - if (ChiselError.hasErrors && !getLineNumbers) { - println("Re-running Chisel in debug mode to obtain erroneous line numbers...") - // apply(args :+ "--lineNumbers", gen, wrapped) - } - } - } - - def apply[T <: Module](args: Array[String], gen: () => T, - ftester: T => Tester[T], wrapped:Boolean): (Circuit, T) = { - val (circuit, mod) = apply(args, gen, wrapped) - if (isTesting) test(mod, ftester) - (circuit, mod) - } - - private def executeUnwrapped[T <: Module](gen: () => T): (Circuit, T) = { - if (!chiselConfigMode.isEmpty && !chiselConfigClassName.isEmpty) { - println("CHISEL PARAMS") - val name = appendString(chiselProjectName,chiselConfigClassName) - val config = try { - Class.forName(name).newInstance.asInstanceOf[ChiselConfig] - } catch { - case e: java.lang.ClassNotFoundException => - throwException("Could not find the ChiselConfig subclass you asked for (\"" + - name + "\"), did you misspell it?", e) - } - val world = if(chiselConfigMode.get == "collect") { - new Collector(config.topDefinitions,config.knobValues) - } else { new Instance(config.topDefinitions,config.knobValues) } - val p = Parameters.root(world) - config.topConstraints.foreach(c => p.constrain(c)) - val (circuit, mod) = execute(() => Module(gen())(p)) - if(chiselConfigMode.get == "collect") { - val v = createOutputFile(chiselConfigClassName.get + ".knb") - v.write(world.getKnobs) - v.close - val w = createOutputFile(chiselConfigClassName.get + ".cst") - w.write(world.getConstraints) - w.close - } - (circuit, mod) - } - else { - execute(() => Module(gen())) - } - } - - private def execute[T <: Module](gen: () => T): (Circuit, T) = { - val emitter = new Emitter - val (c, mod) = build{ gen() } - // setTopComponent(c) - if (!isTesting) { - val s = emitter.emit( c ) - // println(c.components(0)) - val filename = c.main + ".fir" - // println("FILENAME " + filename) - // println("S = " + s) - val out = createOutputFile(filename) - out.write(s) - /* Params - If dumping design, dump space to pDir*/ - if (chiselConfigMode == None || chiselConfigMode.get == "instance") { - if(chiselConfigDump && !Dump.dump.isEmpty) { - val w = createOutputFile(appendString(Some(topComponent.name),chiselConfigClassName) + ".prm") - w.write(Dump.getDump); w.close - } - } - out.close() - } - (c, mod) - } - - private def test[T <: Module](mod: T, ftester: T => Tester[T]): Unit = { - var res = false - var tester: Tester[T] = null - try { - tester = ftester(mod) - } finally { - if (tester != null && tester.process != null) - res = tester.finish() - } - println(if (res) "PASSED" else "*** FAILED ***") - if(!res) throwException("Module under test FAILED at least one test vector.") - } - - def elapsedTime: Long = System.currentTimeMillis - startTime - - def initChisel(args: Array[String]): Unit = { - ChiselError.clear() - warnInputs = false - warnOutputs = false - saveConnectionWarnings = false - saveComponentTrace = false - dontFindCombLoop = false - isGenHarness = false - isDebug = false - getLineNumbers = false - isCSE = false - isIoDebug = true - isVCD = false - isVCDMem = false - isReportDims = false - targetDir = "." - components.clear() - sortedComps.clear() - compStack.clear() - stackIndent = 0 - printStackStruct.clear() - // blackboxes.clear() - chiselOneHotMap.clear() - chiselOneHotBitMap.clear() - isCompiling = false - isCheckingPorts = false - isTesting = false - isDebugMem = false - isSupportW0W = false - partitionIslands = false - lineLimitFunctions = 0 - minimumLinesPerFile = 0 - shadowRegisterInObject = false - allocateOnlyNeededShadowRegisters = false - compileInitializationUnoptimized = false - useSimpleQueue = false - parallelMakeJobs = 0 - isVCDinline = false - isSupportW0W = false - hasMem = false - hasSRAM = false - sramMaxSize = 0 - topComponent = null - // clocks.clear() - // implicitReset.isIo = true - // implicitReset.setName("reset") - // implicitClock = new Clock() - // implicitClock.setName("clk") - isInGetWidth = false - startTime = System.currentTimeMillis - modStackPushed = false - - readArgs(args) - } - - private def readArgs(args: Array[String]): Unit = { - var i = 0 - var backendName = "c" // Default backend is Cpp. - while (i < args.length) { - val arg = args(i) - arg match { - case "--Wall" => { - saveConnectionWarnings = true - saveComponentTrace = true - isCheckingPorts = true - } - case "--wi" => warnInputs = true - case "--wo" => warnOutputs = true - case "--wio" => {warnInputs = true; warnOutputs = true} - case "--Wconnection" => saveConnectionWarnings = true - case "--Wcomponent" => saveComponentTrace = true - case "--W0W" => isSupportW0W = true - case "--noW0W" => isSupportW0W = false - case "--noCombLoop" => dontFindCombLoop = true - case "--genHarness" => isGenHarness = true - case "--debug" => isDebug = true - case "--lineNumbers" => getLineNumbers = true - case "--cse" => isCSE = true - case "--ioDebug" => isIoDebug = true - case "--noIoDebug" => isIoDebug = false - case "--vcd" => isVCD = true - case "--vcdMem" => isVCDMem = true - case "--v" => backendName = "v" - // case "--moduleNamePrefix" => Backend.moduleNamePrefix = args(i + 1); i += 1 - case "--inlineMem" => isInlineMem = true - case "--noInlineMem" => isInlineMem = false - case "--assert" => isAssert = true - case "--noAssert" => isAssert = false - case "--debugMem" => isDebugMem = true - case "--partitionIslands" => partitionIslands = true - case "--lineLimitFunctions" => lineLimitFunctions = args(i + 1).toInt; i += 1 - case "--minimumLinesPerFile" => minimumLinesPerFile = args(i + 1).toInt; i += 1 - case "--shadowRegisterInObject" => shadowRegisterInObject = true - case "--allocateOnlyNeededShadowRegisters" => allocateOnlyNeededShadowRegisters = true - case "--compileInitializationUnoptimized" => compileInitializationUnoptimized = true - case "--useSimpleQueue" => useSimpleQueue = true - case "--parallelMakeJobs" => parallelMakeJobs = args(i + 1).toInt; i += 1 - case "--isVCDinline" => isVCDinline = true - case "--backend" => backendName = args(i + 1); i += 1 - case "--compile" => isCompiling = true - case "--test" => isTesting = true - case "--targetDir" => targetDir = args(i + 1); i += 1 - case "--include" => includeArgs = args(i + 1).split(' ').toList; i += 1 - case "--checkPorts" => isCheckingPorts = true - case "--reportDims" => isReportDims = true - //Jackhammer Flags - case "--configCollect" => chiselConfigMode = Some("collect"); chiselConfigClassName = Some(getArg(args(i+1),1)); chiselProjectName = Some(getArg(args(i+1),0)); i+=1; //dump constraints in dse dir - case "--configInstance" => chiselConfigMode = Some("instance"); chiselConfigClassName = Some(getArg(args(i+1),1)); chiselProjectName = Some(getArg(args(i+1),0)); i+=1; //use ChiselConfig to supply parameters - case "--configDump" => chiselConfigDump = true; //when using --configInstance, write Dump parameters to .prm file in targetDir - case "--dumpTestInput" => dumpTestInput = true - case "--testerSeed" => { - testerSeedValid = true - testerSeed = args(i+1).toLong - i += 1 - } - case "--emitTempNodes" => { - isDebug = true - emitTempNodes = true - } - /* - // Dreamer configuration flags - case "--numRows" => { - if (backend.isInstanceOf[FloBackend]) { - backend.asInstanceOf[FloBackend].DreamerConfiguration.numRows = args(i+1).toInt - } - i += 1 - } - case "--numCols" => { - if (backend.isInstanceOf[FloBackend]) { - backend.asInstanceOf[FloBackend].DreamerConfiguration.numCols = args(i+1).toInt - } - i += 1 - } - */ - case any => ChiselError.warning("'" + arg + "' is an unknown argument.") - } - i += 1 - } - // Check for bogus flags - if (!isVCD) { - isVCDinline = false - } - // Set the backend after we've interpreted all the arguments. - // (The backend may want to configure itself based on the arguments.) - backend = backendName match { - case "v" => new VerilogBackend - case "c" => new CppBackend - case "flo" => new FloBackend - case "dot" => new DotBackend - case "fpga" => new FPGABackend - case "sysc" => new SysCBackend - case _ => Class.forName(backendName).newInstance.asInstanceOf[Backend] - } - } - - var warnInputs = false - var warnOutputs = false - var saveConnectionWarnings = false - var saveComponentTrace = false - var dontFindCombLoop = false - var isDebug = false - var getLineNumbers = false - var isCSE = false - var isIoDebug = true - var isVCD = false - var isVCDMem = false - var isInlineMem = true - var isGenHarness = false - var isReportDims = false - var includeArgs: List[String] = Nil - var targetDir: String = null - var isCompiling = false - var isCheckingPorts = false - var isTesting = false - var isAssert = true - var isDebugMem = false - var partitionIslands = false - var lineLimitFunctions = 0 - var minimumLinesPerFile = 0 - var shadowRegisterInObject = false - var allocateOnlyNeededShadowRegisters = false - var compileInitializationUnoptimized = false - var useSimpleQueue = false - var parallelMakeJobs = 0 - var isVCDinline = false - var isSupportW0W = false - var hasMem = false - var hasSRAM = false - var sramMaxSize = 0 - var backend: Backend = null - var topComponent: Module = null - val components = ArrayBuffer[Module]() - val sortedComps = ArrayBuffer[Module]() - // val blackboxes = ArrayBuffer[BlackBox]() - val chiselOneHotMap = HashMap[(UInt, Int), UInt]() - val chiselOneHotBitMap = HashMap[(Bits, Int), Bool]() - val compStack = Stack[Module]() - val parStack = new Stack[Parameters] - var stackIndent = 0 - val printStackStruct = ArrayBuffer[(Int, Module)]() - // val clocks = ArrayBuffer[Clock]() - // val implicitReset = Bool(INPUT) - // var implicitClock: Clock = null - var isInGetWidth: Boolean = false - var modStackPushed: Boolean = false - var modAdded: Boolean = false - var startTime = 0L - /* ChiselConfig flags */ - var chiselConfigClassName: Option[String] = None - var chiselProjectName: Option[String] = None - var chiselConfigMode: Option[String] = None - var chiselConfigDump: Boolean = false - - def appendString(s1:Option[String],s2:Option[String]):String = { - if(s1.isEmpty && s2.isEmpty) "" else { - if(!s1.isEmpty) { - s1.get + (if(!s2.isEmpty) "." + s2.get else "") - } else { - if(!s2.isEmpty) s2.get else "" - } - } - } - def getArg(s:String,i:Int):String = s.split('.')(i) - - // Setting this to TRUE will case the test harness to print its - // standard input stream to a file. - var dumpTestInput = false - - // Setting this to TRUE will initialize the tester's RNG with the - // seed below. - var testerSeedValid = false - var testerSeed = System.currentTimeMillis() - - // Setting this to TRUE will result in temporary values (ie, nodes - // named "T*") to be emited to the VCD file. - var emitTempNodes = false -} diff --git a/src/main/scala/Enum.scala b/src/main/scala/Enum.scala deleted file mode 100644 index 3bc24220..00000000 --- a/src/main/scala/Enum.scala +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of - California (Regents). All Rights Reserved. Redistribution and use in - source and binary forms, with or without modification, are permitted - provided that the following conditions are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer in the documentation and/or other materials - provided with the distribution. - * Neither the name of the Regents nor the names of its contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - - IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, - SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, - ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF - REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF - ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION - TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR - MODIFICATIONS. -*/ - -package Chisel -import Literal._ - -object Enum { - /** create n enum values of given type */ - def apply[T <: Bits](nodeType: T, n: Int): List[T] = (Range(0, n, 1).map(x => (Lit(x, sizeof(n-1))(nodeType)))).toList; - - /** create enum values of given type and names */ - def apply[T <: Bits](nodeType: T, l: Symbol *): Map[Symbol, T] = (l.toList zip (Range(0, l.length, 1).map(x => Lit(x, sizeof(l.length-1))(nodeType)))).toMap; - - /** create enum values of given type and names */ - def apply[T <: Bits](nodeType: T, l: List[Symbol]): Map[Symbol, T] = (l zip (Range(0, l.length, 1).map(x => Lit(x, sizeof(l.length-1))(nodeType)))).toMap; - -} diff --git a/src/main/scala/Error.scala b/src/main/scala/Error.scala deleted file mode 100644 index 1ad5414d..00000000 --- a/src/main/scala/Error.scala +++ /dev/null @@ -1,167 +0,0 @@ -/* - Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of - California (Regents). All Rights Reserved. Redistribution and use in - source and binary forms, with or without modification, are permitted - provided that the following conditions are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer in the documentation and/or other materials - provided with the distribution. - * Neither the name of the Regents nor the names of its contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - - IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, - SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, - ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF - REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF - ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION - TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR - MODIFICATIONS. -*/ - -package Chisel -import scala.collection.mutable.ArrayBuffer - -/** This Singleton implements a log4j compatible interface. - It is used through out the Chisel package to report errors and warnings - detected at runtime. - */ -object ChiselError { - var hasErrors: Boolean = false; - val ChiselErrors = new ArrayBuffer[ChiselError]; - - def clear() { - ChiselErrors.clear() - hasErrors = false - } - - /** emit an error message */ - def error(mf: => String, line: StackTraceElement) { - hasErrors = true - ChiselErrors += new ChiselError(() => mf, line) - } - - def error(m: String) { - val stack = Thread.currentThread().getStackTrace - error(m, findFirstUserLine(stack) getOrElse stack(0)) - } - - /** Emit an informational message - (useful to track long running passes) */ - def info(m: String): Unit = - println(tag("info", Console.MAGENTA) + " [%2.3f] ".format(Driver.elapsedTime/1e3) + m) - - /** emit a warning message */ - def warning(m: => String) { - val stack = Thread.currentThread().getStackTrace - ChiselErrors += new ChiselError(() => m, - findFirstUserLine(stack) getOrElse stack(0), 1) - } - - def findFirstUserLine(stack: Array[StackTraceElement]): Option[StackTraceElement] = { - findFirstUserInd(stack) map { stack(_) } - } - - def findFirstUserInd(stack: Array[StackTraceElement]): Option[Int] = { - def isUserCode(ste: StackTraceElement): Boolean = { - val className = ste.getClassName() - try { - val cls = Class.forName(className) - if( cls.getSuperclass() == classOf[Module] ) { - true - } else { - /* XXX Do it the old way until we figure if it is safe - to remove from Node.scala - var line: StackTraceElement = findFirstUserLine(Thread.currentThread().getStackTrace) - */ - val dotPos = className.lastIndexOf('.') - if( dotPos > 0 ) { - (className.subSequence(0, dotPos) != "Chisel") && !className.contains("scala") && - !className.contains("java") && !className.contains("$$") - } else { - false - } - } - } catch { - case e: java.lang.ClassNotFoundException => false - } - } - val idx = stack.indexWhere(isUserCode) - if(idx < 0) { - println("COULDN'T FIND LINE NUMBER (" + stack(1) + ")") - None - } else { - Some(idx) - } - } - - // Print stack frames up to and including the "user" stack frame. - def printChiselStackTrace() { - val stack = Thread.currentThread().getStackTrace - val idx = ChiselError.findFirstUserInd(stack) - idx match { - case None => {} - case Some(x) => for (i <- 0 to x) println(stack(i)) - } - } - - /** Prints error messages generated by Chisel at runtime. */ - def report() { - if (!ChiselErrors.isEmpty) { - for(err <- ChiselErrors) err.print; - } - } - - /** Throws an exception if there has been any error recorded - before this point. */ - def checkpoint() { - if(hasErrors) { - throw new IllegalStateException( - Console.UNDERLINED + "CODE HAS " + - Console.UNDERLINED + Console.BOLD + ChiselErrors.filter(_.isError).length + Console.RESET + - Console.UNDERLINED + " " + - Console.UNDERLINED + Console.RED + "ERRORS" + Console.RESET + - Console.UNDERLINED + " and " + - Console.UNDERLINED + Console.BOLD + ChiselErrors.filter(_.isWarning).length + Console.RESET + - Console.UNDERLINED + " " + - Console.UNDERLINED + Console.YELLOW + "WARNINGS" + Console.RESET) - } - } - - def tag(name: String, color: String): String = - s"[${color}${name}${Console.RESET}]" -} - -class ChiselError(val errmsgFun: () => String, val errline: StackTraceElement, -val errlevel: Int = 0) { - - val level = errlevel - val line = errline - val msgFun = errmsgFun - - def isError = (level == 0) - def isWarning = (level == 1) - - def print() { - /* Following conventions for error formatting */ - val levelstr = - if (isError) ChiselError.tag("error", Console.RED) - else ChiselError.tag("warn", Console.YELLOW) - if( line != null ) { - println(levelstr + " " + line.getFileName + ":" + - line.getLineNumber + ": " + msgFun() + - " in class " + line.getClassName) - } else { - println(levelstr + ": " + msgFun()) - } - } -} diff --git a/src/main/scala/FP.scala b/src/main/scala/FP.scala deleted file mode 100644 index c22ee475..00000000 --- a/src/main/scala/FP.scala +++ /dev/null @@ -1,321 +0,0 @@ -/* - Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of - California (Regents). All Rights Reserved. Redistribution and use in - source and binary forms, with or without modification, are permitted - provided that the following conditions are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer in the documentation and/or other materials - provided with the distribution. - * Neither the name of the Regents nor the names of its contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - - IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, - SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, - ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF - REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF - ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION - TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR - MODIFICATIONS. -*/ - -package Chisel -import Chisel._ -import Builder._ -import ChiselError._ -import Commands.NoLits - -/// FLO - -object Flo { - def apply(x: Float): Flo = floLit(x) - def apply(x: Double): Flo = Flo(x.toFloat) - def floLit(value: Float): Flo = { - val b = new Flo(NO_DIR, Some(value)) - pushCommand(DefFlo(b.defd.cid, value)) - b - } - def apply(dir: Direction = null): Flo = - new Flo(dir) -} - -object FloPrimOp { - val FloNeg = PrimOp("flo-neg") - val FloAdd = PrimOp("flo-add") - val FloSub = PrimOp("flo-sub") - val FloMul = PrimOp("flo-mul") - val FloDiv = PrimOp("flo-div") - val FloMod = PrimOp("flo-mod") - val FloEqual = PrimOp("flo-equal") - val FloNotEqual = PrimOp("flo-not-equal") - val FloGreater = PrimOp("flo-greater") - val FloLess = PrimOp("flo-less") - val FloLessEqual = PrimOp("flo-less-equal") - val FloGreaterEqual = PrimOp("flo-greater-equal") - val FloPow = PrimOp("flo-pow") - val FloSin = PrimOp("flo-sin") - val FloCos = PrimOp("flo-cos") - val FloTan = PrimOp("flo-tan") - val FloAsin = PrimOp("flo-asin") - val FloAcos = PrimOp("flo-acos") - val FloAtan = PrimOp("flo-atan") - val FloSqrt = PrimOp("flo-sqrt") - val FloFloor = PrimOp("flo-floor") - val FloCeil = PrimOp("flo-ceil") - val FloRound = PrimOp("flo-round") - val FloLog = PrimOp("flo-log") - val FloToBits = PrimOp("flo-to-bits") - val BitsToFlo = PrimOp("bits-to-flo") -} -import FloPrimOp._ - -class Flo(dir: Direction = NO_DIR, val value:Option[Float] = None) extends Element(dir, 32) with Num[Flo] { - type T = Flo; - override def floLitValue: Float = value.get - def cloneTypeWidth(width: Int): this.type = cloneType - override def fromBits(n: Bits): this.type = { - val d = cloneType - pushCommand(DefPrim(d.defd.cid, d.toType, BitsToFlo, Array(this.ref), NoLits)) - d - } - override def toBits: UInt = { - val d = new UInt(dir, 32) - pushCommand(DefPrim(d.defd.cid, d.toType, FloToBits, Array(this.ref), NoLits)) - d - } - def toType: Kind = FloType(isFlip) - def doCloneType: this.type = new Flo(dir).asInstanceOf[this.type] - def flatten: IndexedSeq[Bits] = IndexedSeq(toBits) - - def fromInt(x: Int): Flo = - Flo(x.toFloat).asInstanceOf[this.type] - - private def flo_unop(op: PrimOp): Flo = { - val d = cloneType - pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref), NoLits)) - d - } - private def flo_binop(op: PrimOp, other: Flo): Flo = { - val d = cloneType - pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits)) - d - } - private def flo_compop(op: PrimOp, other: Flo): Bool = { - val d = new Bool(dir) - pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits)) - d - } - - def unary_-() = flo_unop(FloNeg) - def + (b: Flo) = flo_binop(FloAdd, b) - def - (b: Flo) = flo_binop(FloSub, b) - def * (b: Flo) = flo_binop(FloMul, b) - def / (b: Flo) = flo_binop(FloDiv, b) - def % (b: Flo) = flo_binop(FloMod, b) - def ===(b: Flo) = flo_compop(FloEqual, b) - def != (b: Flo) = flo_compop(FloNotEqual, b) - def > (b: Flo) = flo_compop(FloGreater, b) - def < (b: Flo) = flo_compop(FloLess, b) - def <= (b: Flo) = flo_compop(FloLessEqual, b) - def >= (b: Flo) = flo_compop(FloGreaterEqual, b) - def pow (b: Flo) = flo_binop(FloPow, b) - def sin = flo_unop(FloSin) - def cos = flo_unop(FloCos) - def tan = flo_unop(FloTan) - def asin = flo_unop(FloAsin) - def acos = flo_unop(FloAcos) - def atan = flo_unop(FloAtan) - def sqrt = flo_unop(FloSqrt) - def floor = flo_unop(FloFloor) - def ceil = flo_unop(FloCeil) - def round = flo_unop(FloRound) - def log = flo_unop(FloLog) - def toSInt () = SInt(OUTPUT).fromBits(toBits) - def toUInt () = UInt(OUTPUT).fromBits(toBits) -} - -/// DBL - -import java.lang.Double.doubleToLongBits - -object Dbl { - def apply(x: Float): Dbl = Dbl(x.toDouble); - def apply(x: Double): Dbl = dblLit(x) - def dblLit(value: Double): Dbl = { - val b = new Dbl(NO_DIR, Some(value)) - pushCommand(DefDbl(b.defd.cid, value)) - b - } - def apply(dir: Direction = NO_DIR): Dbl = - new Dbl(dir) -} - -object DblPrimOp { - val DblNeg = PrimOp("dbl-neg") - val DblAdd = PrimOp("dbl-add") - val DblSub = PrimOp("dbl-sub") - val DblMul = PrimOp("dbl-mul") - val DblDiv = PrimOp("dbl-div") - val DblMod = PrimOp("dbl-mod") - val DblEqual = PrimOp("dbl-equal") - val DblNotEqual = PrimOp("dbl-not-equal") - val DblGreater = PrimOp("dbl-greater") - val DblLess = PrimOp("dbl-less") - val DblLessEqual = PrimOp("dbl-less-equal") - val DblGreaterEqual = PrimOp("dbl-greater-equal") - val DblPow = PrimOp("dbl-pow") - val DblSin = PrimOp("dbl-sin") - val DblCos = PrimOp("dbl-cos") - val DblTan = PrimOp("dbl-tan") - val DblAsin = PrimOp("dbl-asin") - val DblAcos = PrimOp("dbl-acos") - val DblAtan = PrimOp("dbl-atan") - val DblSqrt = PrimOp("dbl-sqrt") - val DblFloor = PrimOp("dbl-floor") - val DblCeil = PrimOp("dbl-ceil") - val DblRound = PrimOp("dbl-round") - val DblLog = PrimOp("dbl-log") - val DblToBits = PrimOp("dbl-to-bits") - val BitsToDbl = PrimOp("bits-to-dbl") -} -import DblPrimOp._ - -class Dbl(dir: Direction, val value: Option[Double] = None) extends Element(dir, 64) with Num[Dbl] { - // setIsSigned - - // override def setIsTypeNode = {inputs(0).setIsSigned; super.setIsTypeNode} - - type T = Dbl; - override def dblLitValue: Double = value.get - def cloneTypeWidth(width: Int): this.type = cloneType - override def fromBits(n: Bits): this.type = { - val d = cloneType - pushCommand(DefPrim(d.defd.cid, d.toType, BitsToDbl, Array(this.ref), NoLits)) - d - } - override def toBits: UInt = { - val d = new UInt(dir, 64) - pushCommand(DefPrim(d.defd.cid, d.toType, DblToBits, Array(this.ref), NoLits)) - d - } - def toType: Kind = DblType(isFlip) - def doCloneType: this.type = new Dbl(dir).asInstanceOf[this.type] - def flatten: IndexedSeq[Bits] = IndexedSeq(toBits) - - def fromInt(x: Int): this.type = - Dbl(x.toDouble).asInstanceOf[this.type] - - private def dbl_unop(op: PrimOp): Dbl = { - val d = cloneType - pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref), NoLits)) - d - } - private def dbl_binop(op: PrimOp, other: Dbl): Dbl = { - val d = cloneType - pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits)) - d - } - private def dbl_compop(op: PrimOp, other: Dbl): Bool = { - val d = new Bool(dir) - pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits)) - d - } - - def unary_-() = dbl_unop(DblNeg) - def + (b: Dbl) = dbl_binop(DblAdd, b) - def - (b: Dbl) = dbl_binop(DblSub, b) - def * (b: Dbl) = dbl_binop(DblMul, b) - def / (b: Dbl) = dbl_binop(DblDiv, b) - def % (b: Dbl) = dbl_binop(DblMod, b) - def ===(b: Dbl) = dbl_compop(DblEqual, b) - def != (b: Dbl) = dbl_compop(DblNotEqual, b) - def > (b: Dbl) = dbl_compop(DblGreater, b) - def < (b: Dbl) = dbl_compop(DblLess, b) - def <= (b: Dbl) = dbl_compop(DblLessEqual, b) - def >= (b: Dbl) = dbl_compop(DblGreaterEqual, b) - def pow (b: Dbl) = dbl_binop(DblPow, b) - def sin = dbl_unop(DblSin) - def cos = dbl_unop(DblCos) - def tan = dbl_unop(DblTan) - def asin = dbl_unop(DblAsin) - def acos = dbl_unop(DblAcos) - def atan = dbl_unop(DblAtan) - def sqrt = dbl_unop(DblSqrt) - def floor = dbl_unop(DblFloor) - def ceil = dbl_unop(DblCeil) - def round = dbl_unop(DblRound) - def log = dbl_unop(DblLog) - def toSInt () = SInt(OUTPUT).fromBits(toBits) - def toUInt () = UInt(OUTPUT).fromBits(toBits) -} - -object Sin { - def apply (x: Flo): Flo = x.sin - def apply (x: Dbl): Dbl = x.sin -} - -object Cos { - def apply (x: Flo): Flo = x.cos - def apply (x: Dbl): Dbl = x.cos -} - -object Tan { - def apply (x: Flo): Flo = x.tan - def apply (x: Dbl): Dbl = x.tan -} - -object ASin { - def apply (x: Flo): Flo = x.asin - def apply (x: Dbl): Dbl = x.asin -} - -object ACos { - def apply (x: Flo): Flo = x.acos - def apply (x: Dbl): Dbl = x.acos -} - -object ATan { - def apply (x: Flo): Flo = x.atan - def apply (x: Dbl): Dbl = x.atan -} - -object Sqrt { - def apply (x: Flo): Flo = x.sqrt - def apply (x: Dbl): Dbl = x.sqrt -} - -object Floor { - def apply (x: Flo): Flo = x.floor - def apply (x: Dbl): Dbl = x.floor -} - -object Ceil { - def apply (x: Flo): Flo = x.ceil - def apply (x: Dbl): Dbl = x.ceil -} - -object Round { - def apply (x: Flo): Flo = x.round - def apply (x: Dbl): Dbl = x.round -} - -object Log { - def apply (x: Flo): Flo = x.log - def apply (x: Dbl): Dbl = x.log - def apply (x: Flo, p: Flo): Flo = Log(x)/Log(p) - def apply (x: Dbl, p: Dbl): Dbl = Log(x)/Log(p) -} - -object Pow { - def apply (x: Flo, y: Flo): Flo = x.pow(y) - def apply (x: Dbl, y: Dbl): Dbl = x.pow(y) -} diff --git a/src/main/scala/JHFormat.scala b/src/main/scala/JHFormat.scala deleted file mode 100644 index e177835e..00000000 --- a/src/main/scala/JHFormat.scala +++ /dev/null @@ -1,105 +0,0 @@ -/* - Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of - California (Regents). All Rights Reserved. Redistribution and use in - source and binary forms, with or without modification, are permitted - provided that the following conditions are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer in the documentation and/or other materials - provided with the distribution. - * Neither the name of the Regents nor the names of its contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - - IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, - SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, - ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF - REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF - ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION - TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR - MODIFICATIONS. -*/ - -package Chisel -import scala.collection.mutable.HashMap -import scala.collection.mutable.ArrayBuffer -import scala.io.Source -import java.io._ - -object JHFormat { - type Space = ArrayBuffer[(String,Param[Any],Int)] - def serialize[T<:Param[Any]](space: Space) : String = { - var string = new StringBuilder("") - for ((mname, p, gID) <- space) { - string ++= mname + "," + toStringParam(p) + "\n" - } - string.toString - } - - def deserialize(filename: String):Space = { - var lines = io.Source.fromFile(filename).getLines - var space = new Space - while(lines.hasNext) { - val line = lines.next() - val args = line.split(",") - val mname = args(0) - val ptype = args(1) - val gID = args(2).toInt - val pname = args(3) - val param = ptype match { - case "value" => { val p = new ValueParam(pname,args(4).toInt) - p.gID = gID; p } - case "range" => { val p = new RangeParam(pname,args(4).toInt,args(5).toInt,args(6).toInt) - p.gID = gID; p } - case "less" => { val p = new LessParam(pname,args(4).toInt,args(5).toInt,space.find(i => i._3 == args(6).toInt).get._2) - p.gID = gID; p } - case "lesseq" => { val p = new LessEqParam(pname,args(4).toInt,args(5).toInt,space.find(i => i._3 == args(6).toInt).get._2) - p.gID = gID; p } - case "great" => { val p = new GreaterParam(pname,args(4).toInt,space.find(i => i._3 == args(5).toInt).get._2,args(6).toInt) - p.gID = gID; p } - case "greateq" => { val p = new GreaterEqParam(pname,args(4).toInt,space.find(i => i._3 == args(5).toInt).get._2,args(6).toInt) - p.gID = gID; p } - case "divisor" => { val p = new DivisorParam(pname,args(4).toInt,args(5).toInt,args(6).toInt,space.find(i => i._3 == args(7).toInt).get._2) - p.gID = gID; p } - case "enum" => { val p = new EnumParam(pname,args(4),args.slice(5,args.length).toList) - p.gID = gID; p } - case _ => { throw new ParamInvalidException("Unknown parameter"); new ValueParam("error",0) } - } - space += ((mname,param,gID.toInt)) - } - space - } - - def toStringParam(param: Param[Any]):String = { - param match { - case ValueParam(pname, init) => - "value," + param.gID + "," + pname + "," + init - case RangeParam(pname, init, min, max) => - "range," + param.gID + "," + pname + "," + init + "," + min + "," + max - case LessParam(pname, init, min, par) => - "less," + param.gID + "," + pname + "," + init + "," + min + "," + par.gID - case LessEqParam(pname, init, min, par) => - "lesseq," + param.gID + "," + pname + "," + init + "," + min + "," + par.gID - case GreaterParam(pname, init, par, max) => - "great," + param.gID + "," + pname + "," + init + "," + par.gID + "," + max - case GreaterEqParam(pname, init, par, max) => - "greateq," + param.gID + "," + pname + "," + init + "," + par.gID + "," + max - case DivisorParam(pname, init, min, max, par) => - "divisor," + param.gID + "," + pname + "," + init + "," + min + "," + max + "," + par.gID - case EnumParam(pname, init, values) => - "enum," + param.gID + "," + pname + "," + init + "," + values.mkString(",") - case _ => - throw new ParamInvalidException("Unknown parameter class!"); "" - } - } - - val spaceName = "space.prm" -} diff --git a/src/main/scala/Literal.scala b/src/main/scala/Literal.scala deleted file mode 100644 index fff2780b..00000000 --- a/src/main/scala/Literal.scala +++ /dev/null @@ -1,199 +0,0 @@ -package Chisel -import scala.math.log -import scala.math.abs -import scala.math.ceil -import scala.math.max -import scala.math.min -import Literal._ -import ChiselError._ - -/* Factory for literal values to be used by Bits and SInt factories. */ -object Lit { - def apply[T <: Bits](n: String)(gen: => T): T = { - makeLit(Literal(n, -1))(gen) - } - - def apply[T <: Bits](n: String, width: Int)(gen: => T): T = { - makeLit(Literal(n, width))(gen) - } - - def apply[T <: Bits](n: String, base: Char)(gen: => T): T = { - makeLit(Literal(-1, base, n))(gen) - } - - def apply[T <: Bits](n: String, base: Char, width: Int)(gen: => T): T = { - makeLit(Literal(width, base, n))(gen) - } - - def apply[T <: Bits](n: BigInt)(gen: => T): T = { - makeLit(Literal(n, signed = gen.isInstanceOf[SInt]))(gen) - } - - def apply[T <: Bits](n: BigInt, width: Int)(gen: => T): T = { - val lit = Literal(n, width, signed = gen.isInstanceOf[SInt]) - makeLit(lit)(gen) - } - - def makeLit[T <: Bits](x: Literal)(gen: => T): T = { - gen.makeLit(x.value, x.width) - } -} - -class Literal(val value: BigInt, val width: Int) { } - -object Literal { - - private def bigMax(x: BigInt, y: BigInt): BigInt = if (x > y) x else y; - def sizeof(x: BigInt): Int = { - val y = bigMax(BigInt(1), x.abs).toDouble; - val res = max(1, (ceil(log(y + 1)/log(2.0))).toInt); - res - } - - private def sizeof(base: Char, x: String): Int = { - var res = 0; - var first = true; - val size = - if(base == 'b') { - 1 - } else if(base == 'h') { - 4 - } else if(base == 'o') { - 3 - } else { - -1 - } - for(c <- x) - if (c == '_') { - - } else if(first) { - first = false; - res += sizeof(c.asDigit); - } else if (c != '_') { - res += size; - } - res - } - val hexNibbles = "0123456789abcdef"; - def toHexNibble(x: String, off: Int): Char = { - var res = 0; - for (i <- 0 until 4) { - val idx = off + i; - val c = if (idx < 0) '0' else x(idx); - res = 2 * res + (if (c == '1') 1 else 0); - } - hexNibbles(res) - } - val pads = Vector(0, 3, 2, 1); - def toHex(x: String): String = { - var res = ""; - val numNibbles = (x.length-1) / 4 + 1; - val pad = pads(x.length % 4); - for (i <- 0 until numNibbles) { - res += toHexNibble(x, i*4 - pad); - } - res - } - def toLitVal(x: String): BigInt = { - BigInt(x.substring(2, x.length), 16) - } - - def toLitVal(x: String, shamt: Int): BigInt = { - var res = BigInt(0); - for(c <- x) - if(c != '_'){ - if(!(hexNibbles + "?").contains(c.toLower)) ChiselError.error({"Literal: " + x + " contains illegal character: " + c}); - res = res * shamt + c.asDigit; - } - res - } - - def removeUnderscore(x: String): String = { - var res = "" - for(c <- x){ - if(c != '_'){ - res = res + c - } - } - res - } - - def parseLit(x: String): (String, String, Int) = { - var bits = ""; - var mask = ""; - var width = 0; - for (d <- x) { - if (d != '_') { - if(!"01?".contains(d)) ChiselError.error({"Literal: " + x + " contains illegal character: " + d}); - width += 1; - mask = mask + (if (d == '?') "0" else "1"); - bits = bits + (if (d == '?') "0" else d.toString); - } - } - (bits, mask, width) - } - def stringToVal(base: Char, x: String): BigInt = { - if(base == 'x') { - toLitVal(x, 16); - } else if(base == 'd') { - BigInt(x.toInt) - } else if(base == 'h') { - toLitVal(x, 16) - } else if(base == 'b') { - toLitVal(x, 2) - } else if(base == 'o') { - toLitVal(x, 8) - } else { - BigInt(-1) - } - } - - /** Derive the bit length for a Literal - * - */ - def bitLength(b: BigInt): Int = { - // Check for signedness - // We have seen unexpected values (one too small) when using .bitLength on negative BigInts, - // so use the positive value instead. - val usePositiveValueForBitLength = false - (if (usePositiveValueForBitLength && b < 0) { - -b - } else { - b - }).bitLength - } - /** Creates a *Literal* instance from a scala integer. - */ - def apply(x: BigInt, width: Int = -1, signed: Boolean = false): Literal = { - // Check for signedness - // We get unexpected values (one too small) when using .bitLength on negative BigInts, - // so use the positive value instead. - val bl = bitLength(x) - val xWidth = if (signed) { - bl + 1 - } else { - max(bl, 1) - } - val w = if(width == -1) xWidth else width - val xString = (if (x >= 0) x else (BigInt(1) << w) + x).toString(16) - - if(xWidth > width && width != -1) { - // Is this a zero-width wire with value 0 - if (!(x == 0 && width == 0 && Driver.isSupportW0W)) { - ChiselError.error({"width " + width + " is too small for literal " + x + ". Smallest allowed width is " + xWidth}); - } - } - apply("h" + xString, w) - } - def apply(n: String, width: Int): Literal = - apply(width, n(0), n.substring(1, n.length)); - - def apply(width: Int, base: Char, literal: String): Literal = { - if (!"dhbo".contains(base)) { - ChiselError.error("no base specified"); - } - new Literal(stringToVal(base, literal), width) - } -} - - diff --git a/src/main/scala/Parameters.scala b/src/main/scala/Parameters.scala deleted file mode 100644 index 9a117ee0..00000000 --- a/src/main/scala/Parameters.scala +++ /dev/null @@ -1,644 +0,0 @@ -/* - Constructing Hardware in a Scala Embedded Language, Copyright (c) 2014, The - Regents of the University of California, through Lawrence Berkeley National - Laboratory (subject to receipt of any required approvals from the U.S. Dept. - of Energy). All rights reserved. - - If you have questions about your rights to use or distribute this software, - please contact Berkeley Lab's Technology Transfer Department at TTD@lbl.gov. - - NOTICE. This software is owned by the U.S. Department of Energy. As such, - the U.S. Government has been granted for itself and others acting on its - behalf a paid-up, nonexclusive, irrevocable, worldwide license in the Software - to reproduce, prepare derivative works, and perform publicly and display - publicly. Beginning five (5) years after the date permission to assert - copyright is obtained from the U.S. Department of Energy, and subject to any - subsequent five (5) year renewals, the U.S. Government is granted for itself - and others acting on its behalf a paid-up, nonexclusive, irrevocable, - worldwide license in the Software to reproduce, prepare derivative works, - distribute copies to the public, perform publicly and display publicly, and to - permit others to do so. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - (1) Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - (3) Neither the name of the University of California, Lawrence Berkeley - National Laboratory, U.S. Dept. of Energy nor the names of its contributors - may be used to endorse or promote products derived from this software without - specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You are under no obligation whatsoever to provide any bug fixes, patches, or - upgrades to the features, functionality or performance of the source code - ("Enhancements") to anyone; however, if you choose to make your Enhancements - available either publicly, or directly to Lawrence Berkeley National - Laboratory, without imposing a separate written license agreement for such - Enhancements, then you hereby grant the following license: a non-exclusive, - royalty-free perpetual license to install, use, modify, prepare derivative - works, incorporate into other computer software, distribute, and sublicense - such enhancements or derivative works thereof, in binary and source code form. - - Authors: J. Bachan, A. Izraelevitz, H. Cook -*/ - -package Chisel - -import scala.collection.immutable.{Seq=>Seq, Iterable=>Iterable} -import scala.{collection=>readonly} -import scala.collection.mutable - -// Convention: leading _'s on names means private to the outside world -// but accessible to anything in this file. - -abstract trait UsesParameters { - def params: Parameters -} - -class ParameterUndefinedException(field:Any, cause:Throwable=null) - extends RuntimeException("Parameter " + field + " undefined.", cause) -class KnobUndefinedException(field:Any, cause:Throwable=null) - extends RuntimeException("Knob " + field + " undefined.", cause) - -// Knobs are top level free variables that go into the constraint solver. -final case class Knob[T](name:Any) - - -class ChiselConfig( - val topDefinitions: World.TopDefs = { (a,b,c) => {throw new scala.MatchError(a)}}, - val topConstraints: List[ViewSym=>Ex[Boolean]] = List( ex => ExLit[Boolean](true) ), - val knobValues: Any=>Any = { case x => {throw new scala.MatchError(x)}} -) { - import Implicits._ - type Constraint = ViewSym=>Ex[Boolean] - - def this(that: ChiselConfig) = this(that.topDefinitions, - that.topConstraints, - that.knobValues) - - def ++(that: ChiselConfig) = { - new ChiselConfig(this.addDefinitions(that.topDefinitions), - this.addConstraints(that.topConstraints), - this.addKnobValues(that.knobValues)) - } - - def addDefinitions(that: World.TopDefs): World.TopDefs = { - (pname,site,here) => { - try this.topDefinitions(pname, site, here) - catch { - case e: scala.MatchError => that(pname, site, here) - } - } - } - - def addConstraints(that: List[Constraint]):List[Constraint] = { - this.topConstraints ++ that - } - - - def addKnobValues(that: Any=>Any): Any=>Any = { case x => - try this.knobValues(x) - catch { - case e: scala.MatchError => that(x) - } - } - -} - -object Dump { - val dump = mutable.Set[Tuple2[Any,Any]]() - val knobList = mutable.ListBuffer[Any]() - def apply[T](key:Any,value:T):T = {addToDump(key,value); value} - def apply[T](knob:Knob[T]):Knob[T] = {knobList += knob.name; knob} - def addToDump(key:Any,value:Any) = dump += ((key,value)) - def getDump:String = dump.map(_.toString).reduce(_+"\n"+_) + "\n" -} - -// objects given to the user in mask functions (site,here,up) -abstract class View { - // the list of classes in our current path down the heirarchy - def path: List[Class[_]] - - protected val deftSite: View // when views are queried without a specifying a site this is the default - - // use `this` view's behavior to query for a parameters value as if - // the original site were `site` - def apply[T](pname:Any, site:View):T - def sym[T](pname:Any, site:View):Ex[T] - - // query for a parameters value using the default site - final def apply[T](pname:Any):T = apply[T](pname, deftSite) - final def apply[T](field:Field[T]):T = apply[T](field.asInstanceOf[Any], deftSite) - - final def sym[T](pname:Any):Ex[T] = sym[T](pname, deftSite) - final def sym[T](field:Field[T]):Ex[T] = sym[T](field.asInstanceOf[Any], deftSite) -} - -/* Wrap a View to make the application return the symbolic expression, - * basically a shorthand to save typing '.sym' - * before: - * val v: View - * v.sym[Int]("x") // returns Ex[_] - * now: - * val vs = ViewSym(v) - * vs[Int]("xs") // Ex[_] -*/ -final case class ViewSym(view:View) { - def apply[T](f:Any):Ex[T] = view.sym[T](f) - def apply[T](f:Field[T]):Ex[T] = view.sym[T](f) - def apply[T](f:Any, site:View):Ex[T] = view.sym[T](f, site) - def apply[T](f:Field[T], site:View):Ex[T] = view.sym[T](f, site) -} - - -// internal type to represent functions that evaluate parameter values -abstract class _Lookup { - var path:List[Class[_]] = null - - def apply[T](pname:Any, site:View):Ex[T] - - // build a new Lookup that just defers to this one - final def push() = { - val me = this - new _Lookup { - this.path = me.path - def apply[T](pname:Any, site:View) = me.apply(pname, site) - } - } -} - -// Internal type used as name in all ExVar[T]'s -sealed abstract class _Var[T] - -// Variables which are 'free' parameters when seen from the top level. -final case class _VarKnob[T](kname:Any) extends _Var[T] { - override def toString = kname.toString -} -// Variables whose values are computed by `expr`. The term 'let' comes -// from the idea of 'let' bindings in functional languages i.e.: -final case class _VarLet[T](pname:Any,expr:Ex[T]) extends _Var[T] { - override def toString = pname.toString + "{" + expr.toString + "}" -} - - -object World { - // An alias for the type of function provided by user to describe parameters that - // reach the top level. The return of this function can be either: - // Knob(k): this parameter maps to the constraint variable `k` - // Ex: this parameter is computed using the expression - // Any(thing else): variable takes a literal value - type TopDefs = (/*pname:*/Any,/*site:*/View,/*here:*/View) => Any/*Knob[_] | Ex[_] | Any*/ -} - -// Worlds collect the variable definitions and constraints seen when building hardware. -abstract class World( - topDefs: World.TopDefs - ) { - - val _knobs = new mutable.HashSet[Any] - abstract class _View extends View { - val look: _Lookup - def path = look.path - - def apply[T](pname:Any, site:View):T = { - _eval(look(pname, site).asInstanceOf[Ex[T]]) - } - def sym[T](pname:Any, site:View):Ex[T] = { - _bindLet[T](pname,look(pname, site).asInstanceOf[Ex[T]]) - } - } - - // evaluate an expression against this world - def _eval[T](e:Ex[T]):T = { - Ex.eval(e, { - case v:_VarKnob[_] => { - _knobs += v.kname - val e = _knobValue(v.kname) - if(Dump.knobList.contains(v.kname)) {Dump.addToDump(v.kname,e);e} else e - } - case v:_VarLet[_] => _eval(v.expr.asInstanceOf[Ex[T]]) - }) - } - - // create a view whose default site is itself - def _siteView(look:_Lookup):View = { - val _look = look - new _View { - val look = _look - val deftSite = this - } - } - - // create a View which with a supplied default site - def _otherView(look:_Lookup, deftSite:View):View = { - val _look = look - val _deft = deftSite - new _View { - val look = _look - val deftSite = _deft - } - } - - // the top level lookup - def _topLook():_Lookup = { - class TopLookup extends _Lookup { - this.path = Nil - - def apply[T](pname:Any, site:View):Ex[T] = { - val here = _otherView(this, site) - ( - try topDefs(pname, site, here) - catch { - case e:scala.MatchError => throw new ParameterUndefinedException(pname, e) - } - ) match { - case k:Knob[T] => ExVar[T](_VarKnob[T](k.name)) - case ex:Ex[T] => _bindLet[T](pname,ex) - case lit => ExLit(lit.asInstanceOf[T]) - } - } - } - new TopLookup - } - - def _bindLet[T](pname:Any,expr:Ex[T]):Ex[T] - - def _constrain(e:Ex[Boolean]):Unit - - def _knobValue(kname:Any):Any - - def getConstraints:String = "" - - def getKnobs:String = "" -} - -// a world responsible for collecting all constraints in the first pass -class Collector( - topDefs: World.TopDefs, - knobVal: Any=>Any // maps knob names to default-values - ) - extends World(topDefs) { - - val _constraints = new mutable.HashSet[Ex[Boolean]] - - def knobs():List[Any] = { - _knobs.toList - } - - def constraints():List[Ex[Boolean]] = { - _constraints.toList - } - - def _bindLet[T](pname:Any,expr:Ex[T]):Ex[T] = { - expr match { - case e:ExVar[T] => expr - case e:ExLit[T] => expr - case _ => ExVar[T](_VarLet[T](pname,expr)) - } - } - - def _constrain(c:Ex[Boolean]) = { - _constraints += c // add the constraint - - // Also add all equality constraints for all bound variables in the - // constraint expression and do it recursively for all expressions - // being bound to. - var q = List[Ex[_]](c) - while(!q.isEmpty) { - val e = q.head // pop an expression - q = q.tail - // walk over the variables in `e` - for(e <- Ex.unfurl(e)) { - e match { - case ExVar(_VarLet(p,e1)) => { - // form the equality constraint - val c1 = ExEq[Any](e.asInstanceOf[Ex[Any]], e1.asInstanceOf[Ex[Any]]) - // recurse into the expression if its never been seen before - if(!_constraints.contains(c1)) { - _constraints += c1 - q ::= e1 // push - } - } - case _ => {} - } - } - } - } - - def _knobValue(kname:Any) = { - try knobVal(kname) - catch { - case e:scala.MatchError => throw new KnobUndefinedException(kname, e) - } - } - - override def getConstraints:String = if(constraints.isEmpty) "" else constraints.map("( " + _.toString + " )").reduce(_ +"\n" + _) + "\n" - - override def getKnobs:String = if(knobs.isEmpty) "" else { - knobs.map(_.toString).reduce(_ + "\n" + _) + "\n" - } -} - -// a world instantianted to a specific mapping of knobs to values -class Instance( - topDefs: World.TopDefs, - knobVal: Any=>Any - ) - extends World(topDefs) { - - def _bindLet[T](pname:Any,expr:Ex[T]):Ex[T] = expr - def _constrain(e:Ex[Boolean]) = {} - def _knobValue(kname:Any) = { - try knobVal(kname) - catch { - case e:scala.MatchError => throw new KnobUndefinedException(kname, e) - } - } -} - -object Parameters { - def root(w:World) = { - new Parameters(w, w._topLook()) - } - def empty = Parameters.root(new Collector((a,b,c) => {throw new ParameterUndefinedException(a); a},(a:Any) => {throw new KnobUndefinedException(a); a})) - - // Mask making helpers - - // Lift a regular function into a mask by looking for MatchError's and - // interpreting those as calls to up - def makeMask(mask:(Any,View,View,View)=>Any) = { - (f:Any, site:View, here:View, up:View) => { - try mask(f,site,here,up) - catch {case e:MatchError => up.sym[Any](f, site)} - } - } - - // Lift a Map to be a mask. - def makeMask(mask:Map[Any,Any]) = { - (f:Any, site:View, here:View, up:View) => { - mask.get(f) match { - case Some(y) => y - case None => up.sym[Any](f, site) - } - } - } - - // Lift a PartialFunction to be a mask. - def makeMask(mask:PartialFunction[Any,Any]) = { - (f:Any, site:View, here:View, up:View) => { - - if(mask.isDefinedAt(f)) - mask.apply(f) - else { - up.sym[Any](f, site) - } - } - } -} - -class Field[T] - -final class Parameters( - private val _world: World, - private val _look: _Lookup - ) { - - private def _site() = _world._siteView(_look) - - // Create a new Parameters that just defers to this one. This is identical - // to doing an `alter` but not overriding any values. - def push():Parameters = - new Parameters(_world, _look.push()) - - // parameter's paths should be immutable but I foresee that not being sufficient - // when integrated into the chisel Module factory. - def path = _look.path - def path_=(x:List[Class[_]]) = - _look.path = x - - def apply[T](field:Any):T = - _world._eval(_look(field, _site())).asInstanceOf[T] - - def apply[T](field:Field[T]):T = - _world._eval(_look(field, _site())).asInstanceOf[T] - - def constrain(gen:ViewSym=>Ex[Boolean]) = { - val g = gen(new ViewSym(_site())) - if(!_world._eval(g)) ChiselError.error("Constraint failed: " + g.toString) - _world._constrain(g) - } - - private def _alter(mask:(/*field*/Any,/*site*/View,/*here*/View,/*up*/View)=>Any) = { - class KidLookup extends _Lookup { - this.path = _look.path - - def apply[T](f:Any, site:View):Ex[T] = { - val here = _world._otherView(this, site) - val up = _world._otherView(_look, site) - - mask(f, site, here, up) match { - case e:Ex[T] => e - case lit => ExLit(lit.asInstanceOf[T]) - } - } - } - - new Parameters(_world, new KidLookup) - } - - def alter(mask:(/*field*/Any,/*site*/View,/*here*/View,/*up*/View)=>Any) = - _alter(Parameters.makeMask(mask)) - - def alter[T](mask:Map[T,Any]) = - _alter(Parameters.makeMask(mask.asInstanceOf[Map[Any,Any]])) - - def alterPartial(mask:PartialFunction[Any,Any]) = - _alter(Parameters.makeMask(mask)) -} - - -/* - Expression Library -*/ -abstract class Ex[T] { - override def toString = Ex.pretty(this) -} - -case class IntEx (expr:Ex[Int]) { - def === (x:IntEx):Ex[Boolean] = (ExEq[Int](expr,x.expr)) - def + (x:IntEx):Ex[Int] = ExAdd(expr,x.expr) - def - (x:IntEx):Ex[Int] = ExSub(expr,x.expr) - def * (x:IntEx):Ex[Int] = ExMul(expr,x.expr) - def % (x:IntEx):Ex[Int] = ExMod(expr,x.expr) - def < (x:IntEx):Ex[Boolean] = ExLt(expr,x.expr) - def > (x:IntEx):Ex[Boolean] = ExGt(expr,x.expr) - def <= (x:IntEx):Ex[Boolean] = ExLte(expr,x.expr) - def >= (x:IntEx):Ex[Boolean] = ExGte(expr,x.expr) - def in (x:List[IntEx]):Ex[Boolean] = { - val canBound = x.map(_.expr match { - case e:ExVar[_] => false - case _ => true - }).reduce(_ && _) - if (canBound) { - val max = x.map(i => Ex.eval(i.expr,(x:Any)=>null)).max - val min = x.map(i => Ex.eval(i.expr,(x:Any)=>null)).min - ExAnd(IntEx(expr) in Range(min,max), IntEx(expr) _in x) - } else { - IntEx(expr) _in x - } - } - def in (x:Range):Ex[Boolean] = ExAnd(ExGte(expr,ExLit[Int](x.min)),ExLte(expr,ExLit[Int](x.max))) - private def _in (x:List[IntEx]):Ex[Boolean] = { - if (x.isEmpty) ExLit[Boolean](false) else { - ExOr(IntEx(expr) === x.head,IntEx(expr) _in x.tail) - } - } -} - -case class BoolEx (expr:Ex[Boolean]) { - def && (x:BoolEx):Ex[Boolean] = ExAnd(expr,x.expr) - def || (x:BoolEx):Ex[Boolean] = ExOr(expr,x.expr) - def ^ (x:BoolEx):Ex[Boolean] = ExXor(expr,x.expr) - def === (x:BoolEx):Ex[Boolean] = ExEq[Boolean](expr,x.expr) - def !== (x:BoolEx):Ex[Boolean] = ExEq[Boolean](expr,x.expr) -} - -object Implicits { - implicit def ExInt_IntEx(i:Ex[Int]):IntEx = IntEx(i) - implicit def Int_IntEx(i:Int):IntEx = IntEx(ExLit[Int](i)) - implicit def ExBool_BoolEx(b:Ex[Boolean]):BoolEx = BoolEx(b) - implicit def Bool_IntEx(b:Boolean):BoolEx = BoolEx(ExLit[Boolean](b)) - - implicit def ListInt_ListExInt(l:List[Int]):List[IntEx] = l.map((x:Int) => IntEx(ExLit[Int](x))) - implicit def ListExInt_ListExInt(l:List[Ex[Int]]):List[IntEx] = l.map((x:Ex[Int]) => IntEx(x)) -} - -final case class ExLit[T](value:T) extends Ex[T] -final case class ExVar[T](name:Any) extends Ex[T] - -final case class ExAnd(a:Ex[Boolean], b:Ex[Boolean]) extends Ex[Boolean] -final case class ExOr(a:Ex[Boolean], b:Ex[Boolean]) extends Ex[Boolean] -final case class ExXor(a:Ex[Boolean], b:Ex[Boolean]) extends Ex[Boolean] - -final case class ExEq[T](a:Ex[T], b:Ex[T]) extends Ex[Boolean] -final case class ExNeq[T](a:Ex[T], b:Ex[T]) extends Ex[Boolean] - -final case class ExLt(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean] -final case class ExLte(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean] -final case class ExGt(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean] -final case class ExGte(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean] -final case class ExAdd(a:Ex[Int], b:Ex[Int]) extends Ex[Int] -final case class ExSub(a:Ex[Int], b:Ex[Int]) extends Ex[Int] -final case class ExMul(a:Ex[Int], b:Ex[Int]) extends Ex[Int] -final case class ExMod(a:Ex[Int], b:Ex[Int]) extends Ex[Int] - -object Ex { - // evaluate an expression given a context that maps variable names to values - def eval[T](e:Ex[T], ctx:Any=>Any):T = e match { - case ExLit(v) => v.asInstanceOf[T] - case ExVar(nm) => ctx(nm).asInstanceOf[T] - case ExAnd(a,b) => eval(a,ctx) && eval(b,ctx) - case ExOr(a,b) => eval(a,ctx) || eval(b,ctx) - case ExXor(a,b) => eval(a,ctx) ^ eval(b,ctx) - case e:ExEq[u] => eval(e.a,ctx) == eval(e.b,ctx) - case e:ExNeq[u] => eval(e.a,ctx) != eval(e.b,ctx) - case ExLt(a,b) => eval(a,ctx) < eval(b,ctx) - case ExLte(a,b) => eval(a,ctx) <= eval(b,ctx) - case ExGt(a,b) => eval(a,ctx) > eval(b,ctx) - case ExGte(a,b) => eval(a,ctx) >= eval(b,ctx) - case ExAdd(a,b) => eval(a,ctx) + eval(b,ctx) - case ExSub(a,b) => eval(a,ctx) - eval(b,ctx) - case ExMul(a,b) => eval(a,ctx) * eval(b,ctx) - case ExMod(a,b) => eval(a,ctx) % eval(b,ctx) - } - - // get shallow list of subexpressions - def subExs(e:Ex[_]):List[Ex[_]] = e match { - case ExLit(_) => Nil - case ExVar(_) => Nil - case ExAnd(a,b) => List(a,b) - case ExOr(a,b) => List(a,b) - case ExXor(a,b) => List(a,b) - case ExEq(a,b) => List(a,b) - case ExNeq(a,b) => List(a,b) - case ExLt(a,b) => List(a,b) - case ExLte(a,b) => List(a,b) - case ExGt(a,b) => List(a,b) - case ExGte(a,b) => List(a,b) - case ExAdd(a,b) => List(a,b) - case ExSub(a,b) => List(a,b) - case ExMul(a,b) => List(a,b) - case ExMod(a,b) => List(a,b) - } - - // get all subexpressions including the expression given - def unfurl(e:Ex[_]):List[Ex[_]] = - e :: (subExs(e) flatMap unfurl) - - // pretty-print expression - def pretty(e:Ex[_]):String = { - // precedence rank for deciding where to put parentheses - def rank(e:Ex[_]):Int = e match { - case e:ExAnd => 40 - case e:ExOr => 50 - case e:ExXor => 50 - case e:ExEq[_] => 30 - case e:ExNeq[_] => 30 - case e:ExLt => 30 - case e:ExLte => 30 - case e:ExGt => 30 - case e:ExGte => 30 - case e:ExAdd => 20 - case e:ExSub => 20 - case e:ExMul => 20 - case e:ExMod => 20 - case e:ExLit[_] => 0 - case e:ExVar[_] => 0 - } - - val r = rank(e) - - def term(t:Ex[_]):String = { - val rt = rank(t) - //if(rt >= r) - "( " + t.toString + " )" - //else - //t.toString - } - - import Implicits._ - e match { - case ExLit(v) => v.toString - case e:ExVar[_]=> "$"+e.name - case ExAnd(a,b) => term(a)+" && "+term(b) - case ExOr(a,b) => term(a)+" || "+term(b) - case ExXor(a,b) => term(a)+" ^ "+term(b) - case ExEq(a,b) => term(a)+" = "+term(b) - case ExNeq(a,b) => term(a)+" != "+term(b) - case ExLt(a,b) => term(a)+" < "+term(b) - case ExLte(a,b) => term(a)+" <= "+term(b) - case ExGt(a,b) => term(a)+" > "+term(b) - case ExGte(a,b) => term(a)+" >= "+term(b) - case ExAdd(a,b) => term(a)+" + "+term(b) - case ExSub(a,b) => term(a)+" - "+term(b) - case ExMul(a,b) => term(a)+" * "+term(b) - case ExMod(a,b) => term(a)+" % "+term(b) - } - } -} diff --git a/src/main/scala/Params.scala b/src/main/scala/Params.scala deleted file mode 100644 index 9f98c336..00000000 --- a/src/main/scala/Params.scala +++ /dev/null @@ -1,195 +0,0 @@ -/* - Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of - California (Regents). All Rights Reserved. Redistribution and use in - source and binary forms, with or without modification, are permitted - provided that the following conditions are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer in the documentation and/or other materials - provided with the distribution. - * Neither the name of the Regents nor the names of its contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - - IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, - SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, - ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF - REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF - ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION - TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR - MODIFICATIONS. -*/ - -/* Unfinished. Has 3 basic parameters available */ -package Chisel - -import Builder._ -// import Node._ -import Module._ -import JHFormat._ - -import scala.collection.mutable.HashMap -import scala.collection.mutable.ArrayBuffer - -import java.lang.reflect.{Type, ParameterizedType} - -import scala.io.Source -import java.io._ - -//>Params.scala: Implementation of parameter framework. Defines case class - //containers for parameter types. Params object is what actually stores - //the data structures of parameters, whether they are generated from a Chisel - //design, or read from a json file - -case class ParamInvalidException(msg: String) extends Exception - -abstract class Param[+T] { - def init: T - def max: Int - def min: Int - def pname: String - var index: Int = -2 - var gID: Int = -1 - var register = Params.register(getComponent(), pname, this) - //def register(pName: String) = { pname = pName; Params.register(jack.getComponent(), pname, this)} - def getValue: T = Params.getValue(getComponent(),this.pname,this).asInstanceOf[T] -} - -case class ValueParam(pname:String, init: Any) extends Param[Any] { - val max = init.toString.toInt - val min = init.toString.toInt -} - -case class RangeParam(pname:String, init: Int, min: Int, max: Int) extends Param[Int] - -case class LessParam(pname:String, init: Int, min: Int, par: Param[Any]) extends Param[Int] { - val max = par.max -} - -case class LessEqParam(pname:String, init: Int, min: Int, par: Param[Any]) extends Param[Int] { - val max = par.max -} - -case class GreaterParam(pname:String, init: Int, par: Param[Any], max: Int) extends Param[Int] { - val min = par.min -} - -case class GreaterEqParam(pname:String, init: Int, par: Param[Any], max: Int) extends Param[Int] { - val min = par.min -} - -case class DivisorParam(pname:String, init: Int, min: Int, max: Int, par: Param[Any]) extends Param[Int] - -case class EnumParam(pname:String, init: String, values: List[String]) extends Param[String] { - val max = init.toString.toInt - val min = init.toString.toInt -} - -object IntParam { - def apply(name: String, init: Int) = RangeParam(name, init, init, init) -} - -object Params { - type Space = JHFormat.Space - var space = new Space - var design = new Space - var modules = new HashMap[String, Module] - var gID: Int = 0 - - var buildingSpace = true - - def getValue(module: Module, pname: String, p: Param[Any]) = { - val mname= if(module == null) "TOP" else {module.getClass.getName} - if(buildingSpace) p.init - else{ - val x = design.find(t => (t._3) == (p.gID)) - if(x.isEmpty){ - throw new ParamInvalidException("Missing parameter " + pname + " in Module " + mname) - } else { - x.get._2.init - } - } - } - - def register(module: Module, pname: String, p: Param[Any]) = { - val mname= if(module == null) "TOP" else {module.getClass.getName} - modules(mname) = module - if(buildingSpace) { - space += ((mname,p,gID)) - } - p.gID = gID - gID += 1 - p - } - - def dump_file(filename: String, design: Space) = { - val string = JHFormat.serialize(design) - val writer = new PrintWriter(new File(filename)) - println("Dumping to " + filename + ":\n" + string) - writer.write(string) - writer.close() - } - - def dump(dir: String) = { - buildingSpace = false - dump_file(dir + "/" + JHFormat.spaceName, Params.space) - } - def load(designName: String) = { - buildingSpace = false - design = JHFormat.deserialize(designName) - gID = 0 - } - - def toCxxStringParams : String = { - var string = new StringBuilder("") - for ((mname, p, gID) <- space) { - val rmname = if (mname == "TOP") "" else modules(mname).name + "__"; - string ++= "const int " + rmname + p.pname + " = " + toCxxStringParam(p) + ";\n" - } - string.toString - } - - def toDotpStringParams : String = { - var string = new StringBuilder("") - for ((mname, p, gID) <- space) { - val rmname = if (mname == "TOP") "" else modules(mname).name + ":"; - string ++= rmname + p.pname + " = " + toCxxStringParam(p) + "\n" - } - string.toString - } - - - def toCxxStringParam(param: Param[Any]) = { - param match { - // case EnumParam(init, list) => - //"(range," + init + "," + list + ")" - // "const int " + name + " = " + init + ";\n" - case ValueParam(pname, init) => - init.toString - case RangeParam(pname, init, min, max) => - init.toString - case LessParam(pname, init, min, par) => - init.toString - case LessEqParam(pname, init, min, par) => - init.toString - case GreaterParam(pname, init, min, par) => - init.toString - case GreaterEqParam(pname, init, min, par) => - init.toString - case DivisorParam(pname, init, min, max, par) => - init.toString - case EnumParam(pname, init, values) => - init.toString - case _ => - throw new ParamInvalidException("Unknown parameter class!"); "" - } - } -} diff --git a/src/main/scala/Tester.scala b/src/main/scala/Tester.scala deleted file mode 100644 index bdeb0f68..00000000 --- a/src/main/scala/Tester.scala +++ /dev/null @@ -1,417 +0,0 @@ -/* - Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of - California (Regents). All Rights Reserved. Redistribution and use in - source and binary forms, with or without modification, are permitted - provided that the following conditions are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - two paragraphs of disclaimer in the documentation and/or other materials - provided with the distribution. - * Neither the name of the Regents nor the names of its contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - - IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, - SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, - ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF - REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF - ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION - TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR - MODIFICATIONS. -*/ - -package Chisel -import Chisel._ -import scala.math._ -import scala.collection.mutable.ArrayBuffer -import scala.collection.mutable.HashMap -import scala.util.Random -import java.io.{File, IOException, InputStream, OutputStream, PrintStream} -import java.lang.Double.longBitsToDouble -import java.lang.Float.intBitsToFloat -import java.lang.Double.doubleToLongBits -import java.lang.Float.floatToIntBits -import scala.sys.process._ -import scala.io.Source._ -import Literal._ - -case class Poke(val node: Data, val index: Int, val value: BigInt); - -class Snapshot(val t: Int) { - val pokes = new ArrayBuffer[Poke]() -} - -class ManualTester[+T <: Module] - (val c: T, val isT: Boolean = true) { - var testIn: InputStream = null - var testOut: OutputStream = null - var testErr: InputStream = null - val sb = new StringBuilder() - var delta = 0 - var t = 0 - var isTrace = isT - - /** - * Waits until the emulator streams are ready. This is a dirty hack related - * to the way Process works. TODO: FIXME. - */ - def waitForStreams() = { - var waited = 0 - while (testOut == null || testIn == null || testErr == null) { - Thread.sleep(100) - if (waited % 10 == 0 && waited > 30) { - println("waiting for emulator process treams to be valid ...") - } - } - } - - // TODO: MOVE TO SOMEWHERE COMMON TO BACKEND - def ensureDir(dir: String): String = { - val d = dir + (if (dir == "" || dir(dir.length-1) == '/') "" else "/") - new File(d).mkdirs() - d - } - def createOutputFile(name: String): java.io.FileWriter = { - val baseDir = ensureDir(Driver.targetDir) - new java.io.FileWriter(baseDir + name) - } - - def puts(str: String) = { - while (testOut == null) { Thread.sleep(100) } - for (e <- str) testOut.write(e); - } - - /** - * Sends a command to the emulator and returns the reply. - * The standard protocol treats a single line as a command, which always - * returns a single line of reply. - */ - def emulatorCmd(str: String): String = { - // validate cmd - if (str contains "\n") { - System.err.print(s"emulatorCmd($str): command should not contain newline") - return "error" - } - - waitForStreams() - - // send command to emulator - for (e <- str) testOut.write(e); - testOut.write('\n'); - testOut.flush() - - // read output from emulator - var c = testIn.read - sb.clear() - while (c != '\n' && c != -1) { - if (c == 0) { - Thread.sleep(100) - } - sb += c.toChar - // Look for a "PRINT" command. - if (sb.length == 6 && sb.startsWith("PRINT ")) { - do { - c = testIn.read - sb += c.toChar - } while (c != ' ') - // Get the PRINT character count. - val printCommand = """^PRINT (\d+) """.r - val printCommand(nChars) = sb.toString - sb.clear() - for (i <- 0 until nChars.toInt) { - c = testIn.read - sb += c.toChar - } - System.out.print(sb.toString()) - sb.clear() - } - c = testIn.read - } - - // drain errors - try { - while(testErr.available() > 0) { - System.err.print(Character.toChars(testErr.read())) - } - } catch { - case e : IOException => testErr = null; println("ERR EXCEPTION") - } - - if (sb == "error") { - System.err.print(s"FAILED: emulatorCmd($str): returned error") - ok = false - } - return sb.toString - } - - /* - def setClocks(clocks: HashMap[Clock, Int]) { - var cmd = "set_clocks" - for (clock <- Driver.clocks) { - if (clock.srcClock == null) { - val s = BigInt(clocks(clock)).toString(16) - cmd = cmd + " " + s - } - } - emulatorCmd(cmd) - // TODO: check for errors in return - } - */ - - def doPeekBits(name: String, off: Int = -1): BigInt = { - if (name == "") { - println("Unable to peek data " + name) // TODO: USE DATA - -1 - } else { - var cmd = "" - if (off != -1) { - cmd = "mem_peek " + name + " " + off; - } else { - cmd = "wire_peek " + name; - } - val s = emulatorCmd(cmd) - val rv = toLitVal(s) - if (isTrace) println(" PEEK " + name + " " + (if (off >= 0) (off + " ") else "") + "-> " + s) - rv - } - } - - def peekBits(data: Data, off: Int = -1): BigInt = { - doPeekBits(data.debugName, off) - } - - def signed_fix(dtype: Element, rv: BigInt): BigInt = { - val w = dtype.width - dtype match { - /* Any "signed" node */ - case _: SInt | _ : Flo | _: Dbl => (if(rv >= (BigInt(1) << w - 1)) (rv - (BigInt(1) << w)) else rv) - /* anything else (i.e., UInt) */ - case _ => (rv) - } - } - - def peekAt[T <: Bits](data: Mem[T], off: Int): BigInt = { - // signed_fix(data(1), peekBits(data, off)) - doPeekBits(data.debugName, off) - } - - def peek(data: Bits): BigInt = { - signed_fix(data, peekBits(data)) - } - - def peek(data: Flo): Float = { - intBitsToFloat(peekBits(data).toInt) - } - - def peek(data: Dbl): Double = { - longBitsToDouble(peekBits(data).toLong) - } - - def peek(data: Aggregate /*, off: Int = -1 */): IndexedSeq[BigInt] = { - data.flatten.map(peek(_)) - } - - def reset(n: Int = 1) = { - emulatorCmd("reset " + n) - // TODO: check for errors in return - if (isTrace) println("RESET " + n) - } - - def doPokeBits(name: String, x: BigInt, off: Int): Unit = { - if (name == "") { - println("Unable to poke data " + name) // TODO: data.toString - } else { - - var cmd = "" - if (off != -1) { - cmd = "mem_poke " + name + " " + off; - } else { - cmd = "wire_poke " + name; - } - // Don't prefix negative numbers with "0x" - val radixPrefix = if (x < 0) " -0x" else " 0x" - val xval = radixPrefix + x.abs.toString(16) - cmd = cmd + xval - if (isTrace) { - println(" POKE " + name + " " + (if (off >= 0) (off + " ") else "") + "<- " + xval) - } - val rtn = emulatorCmd(cmd) - if (rtn != "ok") { - System.err.print(s"FAILED: poke(${name}) returned false") - ok = false - } - } - } - - def pokeAt[T <: Bits](data: Mem[T], x: BigInt, off: Int): Unit = { - doPokeBits(data.debugName, x, off) - } - - def pokeBits(data: Data, x: BigInt, off: Int = -1): Unit = { - doPokeBits(data.debugName, x, off) - } - - def poke(data: Bits, x: BigInt): Unit = { - pokeBits(data, x) - } - - def poke(data: Flo, x: Float): Unit = { - pokeBits(data, BigInt(floatToIntBits(x))) - } - - def poke(data: Dbl, x: Double): Unit = { - pokeBits(data, BigInt(doubleToLongBits(x))) - } - - def poke(data: Aggregate, x: Array[BigInt]): Unit = { - val kv = (data.flatten, x.reverse).zipped; - for ((x, y) <- kv) - poke(x, y) - } - - def step(n: Int) = { - val target = t + n - val s = emulatorCmd("step " + n) - delta += s.toInt - if (isTrace) println("STEP " + n + " -> " + target) - t += n - } - - def int(x: Boolean): BigInt = if (x) 1 else 0 - def int(x: Int): BigInt = x - def int(x: Bits): BigInt = x.litValue() - - var ok = true; - var failureTime = -1 - - def expect (good: Boolean, msg: String): Boolean = { - if (isTrace) - println(msg + " " + (if (good) "PASS" else "FAIL")) - if (!good) { ok = false; if (failureTime == -1) failureTime = t; } - good - } - - def expect (data: Bits, expected: BigInt): Boolean = { - // val mask = (BigInt(1) << data) - 1 - val got = peek(data) - - // expect((got & mask) == (expected & mask), - expect(got == expected, - "EXPECT " + data.debugName + " <- 0x" + got.toString(16) + " == 0x" + expected.toString(16)) - } - - def expect (data: Aggregate, expected: Array[BigInt]): Boolean = { - val kv = (data.flatten, expected.reverse).zipped; - var allGood = true - for ((d, e) <- kv) - allGood = expect(d, e) && allGood - allGood - } - - /* We need the following so scala doesn't use our "tolerant" Float version of expect. - */ - def expect (data: Bits, expected: Int): Boolean = { - expect(data, BigInt(expected)) - } - def expect (data: Bits, expected: Long): Boolean = { - expect(data, BigInt(expected)) - } - def expect (data: Flo, expected: Double): Boolean = { - val got = peek(data) - expect(got == expected, "EXPECT " + data.debugName + " <- " + got + " == " + expected) - } - def expect (data: Dbl, expected: Double): Boolean = { - val got = peek(data) - expect(got == expected, "EXPECT " + data.debugName + " <- " + got + " == " + expected) - } - - /* Compare the floating point value of a node with an expected floating point value. - * We will tolerate differences in the bottom bit. - */ - def expect (data: Bits, expected: Float): Boolean = { - val gotBits = peek(data).toInt - val expectedBits = java.lang.Float.floatToIntBits(expected) - var gotFLoat = java.lang.Float.intBitsToFloat(gotBits) - var expectedFloat = expected - if (gotFLoat != expectedFloat) { - val gotDiff = gotBits - expectedBits - // Do we have a single bit difference? - if (abs(gotDiff) <= 1) { - expectedFloat = gotFLoat - } - } - expect(gotFLoat == expectedFloat, - "EXPECT " + data.debugName + " <- " + gotFLoat + " == " + expectedFloat) - } - - val rnd = if (Driver.testerSeedValid) new Random(Driver.testerSeed) else new Random() - var process: Process = null - - def start(): Process = { - val n = Driver.appendString(Some(c.name),Driver.chiselConfigClassName) - val target = Driver.targetDir + "/" + n - val cmd = target - println("OPENING " + cmd) - /* - (if (Driver.backend.isInstanceOf[FloBackend]) { - val dir = Driver.backend.asInstanceOf[FloBackend].floDir - val command = ArrayBuffer(dir + "fix-console", ":is-debug", "true", ":filename", target + ".hex", ":flo-filename", target + ".mwe.flo") - if (Driver.isVCD) { command ++= ArrayBuffer(":is-vcd-dump", "true") } - if (Driver.emitTempNodes) { command ++= ArrayBuffer(":emit-temp-nodes", "true") } - command ++= ArrayBuffer(":target-dir", Driver.targetDir) - command.mkString(" ") - } else { - target + (if (Driver.backend.isInstanceOf[VerilogBackend]) " -q +vcs+initreg+0 " else "") - }) - */ - println("SEED " + Driver.testerSeed) - println("STARTING " + cmd) - val processBuilder = Process(cmd) - val pio = new ProcessIO(in => testOut = in, out => testIn = out, err => testErr = err) - process = processBuilder.run(pio) - waitForStreams() - t = 0 - reset(5) - // Skip vpd message - if (Driver.backend.isInstanceOf[VerilogBackend] && Driver.isDebug) { - var vpdmsg = testIn.read - while (vpdmsg != '\n' && vpdmsg != -1) - vpdmsg = testIn.read - } - process - } - - def finish(): Boolean = { - if (process != null) { - emulatorCmd("quit") - - if (testOut != null) { - testOut.flush() - testOut.close() - } - if (testIn != null) { - testIn.close() - } - if (testErr != null) { - testErr.close() - } - - process.destroy() - } - println("RAN " + t + " CYCLES " + (if (ok) "PASSED" else { "FAILED FIRST AT CYCLE " + failureTime })) - ok - } -} - -class Tester[+T <: Module](c: T, isTrace: Boolean = true) extends ManualTester(c, isTrace) { - start() -} - diff --git a/src/main/scala/utils.scala b/src/main/scala/utils.scala deleted file mode 100644 index 3bbea34a..00000000 --- a/src/main/scala/utils.scala +++ /dev/null @@ -1,561 +0,0 @@ -package Chisel -import Builder._ -import scala.math._ - -object log2Up -{ - def apply(in: Int): Int = if(in == 1) 1 else ceil(log(in)/log(2)).toInt -} - -object log2Ceil -{ - def apply(in: Int): Int = ceil(log(in)/log(2)).toInt -} - - -object log2Down -{ - def apply(x : Int): Int = if (x == 1) 1 else floor(log(x)/log(2.0)).toInt -} - -object log2Floor -{ - def apply(x : Int): Int = floor(log(x)/log(2.0)).toInt -} - - -object isPow2 -{ - def apply(in: Int): Boolean = in > 0 && ((in & (in-1)) == 0) -} - -object FillInterleaved -{ - def apply(n: Int, in: UInt): UInt = apply(n, in.toBools) - def apply(n: Int, in: Seq[Bool]): UInt = Vec(in.map(Fill(n, _))).toBits -} - -/** Returns the number of bits set (i.e value is 1) in the input signal. - */ -object PopCount -{ - def apply(in: Iterable[Bool]): UInt = { - if (in.size == 0) { - UInt(0) - } else if (in.size == 1) { - in.head - } else { - apply(in.slice(0, in.size/2)) + Cat(UInt(0), apply(in.slice(in.size/2, in.size))) - } - } - def apply(in: Bits): UInt = apply((0 until in.getWidth).map(in(_))) -} - -object RegNext { - - def apply[T <: Data](next: T): T = Reg[T](next, next, null.asInstanceOf[T]) - - def apply[T <: Data](next: T, init: T): T = Reg[T](next, next, init) - -} - -object RegInit { - - def apply[T <: Data](init: T): T = Reg[T](init, null.asInstanceOf[T], init) - -} - -object RegEnable -{ - def apply[T <: Data](updateData: T, enable: Bool) = { - val r = Reg(updateData) - when (enable) { r := updateData } - r - } - def apply[T <: Data](updateData: T, resetData: T, enable: Bool) = { - val r = RegInit(resetData) - when (enable) { r := updateData } - r - } -} - -/** Builds a Mux tree out of the input signal vector using a one hot encoded - select signal. Returns the output of the Mux tree. - */ -object Mux1H -{ - def apply[T <: Data](sel: Iterable[Bool], in: Iterable[T]): T = { - if (in.tail.isEmpty) in.head - else { - val masked = (sel, in).zipped map ((s, i) => Mux(s, i.toBits, Bits(0))) - in.head.fromBits(masked.reduceLeft(_|_)) - } - } - def apply[T <: Data](in: Iterable[(Bool, T)]): T = { - val (sel, data) = in.unzip - apply(sel, data) - } - def apply[T <: Data](sel: Bits, in: Iterable[T]): T = - apply((0 until in.size).map(sel(_)), in) - def apply(sel: Bits, in: Bits): Bool = (sel & in).orR -} - -/** Builds a Mux tree under the assumption that multiple select signals - can be enabled. Priority is given to the first select signal. - - Returns the output of the Mux tree. - */ -object PriorityMux -{ - def apply[T <: Bits](in: Iterable[(Bool, T)]): T = { - if (in.size == 1) { - in.head._2 - } else { - Mux(in.head._1, in.head._2, apply(in.tail)) - } - } - def apply[T <: Bits](sel: Iterable[Bool], in: Iterable[T]): T = apply(sel zip in) - def apply[T <: Bits](sel: Bits, in: Iterable[T]): T = apply((0 until in.size).map(sel(_)), in) -} - -object unless { - def apply(c: Bool)(block: => Unit) { - when (!c) { block } - } -} - -object switch { - def apply(c: Bits)(block: => Unit) { - switchKeys.push(c) - block - switchKeys.pop() - } -} - -object is { - def apply(v: Bits)(block: => Unit): Unit = - apply(Seq(v))(block) - def apply(v: Bits, vr: Bits*)(block: => Unit): Unit = - apply(v :: vr.toList)(block) - def apply(v: Iterable[Bits])(block: => Unit): Unit = { - val keys = switchKeys - if (keys.isEmpty) ChiselError.error("The 'is' keyword may not be used outside of a switch.") - else if (!v.isEmpty) when (v.map(_ === keys.top).reduce(_||_)) { block } - } -} - -object MuxLookup { - def apply[S <: UInt, T <: Bits] (key: S, default: T, mapping: Seq[(S, T)]): T = { - var res = default; - for ((k, v) <- mapping.reverse) - res = Mux(k === key, v, res); - res - } - -} - -object Fill { - def apply(n: Int, x: Bool): UInt = n match { - case 0 => UInt(width=0) - case 1 => x - case x if n > 1 => UInt(0,n) - UInt(x) - case _ => throw new IllegalArgumentException(s"n (=$n) must be nonnegative integer.") - } - def apply(n: Int, y: UInt): UInt = { - n match { - case 0 => UInt(width=0) - case 1 => y - case x if n > 1 => - val p2 = Array.ofDim[UInt](log2Up(n+1)) - p2(0) = y - for (i <- 1 until p2.length) - p2(i) = Cat(p2(i-1), p2(i-1)) - Cat((0 until log2Up(x+1)).filter(i => (x & (1 << i)) != 0).map(p2(_))) - case _ => throw new IllegalArgumentException(s"n (=$n) must be nonnegative integer.") - } - } -} - -object MuxCase { - def apply[T <: Bits] (default: T, mapping: Seq[(Bool, T)]): T = { - var res = default; - for ((t, v) <- mapping.reverse){ - res = Mux(t, v, res); - } - res - } -} - -object ListLookup { - def apply[T <: Data](addr: UInt, default: List[T], mapping: Array[(BitPat, List[T])]): List[T] = { - val map = mapping.map(m => (m._1 === addr, m._2)) - default.zipWithIndex map { case (d, i) => - map.foldRight(d)((m, n) => Mux(m._1, m._2(i), n)) - } - } -} - -object Lookup { - def apply[T <: Bits](addr: UInt, default: T, mapping: Seq[(BitPat, T)]): T = - ListLookup(addr, List(default), mapping.map(m => (m._1, List(m._2))).toArray).head -} - -/** Litte/big bit endian convertion: reverse the order of the bits in a UInt. -*/ -object Reverse -{ - private def doit(in: UInt, length: Int): UInt = { - if (length == 1) { - in - } else if (isPow2(length) && length >= 8 && length <= 64) { - // Do it in logarithmic time to speed up C++. Neutral for real HW. - var res = in - var shift = length >> 1 - var mask = UInt((BigInt(1) << length) - 1, length) - do { - mask = mask ^ (mask(length-shift-1,0) << UInt(shift)) - res = ((res >> UInt(shift)) & mask) | (res(length-shift-1,0) << UInt(shift) & ~mask) - shift = shift >> 1 - } while (shift > 0) - res - } else { - val half = (1 << log2Up(length))/2 - Cat(doit(in(half-1,0), half), doit(in(length-1,half), length-half)) - } - } - def apply(in: UInt): UInt = doit(in, in.getWidth) -} - -/** Returns the n-cycle delayed version of the input signal. - */ -object ShiftRegister -{ - def apply[T <: Data](in: T, n: Int, en: Bool = Bool(true)): T = - { - // The order of tests reflects the expected use cases. - if (n == 1) { - RegEnable(in, en) - } else if (n != 0) { - RegNext(apply(in, n-1, en)) - } else { - in - } - } -} - -/** Returns the one hot encoding of the input UInt. - */ -object UIntToOH -{ - def apply(in: UInt, width: Int = -1): UInt = - if (width == -1) UInt(1) << in - else (UInt(1) << in(log2Up(width)-1,0))(width-1,0) -} - -class Counter(val n: Int) { - val value = if (n == 1) UInt(0) else Reg(init=UInt(0, log2Up(n))) - def inc(): Bool = { - if (n == 1) Bool(true) - else { - val wrap = value === UInt(n-1) - value := Mux(Bool(!isPow2(n)) && wrap, UInt(0), value + UInt(1)) - wrap - } - } -} - -object Counter -{ - def apply(n: Int): Counter = new Counter(n) - def apply(cond: Bool, n: Int): (UInt, Bool) = { - val c = new Counter(n) - var wrap: Bool = null - when (cond) { wrap = c.inc() } - (c.value, cond && wrap) - } -} - -class ValidIO[+T <: Data](gen2: T) extends Bundle -{ - val valid = Bool(OUTPUT) - val bits = gen2.cloneType.asOutput - def fire(dummy: Int = 0): Bool = valid - override def doCloneType: this.type = new ValidIO(gen2).asInstanceOf[this.type] -} - -/** Adds a valid protocol to any interface. The standard used is - that the consumer uses the flipped interface. -*/ -object Valid { - def apply[T <: Data](gen: T): ValidIO[T] = new ValidIO(gen) -} - -class DecoupledIO[+T <: Data](gen: T) extends Bundle -{ - val ready = Bool(INPUT) - val valid = Bool(OUTPUT) - val bits = gen.cloneType.asOutput - def fire(dummy: Int = 0): Bool = ready && valid - override def doCloneType: this.type = new DecoupledIO(gen).asInstanceOf[this.type] -} - -/** Adds a ready-valid handshaking protocol to any interface. - The standard used is that the consumer uses the flipped - interface. - */ -object Decoupled { - def apply[T <: Data](gen: T): DecoupledIO[T] = new DecoupledIO(gen) -} - -class EnqIO[T <: Data](gen: T) extends DecoupledIO(gen) -{ - def enq(dat: T): T = { valid := Bool(true); bits := dat; dat } - override def init(dummy: Int = 0) = { - valid := Bool(false); - for (io <- bits.flatten) - io := UInt(0) - } - override def doCloneType: this.type = { new EnqIO(gen).asInstanceOf[this.type]; } -} - -class DeqIO[T <: Data](gen: T) extends DecoupledIO(gen) -{ - flip() - override def init(dummy: Int = 0) = { - ready := Bool(false) - } - def deq(b: Boolean = false): T = { ready := Bool(true); bits } - override def doCloneType: this.type = { new DeqIO(gen).asInstanceOf[this.type]; } -} - - -class DecoupledIOC[+T <: Data](gen: T) extends Bundle -{ - val ready = Bool(INPUT) - val valid = Bool(OUTPUT) - val bits = gen.cloneType.asOutput -} - -class QueueIO[T <: Data](gen: T, entries: Int) extends Bundle -{ - val enq = Decoupled(gen.cloneType).flip - val deq = Decoupled(gen.cloneType) - val count = UInt(OUTPUT, log2Up(entries + 1)) -} - -class Queue[T <: Data](gen: T, val entries: Int, pipe: Boolean = false, flow: Boolean = false, _reset: Bool = null) extends Module(_reset=_reset) -{ - val io = new QueueIO(gen, entries) - - val ram = Mem(gen, entries) - val enq_ptr = Counter(entries) - val deq_ptr = Counter(entries) - val maybe_full = Reg(init=Bool(false)) - - val ptr_match = enq_ptr.value === deq_ptr.value - val empty = ptr_match && !maybe_full - val full = ptr_match && maybe_full - val maybe_flow = Bool(flow) && empty - val do_flow = maybe_flow && io.deq.ready - - val do_enq = io.enq.ready && io.enq.valid && !do_flow - val do_deq = io.deq.ready && io.deq.valid && !do_flow - when (do_enq) { - ram(enq_ptr.value) := io.enq.bits - enq_ptr.inc() - } - when (do_deq) { - deq_ptr.inc() - } - when (do_enq != do_deq) { - maybe_full := do_enq - } - - io.deq.valid := !empty || Bool(flow) && io.enq.valid - io.enq.ready := !full || Bool(pipe) && io.deq.ready - io.deq.bits := Mux(maybe_flow, io.enq.bits, ram(deq_ptr.value)) - - val ptr_diff = enq_ptr.value - deq_ptr.value - if (isPow2(entries)) { - io.count := Cat(maybe_full && ptr_match, ptr_diff) - } else { - io.count := Mux(ptr_match, Mux(maybe_full, UInt(entries), UInt(0)), Mux(deq_ptr.value > enq_ptr.value, UInt(entries) + ptr_diff, ptr_diff)) - } -} - -/** Generic hardware queue. Required parameter entries controls - the depth of the queues. The width of the queue is determined - from the inputs. - - Example usage: - val q = new Queue(UInt(), 16) - q.io.enq <> producer.io.out - consumer.io.in <> q.io.deq - */ -object Queue -{ - def apply[T <: Data](enq: DecoupledIO[T], entries: Int = 2, pipe: Boolean = false): DecoupledIO[T] = { - val q = Module(new Queue(enq.bits.cloneType, entries, pipe)) - q.io.enq.valid := enq.valid // not using <> so that override is allowed - q.io.enq.bits := enq.bits - enq.ready := q.io.enq.ready - q.io.deq - } -} - -object PriorityEncoderOH -{ - private def encode(in: Seq[Bool]): UInt = { - val outs = Vec.tabulate(in.size)(i => UInt(BigInt(1) << i, in.size)) - PriorityMux(in :+ Bool(true), outs :+ UInt(0, in.size)) - } - def apply(in: Seq[Bool]): Vec[Bool] = { - val enc = encode(in) - Vec.tabulate(in.size)(enc(_)) - } - def apply(in: Bits): UInt = encode((0 until in.getWidth).map(i => in(i))) -} - -class ArbiterIO[T <: Data](gen: T, n: Int) extends Bundle { - val in = Vec(Decoupled(gen), n).flip - val out = Decoupled(gen) - val chosen = UInt(OUTPUT, log2Up(n)) -} - -object ArbiterCtrl -{ - def apply(request: Seq[Bool]): Seq[Bool] = { - Bool(true) +: (1 until request.length).map(i => !request.slice(0, i).foldLeft(Bool(false))(_ || _)) - } -} - -abstract class LockingArbiterLike[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) extends Module { - require(isPow2(count)) - def grant: Seq[Bool] - val io = new ArbiterIO(gen, n) - val locked = if(count > 1) Reg(init=Bool(false)) else Bool(false) - val lockIdx = if(count > 1) Reg(init=UInt(n-1)) else UInt(n-1) - val chosen = Wire(UInt(width = log2Up(n))) - - for ((g, i) <- grant.zipWithIndex) - io.in(i).ready := Mux(locked, lockIdx === UInt(i), g) && io.out.ready - io.out.valid := io.in(chosen).valid - io.out.bits := io.in(chosen).bits - io.chosen := chosen - - if(count > 1){ - val cnt = Reg(init=UInt(0, width = log2Up(count))) - val cnt_next = cnt + UInt(1) - when(io.out.fire()) { - when(needsLock.map(_(io.out.bits)).getOrElse(Bool(true))) { - cnt := cnt_next - when(!locked) { - locked := Bool(true) - lockIdx := Vec(io.in.map{ in => in.fire()}).indexWhere{i: Bool => i} - } - } - when(cnt_next === UInt(0)) { - locked := Bool(false) - } - } - } -} - -class LockingRRArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) extends LockingArbiterLike[T](gen, n, count, needsLock) { - lazy val last_grant = Reg(init=UInt(0, log2Up(n))) - override def grant: Seq[Bool] = { - val ctrl = ArbiterCtrl((0 until n).map(i => io.in(i).valid && UInt(i) > last_grant) ++ io.in.map(_.valid)) - (0 until n).map(i => ctrl(i) && UInt(i) > last_grant || ctrl(i + n)) - } - - var choose = UInt(n-1) - for (i <- n-2 to 0 by -1) - choose = Mux(io.in(i).valid, UInt(i), choose) - for (i <- n-1 to 1 by -1) - choose = Mux(io.in(i).valid && UInt(i) > last_grant, UInt(i), choose) - chosen := Mux(locked, lockIdx, choose) - - when (io.out.fire()) { last_grant := chosen } -} - -class LockingArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) extends LockingArbiterLike[T](gen, n, count, needsLock) { - def grant: Seq[Bool] = ArbiterCtrl(io.in.map(_.valid)) - - var choose = UInt(n-1) - for (i <- n-2 to 0 by -1) { - choose = Mux(io.in(i).valid, UInt(i), choose) - } - chosen := Mux(locked, lockIdx, choose) -} - -/** Hardware module that is used to sequence n producers into 1 consumer. - Producers are chosen in round robin order. - - Example usage: - val arb = new RRArbiter(2, UInt()) - arb.io.in(0) <> producer0.io.out - arb.io.in(1) <> producer1.io.out - consumer.io.in <> arb.io.out - */ -class RRArbiter[T <: Data](gen:T, n: Int) extends LockingRRArbiter[T](gen, n, 1) - -/** Hardware module that is used to sequence n producers into 1 consumer. - Priority is given to lower producer - - Example usage: - val arb = Module(new Arbiter(2, UInt())) - arb.io.in(0) <> producer0.io.out - arb.io.in(1) <> producer1.io.out - consumer.io.in <> arb.io.out - */ -class Arbiter[T <: Data](gen: T, n: Int) extends LockingArbiter[T](gen, n, 1) - -/** linear feedback shift register - */ -object LFSR16 -{ - def apply(increment: Bool = Bool(true)): UInt = - { - val width = 16 - val lfsr = Reg(init=UInt(1, width)) - when (increment) { lfsr := Cat(lfsr(0)^lfsr(2)^lfsr(3)^lfsr(5), lfsr(width-1,1)) } - lfsr - } -} - -/** A hardware module that delays data coming down the pipeline - by the number of cycles set by the latency parameter. Functionality - is similar to ShiftRegister but this exposes a Pipe interface. - - Example usage: - val pipe = new Pipe(UInt()) - pipe.io.enq <> produce.io.out - consumer.io.in <> pipe.io.deq - */ -object Pipe -{ - def apply[T <: Data](enqValid: Bool, enqBits: T, latency: Int): ValidIO[T] = { - if (latency == 0) { - val out = Valid(enqBits) - out.valid <> enqValid - out.bits <> enqBits - out - } else { - val v = Reg(Bool(), next=enqValid, init=Bool(false)) - val b = RegEnable(enqBits, enqValid) - apply(v, b, latency-1) - } - } - def apply[T <: Data](enqValid: Bool, enqBits: T): ValidIO[T] = apply(enqValid, enqBits, 1) - def apply[T <: Data](enq: ValidIO[T], latency: Int = 1): ValidIO[T] = apply(enq.valid, enq.bits, latency) -} - -class Pipe[T <: Data](gen: T, latency: Int = 1) extends Module -{ - val io = new Bundle { - val enq = Valid(gen).flip - val deq = Valid(gen) - } - - io.deq <> Pipe(io.enq, latency) -} -- cgit v1.2.3