Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Requirements for converting compressed Bundles to uncompressed Bundles #7

Closed
dreamflyings opened this issue May 14, 2022 · 9 comments
Closed

Comments

@dreamflyings
Copy link

Many times, we need to integrate systemverilog/verilog (or languages ​​that can generate them) into our SpinalHDL programs. In this process we need to define some compressed Bundles, such as:

case class AxiLite4DirectDemo(AW:Int, DW:Int, num:Int) extends Bundle with IMasterSlave {
    val STRBW = DW / 8
    val aw_addr = UInt(AW * num bits)
    val aw_valid = UInt(num bits)
    val aw_ready = UInt(num bits)
    val w_data = UInt(DW * num bits)
    val w_strb = UInt(STRBW * num bits)
    val w_valid = UInt(num bits)
    val w_ready = UInt(num bits)
    val b_resp = UInt(2 * num bits)
    val b_valid = UInt(num bits)
    val b_ready = UInt(num bits)
    val ar_addr = UInt(AW * num bits)
    val ar_valid = UInt(num bits)
    val ar_ready = UInt(num bits)
    val r_data = UInt(DW * num bits)
    val r_resp = UInt(2 * num bits)
    val r_valid = UInt(num bits)
    val r_ready = UInt(num bits)
    override def asMaster(): Unit = {
      in(b_resp, b_valid, aw_ready, w_ready, ar_ready, r_data, r_resp, r_valid)
      out(aw_addr, aw_valid, w_data, w_strb, w_valid, b_ready, ar_addr, ar_valid, r_ready)
    }
  }

For the convenience of use, we usually define it like this when using:

 Vec((AxiLite4Demo(AW, DW, 1)), num)

So, we need a helper that maps from (AxiLite4Demo(AW, DW, num)) to Vec((AxiLite4Demo(AW, DW, 1)), num). Of course, the more general the better. I have implemented a very low program to do this. There may be some situations that I have not considered, and the generality is not good. So, is there a better implementation?
My code is as follows:

object UnpackedBundlePlay extends App{
  case class AxiLite4Demo(AW:Int, DW:Int, num:Int) extends Bundle with IMasterSlave {
    val STRBW = DW / 8
    val aw_addr = UInt(AW * num bits)
    val aw_valid = UInt(num bits)
    val aw_ready = UInt(num bits)
    val w_data = UInt(DW * num bits)
    val w_strb = UInt(STRBW * num bits)
    val w_valid = UInt(num bits)
    val w_ready = UInt(num bits)
    val b_resp = UInt(2 * num bits)
    val b_valid = UInt(num bits)
    val b_ready = UInt(num bits)
    val ar_addr = UInt(AW * num bits)
    val ar_valid = UInt(num bits)
    val ar_ready = UInt(num bits)
    val r_data = UInt(DW * num bits)
    val r_resp = UInt(2 * num bits)
    val r_valid = UInt(num bits)
    val r_ready = UInt(num bits)
    def unpacked(): Vec[AxiLite4Demo] = new Composite(this, "unpacked") {
      val ret = Vec((AxiLite4Demo(AW, DW, 1)), num)
      val direct = self.elements.map { g => g._2.getDirection }
      (ret.map(_.elements).transpose zip self.elements).zip(direct).map { case ((r, s), d) =>
        if(d == `in`) (r.map(_._2) zip s._2.asBits.subdivideIn(r.head._2.getBitsWidth bits)).map{case(i,j) => i. assignFromBits(j)}
        else s._2.assignFromBits(Cat(r.map(_._2)))
      }
    }.ret
    def packed(va: Vec[AxiLite4Demo]):Unit = new AreaObject {
      va <> unpacked()
    }
    override def asMaster(): Unit = {
      in(b_resp, b_valid, aw_ready, w_ready, ar_ready, r_data, r_resp, r_valid)
      out(aw_addr, aw_valid, w_data, w_strb, w_valid, b_ready, ar_addr, ar_valid, r_ready)
    }
  }
  SpinalConfig().generateSystemVerilog(new Module{
    val io = new Bundle{
      val ain = slave( AxiLite4Demo(8,32,4))
      val aout= Vec(master(AxiLite4Demo(8,32,1)), 4)
    }
    io.aout <> io.ain.unpacked()
  }.setDefinitionName("UnpackedMod"))
  SpinalConfig().generateSystemVerilog(new Module{
    val io = new Bundle{
      val aout = master(AxiLite4Demo(8,32,4))
      val ain = Vec(slave(AxiLite4Demo(8,32,1)), 4)
    }
    io.aout.packed(io.ain)
  }.setDefinitionName("PackedMod"))
}

By the way, the user-defined instruction flow has been run through, and the parameter system is also good to use. It is roughly used as follows:

object TestModPlugin extends AreaObject{
  val P = NaxParameter[TestModPlugin_P]
}
...var p:TestModPlugin_P...
  create config {
    TestModPlugin.P.set(p)
  }

Thank you very much!

@Dolu1990
Copy link
Member

Hi,

compressed Bundles

Hoo yes, i remember the pain of those :)

I'm asking myself if the best would not be to have a general data type for this (grosso modo):

class PacketData[T <: Data](template : T, size : Int) extends Data{
   val elements = LinkedHashMap[BaseType, Bits]()
   //fill elements
   for(e <- template.flatten){
      //Fill elements cache which map a element of the template to its packed representation (e * size)
   }
   //Utilities to manipulate stuff
   def apply(key : T => BaseType, index : Int) = {
      val e = elements(key(template))
      val w = widthOf(e)
      e(w*index, w bits)
   }
}

And having utility to automaticaly convert from / to the original type T

That way you would not have to manualy redefine things by hands

@Dolu1990
Copy link
Member

Here is a working example, which isn't read for use in IO, but already as a prototype to talk about :

object PlayPackedData extends App{
  class PackedData[T <: Data](hardType : HardType[T], size : Int) extends MultiData {
    override val elements = ArrayBuffer[(String, Data)]()
    class Element(val name : String, val raw : Bits, val width : Int)
    val elementsMap = mutable.LinkedHashMap[String, Element]()

    packedBuild()

    def packedBuild() {
      val template = hardType()
      for ((e, name) <- (template.flatten, template.flattenLocalName).zipped) {
        println(e + " " + name)
        val w = widthOf(e)
        val ref = Bits(widthOf(e) * size bits)
        elements += name -> ref
        elementsMap(name) = new Element(name, ref, w)
        ref.parent = this
        if (OwnableRef.proposal(ref, this)) ref.setPartialName(name, Nameable.DATAMODEL_WEAK)
      }
    }

    def pack(that : T, index : Int) = {
      for((from, name) <- (that.flatten, that.flattenLocalName).zipped){
        val to = elementsMap(name)
        assert(widthOf(from) == to.width)
        to.raw(to.width*index, to.width bits) := from.asBits
      }
    }

    def unpack(index : Int) : T = {
      val ret = hardType()
      for((to, name) <- (ret.flatten, ret.flattenLocalName).zipped){
        val from = elementsMap(name)
        to.assignFromBits(from.raw(from.width*index, from.width bits))
      }
      ret
    }

    override def assignFromImpl(that: AnyRef, target: AnyRef, kind: AnyRef): Unit = {
      that match {
        case that: PackedData[_] =>
          ???
        case _ => throw new Exception("Undefined assignment")
      }
    }
  }

  SpinalVerilog(new Component {
    val x = new PackedData(Rgb(5,6,5), 4).assignDontCare()
    val y = Rgb(5,6,5)
    x.pack(y, 2)
    val z = x.unpack(2)
  })
}

Let's me know what you think

@dreamflyings
Copy link
Author

dreamflyings commented May 17, 2022

@Dolu1990
Dear Dolu1990
Thank you for trying to implement this feature in your busy schedule. It's just that this helper class doesn't do what I want, and it's not intuitive to use.
The result of my code after generation is this:

module UnpackedMod (
  input[31:0] io_ain_aw_addr,
  input[3:0] io_ain_aw_valid,
  output[3:0] io_ain_aw_ready,
  input[127:0] io_ain_w_data,
  input[15:0] io_ain_w_strb,
  input[3:0] io_ain_w_valid,
  output[3:0] io_ain_w_ready,
  output[7:0] io_ain_b_resp,
  output[3:0] io_ain_b_valid,
  input[3:0] io_ain_b_ready,
  input[31:0] io_ain_ar_addr,
  input[3:0] io_ain_ar_valid,
  output[3:0] io_ain_ar_ready,
  output[127:0] io_ain_r_data,
  output[7:0] io_ain_r_resp,
  output[3:0] io_ain_r_valid,
  input[3:0] io_ain_r_ready,
  output[7:0] io_aout_0_aw_addr,
  output [0:0] io_aout_0_aw_valid,
  input[0:0] io_aout_0_aw_ready,
  output[31:0] io_aout_0_w_data,
  output[3:0] io_aout_0_w_strb,
  output [0:0] io_aout_0_w_valid,
  input [0:0] io_aout_0_w_ready,
  input[1:0] io_aout_0_b_resp,
  input [0:0] io_aout_0_b_valid,
  output [0:0] io_aout_0_b_ready,
  output[7:0] io_aout_0_ar_addr,
  output [0:0] io_aout_0_ar_valid,
  input [0:0] io_aout_0_ar_ready,
  input[31:0] io_aout_0_r_data,
  input[1:0] io_aout_0_r_resp,
  input [0:0] io_aout_0_r_valid,
  output [0:0] io_aout_0_r_ready,
  output[7:0] io_aout_1_aw_addr,
  output [0:0] io_aout_1_aw_valid,
  input [0:0] io_aout_1_aw_ready,
  output[31:0] io_aout_1_w_data,
  output[3:0] io_aout_1_w_strb,
  output [0:0] io_aout_1_w_valid,
  input[0:0] io_aout_1_w_ready,
  input[1:0] io_aout_1_b_resp,
  input[0:0] io_aout_1_b_valid,
  output [0:0] io_aout_1_b_ready,
  output[7:0] io_aout_1_ar_addr,
  output [0:0] io_aout_1_ar_valid,
  input [0:0] io_aout_1_ar_ready,
  input[31:0] io_aout_1_r_data,
  input[1:0] io_aout_1_r_resp,
  input [0:0] io_aout_1_r_valid,
  output [0:0] io_aout_1_r_ready,
  output[7:0] io_aout_2_aw_addr,
  output [0:0] io_aout_2_aw_valid,
  input[0:0] io_aout_2_aw_ready,
  output[31:0] io_aout_2_w_data,
  output[3:0] io_aout_2_w_strb,
  output [0:0] io_aout_2_w_valid,
  input[0:0] io_aout_2_w_ready,
  input[1:0] io_aout_2_b_resp,
  input[0:0] io_aout_2_b_valid,
  output [0:0] io_aout_2_b_ready,
  output[7:0] io_aout_2_ar_addr,
  output [0:0] io_aout_2_ar_valid,
  input [0:0] io_aout_2_ar_ready,
  input[31:0] io_aout_2_r_data,
  input[1:0] io_aout_2_r_resp,
  input [0:0] io_aout_2_r_valid,
  output [0:0] io_aout_2_r_ready,
  output[7:0] io_aout_3_aw_addr,
  output [0:0] io_aout_3_aw_valid,
  input[0:0] io_aout_3_aw_ready,
  output[31:0] io_aout_3_w_data,
  output[3:0] io_aout_3_w_strb,
  output [0:0] io_aout_3_w_valid,
  input[0:0] io_aout_3_w_ready,
  input[1:0] io_aout_3_b_resp,
  input[0:0] io_aout_3_b_valid,
  output [0:0] io_aout_3_b_ready,
  output[7:0] io_aout_3_ar_addr,
  output [0:0] io_aout_3_ar_valid,
  input [0:0] io_aout_3_ar_ready,
  input[31:0] io_aout_3_r_data,
  input[1:0] io_aout_3_r_resp,
  input [0:0] io_aout_3_r_valid,
  output[0:0] io_aout_3_r_ready
);

Among them, the following interface will be connected to the wrapper of the systemverilog interface converter

input[31:0] io_ain_aw_addr,
  input[3:0] io_ain_aw_valid,
  output[3:0] io_ain_aw_ready,
  input[127:0] io_ain_w_data,
  input[15:0] io_ain_w_strb,
  input[3:0] io_ain_w_valid,
  output[3:0] io_ain_w_ready,
  output[7:0] io_ain_b_resp,
  output[3:0] io_ain_b_valid,
  input[3:0] io_ain_b_ready,
  input[31:0] io_ain_ar_addr,
  input[3:0] io_ain_ar_valid,
  output[3:0] io_ain_ar_ready,
  output[127:0] io_ain_r_data,
  output[7:0] io_ain_r_resp,
  output[3:0] io_ain_r_valid,
  input[3:0] io_ain_r_ready,

The ultimate intent of this is to automate the connection to the systemverilog interface.
If I were to use PlayPackedData, I might need to do this:

  case class AxiLite4Demo(AW:Int, DW:Int, num:Int) extends Bundle with IMasterSlave {
    val STRBW = DW / 8
    val aw_addr = UInt(AW * num bits)
    val aw_valid = UInt(num bits)
    val aw_ready = UInt(num bits)
    val w_data = UInt(DW * num bits)
    val w_strb = UInt(STRBW * num bits)
    val w_valid = UInt(num bits)
    val w_ready = UInt(num bits)
    val b_resp = UInt(2 * num bits)
    val b_valid = UInt(num bits)
    val b_ready = UInt(num bits)
    val ar_addr = UInt(AW * num bits)
    val ar_valid = UInt(num bits)
    val ar_ready = UInt(num bits)
    val r_data = UInt(DW * num bits)
    val r_resp = UInt(2 * num bits)
    val r_valid = UInt(num bits)
    val r_ready = UInt(num bits)
    override def asMaster(): Unit = {
      in(b_resp, b_valid, aw_ready, w_ready, ar_ready, r_data, r_resp, r_valid)
      out(aw_addr, aw_valid, w_data, w_strb, w_valid, b_ready, ar_addr, ar_valid, r_ready)
    }
  }
  SpinalConfig().generateSystemVerilog(new Module{
    val io = new Bundle{
      val ain = slave( AxiLite4Demo(8,32,4))
      val aout= Vec(master(AxiLite4Demo(8,32,1)), 4)
    }
    //todo  io.ain cannot connect to tmp
    val tmp = new PackedData(AxiLite4Demo(8,32,1), 4)
    io.aout.zipWithIndex.map{case(i,v) => i := tmp.unpack(v)}
  }.setDefinitionName("UnpackedMod"))
  SpinalConfig().generateSystemVerilog(new Module{
    val io = new Bundle{
      val aout = master( AxiLite4Demo(8,32,4))
      val ain  = Vec(slave(AxiLite4Demo(8,32,1)), 4)
    }
    val tmp = new PackedData(AxiLite4Demo(8,32,1), 4)
    io.ain.zipWithIndex.map{case(j,v)=> tmp.pack(j,v)}
    //todo tmp cannot connect to io.aout
  }.setDefinitionName("PackedMod"))

Still, thank you again!

@dreamflyings
Copy link
Author

Here is a working example, which isn't read for use in IO, but already as a prototype to talk about :

object PlayPackedData extends App{
  class PackedData[T <: Data](hardType : HardType[T], size : Int) extends MultiData {
    override val elements = ArrayBuffer[(String, Data)]()
    class Element(val name : String, val raw : Bits, val width : Int)
    val elementsMap = mutable.LinkedHashMap[String, Element]()

    packedBuild()

    def packedBuild() {
      val template = hardType()
      for ((e, name) <- (template.flatten, template.flattenLocalName).zipped) {
        println(e + " " + name)
        val w = widthOf(e)
        val ref = Bits(widthOf(e) * size bits)
        elements += name -> ref
        elementsMap(name) = new Element(name, ref, w)
        ref.parent = this
        if (OwnableRef.proposal(ref, this)) ref.setPartialName(name, Nameable.DATAMODEL_WEAK)
      }
    }

    def pack(that : T, index : Int) = {
      for((from, name) <- (that.flatten, that.flattenLocalName).zipped){
        val to = elementsMap(name)
        assert(widthOf(from) == to.width)
        to.raw(to.width*index, to.width bits) := from.asBits
      }
    }

    def unpack(index : Int) : T = {
      val ret = hardType()
      for((to, name) <- (ret.flatten, ret.flattenLocalName).zipped){
        val from = elementsMap(name)
        to.assignFromBits(from.raw(from.width*index, from.width bits))
      }
      ret
    }

    override def assignFromImpl(that: AnyRef, target: AnyRef, kind: AnyRef): Unit = {
      that match {
        case that: PackedData[_] =>
          ???
        case _ => throw new Exception("Undefined assignment")
      }
    }
  }

  SpinalVerilog(new Component {
    val x = new PackedData(Rgb(5,6,5), 4).assignDontCare()
    val y = Rgb(5,6,5)
    x.pack(y, 2)
    val z = x.unpack(2)
  })
}

Let's me know what you think

For example, the following systemverilog code, do we have a better way to automatically connect it to spinalHDL as a black box?

interface AXI_LITE #(
  parameter AXI_ADDR_WIDTH = -1,
  parameter AXI_DATA_WIDTH = -1
);

  localparam AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8;

  typedef logic [AXI_ADDR_WIDTH-1:0] addr_t;
  typedef logic [AXI_DATA_WIDTH-1:0] data_t;
  typedef logic [AXI_STRB_WIDTH-1:0] strb_t;

  // AW channel
  addr_t aw_addr;
  logic  aw_valid;
  logic  aw_ready;

  data_t w_data;
  strb_t w_strb;
  logic  w_valid;
  logic  w_ready;

  resp_t b_resp;
  logic  b_valid;
  logic  b_ready;

  addr_t ar_addr;
  logic  ar_valid;
  logic  ar_ready;

  data_t r_data;
  resp_t r_resp;
  logic  r_valid;
  logic  r_ready;

  modport Master (
    output aw_addr, aw_valid, input aw_ready,
    output w_data, w_strb, w_valid, input w_ready,
    input b_resp, b_valid, output b_ready,
    output ar_addr, ar_valid, input ar_ready,
    input r_data, r_resp, r_valid, output r_ready
  );

  modport Slave (
    input aw_addr, aw_valid, output aw_ready,
    input w_data, w_strb, w_valid, output w_ready,
    output b_resp, b_valid, input b_ready,
    input ar_addr, ar_valid, output ar_ready,
    output r_data, r_resp, r_valid, input r_ready
  );

endinterface

interface AXI_ROUTING_RULES #(
  /// The address width.
  parameter int AXI_ADDR_WIDTH = -1,
  /// The number of slaves in the routing table.
  parameter int NUM_SLAVE  = -1,
  /// The number of rules in the routing table.
  parameter int NUM_RULES  = -1
);

  struct packed {
    logic enabled;
    logic [AXI_ADDR_WIDTH-1:0] mask;
    logic [AXI_ADDR_WIDTH-1:0] base;
  } [NUM_RULES-1:0] rules [NUM_SLAVE];

  modport xbar(input rules);
  modport cfg(output rules);

endinterface

module axi_lite_xbar #(
  /// The address width.
  parameter int ADDR_WIDTH = -1,
  /// The data width.
  parameter int DATA_WIDTH = -1,
  /// The number of master ports.
  parameter int NUM_MASTER = 1,
  /// The number of slave ports.
  parameter int NUM_SLAVE = 1,
  /// The number of routing rules.
  parameter int NUM_RULES = -1
)(
  input logic            clk_i               ,
  input logic            rst_ni              ,
  AXI_LITE.Slave         master [NUM_MASTER] ,
  AXI_LITE.Master        slave  [NUM_SLAVE]  ,
  AXI_ROUTING_RULES.xbar rules
);

endmodule

@Dolu1990
Copy link
Member

Hi ^^

Ahhhh, so by packing you mean putting all the signal of the interface into a single signal ?
And unpacking you mean taking a single large signal and recreating a interface with many signal ?

I'm not used at all to system verilog packed feature ^^

Else about AxiLite4Demo, the goal of PacketData is to not having you to do "* num" on everything in a custom bundle, but instead just use the regular AxiLite4 definition from the SpinalLib.
For instance you would only use PackedData(AxiLite4(32,32), 4) inside the blackbox definition, never outside the blackbox. And to interface with it from SpinalHDL component you would directly pack / unpack it from regular Vec(AxiLite4(32,32), 4)

(PackedData isn't implemented enough to be used as io yet, but that was just to show the concept)

Does it make sense or i'm still off what you want to do XD ?

@dreamflyings
Copy link
Author

dreamflyings commented May 18, 2022

Hi ^^

Ahhhh, so by packing you mean putting all the signal of the interface into a single signal ? And unpacking you mean taking a single large signal and recreating a interface with many signal ?

I'm not used at all to system verilog packed feature ^^

Else about AxiLite4Demo, the goal of PacketData is to not having you to do "* num" on everything in a custom bundle, but instead just use the regular AxiLite4 definition from the SpinalLib. For instance you would only use PackedData(AxiLite4(32,32), 4) inside the blackbox definition, never outside the blackbox. And to interface with it from SpinalHDL component you would directly pack / unpack it from regular Vec(AxiLite4(32,32), 4)

(PackedData isn't implemented enough to be used as io yet, but that was just to show the concept)

Does it make sense or i'm still off what you want to do XD ?

Dear Dolu1990:
It's great to do the packing or unpacking of the systemverilog interface(or something else) in BlackBox or define a subclass of BlackBoxWrapper. We have reached a consensus on this point, and this technical route is likely to go further in the future.
My vision is this, through which I can quickly integrate codes of different IP types from different people and teams, and automate wiring through SpinalHDL. In this way, our Spinaler's living space will be greatly expanded. It is an important step for the rapid integration of systemveriog code with Interface.
My BlackBoxWrapper Demo is as follows:

object BlackBoxWrapperPlay extends App{
  class BlackBoxWrapper extends BlackBox
  case class TestIF(dw:Int) extends Bundle with IMasterSlave{
    val v = Bool()
    val r = Bool()
    val d = UInt(dw bits)

    override def asMaster(): Unit = {
      in(v,d)
      out(r)
    }
  }
  class MyBox(
    mn:Int = 1,
    sn:Int = 1,
    dw:Int = 1
  ) extends BlackBox{
    // todo add func
//    addInterfaceGenerics(
//      "DW" -> dw
//    )
    addGenerics(
      "MN" -> mn,
      "SN" -> sn
    )
    val io = new Bundle{
      val clock     = in(Bool())
      val reset     = in(Bool())
      val sif       = new PackedData( slave(TestIF(dw)), mn)
      val mif       = new PackedData(master(TestIF(dw)), sn)
    }
    addRTLPath("./test.sv")
    noIoPrefix()
  }

  val sv =
    s"""systemverilog
       |
       |interface TestIF #(
       |  parameter int DW = 1
       |);
       |  logic v;
       |  logic r;
       |  logic [DW-1:0] d;
       |  modport Master(
       |    input v,d,
       |    output r
       |  );
       |  modport Slave(
       |    output v,d,
       |    input r
       |  );
       |endinterface
       |
       |module xbar #(
       |  parameter int MN = 2,
       |  parameter int SN = 2,
       |)(
       |  input logic clock,
       |  input logic reset,
       |  TestIF.Master mif [MN],
       |  TestIF.Slave  sif [SN]
       |);
       | ...
       |endmodule
       |
       |""".stripMargin
  // todo SpinalHDL generate systemverilog
  val generateSV =
    s"""module xbar_wrapper(
        | ...
        |)
        |
        | ... connect ...
        | TestIF#(
        | .DW(1)
        | ) mif[0:1]();
        | TestIF#(
        |  .DW(1)
        |  ) sif[0:1]();
        |
        |xbar#(
        | .MN(2),
        | .SN(2)
        |) xbar_0(
        |  .clock  ( clock     ),
        |  .reset ( reset    ),
        |  .mif ( mif   ),
        |  .sif  ( sif  )
        |);
        |endmodule
       |""".stripMargin
}

But the biggest difficulty in this is how to generate such a Systemverilog Wrapper.
Also need to learn some Systemverilog interface knowledge, I don't know if it is good to implement.
grateful!

@Dolu1990
Copy link
Member

Hi :D

Ahhh damned, currently PackedData with master/slave will not play well :/
Would need a bit of rework to handle it properley

But the biggest difficulty in this is how to generate such a Systemverilog Wrapper.

I don't realy know much details about SystemVerilog, so far the aim was more about regular old Verilog / Vhdl blackboxes, but seems like the Verilog/Vhdl people are more and more migrating toward system verilog ^^

About "struct packed" if i understand well, it allow to access all bits of a structure as if they were all put together in a single bit vector right ?

@dreamflyings
Copy link
Author

Hi :D

Ahhh damned, currently PackedData with master/slave will not play well :/ Would need a bit of rework to handle it properley

But the biggest difficulty in this is how to generate such a Systemverilog Wrapper.

I don't realy know much details about SystemVerilog, so far the aim was more about regular old Verilog / Vhdl blackboxes, but seems like the Verilog/Vhdl people are more and more migrating toward system verilog ^^

About "struct packed" if i understand well, it allow to access all bits of a structure as if they were all put together in a single bit vector right ?

The default struct is unpacked. From the perspective of memory storage, unpacked means that the address space is not continuous; if a continuous address space is required, packed. From a design synthesis perspective, usually unpacked and packed synthesis results are the same, but there are exceptions. There are plenty of FPGA synthesis tools that will convert unpacked arrays into some kind of memory (either FFs or RAMs).
Regarding how to efficiently integrate the systemverilog black box, or generateSystemVerilog to generate a wrapper with a systemverilog interface, these can be gradually improved. I shared a possible implementation in the demo above. In this way, we need to integrate the SV top layer by generating a wrapper instantiation of an intermediate SV file, and then use this SV wrapper as a black box for spinalHDL to call. In the project implementation, I did this, but manually + script to implement this wrapper.
Regarding better support of systemverilog, I think it is necessary, mainly in the foreseeable future, the use of systemverilog this will still be the majority. How to efficiently integrate their codes, or even connect them automatically, should be one of our research topics. In the Chisel language, someone has already implemented the automatic conversion of chisel to systemverilog, but unfortunately SpinalHDL has not yet implemented this function in Spinaler. This chisel2sv also has many defects, one of which is that it does not support systemverilog with interfaces, which also shows from the side that there are objective technical difficulties in using scala to operate systemverilog with interfaces. Let's gradually get to a user friendly state, I believe, we can.
Thank you so much for your hard work!

@Dolu1990
Copy link
Member

Hi ^^

What solution did you adopted ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants