Showing posts with label Digital design. Show all posts
Showing posts with label Digital design. Show all posts

Wednesday, May 3, 2017

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.

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.

Wednesday, June 18, 2014

Wednesday Night Hack #4 - Commentary on SystemVerilog-Design Interface Example

I did not get around to synthesizing the example in Chapter 10 of Sutherland's book (refer to my previous post).  Instead, I have some comments about the published example. Most of my time tonight was spent preparing BARF for release.

To keep this post concise, I won't post snippets.  A copy of the source code can be found here.

Comment #1 : Modports TopReceive and CoreReceive are duplicated in interface Utopia.  I don't understand the decision to duplicate the modports.  The SVTB interface should describe the Utopia interface.  The Utopia interface is a set of signals and those signals can either be seen from point-of-view of receiver or transmitter.

Comment #2: The author made an interesting decision to model the register file using interface LookupTable.  I understand what he's trying to do -- DNR, do not repeat (yourself).  His control logic calls a function to read or write a memory array.  The function and memory array live in the interface rather than the module.  If you expect the synthesis tool to infer memories from RTL code, then it's a viable option.  If you need the ability to manually instantiate library cells for memory, then it's not so viable - you cannot instantiate modules within an interface.  I am somewhat weary about the approach for the following reason.  Yes, you can start with synthesis-inferred memory arrays, but what happens when/if you need to move to custom cells?  Then, the interface may not be able to serve its original purpose.

Comment #3: Why didn't author have the main FSM use signals in interfaces rather than drive temporary signals which are then assigned to the interface nets.

bit [0:NumTx-1] Txvalid; // FSM 'drives' this

for (TxIter=0; TxIter<NumTx; TxIter+=1) begin: GenTx
  assign Tx[TxIter].valid = Txvalid[TxIter] // assign to ifc

Comment #4: Combined blocking and non-blocking assignment in rx_valid_state

This example is all kinds of confusing.  I had to turn to StackOverflow to understand what was going on and I'm still not entirely clear how exactly that RTL code gets translated into gates.  The logic basically says to rotate the the round-robin pointer until one of the receivers has a valid cell that is ready to be processed.  Then, the cell is latched and the FSM advances to the next state.  It's an interesting strategy that I assume works because of SystemVerilog's always_ff.

Comment #5: What did I learn about networking?

Not much.  That ATM is a very old protocol.  That ATM is has nearly 10% "cell tax", meaning the header makes up that much of the total size of the cell.  The purpose of the design is to take in incoming ATM cells and arbitrate among receivers.  After a receiver is selected, the register file is accessed update the to-be-transmitted cell's VPI and compute it's new header error control (HEC) value.  Finally, there are two state machine that receive and transmit the cells according to Utopia protocol.

Tuesday, June 17, 2014

Two New Technical Books

I have two new technical books on their way to bookshelf :
I read through the table of contents of the first book and couldn't pass up its sub-$40 price tag (and 728 pages).  I'm especially interested in the second book.  PCB design is not a sexy field, but I've always been interested in creating something I can touch.  I've researched and found TechShop in San Jose has some equipment that can help support that experiment.  Likely, it's a far cry from the equipment that I could get access to at work, but alas, I want to keep my day job.  I have no concrete plans for a circuit board project right now, but maybe one day ...