summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjackbackrack2015-04-28 23:33:59 -0700
committerjackbackrack2015-04-28 23:33:59 -0700
commit7ada20e324ca75116441d00b575ed217c41cc1c8 (patch)
tree1a486c5782fdf1a58a5f797f4b4b7f780b6febe3 /src
parent189f2a123300f0c2ffe4487bb67c71a08736bd3e (diff)
add params, limited partial eval, conforming to compile riscv-mini
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/Core.scala200
-rw-r--r--src/main/scala/Driver.scala24
-rw-r--r--src/main/scala/FP.scala4
-rw-r--r--src/main/scala/JHFormat.scala105
-rw-r--r--src/main/scala/Parameters.scala644
-rw-r--r--src/main/scala/Params.scala195
-rw-r--r--src/main/scala/Tester.scala6
-rw-r--r--src/main/scala/utils.scala153
8 files changed, 1248 insertions, 83 deletions
diff --git a/src/main/scala/Core.scala b/src/main/scala/Core.scala
index 7725d242..c3c5da80 100644
--- a/src/main/scala/Core.scala
+++ b/src/main/scala/Core.scala
@@ -34,6 +34,7 @@ object Builder {
def pushModule(mod: Module) {
modulez.push(mod)
}
+ def getComponent(): Module = modulez.head
def popModule() {
modulez.pop
}
@@ -77,7 +78,7 @@ object Builder {
}
def setFieldForId(parentid: String, id: String, name: String) {
- refmap(id) = Field(Alias(parentid), name)
+ refmap(id) = Slot(Alias(parentid), name)
}
def setIndexForId(parentid: String, id: String, index: Int) {
@@ -159,7 +160,7 @@ case class Alias(val id: String) extends Immediate {
case class Ref(val name: String) extends Immediate {
def fullname = name
}
-case class Field(val imm: Immediate, val name: String) extends Immediate {
+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
@@ -172,20 +173,20 @@ case class Index(val imm: Immediate, val value: Int) extends Immediate {
}
}
-case class Port(val id: String, val dir: Direction, val kind: Type);
+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 Type(val isFlip: Boolean);
-case class UnknownType(flip: Boolean) extends Type(flip);
-case class UIntType(val width: Width, flip: Boolean) extends Type(flip);
-case class SIntType(val width: Width, flip: Boolean) extends Type(flip);
-case class FloType(flip: Boolean) extends Type(flip);
-case class DblType(flip: Boolean) extends Type(flip);
-case class BundleType(val ports: Array[Port], flip: Boolean) extends Type(flip);
-case class VectorType(val size: Int, val kind: Type, flip: Boolean) extends Type(flip);
+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 {
@@ -197,11 +198,11 @@ case class DefSInt(val id: String, val value: BigInt, val width: Int) extends De
case class DefFlo(val id: String, val value: Float) extends Definition;
case class DefDbl(val id: String, val value: Double) extends Definition;
case class DefMInt(val id: String, val value: String, val width: Int) extends Definition;
-case class DefPrim(val id: String, val kind: Type, val op: PrimOp, val args: Array[Alias], val lits: Array[BigInt]) extends Definition;
-case class DefPrimPad(val id: String, val kind: Type, val op: PrimOp, val args: Array[Alias], val lits: Array[BigInt]) extends Definition;
-case class DefWire(val id: String, val kind: Type) extends Definition;
-case class DefRegister(val id: String, val kind: Type) extends Definition;
-case class DefMemory(val id: String, val kind: Type, val size: Int) extends Definition;
+case class DefPrim(val id: String, val kind: Kind, val op: PrimOp, val args: Array[Alias], val lits: Array[BigInt]) extends Definition;
+case class DefPrimPad(val id: String, val kind: Kind, val op: PrimOp, val args: Array[Alias], 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 DefAccessor(val id: String, val source: Alias, val direction: Direction, val index: Alias) extends Definition;
case class DefInstance(val id: String, val module: String) extends Definition;
case class Conditionally(val pred: Alias, val conseq: Command, val alt: Command) extends Command;
@@ -255,7 +256,7 @@ abstract class Id {
abstract class Data(dirArg: Direction) extends Id {
val mod = modulez.top
- def toType: Type
+ def toType: Kind
var isFlipVar = dirArg == INPUT
def isFlip = isFlipVar
def dir: Direction = if (isFlip) INPUT else OUTPUT
@@ -270,7 +271,7 @@ abstract class Data(dirArg: Direction) extends Id {
setDir(OUTPUT)
this
}
- def flip: this.type = {
+ def flip(): this.type = {
isFlipVar = !isFlipVar
this
}
@@ -284,6 +285,9 @@ abstract class Data(dirArg: Direction) extends Id {
Alias(id)
def name = getRefForId(id).name
def debugName = mod.debugName + "." + name
+ def litValue(): BigInt = -1
+ def isLitValue(): Boolean = false
+ def setLitValue(x: BigInt) { }
def getWidth: Int
def flatten: Array[Bits]
def fromBits(n: Bits): this.type = {
@@ -312,6 +316,7 @@ abstract class Data(dirArg: Direction) extends Id {
def collectElts: Unit
var isReg_ = false
def isReg = isReg_
+ def params = if(Driver.parStack.isEmpty) Parameters.empty else Driver.parStack.top
}
object Wire {
@@ -359,12 +364,14 @@ object Mem {
}
}
-class Mem[T <: Data](val t: T, val size: Int) /* with VecLike[T] */ { // TODO: VECLIKE
+class Mem[T <: Data](val t: T, val n: Int) /* with VecLike[T] */ { // TODO: VECLIKE
def apply(idx: Bits): T = {
val x = t.cloneType
pushCommand(DefAccessor(x.defd.id, Alias(t.id), NO_DIR, idx.ref))
x
}
+ def name = getRefForId(t.id).name
+ def debugName = t.mod.debugName + "." + name
}
object Vec {
@@ -417,7 +424,7 @@ class Vec[T <: Data](val elts: Iterable[T], dirArg: Direction = NO_DIR) extends
self(idx)
def toPorts: Array[Port] =
self.map(d => d.toPort).toArray
- def toType: Type =
+ def toType: Kind =
VectorType(self.size, elt0.toType, isFlipVar)
override def cloneType: this.type = {
val v = Vec(elt0.cloneType, self.size).asInstanceOf[this.type]
@@ -482,7 +489,7 @@ class MInt(val value: String, val width: Int) extends Data(NO_DIR) {
def collectElts: Unit = { }
override def dir: Direction = NO_DIR
override def setDir(dir: Direction): Unit = { }
- override def toType: Type = UIntType(UnknownWidth(), isFlip)
+ override def toType: Kind = UIntType(UnknownWidth(), isFlip)
override def getWidth: Int = width
override def flatten: Array[Bits] = Array[Bits](Bits(0))
override def cloneType: this.type =
@@ -492,13 +499,16 @@ class MInt(val value: String, val width: Int) extends Data(NO_DIR) {
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)
+ def != (other: Bits): Bool = !zEquals(other)
}
object MInt {
- def mintLit(value: String, width: Int) = new MInt(value, width)
- def apply(value: String, width: Int) = mintLit(value, width)
- def apply(value: String) = mintLit(value, -1)
+ def mintLit(n: String, width: Int) = {
+ assert(n(0) == 'b', "BINARY MINTS ONLY")
+ new MInt(n.substring(1, n.length), width)
+ }
+ def apply(value: String, width: Int): MInt = mintLit(value, width)
+ def apply(value: String): MInt = apply(value, -1)
}
abstract class Element(dirArg: Direction, val width: Int) extends Data(dirArg) {
@@ -507,25 +517,31 @@ abstract class Element(dirArg: Direction, val width: Int) extends Data(dirArg) {
}
abstract class Bits(dirArg: Direction, width: Int) extends Element(dirArg, width) {
- var litValue: Option[BigInt] = Some(-1)
+ var litValueVar: Option[BigInt] = Some(-1)
- def litValueGet: BigInt = litValue.getOrElse(-1)
+ override def litValue(): BigInt = litValueVar.getOrElse(-1)
+ override def isLitValue(): Boolean = litValueVar.isDefined
+ override def setLitValue(x: BigInt) { litValueVar = Some(x) }
override def flatten: Array[Bits] = Array[Bits](this)
- def apply(x: UInt): Bool =
- apply(x.litValueGet)
+ final def apply(x: UInt): Bool =
+ apply(x.litValue())
- def apply(x: BigInt): Bool = {
+ final def apply(x: BigInt): Bool = {
val d = new Bool(dir)
+ if (this.isLitValue())
+ setLitValue((this.litValue() >> x.toInt) & 1)
pushCommand(DefPrim(d.defd.id, d.toType, BitSelectOp, Array(this.ref), Array(x)))
d
}
- def apply(x: UInt, y: UInt): this.type =
- apply(x.litValueGet, y.litValueGet)
+ final def apply(x: UInt, y: UInt): UInt =
+ apply(x.litValue(), y.litValue())
- def apply(x: BigInt, y: BigInt): this.type = {
- val d = cloneTypeWidth(-1)
+ final def apply(x: BigInt, y: BigInt): UInt = {
+ val d = UInt(width = (y - x + 1).toInt)
+ if (this.isLitValue())
+ setLitValue((this.litValue() >> y.toInt) & ((BigInt(1)<<d.getWidth)-BigInt(1)))
pushCommand(DefPrim(d.defd.id, d.toType, BitsExtractOp, Array(this.ref), Array(x, y)))
d
}
@@ -579,14 +595,24 @@ abstract class Bits(dirArg: Direction, width: Int) extends Element(dirArg, width
def >> (other: Bits) = bits_binop(DynamicShiftRightOp, other)
def unary_~(): Bits = bits_unop(BitNotOp)
- def & (other: Bits) = bits_binop_pad(BitAndOp, other)
+ def & (other: Bits) = {
+ val r = bits_binop_pad(BitAndOp, other)
+ if (isLitValue() && other.isLitValue())
+ r.setLitValue(litValue() & other.litValue())
+ r
+ }
def | (other: Bits) = bits_binop_pad(BitOrOp, other)
def ^ (other: Bits) = bits_binop_pad(BitXorOp, other)
def < (other: Bits) = bits_compop_pad(LessOp, other)
def > (other: Bits) = bits_compop_pad(GreaterOp, other)
- def === (other: Bits) = bits_compop_pad(EqualOp, other)
- def !== (other: Bits) = bits_compop_pad(NotEqualOp, other)
+ def === (other: Bits) = {
+ val r = bits_compop_pad(EqualOp, other)
+ if (isLitValue() && other.isLitValue())
+ r.setLitValue(if (litValue() == other.litValue()) 1 else 0)
+ r
+ }
+ def != (other: Bits) = bits_compop_pad(NotEqualOp, other)
def <= (other: Bits) = bits_compop_pad(LessEqOp, other)
def >= (other: Bits) = bits_compop_pad(GreaterEqOp, other)
def pad (other: BigInt) = bits_binop(PadOp, other)
@@ -619,8 +645,11 @@ import UInt._
object Bits {
def apply(dir: Direction = OUTPUT, width: Int = -1) = new UInt(dir, width)
- def apply(value: BigInt, width: Int) = uintLit(value, width)
- def apply(value: BigInt) = uintLit(value, -1)
+ 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 =
+ apply(stringToVal(n(0), n.substring(1, n.length)), width)
+ def apply(n: String): UInt = apply(n, -1)
}
abstract trait Num[T <: Data] {
@@ -646,7 +675,7 @@ class UInt(dir: Direction, width: Int) extends Bits(dir, width) with Num[UInt] {
new UInt(dir, w).asInstanceOf[this.type]
override def cloneType : this.type = cloneTypeWidth(width)
- def toType: Type =
+ def toType: Kind =
UIntType(if (width == -1) UnknownWidth() else IntWidth(width), isFlipVar)
def fromInt(x: BigInt): this.type = UInt(x).asInstanceOf[this.type]
@@ -694,14 +723,24 @@ class UInt(dir: Direction, width: Int) extends Bits(dir, width) with Num[UInt] {
def >> (other: UInt) = uint_binop(DynamicShiftRightOp, other)
override def unary_~(): UInt = uint_unop(BitNotOp)
- def & (other: UInt) = uint_binop_pad(BitAndOp, other)
+ def & (other: UInt) = {
+ val r = uint_binop_pad(BitAndOp, other)
+ if (isLitValue() && other.isLitValue())
+ r.setLitValue(litValue() & other.litValue())
+ r
+ }
def | (other: UInt) = uint_binop_pad(BitOrOp, other)
def ^ (other: UInt) = uint_binop_pad(BitXorOp, other)
def < (other: UInt) = uint_compop_pad(LessOp, other)
def > (other: UInt) = uint_compop_pad(GreaterOp, other)
- def === (other: UInt) = uint_compop_pad(EqualOp, other)
- def !== (other: UInt) = uint_compop_pad(NotEqualOp, other)
+ def === (other: UInt) = {
+ val r = uint_compop_pad(EqualOp, other)
+ if (isLitValue() && other.isLitValue())
+ r.setLitValue(if (litValue() == other.litValue()) 1 else 0)
+ r
+ }
+ def != (other: UInt) = uint_compop_pad(NotEqualOp, other)
def <= (other: UInt) = uint_compop_pad(LessEqOp, other)
def >= (other: UInt) = uint_compop_pad(GreaterEqOp, other)
@@ -714,18 +753,22 @@ object UInt {
def uintLit(value: BigInt, width: Int) = {
val w = if(width == -1) max(bitLength(value), 1) else width
val b = new UInt(NO_DIR, w)
+ b.litValueVar = Some(value)
pushCommand(DefUInt(b.defd.id, value, w))
b
}
- def apply(value: BigInt, width: Int) = uintLit(value, width)
- def apply(value: BigInt) = uintLit(value, -1)
+ 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 =
+ apply(stringToVal(n(0), n.substring(1, n.length)), width)
+ def apply(n: String): UInt = apply(n, -1)
}
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]
override def cloneType: this.type = cloneTypeWidth(width)
- def toType: Type =
+ def toType: Kind =
SIntType(if (width == -1) UnknownWidth() else IntWidth(width), isFlipVar)
def fromInt(x: BigInt): this.type = SInt(x).asInstanceOf[this.type]
@@ -779,8 +822,13 @@ class SInt(dir: Direction, width: Int) extends Bits(dir, width) with Num[SInt] {
def < (other: SInt) = sint_compop_pad(LessOp, other)
def > (other: SInt) = sint_compop_pad(GreaterOp, other)
- def === (other: SInt) = sint_compop_pad(EqualOp, other)
- def !== (other: SInt) = sint_compop_pad(NotEqualOp, other)
+ def === (other: SInt) = {
+ val r = sint_compop_pad(EqualOp, other)
+ if (isLitValue() && other.isLitValue())
+ r.setLitValue(if (litValue() == other.litValue()) 1 else 0)
+ r
+ }
+ def != (other: SInt) = sint_compop_pad(NotEqualOp, other)
def <= (other: SInt) = sint_compop_pad(LessEqOp, other)
def >= (other: SInt) = sint_compop_pad(GreaterEqOp, other)
@@ -793,11 +841,15 @@ object SInt {
def sintLit(value: BigInt, width: Int) = {
val w = if (width == -1) bitLength(value) + 1 else width
val b = new SInt(NO_DIR, w)
+ b.litValueVar = Some(value)
pushCommand(DefSInt(b.defd.id, value, w))
b
}
- def apply(value: BigInt, width: Int) = sintLit(value, width)
- def apply(value: BigInt) = sintLit(value, -1)
+ 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) {
@@ -862,7 +914,10 @@ object Cat {
else {
val l = doCat(r.slice(0, r.length/2))
val h = doCat(r.slice(r.length/2, r.length))
- val d = l.cloneType
+ val isConst = (l.isLitValue() && h.isLitValue())
+ val w = if (isConst) l.getWidth + h.getWidth else -1
+ val d = l.cloneTypeWidth(w)
+ if (isConst) d.setLitValue((l.litValue() << l.getWidth) | h.litValue())
pushCommand(DefPrim(d.id, d.toType, ConcatOp, Array(l.ref, h.ref), NoLits))
d
}
@@ -874,6 +929,17 @@ object Bundle {
"flatten", "binding", "asInput", "asOutput", "unary_$tilde",
"unary_$bang", "unary_$minus", "cloneType", "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) {
@@ -944,30 +1010,42 @@ class Bundle(dirArg: Direction = NO_DIR) extends Aggregate(dirArg) {
}
object Module {
- def apply[T <: Module](c: T): T = {
+ 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
- c.io.collectElts
- c.setRefs
- val ports = c.io.toPorts
- val component = UniqueComponent(c.name, ports, cmd)
+ m.io.collectElts
+ m.setRefs
+ val ports = m.io.toPorts
+ val component = UniqueComponent(m.name, ports, cmd)
components += component
- pushCommand(DefInstance(c.defd.id, component.name))
- c
+ pushCommand(DefInstance(m.defd.id, 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 extends Id {
+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(id)
- val reset = Bool().defd
+ val reset = if (_reset == null) Bool().defd else _reset
setRefForId(reset.id, "reset")
def name = {
@@ -1107,7 +1185,7 @@ class Emitter {
case e: IntWidth => "(" + e.value.toString + ")"
}
}
- def emitType(e: Type): String = {
+ def emitType(e: Kind): String = {
e match {
case e: UnknownType => "?"
case e: UIntType => "UInt" + emit(e.width)
diff --git a/src/main/scala/Driver.scala b/src/main/scala/Driver.scala
index 1f3f49b8..7d5c2e6a 100644
--- a/src/main/scala/Driver.scala
+++ b/src/main/scala/Driver.scala
@@ -84,15 +84,16 @@ object chiselMain {
//Is this antiquated?
object chiselMainTest {
- def apply[T <: Module](args: Array[String], gen: () => T)(tester: T => Tester[T]): (Circuit, T) =
+ 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 {
- execute(gen) /* else executeUnwrapped(gen) */
+ if(wrapped) execute(gen) else executeUnwrapped(gen)
} finally {
ChiselError.report
if (ChiselError.hasErrors && !getLineNumbers) {
@@ -109,9 +110,9 @@ object Driver extends FileSystemUtilities{
(circuit, mod)
}
- /*
- private def executeUnwrapped[T <: Module](gen: () => T): T = {
+ 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]
@@ -125,7 +126,7 @@ object Driver extends FileSystemUtilities{
} else { new Instance(config.topDefinitions,config.knobValues) }
val p = Parameters.root(world)
config.topConstraints.foreach(c => p.constrain(c))
- val c = execute(() => Module(gen())(p))
+ val (circuit, mod) = execute(() => Module(gen())(p))
if(chiselConfigMode.get == "collect") {
val v = createOutputFile(chiselConfigClassName.get + ".knb")
v.write(world.getKnobs)
@@ -134,35 +135,30 @@ object Driver extends FileSystemUtilities{
w.write(world.getConstraints)
w.close
}
- c
+ (circuit, mod)
}
else {
execute(() => Module(gen()))
}
}
- */
private def execute[T <: Module](gen: () => T): (Circuit, T) = {
val emitter = new Emitter
- val (c, mod) = build{ Module(gen()) }
+ val (c, mod) = build{ gen() }
+ // setTopComponent(c)
val s = emitter.emit( c )
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") {
- setTopComponent(c)
- backend.elaborate(c)
- if (isCompiling && isGenHarness) backend.compile(c)
if(chiselConfigDump && !Dump.dump.isEmpty) {
val w = createOutputFile(appendString(Some(topComponent.name),chiselConfigClassName) + ".prm")
w.write(Dump.getDump); w.close
}
}
- */
out.close()
(c, mod)
}
@@ -379,7 +375,7 @@ object Driver extends FileSystemUtilities{
val chiselOneHotMap = HashMap[(UInt, Int), UInt]()
val chiselOneHotBitMap = HashMap[(Bits, Int), Bool]()
val compStack = Stack[Module]()
- // val parStack = new Stack[Parameters]
+ val parStack = new Stack[Parameters]
var stackIndent = 0
val printStackStruct = ArrayBuffer[(Int, Module)]()
// val clocks = ArrayBuffer[Clock]()
diff --git a/src/main/scala/FP.scala b/src/main/scala/FP.scala
index 5f6cf579..8b1c2b0a 100644
--- a/src/main/scala/FP.scala
+++ b/src/main/scala/FP.scala
@@ -91,7 +91,7 @@ class Flo(dir: Direction = NO_DIR) extends Element(dir, 32) with Num[Flo] {
pushCommand(DefPrim(d.defd.id, d.toType, FloToBits, Array(this.ref), NoLits))
d
}
- def toType: Type = FloType(isFlip)
+ def toType: Kind = FloType(isFlip)
def cloneType: this.type = new Flo(dir).asInstanceOf[this.type]
def flatten: Array[Bits] = Array[Bits](toBits)
@@ -205,7 +205,7 @@ class Dbl(dir: Direction = null) extends Element(dir, 64) with Num[Dbl] {
pushCommand(DefPrim(d.defd.id, d.toType, DblToBits, Array(this.ref), NoLits))
d
}
- def toType: Type = DblType(isFlip)
+ def toType: Kind = DblType(isFlip)
def cloneType: this.type = new Dbl(dir).asInstanceOf[this.type]
def flatten: Array[Bits] = Array[Bits](toBits)
diff --git a/src/main/scala/JHFormat.scala b/src/main/scala/JHFormat.scala
new file mode 100644
index 00000000..e177835e
--- /dev/null
+++ b/src/main/scala/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/Parameters.scala b/src/main/scala/Parameters.scala
new file mode 100644
index 00000000..9a117ee0
--- /dev/null
+++ b/src/main/scala/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/Params.scala b/src/main/scala/Params.scala
new file mode 100644
index 00000000..9f98c336
--- /dev/null
+++ b/src/main/scala/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/Tester.scala b/src/main/scala/Tester.scala
index fc55fc53..08bc9d11 100644
--- a/src/main/scala/Tester.scala
+++ b/src/main/scala/Tester.scala
@@ -194,7 +194,7 @@ class ManualTester[+T <: Module]
}
}
- def peekAt[T <: Bits](data: Data, off: Int): BigInt = {
+ def peekAt[T <: Bits](data: Mem[T], off: Int): BigInt = {
// signed_fix(data(1), peekBits(data, off))
doPeekBits(data.debugName, off)
}
@@ -239,7 +239,7 @@ class ManualTester[+T <: Module]
}
}
- def pokeAt[T <: Bits](data: Data, x: BigInt, off: Int): Unit = {
+ def pokeAt[T <: Bits](data: Mem[T], x: BigInt, off: Int): Unit = {
doPokeBits(data.debugName, x, off)
}
@@ -267,7 +267,7 @@ class ManualTester[+T <: Module]
def int(x: Boolean): BigInt = if (x) 1 else 0
def int(x: Int): BigInt = x
- def int(x: Bits): BigInt = x.litValue.getOrElse(-1)
+ def int(x: Bits): BigInt = x.litValue()
var ok = true;
var failureTime = -1
diff --git a/src/main/scala/utils.scala b/src/main/scala/utils.scala
index 346ce657..f3642822 100644
--- a/src/main/scala/utils.scala
+++ b/src/main/scala/utils.scala
@@ -148,7 +148,7 @@ 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(key === k, v, res);
+ res = Mux(k === key, v, res);
res
}
@@ -187,7 +187,7 @@ object MuxCase {
}
object ListLookup {
- def apply[T <: Data](addr: UInt, default: List[T], mapping: Array[(UInt, List[T])]): List[T] = {
+ def apply[T <: Data](addr: UInt, default: List[T], mapping: Array[(MInt, 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))
@@ -196,7 +196,7 @@ object ListLookup {
}
object Lookup {
- def apply[T <: Bits](addr: UInt, default: T, mapping: Seq[(UInt, T)]): T =
+ def apply[T <: Bits](addr: UInt, default: T, mapping: Seq[(MInt, T)]): T =
ListLookup(addr, List(default), mapping.map(m => (m._1, List(m._2))).toArray).head
}
@@ -251,3 +251,150 @@ object UIntToOH
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](gen: T) extends Bundle
+{
+ val valid = Bool(OUTPUT)
+ val bits = gen.cloneType.asOutput
+ def fire(dummy: Int = 0): Bool = valid
+ override def cloneType: this.type = new ValidIO(gen).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 cloneType: 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 }
+ valid := Bool(false);
+ for (io <- bits.flatten)
+ io := UInt(0)
+ override def cloneType: this.type = { new EnqIO(gen).asInstanceOf[this.type]; }
+}
+
+class DeqIO[T <: Data](gen: T) extends DecoupledIO(gen)
+{
+ flip()
+ ready := Bool(false);
+ def deq(b: Boolean = false): T = { ready := Bool(true); bits }
+ override def cloneType: 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
+ }
+}