val pageReg: Page = RegInit({ val page = Wire(new Page()) page.initialize() page })
Showing posts with label Scala. Show all posts
Showing posts with label Scala. Show all posts
Thursday, September 6, 2018
Register a bundle in Chisel3
A quick update to a previous post that I made: http://blog.edmondcote.com/2017/03/register-bundle-in-chisel.html. Here is how I now create a register (sequential storage element) of a bundle in Chisel3. The benefit is the elimination of the previously-necessary wire declaration.
Thursday, May 10, 2018
Another Scala Cheatsheet
I recently wrote up a "cheat sheet" for Scala.
You can download a .pdf copy of the file here.
My office is coming together nicely thanks to "decorations" as such.
References
https://alvinalexander.com/downloads/scala/Scala-Cheat-Sheet-devdaily.pdf (75% “copied” from his material)
https://alvinalexander.com/scala/how-to-define-use-partial-functions-in-scala-syntax-examples
http://blog.originate.com/blog/2014/06/15/idiomatic-scala-your-options-do-not-match/ (see: The Ultimate Scala Option Cheat Sheet)
You can download a .pdf copy of the file here.
My office is coming together nicely thanks to "decorations" as such.
References
https://alvinalexander.com/downloads/scala/Scala-Cheat-Sheet-devdaily.pdf (75% “copied” from his material)
https://alvinalexander.com/scala/how-to-define-use-partial-functions-in-scala-syntax-examples
http://blog.originate.com/blog/2014/06/15/idiomatic-scala-your-options-do-not-match/ (see: The Ultimate Scala Option Cheat Sheet)
Friday, January 12, 2018
Address Masking for RAM Devices
I found the problem of generating the correct address for a memory operation confusing and decided that it would be of value to me (and others) to take notes.
Assume we have an implementation of a slave device on a TileLink2 bus. It can receive either read (Get) or write (PutFullData) messages on channel A and correctly return the response on channel D. More information about this in the spec.
The following covers the implementation of the module, specifically on the mask generation, nothing more.
Assume we have an implementation of a slave device on a TileLink2 bus. It can receive either read (Get) or write (PutFullData) messages on channel A and correctly return the response on channel D. More information about this in the spec.
The following covers the implementation of the module, specifically on the mask generation, nothing more.
Assumptions. The slave device covers address range 0x2000000, size 0x1FFF (or 8KB). The system bus uses 8 bytes per beat (matching the 64 bit bus). The memory width matches the bus width. Number of memory words is 1024 and address width is 10 bits.
val address = in.a.bits.address // receive the full 64-bit physical address
val size = 0x1FFF // 8KB size, get using addressSet.mask
val size = in.a.size // log2(bytes) of total amount of the data requested, e.g., 8B cache line == 1
Problem. To compute the word-aligned address, you need a mask. Here is an example worked out by hand.
2000_1000 ^ (0x2000_1000 & ~mask-1) = 0x1000 (byte aligned) // where mask = 0x2000
1000 / 8 = 0x200 (8B word aligned)
addr[9:0] = 0x200
That was the easy part. I got confused by the operation of the circuit generator. Isn't the following great ;)
val a_address = Cat((mask zip (in.haddr >> log2Ceil(beatBytes)).toBools).filter(_._1).map(_._2).reverse)
This is definitely one the least appealing parts of functional programming. It would take me a few hours to reverse engineer this. How this should work is any non-trivial function should be placed in its own container and unit tested. The unit tests are commented and serve as a description of the functional algorithm. But, I digress ...
There is a helper object in the util package. Moral of the story. Use it.
// This gets used everywhere, so make the smallest circuit possible ...
// Given an address and size, create a mask of beatBytes size
// eg: (0x3, 0, 4) => 0001, (0x3, 1, 4) => 0011, (0x3, 2, 4) => 1111
// groupBy applies an interleaved OR reduction; groupBy=2 take 0010 => 01
object MaskGen {
def apply(addr_lo: UInt, lgSize: UInt, beatBytes: Int, groupBy: Int = 1): UInt = {
[..]Mid-January Update
November was mostly about writing a grant proposal for DARPA. It has been 110% technical work since then. Beginning in February, I will shift to writing pretty PowerPoint slides for the company. I should have a minimum viable prototype by then.
I worked on an experiment to build a continuous integration environment for the software assets of the RISC-V Foundation; learning Groovy and Gradle the process. The prototype uses Jenkins2 for which I have been pleasantly surprised. My previous experience was Jenkins 1.x. I published source code for the prototype here. I plan to volunteer some time to help coordinate some this activity. It is a small <5%-of-week commitment.
I began to move parts of my internal wiki to GitHub gists. I plan to add more over time.
Finally, I am accumulating notes on how to bootstrap RocketChip. You can find the notes here.
Also, compared to six months ago, I am beginning to feel very comfortable writing functional code using Scala. I struggle a bit here and there (i.e., when recursion comes into play), but overall it is a positive experience. If I had time, I would love to take an advanced class. It would be interesting to re-learn data structures, algorithms through a functional lense.
Wednesday, November 22, 2017
Connecting Zeppelin, Spark, and MongoDB
It took me a few hours to connect Zeppelin, Spark, and MongoDB. I didn't find a solution to this problem online; thus the short entry.
First, I added a dependency to the MongoDB Connector for Spark in my Zeppelin notebook.
%dep z.reset() z.load("org.mongodb.spark:mongo-spark-connector_2.10:2.2.0") %spark import com.mongodb.spark._ import com.mongodb.spark.rdd.MongoRDD val rdd = MongoSpark.load(sc)
This gave :
java.lang.IllegalArgumentException: Missing database name. Set via the 'spark.mongodb.input.uri' or 'spark.mongodb.input.database' property
Then, after realizing, that you cannot dynamically reconfigure the SparkContext. I used the GUI to set the property.
It is working well now!
rdd: com.mongodb.spark.rdd.MongoRDD[org.bson.Document] = MongoRDD[0] at RDD at MongoRDD.scala:47
Saturday, October 21, 2017
Script to generate Verilog ports from Chisel source
Here's a script I wrote that will (naively) parse a Verilog file and output it's corresponding ports in Chisel format. This is useful to import a Verilog module as a blackbox in a Chisel design.
The chosen regular expression was testing using regex101.com, a populate online regular expression tester.
#!/bin/sh exec scala "$0" "$@" !# import scala.util.{Success, Try} import scala.util.matching.Regex val port = raw"\s*(input|output|inout)\s+(wire\s*|reg\s*)?\s*(\[(\d+):(\d+)\])?\s*(\w+)?\s*;?".r val p = scala.io.Source.fromFile(args(0)).getLines.foreach { f: String => val b = f match { case port(d, tzpe, _, msb, lsb, name) => val dir = d match { case "input" => "Input" case "output" => "Output" case "inout" => "Analog" case _ => } val w = Try({msb.toInt - lsb.toInt + 1}) match { case Success(s) => s"%d".W.format(s) case _ => "1.W" } s"val $name = $dir(UInt($w))" case _ => "" } if (b.nonEmpty) println(b) }
The chosen regular expression was testing using regex101.com, a populate online regular expression tester.
Monday, October 16, 2017
My Clocking and Reset Strategy with RawModule
This post is originally a reply to: https://groups.google.com/forum/#!topic/chisel-users/LTujWW6DtI4
The following snippet of code illustrates my top level clocking and reset strategy. I opt to use LazyRawModuleImp and explicitly specify the clocks and reset.
Module GSR is a Chisel BlackBox for my FPGA's GSR (global set reset) library cell.
The following snippet of code illustrates my top level clocking and reset strategy. I opt to use LazyRawModuleImp and explicitly specify the clocks and reset.
class LazyTop(implicit p: Parameters) extends LazyModule { lazy val module = new LazyRawModuleImp(this) { val io = IO(new Bundle { val ref_clk_p = Input(Clock()) val rst_sw_n = Input(Bool()) // async reset, debounced on board? val led_n = Output(Bits(8.W)) }) val GSR_INST = Module(new GSR()) // this is blackbox module GSR_INST.io.GSR := io.rst_sw_n val global_reset = Wire(Bool()) val global_reset_n = Wire(Bool()) global_reset_n := GSR_INST.io.GSR // appears GSR is active low global_reset := !GSR_INST.io.GSR // use active high clock withClockAndReset(ref_clk_p, global_reset) { io.led_n := RegNext("h5A".asUInt(8.W), init = 0.U) } } }
Module GSR is a Chisel BlackBox for my FPGA's GSR (global set reset) library cell.
class GSR extends BlackBox { val io = IO(new Bundle { val GSR = Input(Bool()) }) }
Wednesday, October 4, 2017
To link Chisel annotations and circuit info
Here's another snippet of Chisel code. It was well worth the (ashamed to admit) 4+ hrs to write. Admittedly, I am still getting a hand of functional programming. I am particularly proud of the recursive function call to populate an immutable val. The function's use case is to return Chisel circuit level information from an Annotation object. It is necessary because Annotation does not contain (do best of my knowledge) a reference to a Data object.
private def getDirection(circuit: Circuit, a: Annotation): ActualDirection = { // get net info from annotation object val thisModName = a.target.asInstanceOf[ComponentName].module.name val thisPortName = a.target.name.replace("io.", "") // FIXME: this is a HACK .. // find matching module in Chisel circuit val module = circuit.components.flatMap { case m: DefModule => Some(m) case b: DefBlackBox => None }.find { _.name == thisModName }.head // recursively return Element objects def elemsFromData(d: Data): Seq[Element] = d match { case e: Element => Seq(e) case r: Record => r.elements.flatMap((e: (String, Data)) => { elemsFromData(e._2) }).toSeq } // all elements for all module port val elems: Seq[Element] = module.ports.flatMap((p: Port) => { elemsFromData(p.id) }) // use DataMirror to find direction, have yet to test whether fully accurate // FIXME: obviously not optimal, should filter above val dir = DataMirror.directionOf(elems.find(_.name == thisPortName).head) dir }
Tuesday, September 26, 2017
Generate custom Chisel bundle using meta programming
I found the example to extend a Bundle's functionality limiting. You need to pass a varargs of (String,Data) tuple to the function. Here's a snippet:
I could have found a solution using the above (not sure, is it possible to convert ListMap to varargs?), but I dug into Scala meta programming for the purpose of ramp. Behold! Here's an alternative (though incomplete) method of generating a bundle.
The code above returns an instance of a typeless bundle. The result isn't equivalent to above, but serves my purpose. Have yet to try, but suspect the technique can be extended to other cases. There's likely implications wrt. statically typed nature of Scala. Use at your own risk. I am only posting this because it's a neat hack.
final class CustomBundle(elts: (String, Data)*) extends Record { val elements = ListMap(elts map { case (field, elt) => field -> elt.chiselCloneType }: _*) def apply(elt: String): Data = elements(elt) override def cloneType = (new CustomBundle(elements.toList: _*)).asInstanceOf[this.type] }
I could have found a solution using the above (not sure, is it possible to convert ListMap to varargs?), but I dug into Scala meta programming for the purpose of ramp. Behold! Here's an alternative (though incomplete) method of generating a bundle.
object MetaBundle { import reflect.runtime.currentMirror import tools.reflect.ToolBox val toolbox = currentMirror.mkToolBox() import toolbox.u._ def apply(): Bundle = { val tree = q""" import chisel3.core._ val b = new Bundle { // placeholder for your interface val i = Input(UInt(1.W)) val o = Output(UInt(1.W)) } b """
toolbox.eval(tree).asInstanceOf[Bundle] } }
The code above returns an instance of a typeless bundle. The result isn't equivalent to above, but serves my purpose. Have yet to try, but suspect the technique can be extended to other cases. There's likely implications wrt. statically typed nature of Scala. Use at your own risk. I am only posting this because it's a neat hack.
Monday, September 25, 2017
Driving random values on all elements of a bundle
Quick addition to the previous post. This technique is useful when prototyping hardware. Use LFSRs to drive pins/ports such that no logic pruning occurs its cone of logic during synthesis.
final def prng(bundle: Bundle): Unit = { bundle.elements.filter(_._2.dir == OUTPUT).foreach { case (n, d) => { val r = Module(new LFSR(d.getWidth)) when(true.B) { d := r.io.y } } } }
Friday, August 25, 2017
Decomposing TileLink2 in RocketChip: A Barebones System
Quick post. I spent some time yesterday/today hacking at the TileLink2 implementation in RocketChip.
(As a matter of coincidence, SiFive recently released a draft spec of the protocol.)
My preferred method of learning is first to understand the engineer's original intent before enhancing or leveraging code. This means taking things apart.
The most difficult aspect in getting something up was understanding the inner workings of SystemBus class. I kept hitting run time assertions and it was helpful to manually sketch out the connections between the TL objects:
Here is a summary of my findings.
I identified the minimal set of configuration knobs for this experiment.
This is the system itself. It extends BaseComplex. Not RocketComplex.
This should be familiar. It is your top level Chisel3 module.
Here are the important parts of the system generator. This will generate your firrtl and verilog output.
Finally, one should never forget unit testing!
(As a matter of coincidence, SiFive recently released a draft spec of the protocol.)
My preferred method of learning is first to understand the engineer's original intent before enhancing or leveraging code. This means taking things apart.
The most difficult aspect in getting something up was understanding the inner workings of SystemBus class. I kept hitting run time assertions and it was helpful to manually sketch out the connections between the TL objects:
Here is a summary of my findings.
I identified the minimal set of configuration knobs for this experiment.
// Barebones system configuration class BarebonesSystemConfig extends Config((site, here, up) => { case XLen => 64 case BankedL2Params => BankedL2Params(nMemoryChannels = 0, nBanksPerChannel = 1, coherenceManager = { // FIXME: not really a coherence manager case (q, _) => implicit val p = q val cork = LazyModule(new TLCacheCork(unsafe = true)) (cork.node, cork.node) }) case SystemBusParams => SystemBusParams(beatBytes = site(XLen) / 8, blockBytes = site(CacheBlockBytes)) case PeripheryBusParams => PeripheryBusParams(beatBytes = site(XLen) / 8, blockBytes = site(CacheBlockBytes)) case MemoryBusParams => MemoryBusParams(beatBytes = 8, blockBytes = site(CacheBlockBytes)) case CacheBlockBytes => 64 case DTSTimebase => BigInt(1000000) // 1 MHz case DTSModel => "bboneschip" case DTSCompat => Nil case TLMonitorBuilder => (args: TLMonitorArgs) => Some(LazyModule(new TLMonitor(args))) case TLCombinationalCheck => false case TLBusDelayProbability => 0.0 })
This is the system itself. It extends BaseComplex. Not RocketComplex.
class BarebonesSystem(implicit p: Parameters) extends BaseCoreplex { // connect single master device (fuzzer) to system bus (sbus) sbus.fromSyncPorts() :=* LazyModule(new TLFuzzer(1)).node // connect single slave device (memory) to the periphery bus (pbus) LazyModule(new TLTestRAM(AddressSet(0x0, 0xfff))).node :=* pbus.toFixedWidthSingleBeatSlave(4) override lazy val module = new BarebonesSystemModule(this) } class BarebonesSystemModule[T <: BarebonesSystem](_outer: T) extends BaseCoreplexModule(_outer) {}
This should be familiar. It is your top level Chisel3 module.
// Chisel top module class Top(implicit val p: Parameters) extends Module { val io = new Bundle { val success = Bool(OUTPUT) } val dut = Module(LazyModule(new BarebonesSystem).module) dut.reset := reset }
Here are the important parts of the system generator. This will generate your firrtl and verilog output.
// System generator class System extends HasGeneratorUtilities { val names = new ParsedInputNames( targetDir = ".", topModuleProject = "com.bbones", topModuleClass = "Top", configProject = "", configs = "system" ) val config = new BarebonesSystemConfig val params = Parameters.root(config.toInstance) val circuit = elaborate(names, params) def generateArtefacts: Unit = ElaborationArtefacts.files.foreach { case (extension, contents) => writeOutputFile(names.targetDir, s"${names.configs}.${extension}", contents()) } def generateFirrtl: Unit = Driver.dumpFirrtl(circuit, Some(new File(names.targetDir, s"${names.configs}.fir"))) def generateVerilog: Unit = { import sys.process._ val firrtl = "/home/edc/gitrepos/rocket-chip/firrtl/utils/bin/firrtl" val path = s"${names.targetDir}/${names.configs}" val bin = s"$firrtl -i $path.fir -o $path.v -X verilog" bin.! } generateArtefacts generateFirrtl generateVerilog }
Finally, one should never forget unit testing!
// Unit test class SystemSpec extends FlatSpec with Matchers { "An instance of the system generator " should "compile" in { val s = new System } }
Thursday, August 17, 2017
Becoming Functional: Book and Personal Experience
Becoming Functional is a book written by Joshua Backfield that lays out steps to transform oneself into a functional programmer.
It is a short book (under 150 pages) and is a very enjoyable read. I did learn a thing or ten. I refer back to the book whenever I have a suspicion that a certain aspect of my code can be improved.
The most interesting revelation is how my background in hardware design and verification engineers lends well to functional programming. Functional concepts seem to be come naturally to me. I am no expert by any means, but looking at Scala code doesn't frighten me anymore.
It is a short book (under 150 pages) and is a very enjoyable read. I did learn a thing or ten. I refer back to the book whenever I have a suspicion that a certain aspect of my code can be improved.
The most interesting revelation is how my background in hardware design and verification engineers lends well to functional programming. Functional concepts seem to be come naturally to me. I am no expert by any means, but looking at Scala code doesn't frighten me anymore.
Monday, May 8, 2017
How to test a parameterized module in Chisel
Quick update today. Busy with real work. This quick post is written because how to test these modules in not adequately covered in the documentation for chisel-testers.
Consider the case for a parameterizable LSFR module.
Below I show a test containing two examples. First using PokeTester and the second using PeekPokeTester. See if you can spot the difference ...
In the PokeTester case, the first argument to test is new LSFR(new DDRCommand). For PeekPokeTester, you pass a function to generate the module () => new LSFR(new DDRCommand). Not immediately obvious. Now, look at the function prototypes for PokeTester and PeekPokeTester respectively ...
The definition of dutGen is different.
Wise to keep in mind that PokeTester is under iotesters.experimental.
Consider the case for a parameterizable LSFR module.
class LSFR[T <: Bundle](gen: T = UInt(4.W)) extends Module { val io = IO(new Bundle { val rand = Output(gen) }) val width = gen.getWidth val regLFSR = Reg(UInt(width.W), init = UInt(0)) when(true.B) { regLFSR := Cat(regLFSR(0) ^ regLFSR(1), regLFSR(width - 1, 1)) } io.rand := gen.fromBits(regLFSR) }
Below I show a test containing two examples. First using PokeTester and the second using PeekPokeTester. See if you can spot the difference ...
class LSFRPeekPokeTester[T <: Bundle](gen: T, c: LSFR[T]) extends PeekPokeTester(c) { println("peekpoke test") } class LSFRSpec extends ChiselFlatSpec with PokeTester { behavior of "LSFR" it should "elaborate with peek test" in { val options = new TesterOptionsManager options.setTargetDirName("test_run_dir/LSFRSpec") test(new LSFR(new DDRCommand), testerBackend = FirrtlInterpreterBackend, options = options) { (t, c) => { println("poke test") } } } it should "elaborate with peekpoke test" in { Driver(() => new LSFR(new DDRCommand)) { c => new LSFRPeekPokeTester(new DDRCommand, c) } } }
In the PokeTester case, the first argument to test is new LSFR(new DDRCommand). For PeekPokeTester, you pass a function to generate the module () => new LSFR(new DDRCommand). Not immediately obvious. Now, look at the function prototypes for PokeTester and PeekPokeTester respectively ...
// PokeTester source def test[T <: Module](dutGen: => T, testerBackend: TesterBackend, options: TesterOptionsManager)(block: (InnerTester, T) => Unit) { //[..] // PeekPokeTester source def apply[T <: Module]( dutGen: () => T, backendType: String = "firrtl", verbose: Boolean = false, testerSeed: Long = System.currentTimeMillis())( testerGen: T => PeekPokeTester[T]): Boolean = { //[..]
The definition of dutGen is different.
Wise to keep in mind that PokeTester is under iotesters.experimental.
Saturday, May 6, 2017
Use of HellaQueue in Chisel, secondary constructor
This post is an expanded update to an entry in my personal "NOTES" file. At first glance, I found the following code perplxing, therefore I decided to break it down.
What does the :< operator do in [T <: Data>]?
It is obvious (to me at least) that this is for type parameterization. The <: operator indicates that the type supplied to the class instance must have chisel3.core.Data as an ancestor.
Why does (data: => T) do?
No suprise that (val entries: Int) is the primary constructor. The fat arrow (=>) implies a function. The first argument to the constructor lets you specific the number of entries. The second argument data helps to parameterize the class.
Why is a class definion and a object definition of the same name?
The object is known as a companion class, consult stackoverflow.com for more info
What does the apply function do in the object?
The apply function acts as an auxillary constructor. Allows alternative syntax for creating HellaQueue.
class HellaQueue[T <: Data](val entries: Int)(data: => T) extends Module { val io = new QueueIO(data, entries) val fq = Module(new HellaFlowQueue(entries)(data)) fq.io.enq <> io.enq io.deq <> Queue(fq.io.deq, 1, pipe = true) } object HellaQueue { def apply[T <: Data](enq: DecoupledIO[T], entries: Int) = { val q = Module((new HellaQueue(entries)) { enq.bits }) 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 } }
What does the :< operator do in [T <: Data>]?
It is obvious (to me at least) that this is for type parameterization. The <: operator indicates that the type supplied to the class instance must have chisel3.core.Data as an ancestor.
Why does (data: => T) do?
No suprise that (val entries: Int) is the primary constructor. The fat arrow (=>) implies a function. The first argument to the constructor lets you specific the number of entries. The second argument data helps to parameterize the class.
// example usage val xy: Data val hq1 = (new HellaQueue(entries = 90)){xy} // equivalent to above, without (data: => T) in the class constructor val hq2 = (new HellaQueue[SInt](entries = 90))
Why is a class definion and a object definition of the same name?
The object is known as a companion class, consult stackoverflow.com for more info
What does the apply function do in the object?
The apply function acts as an auxillary constructor. Allows alternative syntax for creating HellaQueue.
Wednesday, May 3, 2017
Using IDEA Scala debugger for Chisel
This a quick follow up on an older post where I set up IntelliJ IDEA and Scala. I wrote this to make sure my steps for getting the debugger up and running were reproducable. The steps assume you have a working Chisel project that compiles using sbt.
Check if sbt compile works from the command line for your Chisel project ...
Check if sbt compile works from the command line for your Chisel project ...
[plus]:~/gitrepos/plus/arbiterdemo$ sbt compile [info] Loading global plugins from /home/edc/.sbt/0.13/plugins [info] Loading project definition from /home/edc/gitrepos/plus/arbiterdemo/project [info] Set current project to memctrldemo (in build file:/home/edc/gitrepos/plus/arbiterdemo/) [info] Updating {file:/home/edc/gitrepos/plus/arbiterdemo/}arbiterdemo... [..] [info] Done updating. [info] Compiling 3 Scala sources to /home/edc/gitrepos/plus/arbiterdemo/target/scala-2.11/classes... [success] Total time: 4 s, completed May 3, 2017 8:26:36 PM
Use the default project settings ...
Right click on your class that contains call to chisel3.Driver.execute, hit Run ...
Right click on your class that contains call to chisel3.Driver.execute, hit Run ...
Follow up by checking that that Verilog code is generated as expected (yes)
Finally, try setting a breakpoint by right clicking to the left of the source window and hit shift-F9 to begin debug. I was 100% successfull following only these steps on IDEA 2017.1 with the project-specific IDEA settings (i.e. .idea/ diretory) wiped out prior.
Finally, try setting a breakpoint by right clicking to the left of the source window and hit shift-F9 to begin debug. I was 100% successfull following only these steps on IDEA 2017.1 with the project-specific IDEA settings (i.e. .idea/ diretory) wiped out prior.
Gentle introduction to diplomacy
In a previous post, I was looking at how to use the diplomacy and uncore libraries (in Rocket Chip Generator) to hook up a simple AHB master module to AHB slave module. To my knowledge, none of the library code is documented. IDEA's debugger came in handy to grow my understanding of the code base. I can confirm the wiring portion now works. May come back to this in the future.
... there might be a bug in naming of ports for hrdata.
Master module
class Master()(implicit p: Parameters) extends LazyModule { val ahbMasterParameters = AHBMasterParameters( // nothing for now .. ) val ahbMasterPortParameters = AHBMasterPortParameters( masters = Seq(ahbMasterParameters) ) val node = AHBMasterNode( portParams = Seq(ahbMasterPortParameters) ) lazy val module = new LazyModuleImp(this) { val io = new Bundle { val out = node.bundleOut } } }
Slave module
class Slave()(implicit p: Parameters) extends LazyModule { val ahbSlaveParameters = AHBSlaveParameters( address = Seq(AddressSet(0x0, 0xFFFF)), regionType = RegionType.UNCACHED, executable = true, supportsRead = TransferSizes(1, 4), supportsWrite = TransferSizes(1, 4) ) val ahbSlavePortParameters = AHBSlavePortParameters( slaves = Seq(ahbSlaveParameters), beatBytes = 4 ) val node = AHBSlaveNode( portParams = Seq(ahbSlavePortParameters) ) lazy val module = new LazyModuleImp(this) { val io = new Bundle { val in = node.bundleIn } } }
Connect master to slave
class Slave()(implicit p: Parameters) extends LazyModule { val ahbSlaveParameters = AHBSlaveParameters( address = Seq(AddressSet(0x0, 0xFFFF)), regionType = RegionType.UNCACHED, executable = true, supportsRead = TransferSizes(1, 4), supportsWrite = TransferSizes(1, 4) ) val ahbSlavePortParameters = AHBSlavePortParameters( slaves = Seq(ahbSlaveParameters), beatBytes = 4 ) val node = AHBSlaveNode( portParams = Seq(ahbSlavePortParameters) ) lazy val module = new LazyModuleImp(this) { val io = new Bundle { val in = node.bundleIn } } }
Top level hookup
class ChiselTopTest extends ChiselFlatSpec { class ChiselTopTester(c: ChiselTopWrapper) extends PeekPokeTester(c) { println("Hello World!") } // https://github.com/ucb-bar/rocket-chip/issues/359 class ChiselTopWrapper(p: Parameters) extends Module { // must wrap Module into Module() .. val top = Module(LazyModule(new ChiselTop()(p)).module) // must wrap IO into IO(), thought it wasn't necessary with Chisel3 .. val io = IO(top.io.cloneType) io <> top.io } implicit val p: Parameters = new BlankConfig chisel3.iotesters.Driver(() => new ChiselTopWrapper(p)) { c => new ChiselTopTester(c) } }
Generated verilog (abridged), woo!
module ChiselTop( input clock, input reset, input io_ddrClock ); Master_master master ( .io_out_0_hwdata(master_io_out_0_hwdata), .io_out_0_hrdata(master_io_out_0_hrdata) //--TODO: check naming ); Slave_slave slave ( .io_in_0_hwdata(slave_io_in_0_hwdata), .io_in_0_hrdata(slave_io_in_0_hrdata) ); // slave to master for read data assign master_io_out_0_hrdata = slave_io_in_0_hrdata; // master to slave for write data assign slave_io_in_0_hwdata = master_io_out_0_hwdata; endmodule
... there might be a bug in naming of ports for hrdata.
Subscribe to:
Posts (Atom)