Jump to content

Still Having Problem With Bind for VHDL Architecture Signals

Recommended Posts

I am still having a problem trying to read (not write) VHDL architecture signals (not entity ports) using the bind construct. I have sent my sample code off to the Mentor support people and they tell me that bind cannot be used to read VHDL signals, only the VHDL entity ports. They recommend 'signal_spy' which I have used for years, and yet others in this forum have indicated that you can access the VHDL signals in a (read only) mode using the bind construct. Is this just a QuestaSim problem and not an LRM bug? Do I need to put my virtual interface inside a 'program' block and then use bind to embed that program block inside my VHDL DUT?. I have tried using bind in the attached sample code, but it always shows 'z' as the value of the signal when read. Although attached also, here is the interface and some pertinent code snippets. I know I don't fully understand the bind construct, but I think this should work. Any and all help is appreciated.

The VHDL Code:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity cpld_glue is
  port (
    cpld_clk : in  std_logic;
    cmd_clk  : in  std_logic;
    cmd_dat  : in  std_logic;
    cmd_clr  : in  std_logic;
    mosfet   : out std_logic_vector(6 downto 0);
    display  : out std_logic_vector(3 downto 0);  -- 4 bit mode d7:5 tied low d4 tied hi
    disp_e   : out std_logic;
    disp_wrn : out std_logic;
    cmd_ack  : out std_logic
end cpld_glue;

architecture rtl of cpld_glue is
  type cur_cmd_smtyp   is (wait4clk,
  signal cur_cmd_state   : cur_cmd_smtyp := wait4clk; 
  signal bit_count       : unsigned(3 downto 0) := "0000";
  signal ser_in_buf      : std_logic_vector(7 downto 0);  -- 2 extra bits for command decoding
  -- commands are always write (no read cmds)
  -- bit(7) selects if write is to display(1) or MOSFETs(0)
  -- bit(6:0) is the byte to send to the display or MOSFETs
  [COLOR="Red"]signal cmd_clk1    : std_logic := '0';
  signal cmd_clk2    : std_logic := '0';[/COLOR]
  -- sync the cmd_clk and cmd_dat signals to cpld clock

The signal interface code:

interface dut_if_sigs(input logic cmd_clk1, input logic cmd_clk2);
endinterface: dut_if_sigs

The instantiation in the top.sv:

module top;
   import uvm_pkg::*;
   import agent_pkg::*;
   import seq_lib_pkg::*;
   import test_lib_pkg::*;

   dut_if dut();
   cpld_glue myvhdl(dut.cpld_clk, // : in  std_logic;
					dut.cmd_clk,  // : in  std_logic;
					dut.cmd_dat,  // : in  std_logic;
					dut.cmd_clr,  // : in  std_logic;
					dut.mosfet,   // : out std_logic_vector(6 downto 0);
					dut.display,  // : out std_logic_vector(3 downto 0);
					dut.disp_e,   // : out std_logic;
					dut.disp_wrn, // : out std_logic;
					dut.cmd_ack); // : out std_logic
   dut_if_sigs sigs();
   bind cpld_glue dut_if_sigs sigs(.cmd_clk1(cmd_clk1),.cmd_clk2(cmd_clk2));

   // Free running clock
Link to comment
Share on other sites

It seems the interface reference you are storing in the config_db is a local instance inside top, and not the bound interface. That can not work. I'd recommend not using the config_db for this purpose and instead place all code using interface signals inside the interface. Avoid virtual interfaces in general.



Link to comment
Share on other sites

Erling, are you suggesting that I put the driver, monitor and scoreboard classes all inside the dut_if interface file since they all use the interface signals. That would also mean putting the bind statement ( bind cpld_glue dut_if_sigs sigs(.cmd_clk1(cmd_clk1),.cmd_clk2(cmd_clk2)); ) inside the interface as well? I will work on that and see if I can get it to work.


Link to comment
Share on other sites

Erling, are you suggesting that I put the driver, monitor and scoreboard classes all inside the dut_if interface file since they all use the interface signals.

No, I suggest that you group signals and code using them (directly) inside an interface (or module), and dispatch that code virtually, i.e transfers control to the "privileged" code which has direct signal access, instead of distributing references to dut signals for everyone to use via the config_db.

FWIW, here is one way to bind an interface with code in it to a design entity:

Say we have a VHDL architecture with internal signals to be monitored from a testbench, for example:

architecture rtl of MyEntity is
  signal s_clk, s_valid: std_logic;
  signal s_data: std_logic_vector(15 downto 0);
  -- much bla bla here driving signals above
end architecture rtl;

First step is to place the monitor definition in a package (perhaps together with other low level components like coverage collectors and drivers), for example:

package MyPkg;

  class MyDataCollector extends uvm_monitor;
    uvm_analysis_port #(bit[15:0]) m_dutData; // collected data posted here
    function new(...); super.new(...);
      m_dutData = new(...);
    endfunction: new
  endclass: MyDataCollector

endpackage: MyPkg

The implementation of the data collector goes into the interface to be bound to the VHDL architecture above, for example:

interface MyEntityIf(logic s_clk, logic s_valid, logic[15:0] s_data);

  import uvm_pkg::*;
  import MyPkg::*;

  class MyDataCollectorImp extends MyDataCollector;
    task run_phase(...);
      forever @(posedge s_clk)
        if (s_valid) m_dutData.write(s_data);
    endtask: run_phase

  endclass: MyDataCollectorImp

  initial // have the factory create MyDataCollectorImp when asked for MyDataCollector
    factory.set_type_override_by_type(MyDataCollector::get_type(), MyDataCollectorImp::get_type());

endinterface: MyEntityIf

The monitor can then be instantiated and connected by the testbench as any other component, for example:

package MyTestPkg;

import uvm_pkg::*;
import MyPkg::*;

class MyTestbench extends uvm_env;

  MyScoreboard m_scoreboard;
  MyDataCollector m_dataCollector;

  function void build_phase(...);
    m_scoreboard = MyScoreboard::type_id::create();
    m_dataCollector = MyDataCollector::type_id::create();
  function void connect_phase(...);
endclass: MyTestbench

class MyTest extends uvm_test;

  MyTestbench m_tb;
  function new...;
  function void build_phase(...);
    m_tb = MyTestbench::type_id::create();
  endfunction: build_phase
  task run_phase(...);
    // have sequences traverse the dut here to have it produce data to be collected
  endtask: run_phase
endclass: MyTest

endpackage: MyTestPkg

And, finally, instantiation, binding and test program in the top module, for example:

module top;

  MyDutIf dif();
  MyDesign dut(dif...);
  bind MyEntity MyEntityIf eif(.*);
  program test;
    import uvm_pkg::*;
    import MyTestPkg::*;
    initial run_test();
  endprogram: test
endmodule: top

Using the same technique for regular monitors and drivers will eliminate virtual interfaces altogether, and bound interfaces will then be just more of the same.

Hope this helps.



Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...