diff options
| author | jackbackrack | 2015-04-28 23:33:59 -0700 |
|---|---|---|
| committer | jackbackrack | 2015-04-28 23:33:59 -0700 |
| commit | 7ada20e324ca75116441d00b575ed217c41cc1c8 (patch) | |
| tree | 1a486c5782fdf1a58a5f797f4b4b7f780b6febe3 /src | |
| parent | 189f2a123300f0c2ffe4487bb67c71a08736bd3e (diff) | |
add params, limited partial eval, conforming to compile riscv-mini
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/scala/Core.scala | 200 | ||||
| -rw-r--r-- | src/main/scala/Driver.scala | 24 | ||||
| -rw-r--r-- | src/main/scala/FP.scala | 4 | ||||
| -rw-r--r-- | src/main/scala/JHFormat.scala | 105 | ||||
| -rw-r--r-- | src/main/scala/Parameters.scala | 644 | ||||
| -rw-r--r-- | src/main/scala/Params.scala | 195 | ||||
| -rw-r--r-- | src/main/scala/Tester.scala | 6 | ||||
| -rw-r--r-- | src/main/scala/utils.scala | 153 |
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 + } +} |
