val path = System.getProperty("user.dir") + "/source/load-ivy.sc" interp.load.module(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(path))) import chisel3._ import chisel3.util._ import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester} println(10.getClass) println(10.0.getClass) println("ten".getClass) class MyClass { def myMethod = ??? } println(new MyClass().getClass) def double(s: String): String = s + s // Uncomment the code below to test it // double("hi") // Proper use of double // double(10) // Bad input argument! // double("hi") / 10 // Inproper use of double's output! var counter = 0 def increment(): Unit = { counter += 1 } increment() val x: UInt = 3.U try { println(x.asInstanceOf[Int]) } catch { case e: java.lang.ClassCastException => println("As expected, we can't cast UInt to Int") } // But we can cast UInt to Data since UInt inherits from Data. println(x.asInstanceOf[Data]) class TypeConvertDemo extends Module { val io = IO(new Bundle { val in = Input(UInt(4.W)) val out = Output(SInt(4.W)) }) io.out := io.in//.asTypeOf(io.out) } Driver(() => new TypeConvertDemo) { c => new PeekPokeTester(c) { poke(c.io.in, 3) expect(c.io.out, 3) poke(c.io.in, 15) expect(c.io.out, -1) }} class ConstantSum(in1: Data, in2: Data) extends Module { val io = IO(new Bundle { val out = Output(in1.cloneType) }) (in1, in2) match { case (x: UInt, y: UInt) => io.out := x + y case (x: SInt, y: SInt) => io.out := x + y case _ => throw new Exception("I give up!") } } println(getVerilog(dut = new ConstantSum(3.U, 4.U))) println(getVerilog(dut = new ConstantSum(-3.S, 4.S))) println(getVerilog(dut = new ConstantSum(3.U, 4.S))) class InputIsZero extends Module { val io = IO(new Bundle { val in = Input(UInt(16.W)) val out = Output(Bool()) }) io.out := (io.in match { // note that case 0.U is an error case (0.U) => true.B case _ => false.B }) } println(getVerilog(new InputIsZero)) case class SomeGeneratorParameters( someWidth: Int, someOtherWidth: Int = 10, pipelineMe: Boolean = false ) { require(someWidth >= 0) require(someOtherWidth >= 0) val totalWidth = someWidth + someOtherWidth } def delay(p: SomeGeneratorParameters): Int = p match { case sg @ SomeGeneratorParameters(_, _, true) => sg.totalWidth * 3 case SomeGeneratorParameters(_, sw, false) => sw * 2 } println(delay(SomeGeneratorParameters(10, 10))) println(delay(SomeGeneratorParameters(10, 10, true))) class Boat(val name: String, val length: Int) object Boat { def unapply(b: Boat): Option[(String, Int)] = Some((b.name, b.length)) def apply(name: String, length: Int): Boat = new Boat(name, length) } def getSmallBoats(seq: Seq[Boat]): Seq[Boat] = seq.filter { b => b match { case Boat(_, length) if length < 60 => true case Boat(_, _) => false } } val boats = Seq(Boat("Santa Maria", 62), Boat("Pinta", 56), Boat("Nina", 50)) println(getSmallBoats(boats).map(_.name).mkString(" and ") + " are small boats!") // Helper function to make this cell a bit less tedious. def printAndAssert(cmd: String, result: Boolean, expected: Boolean): Unit = { println(s"$cmd = $result") assert(result == expected) } // Defined for -1, 2, 5, etc. val partialFunc1: PartialFunction[Int, String] = { case i if (i + 1) % 3 == 0 => "Something" } printAndAssert("partialFunc1.isDefinedAt(2)", partialFunc1.isDefinedAt(2), true) printAndAssert("partialFunc1.isDefinedAt(5)", partialFunc1.isDefinedAt(5), true) printAndAssert("partialFunc1.isDefinedAt(1)", partialFunc1.isDefinedAt(1), false) printAndAssert("partialFunc1.isDefinedAt(0)", partialFunc1.isDefinedAt(0), false) println(s"partialFunc1(2) = ${partialFunc1(2)}") try { println(partialFunc1(0)) } catch { case e: scala.MatchError => println("partialFunc1(0) = can't apply PartialFunctions where they are not defined") } // Defined for 1, 4, 7, etc. val partialFunc2: PartialFunction[Int, String] = { case i if (i + 2) % 3 == 0 => "Something else" } printAndAssert("partialFunc2.isDefinedAt(1)", partialFunc2.isDefinedAt(1), true) printAndAssert("partialFunc2.isDefinedAt(0)", partialFunc2.isDefinedAt(0), false) println(s"partialFunc2(1) = ${partialFunc2(1)}") try { println(partialFunc2(0)) } catch { case e: scala.MatchError => println("partialFunc2(0) = can't apply PartialFunctions where they are not defined") } val partialFunc3 = partialFunc1 orElse partialFunc2 printAndAssert("partialFunc3.isDefinedAt(0)", partialFunc3.isDefinedAt(0), false) printAndAssert("partialFunc3.isDefinedAt(1)", partialFunc3.isDefinedAt(1), true) printAndAssert("partialFunc3.isDefinedAt(2)", partialFunc3.isDefinedAt(2), true) printAndAssert("partialFunc3.isDefinedAt(3)", partialFunc3.isDefinedAt(3), false) println(s"partialFunc3(1) = ${partialFunc3(1)}") println(s"partialFunc3(2) = ${partialFunc3(2)}") class Bundle1 extends Bundle { val a = UInt(8.W) override def cloneType = (new Bundle1).asInstanceOf[this.type] } class Bundle2 extends Bundle1 { val b = UInt(16.W) override def cloneType = (new Bundle2).asInstanceOf[this.type] } class BadTypeModule extends Module { val io = IO(new Bundle { val c = Input(Clock()) val in = Input(UInt(2.W)) val out = Output(Bool()) val bundleIn = Input(new Bundle2) val bundleOut = Output(new Bundle1) }) //io.out := io.c // won't work due to different types // Okay, but Chisel will truncate the input width to 1 to match the output. io.out := io.in // Compiles; Chisel will connect the common subelements of the two Bundles (in this case, 'a'). io.bundleOut := io.bundleIn } println(getVerilog(new BadTypeModule)) val seq1 = Seq("1", "2", "3") // Type is Seq[String] val seq2 = Seq(1, 2, 3) // Type is Seq[Int] val seq3 = Seq(1, "2", true) // Type is Seq[Any] //val default = Seq() // Error! val default = Seq[String]() // User must tell compiler that default is of type Seq[String] Seq(1, "2", true).foldLeft(default){ (strings, next) => next match { case s: String => strings ++ Seq(s) case _ => strings } } def time[T](block: => T): T = { val t0 = System.nanoTime() val result = block val t1 = System.nanoTime() val timeMillis = (t1 - t0) / 1000000.0 println(s"Block took $timeMillis milliseconds!") result } // Adds 1 through a million val int = time { (1 to 1000000).reduce(_ + _) } println(s"Add 1 through a million is $int") // Finds the largest number under a million that, in hex, contains "beef" val string = time { (1 to 1000000).map(_.toHexString).filter(_.contains("beef")).last } println(s"The largest number under a million that has beef: $string") class ShiftRegisterIO[T <: Data](gen: T, n: Int) extends Bundle { require (n >= 0, "Shift register must have non-negative shift") val in = Input(gen.cloneType) val out = Output(Vec(n + 1, gen.cloneType)) // + 1 because in is included in out override def cloneType: this.type = (new ShiftRegisterIO(gen, n)).asInstanceOf[this.type] } class ShiftRegister[T <: Data](gen: T, n: Int) extends Module { val io = IO(new ShiftRegisterIO(gen, n)) io.out.foldLeft(io.in) { case (in, out) => out := in RegNext(in) } } class ShiftRegisterTester[T <: Bits](c: ShiftRegister[T]) extends PeekPokeTester(c) { println(s"Testing ShiftRegister of type ${c.io.in} and depth ${c.io.out.length}") for (i <- 0 until 10) { poke(c.io.in, i) println(s"$i: ${peek(c.io.out)}") step(1) } } Driver(() => new ShiftRegister(UInt(4.W), 5)) { c => new ShiftRegisterTester(c) } Driver(() => new ShiftRegister(SInt(6.W), 3)) { c => new ShiftRegisterTester(c) } import chisel3.experimental._ import dsptools.numbers._ class Mac[T <: Data : Ring](genIn : T, genOut: T) extends Module { val io = IO(new Bundle { val a = Input(genIn.cloneType) val b = Input(genIn.cloneType) val c = Input(genIn.cloneType) val out = Output(genOut.cloneType) }) io.out := io.a * io.b + io.c } println(getVerilog(new Mac(UInt(4.W), UInt(6.W)) )) println(getVerilog(new Mac(SInt(4.W), SInt(6.W)) )) println(getVerilog(new Mac(FixedPoint(4.W, 3.BP), FixedPoint(6.W, 4.BP)))) object Mac { def apply[T <: Data : Ring](a: T, b: T, c: T): T = { } } class MacTestModule extends Module { val io = IO(new Bundle { val uin = Input(UInt(4.W)) val uout = Output(UInt()) val sin = Input(SInt(4.W)) val sout = Output(SInt()) //val fin = Input(FixedPoint(16.W, 12.BP)) //val fout = Output(FixedPoint()) }) // for each IO pair, do out = in * in + in io.uout := Mac(io.uin, io.uin, io.uin) io.sout := Mac(io.sin, io.sin, io.sin) //io.fout := Mac(io.fin, io.fin, io.fin) } println(getVerilog(new MacTestModule)) class Integrator[T <: Data : Ring](genIn: T, genReg: T) extends Module { val io = IO(new Bundle { val in = Input(genIn.cloneType) val out = Output(genReg.cloneType) }) val reg = RegInit(genReg, Ring[T].zero) // init to zero reg := reg + io.in io.out := reg } class IntegratorSIntTester(c: Integrator[SInt]) extends PeekPokeTester(c) { poke(c.io.in, 3) expect(c.io.out, 0) step(1) poke(c.io.in, -4) expect(c.io.out, 3) step(1) poke(c.io.in, 6) expect(c.io.out, -1) step(1) expect(c.io.out, 5) } chisel3.iotesters.Driver(() => new Integrator(SInt(4.W), SInt(8.W))) { c => new IntegratorSIntTester(c) } println(getVerilog(new Mac(DspComplex(SInt(4.W), SInt(4.W)), DspComplex(SInt(6.W), SInt(6.W))) )) class SignMagnitude(val magnitudeWidth: Option[Int] = None) extends Bundle { val sign = Bool() val magnitude = magnitudeWidth match { case Some(w) => UInt(w.W) case None => UInt() } def +(that: SignMagnitude): SignMagnitude = { // Implement this! } def -(that: SignMagnitude): SignMagnitude = { this.+(-that) } def unary_-(): SignMagnitude = { val result = Wire(new SignMagnitude()) result.sign := !this.sign result.magnitude := this.magnitude result } def *(that: SignMagnitude): SignMagnitude = { // Implement this! } override def cloneType: this.type = new SignMagnitude(magnitudeWidth).asInstanceOf[this.type] } trait SignMagnitudeRing extends Ring[SignMagnitude] { def plus(f: SignMagnitude, g: SignMagnitude): SignMagnitude = { f + g } def times(f: SignMagnitude, g: SignMagnitude): SignMagnitude = { f * g } def one: SignMagnitude = { val one = Wire(new SignMagnitude(Some(1))) one.sign := false.B one.magnitude := 1.U one } def zero: SignMagnitude = { val zero = Wire(new SignMagnitude(Some(0))) zero.sign := false.B zero.magnitude := 0.U zero } def negate(f: SignMagnitude): SignMagnitude = { -f } // Leave unimplemented for this example def minusContext(f: SignMagnitude, g: SignMagnitude): SignMagnitude = ??? def negateContext(f: SignMagnitude): SignMagnitude = ??? def plusContext(f: SignMagnitude,g: SignMagnitude): SignMagnitude = ??? def timesContext(f: SignMagnitude,g: SignMagnitude): SignMagnitude = ??? } implicit object SignMagnitudeRingImpl extends SignMagnitudeRing class SignMagnitudeMACTester(c: Mac[SignMagnitude]) extends PeekPokeTester(c) { // 3 * 3 + 2 = 11 poke(c.io.a.sign, 0) poke(c.io.a.magnitude, 3) poke(c.io.b.sign, 0) poke(c.io.b.magnitude, 3) poke(c.io.c.sign, 0) poke(c.io.c.magnitude, 2) expect(c.io.out.sign, 0) expect(c.io.out.magnitude, 11) // 3 * 3 - 2 = 7 poke(c.io.c.sign, 1) expect(c.io.out.sign, 0) expect(c.io.out.magnitude, 7) // 3 * (-3) - 2 = -11 poke(c.io.b.sign, 1) expect(c.io.out.sign, 1) expect(c.io.out.magnitude, 11) } val works = iotesters.Driver(() => new Mac(new SignMagnitude(Some(4)), new SignMagnitude(Some(5)))) { c => new SignMagnitudeMACTester(c) } assert(works) // Scala Code: if works == false, will throw an error println("SUCCESS!!") // Scala Code: if we get here, our tests passed! println(getVerilog(new Mac(new SignMagnitude(Some(4)), new SignMagnitude(Some(5))))) println(getVerilog(new Mac(DspComplex(new SignMagnitude(Some(4)), new SignMagnitude(Some(4))), DspComplex(new SignMagnitude(Some(5)), new SignMagnitude(Some(5))))))