2

I'm working on a Z-Scale RISCV-processor where I've implemented new functionality and logic into the datapath. I'm wondering if there exist an easy way to "power off" certain parts of the code without using a bunch of if-loops? I would like to make it easy to switch between the regular implementation of the Z-scale processor and the one with extended implementation.

The new logic I've implemented does not replace the main components of the datapath, but rather extends the functionality.

Mrchacha
  • 197
  • 1
  • 17

2 Answers2

3

This question really strikes at the heart of what makes Chisel powerful. As a DSL embedded in Scala, you have access to the full power of an object-oriented and functional programming language.

While I'm not sure of exactly what you're doing, this seems like a good place to use inheritance. You could make a new Module class that extends the datapath Module and adds the additional functionality.

A toy example:

import Chisel._

class ParentIO extends Bundle {
  val foo = UInt(width = 32).asInput
  val bar = UInt(width = 32).asOutput
}

class Parent extends Module {
  // Note the use of lazy val
  // Due to Scala initialization order (http://docs.scala-lang.org/tutorials/FAQ/initialization-order.html)
  //   this cannot be a val
  // Due to quirks of Chisel, this cannot be a def
  lazy val io = new ParentIO
  io.bar := io.foo
}

class ChildIO extends ParentIO {
  val isOdd = Bool().asOutput
}

class Child extends Parent {
  override lazy val io = new ChildIO
  io.isOdd := io.foo(0)
}

// Note use of call-by-name for passing gen
// Chisel Modules must be constructed within a call to the Module(...) function
class Top(gen: => Parent) extends Module {
  val dut = Module(gen)
  val io = dut.io.cloneType
  io <> dut.io
}

Module Top is parameterized by the type of Module it instantiates: Parent or Child. You can thus conditionally instantiate Parent or Child rather than all of the logic that differentiates them. If you want the Child to be overriding certain functionality of the parent, Chisel's last connection semantics allow any connections in the Child to overrule connections in the Parent.

Jack Koenig
  • 5,840
  • 15
  • 21
  • Thanks for the reply! I wondering if it is possible to have a variable that can control the parameter of Module Top, so it will instantiate Child if the variable is set to 1, and the Parent otherwise? I have tried different idea without getting what I want. – Mrchacha Jan 18 '17 at 15:07
  • I have responded to http://stackoverflow.com/questions/41720320/initialize-class-depending-on-config-value – Jack Koenig Jan 18 '17 at 23:33
  • @JackKoenig Hi, I tried your way but came out with the error below, ```Error:(210, 21) overriding lazy value io in class SPadCommonModule of type SPadCommonModuleIO; lazy value io has incompatible type override lazy val io = new SPadModuleIO (dataWidth = DataWidth, padSize = PadSize)```, wonder how to override the IO in this case. – Daily Coder Weekly Hooper Jun 10 '20 at 06:09
  • I think this is saying that you're overriding the `lazy val io` with a type that isn't a subtype. For example, if `lazy val io = IO(new Animal)`, it's legal to override with `override lazy val io = IO(new Cat)` but not with `override lazy val io = IO(new Apple)`, make sure the Bundle class you're instantiating in the override extends the Bundle used by the parent you're extending. – Jack Koenig Jun 10 '20 at 16:44
2

Sounds like your code looks like this:

val a = Wire(UInt())
if (extension)
    a := 1.U
else
    a := 2.U

What you could do is create a Z-scale class and a Z-scale-extended class that implements a trait that contains the differences between the two designs.

trait RISC_V_Processor {
    def do_a : UInt
}

class Z_Scale with RISC_V_Processor {
    def do_a : UInt = 2.U
}

class Z_Scale_extended with RISC_V_Processor {
    def do_a : UInt = 1.U
}

val processor = new Z_Scale_extended()
val a = processor.do_a()

This is essentially replacing conditionals with polymorphism. https://sourcemaking.com/refactoring/replace-conditional-with-polymorphism

Sebastian Bøe
  • 479
  • 1
  • 3
  • 8
  • 1
    I just wanted to point out that the first example won't compile because of reassignment to `a` instead of connection, it should be `a := 1.U` and `a := 2.U` – Jack Koenig Nov 17 '16 at 23:24
  • Yeah, this was sketched up quickly to demonstrate a point, will fix it though. – Sebastian Bøe Nov 18 '16 at 22:44