Search code examples
scalaxilinxchisel

How to instanciate Xilinx differential clock buffer with chisel3 blackboxes?


I want to write a simple chisel3 blinking led design on my AC701 kit (artix7). But to do that I have to instantiate a clock input differential buffer. Xilinx give the following verilog template to do that :

IBUFDS #(
    .DIFF_TERM("TRUE"),
    .IOSTANDARD("DEFAULT")
) IBUFDS1_inst (
    .O(clock1), // Clock buffer
    .I(clock1_p), // Diff_p clock
    .IB(clock1_n) // Diff_n clock
);

I read on chisel documentation that I have to use «blackbox» class to instantiate it. But I can't do it. I tried this :

class IbufdsParam extends VerilogParameters {
    val DIFF_TERM  = "TRUE" 
    val IOSTANDARD = "DEFAULT"
}

class IBUFDS extends BlackBox {
  val params = new IbufdsParam()
  val io = IO(new Bundle {
    val O = Output(Bool())
    val I = Input(Bool())
    val IB = Input(Bool())})
  io.O.setName("O")
  io.I.setName("I")
  io.IB.setName("IB")

  /* For simulation */
  io.O := io.I & ~io.IB
}

But it seem that chisel3 doesn't know VerilogParameters class :

[error] blinking_led/blink.scala:5: not found: type VerilogParameters
[error] class IbufdsParam extends VerilogParameters {

And I don't know how to say «do not use clock and reset with this module».

Once this blackbox correctly declared, I will have to connect the output clock ('O') to the main clock of my blinking module. I'm not sure about how to do that. I'm thinking about that :

class Blink extends Module {
  val io = IO(new Bundle {
    val clock_p = Input(Bool())
    val clock_n = Input(Bool())
    val led  = Output(Bool())
  })

  val ibufds = IBUFDS()

  Driver.implicitClock := ibufds.io.O
  ibufds.io.I := io.clock_p
  ibufds.io.IB:= io.clock_n

...
}

But I think it's maybe not the right way, isn't it ?


Solution

  • This is a documentation failure, I'll be sure to add a page on the chisel3 wiki for parameterized blackboxes shortly. Parameterized blackboxes are currently any experimental feature of Chisel3 that can be used by passing a Map of String to Strings or Ints or Longs to the BlackBox constructor. Thus for your particular case, try:

    import chisel3._
    import chisel3.experimental._
    
    class IBUFDS extends BlackBox(Map("DIFF_TERM" -> "TRUE",
                                      "IOSTANDARD" -> "DEFAULT")) {
      val io = IO(new Bundle {
        val O = Output(Clock())
        val I = Input(Clock())
        val IB = Input(Clock())
      })
    }
    

    In chisel3, there is no implicit clock or reset for BlackBoxes, ports also can't be renamed but will instead get the name given in the io Bundle (without any io_ added). Simulation behavior is also not currently supported, but you can provide a Verilog implementation and simulate your whole design with Verilator.

    Now, we want to use the O output of IBUFDS and connect it to some Blink Module. You cannot use a submodule to overrule the clock of its parent, but you can set the clock of a submodule. Thus, I can provide some Top Module that instantiates both IBUFDS and Blink, eg.

    class Blink extends Module {
      val io = IO(new Bundle {
        val led = Output(Bool())
      })
      val reg = Reg(init = false.B)
      reg := !reg
      io.led := reg
    }
    
    class Top extends Module {
      val io = IO(new Bundle {
        val clock_p = Input(Clock())
        val clock_n = Input(Clock())
        val led  = Output(Bool())
      })
    
      val ibufds = Module(new IBUFDS)
      ibufds.io.I := io.clock_p
      ibufds.io.IB:= io.clock_n
    
      val blink = Module(new Blink)
      blink.clock := ibufds.io.O
      io.led := blink.io.led   
    }
    

    This code leads to IBUFDS being instantiated as follows:

    IBUFDS #(.DIFF_TERM("TRUE"), .IOSTANDARD("DEFAULT")) ibufds (
      .IB(ibufds_IB),
      .I(ibufds_I),
      .O(ibufds_O)
    );
    

    which I believe should do what you want!