diff --git a/README.md b/README.md index d3b7ee42..971f56c2 100644 --- a/README.md +++ b/README.md @@ -83,21 +83,16 @@ By passing the +blkdev argument on the simulator command line, you can allow the RTL simulation to read and write from a file. Take a look at tests/blkdev.c for an example of how Rocket can program the block device controller. -## Creating your own project +## Adding an MMIO peripheral -To create your own project, you should create your own scala package. -Let's use the PWM package as an example. First you create a directory -under src/main/scala that has the same name as your package. - - mkdir src/main/scala/pwm - -Now let's add a peripheral device to the new SoC. The easiest way to create a -TileLink peripheral is to use the TLRegisterRouter, which abstracts away the -details of handling the TileLink protocol and provides a convenient interface -for specifying memory-mapped registers. To create a RegisterRouter-based -peripheral, you will need to specify a parameter case class for the -configuration settings, a bundle trait with the extra top-level ports, and -a module implementation containing the actual RTL. +You can RocketChip to create your own memory-mapped IO device and add it into +the SoC design. The easiest way to create a TileLink peripheral is to use the +TLRegisterRouter, which abstracts away the details of handling the TileLink +protocol and provides a convenient interface for specifying memory-mapped +registers. To create a RegisterRouter-based peripheral, you will need to +specify a parameter case class for the configuration settings, a bundle trait +with the extra top-level ports, and a module implementation containing the +actual RTL. case class PWMParams(address: BigInt, beatBytes: Int) @@ -142,7 +137,7 @@ module trait. new TLRegBundle(c, _) with PWMTLBundle)( new TLRegModule(c, _, _) with PWMTLModule) -The full module code with comments can be found in src/main/scala/pwm/PWM.scala. +The full module code with comments can be found in src/main/scala/example/PWM.scala. After creating the module, we need to hook it up to our SoC. Rocketchip accomplishes this using the [cake pattern](http://www.cakesolutions.net/teamblogs/2011/12/19/cake-pattern-in-depth). @@ -186,7 +181,7 @@ functionality. We then connect the PWMTL's pwmout to the pwmout we declared. } Now we want to mix our traits into the system as a whole. This code is from -src/main/scala/pwm/Top.scala. +src/main/scala/example/Top.scala. class ExampleTopWithPWM(q: Parameters) extends ExampleTop(q) with PeripheryPWM { @@ -198,38 +193,23 @@ src/main/scala/pwm/Top.scala. extends ExampleTopModule(l) with HasPeripheryPWMModuleImp Just as we need separate traits for LazyModule and module implementation, we -need two classes to build the system. The ExampleTop classes from the example -package already have the basic peripherals included for us, so we will just -extend those. +need two classes to build the system. The ExampleTop classes already have the +basic peripherals included for us, so we will just extend those. The ExampleTop class includes the pre-elaboration code and also a lazy val to produce the module implementation (hence LazyModule). The ExampleTopModule class is the actual RTL that gets synthesized. -Now we have the RTL for the chip, but we need a test harness to simulate it. +Finally, we need to add a configuration class in +src/main/scala/example/Configs.scala that tells the TestHarness to instantiate +ExampleTopWithPWM instead of the default ExampleTop. - class TestHarness(q: Parameters) extends example.TestHarness()(q) { - override def buildTop(p: Parameters) = - LazyModule(new ExampleTopWithPWM(p)) - } + class WithPWM extends Config((site, here, up) => { + case BuildTop => (p: Parameters) => + Module(LazyModule(new ExampleTopWithPWM()(p)).module) + }) -We just extend the TestHarness from the example package, which already has -the extra RTL to simulate the memory system and tethered serial port. -It provides us the hook function `buildTop` which we can override to build -our ExampleTopWithPWM instead of the regular ExampleTop. - -We also need to create a Generator object, which gets called as the entry -point for elaboration. - - object Generator extends GeneratorApp { - generateFirrtl - } - -Finally, we need to add a configuration class in src/main/scala/pwm/Configs.scala. -This defines all the settings in the Parameters object. We aren't adding any -new parameters, so we can just extend the default configuration. - - class PWMTLConfig extends Config(new example.DefaultExampleConfig) + class PWMConfig extends Config(new WithPWM ++ new BaseExampleConfig) Now we can test that the PWM is working. The test program is in tests/pwm.c @@ -265,8 +245,8 @@ Compiling this program with make produces a `pwm.riscv` executable. Now with all of that done, we can go ahead and run our simulation. cd verisim - make PROJECT=pwm CONFIG=PWMTLConfig - ./simulator-pwm-PWMTLConfig ../tests/pwm.riscv + make PROJECT=pwm CONFIG=PWMConfig + ./simulator-pwm-PWMConfig ../tests/pwm.riscv ## Adding a DMA port diff --git a/src/main/scala/blkdev/Configs.scala b/src/main/scala/blkdev/Configs.scala deleted file mode 100644 index c7eefa70..00000000 --- a/src/main/scala/blkdev/Configs.scala +++ /dev/null @@ -1,21 +0,0 @@ -package blkdev - -import config.{Parameters, Config} -import example.DefaultExampleConfig -import testchipip.{WithBlockDevice, WithNBlockDeviceTrackers} - -class WithSimBlockDevice extends Config((site, here, up) => { - case UseSimBlockDevice => true -}) - -class WithBlockDeviceModel extends Config((site, here, up) => { - case UseSimBlockDevice => false -}) - -class BlockDeviceConfig extends Config( - new WithSimBlockDevice ++ - new WithBlockDevice ++ - new DefaultExampleConfig) - -class WithTwoTrackers extends WithNBlockDeviceTrackers(2) -class WithFourTrackers extends WithNBlockDeviceTrackers(4) diff --git a/src/main/scala/blkdev/TestHarness.scala b/src/main/scala/blkdev/TestHarness.scala deleted file mode 100644 index b948ca44..00000000 --- a/src/main/scala/blkdev/TestHarness.scala +++ /dev/null @@ -1,27 +0,0 @@ -package blkdev - -import diplomacy.LazyModule -import chisel3._ -import config.{Parameters, Field} -import testchipip.GeneratorApp -import example._ - -case object UseSimBlockDevice extends Field[Boolean] - -class TestHarness(implicit p: Parameters) extends Module { - val io = IO(new Bundle { - val success = Output(Bool()) - }) - - val dut = Module(LazyModule(new ExampleTopWithBlockDevice).module) - dut.connectSimAXIMem() - if (p(UseSimBlockDevice)) - dut.connectSimBlockDevice() - else - dut.connectBlockDeviceModel() - io.success := dut.connectSimSerial() -} - -object Generator extends GeneratorApp { - generateFirrtl -} diff --git a/src/main/scala/blkdev/Top.scala b/src/main/scala/blkdev/Top.scala deleted file mode 100644 index 5d7f9a4c..00000000 --- a/src/main/scala/blkdev/Top.scala +++ /dev/null @@ -1,15 +0,0 @@ -package blkdev - -import chisel3._ -import config.Parameters -import testchipip._ -import example._ - -class ExampleTopWithBlockDevice(implicit p: Parameters) extends ExampleTop - with HasPeripheryBlockDevice { - override lazy val module = new ExampleTopWithBlockDeviceModule(this) -} - -class ExampleTopWithBlockDeviceModule(l: ExampleTopWithBlockDevice) - extends ExampleTopModule(l) - with HasPeripheryBlockDeviceModuleImp diff --git a/src/main/scala/example/Configs.scala b/src/main/scala/example/Configs.scala index e1c48f8d..e2e77fe0 100644 --- a/src/main/scala/example/Configs.scala +++ b/src/main/scala/example/Configs.scala @@ -1,14 +1,56 @@ package example +import chisel3._ import config.{Parameters, Config} -import testchipip.WithSerialAdapter +import diplomacy.LazyModule import coreplex.WithRoccExample import rocketchip.WithoutTLMonitors +import testchipip._ -class DefaultExampleConfig extends Config( +class WithExampleTop extends Config((site, here, up) => { + case BuildTop => (p: Parameters) => + Module(LazyModule(new ExampleTop()(p)).module) +}) + +class WithPWM extends Config((site, here, up) => { + case BuildTop => (p: Parameters) => + Module(LazyModule(new ExampleTopWithPWM()(p)).module) +}) + +class WithBlockDeviceModel extends Config((site, here, up) => { + case BuildTop => (p: Parameters) => { + val top = Module(LazyModule(new ExampleTopWithBlockDevice()(p)).module) + top.connectBlockDeviceModel() + top + } +}) + +class WithSimBlockDevice extends Config((site, here, up) => { + case BuildTop => (p: Parameters) => { + val top = Module(LazyModule(new ExampleTopWithBlockDevice()(p)).module) + top.connectSimBlockDevice() + top + } +}) + +class BaseExampleConfig extends Config( new WithoutTLMonitors ++ new WithSerialAdapter ++ new rocketchip.DefaultConfig) +class DefaultExampleConfig extends Config( + new WithExampleTop ++ new BaseExampleConfig) + class RoccExampleConfig extends Config( new WithRoccExample ++ new DefaultExampleConfig) + +class PWMConfig extends Config(new WithPWM ++ new BaseExampleConfig) + +class SimBlockDeviceConfig extends Config( + new WithBlockDevice ++ new WithSimBlockDevice ++ new BaseExampleConfig) + +class BlockDeviceModelConfig extends Config( + new WithBlockDevice ++ new WithBlockDeviceModel ++ new BaseExampleConfig) + +class WithTwoTrackers extends WithNBlockDeviceTrackers(2) +class WithFourTrackers extends WithNBlockDeviceTrackers(4) diff --git a/src/main/scala/pwm/PWM.scala b/src/main/scala/example/PWM.scala similarity index 99% rename from src/main/scala/pwm/PWM.scala rename to src/main/scala/example/PWM.scala index 8083b078..b9173467 100644 --- a/src/main/scala/pwm/PWM.scala +++ b/src/main/scala/example/PWM.scala @@ -1,4 +1,4 @@ -package pwm +package example import chisel3._ import chisel3.util._ diff --git a/src/main/scala/example/TestHarness.scala b/src/main/scala/example/TestHarness.scala index 5cfc67d1..f0d00ab3 100644 --- a/src/main/scala/example/TestHarness.scala +++ b/src/main/scala/example/TestHarness.scala @@ -4,16 +4,16 @@ import diplomacy.LazyModule import rocketchip._ import testchipip._ import chisel3._ -import config.Parameters +import config.{Field, Parameters} + +case object BuildTop extends Field[Parameters => ExampleTopModule[ExampleTop]] class TestHarness(implicit val p: Parameters) extends Module { val io = IO(new Bundle { val success = Output(Bool()) }) - def buildTop(p: Parameters): ExampleTop = LazyModule(new ExampleTop()(p)) - - val dut = Module(buildTop(p).module) + val dut = p(BuildTop)(p) dut.connectSimAXIMem() io.success := dut.connectSimSerial() } diff --git a/src/main/scala/example/Top.scala b/src/main/scala/example/Top.scala index fa90ad79..d9b484a1 100644 --- a/src/main/scala/example/Top.scala +++ b/src/main/scala/example/Top.scala @@ -24,3 +24,20 @@ class ExampleTopModule[+L <: ExampleTop](l: L) extends BaseSystemModule(l) with HasRocketPlexMasterModuleImp with HasNoDebugModuleImp with HasPeripherySerialModuleImp + +class ExampleTopWithPWM(implicit p: Parameters) extends ExampleTop + with HasPeripheryPWM { + override lazy val module = new ExampleTopWithPWMModule(this) +} + +class ExampleTopWithPWMModule(l: ExampleTopWithPWM) + extends ExampleTopModule(l) with HasPeripheryPWMModuleImp + +class ExampleTopWithBlockDevice(implicit p: Parameters) extends ExampleTop + with HasPeripheryBlockDevice { + override lazy val module = new ExampleTopWithBlockDeviceModule(this) +} + +class ExampleTopWithBlockDeviceModule(l: ExampleTopWithBlockDevice) + extends ExampleTopModule(l) + with HasPeripheryBlockDeviceModuleImp diff --git a/src/main/scala/pwm/Configs.scala b/src/main/scala/pwm/Configs.scala deleted file mode 100644 index 4096a6a0..00000000 --- a/src/main/scala/pwm/Configs.scala +++ /dev/null @@ -1,8 +0,0 @@ -package pwm - -import config.{Parameters, Config} -import testchipip.WithSerialAdapter -import uncore.tilelink.ClientUncachedTileLinkIO -import chisel3._ - -class PWMConfig extends Config(new example.DefaultExampleConfig) diff --git a/src/main/scala/pwm/TestHarness.scala b/src/main/scala/pwm/TestHarness.scala deleted file mode 100644 index 2e6d9c73..00000000 --- a/src/main/scala/pwm/TestHarness.scala +++ /dev/null @@ -1,14 +0,0 @@ -package pwm - -import config.Parameters -import diplomacy.LazyModule -import testchipip.GeneratorApp - -class TestHarness(q: Parameters) extends example.TestHarness()(q) { - override def buildTop(p: Parameters) = - LazyModule(new ExampleTopWithPWM()(p)) -} - -object Generator extends GeneratorApp { - generateFirrtl -} diff --git a/src/main/scala/pwm/Top.scala b/src/main/scala/pwm/Top.scala deleted file mode 100644 index 2e99007c..00000000 --- a/src/main/scala/pwm/Top.scala +++ /dev/null @@ -1,13 +0,0 @@ -package pwm - -import chisel3._ -import example._ -import config.Parameters - -class ExampleTopWithPWM(implicit p: Parameters) extends ExampleTop - with HasPeripheryPWM { - override lazy val module = new ExampleTopWithPWMModule(this) -} - -class ExampleTopWithPWMModule(l: ExampleTopWithPWM) - extends ExampleTopModule(l) with HasPeripheryPWMModuleImp