How to write testbench file?

Discussion in 'VHDL' started by RaulGonz, Jan 27, 2010.

  1. RaulGonz

    RaulGonz Guest

    Hi, i am using an actel fpga to generate pwm signal. There are these
    IP cores in the libero software for you to drage and drop into your
    design. I have the following .vhd code and is having a hard time
    trying to write the testbench for it..

    "library ieee;
    use ieee.std_logic_1164.all;

    entity FSM_CorePWM is
    GENERIC (PWM_NUM : integer := 1);
    port (PCLK, PRESET_N, PSEL, PENABLE, PWRITE: in std_logic;
    DUTY_CYC: in std_logic_vector (2 downto 0);
    PWM: out std_logic_vector (PWM_NUM downto 1);
    PRDATA: out std_logic_vector (7 downto 0);
    INT: out std_logic);
    end entity FSM_CorePWM;

    architecture HIERARCHICAL of FSM_CorePWM is
    component FSM
    port (PCLK, PRESET_N: in std_logic;
    DUTY_CYC: in std_logic_vector (2 downto 0);
    PADDR: out std_logic_vector (7 downto 0);
    PWDATA: out std_logic_vector (7 downto 0));
    end component;
    component core_pwm
    GENERIC (PWM_NUM : integer := 8);
    port (PCLK, PRESET_N, PSEL, PENABLE,
    PWRITE: in std_logic;
    PADDR: in std_logic_vector(7
    downto 0);
    PWDATA: in std_logic_vector(7
    downto 0);
    PWM: out std_logic_vector
    (PWM_NUM downto 1);
    PRDATA: out std_logic_vector(7
    downto 0);
    INT: out std_logic);
    end component;
    signal PADDR_TOP: std_logic_vector(7 downto 0);
    signal PWDATA_TOP: std_logic_vector(7 downto 0);
    begin
    FSM_TOP: FSM port map
    (PCLK=>PCLK,PRESET_N=>PRESET_N,DUTY_CYC=>DUTY_CYC,PADDR=>PADDR_TOP,PWDATA=>PWDATA_TOP);
    COREPWM_TOP: core_pwm
    GENERIC MAP (PWM_NUM =>PWM_NUM)
    port map
    (PCLK=>PCLK,PRESET_N=>PRESET_N,PSEL=>PSEL,PENABLE=>PENABLE,PWRITE=>PWRITE,
    PADDR=>PADDR_TOP,PWDATA=>PWDATA_TOP,PWM=>PWM,PRDATA=>PRDATA,INT=>INT);
    end HIERARCHICAL; "

    In the above, component "FSM" is another .vhd code while component
    "core_pwm" is the IP core. please help to guide me how to generate the
    testbench/stimulus for this.
     
    RaulGonz, Jan 27, 2010
    #1
    1. Advertising

  2. RaulGonz

    Andy Guest

    Instantiate your unit under test (fsm_corepwm in this case) in a test
    bench entity/architecture. Write processes, procedures, etc. in the
    architecture as required to drive the UUT inputs to excercise the UUT
    (i.e. give the UUT data to work on, command it to do specific
    operations, etc.)

    Now you have two options. For simple UUTs you can simply gather up all
    the UUT inputs and outputs in a waveform viewer and manually determine
    whether or not it is working as you expected.

    Or you can write more processes, procedures, etc. to examine the UUT
    inputs and outputs, to determine if they are functioning as expected.
    This is called a self checking test bench. This method is more work to
    create, but is easier to use, especially by someone else who may not
    be as familiar with your design as you are (that someone else could be
    yourself after you've left the project for a while). Sometimes the
    verification uses a separate reference model of what the UUT is
    supposed to do, and the outputs of the UUT and reference model are
    compared to determine whether the UUT works. Remember, this reference
    model does not need to be synthesizable, so you can use lots of tricks
    in vhdl that are not available in synthesis, like waiting on arbitrary
    signals, inserting time delays, etc. Also, your checking code can use
    assertion statements to report failures (easy), or you can log
    failures to a separate text file for later review (harder, but can be
    more elaborate). I usually write self checking testbenches with
    assertion statements to report failures, and it works well for me.

    Hope this helps,

    Andy
     
    Andy, Jan 27, 2010
    #2
    1. Advertising

  3. RaulGonz

    RaulGonz Guest

    hi Andy,

    i wrote the following testbench for "fsm_pwmcore.vhd"

    "library ieee;
    use ieee.std_logic_1164.all;

    entity TB_FSM is
    end TB_FSM;

    architecture behv of TB_FSM is

    component FSM_CorePWM is
    GENERIC (PWM_NUM : integer := 8);
    port (PCLK, PRESET_N, PSEL, PENABLE, PWRITE: in std_logic;
    DUTY_CYC: in std_logic_vector (2 downto 0);
    PWM: out std_logic_vector (8 downto 1);
    PRDATA: out std_logic_vector (8 downto 1);
    INT: out std_logic);
    end component;

    signal TB_PCLK: std_logic;
    signal TB_PRESET_N: std_logic;
    signal TB_PSEL: std_logic;
    signal TB_PENABLE: std_logic;
    signal TB_PWRITE: std_logic;
    signal TB_DUTY_CYC: std_logic_vector (2 downto 0);
    signal TB_PWM: std_logic_vector (8 downto 1);
    signal TB_PRDATA: std_logic_vector (8 downto 1);
    signal TB_INT: std_logic;

    begin

    unit: FSM_CorePWM --GENERIC map (PWM_NUM)
    port map (TB_PCLK, TB_PRESET_N, TB_PSEL, TB_PENABLE, TB_PWRITE,
    TB_DUTY_CYC, TB_PWM, TB_PRDATA, TB_INT);

    process
    begin

    TB_PSEL <= '1';
    TB_PENABLE <= '1';
    TB_PWRITE <= '1';
    TB_PCLK <= '0';
    wait for 5 ns;
    TB_PCLK <= '1';
    wait for 5 ns;

    end process;
    end behv; "

    now the problem is this fsm_pwmcore consist of two components which
    are the corepwm and fsm. How can i like this fsm_pwmcore to the two
    components in testbench format?? Please advise. Thank you.
     
    RaulGonz, Jan 28, 2010
    #3
  4. RaulGonz

    RaulGonz Guest

    Sorry, i mean how can i ADD this fsm_pwmcore to the two
    components in testbench format?? Please advise. Thank you.
     
    RaulGonz, Jan 28, 2010
    #4
  5. RaulGonz

    Andy Guest

    On Jan 28, 12:29 am, RaulGonz <> wrote:
    > Sorry, i mean how can i ADD this fsm_pwmcore to the two
    > components in testbench format?? Please advise. Thank you.


    I'm not sure I understand your question, but when you instantiate the
    FSM_CorePWM in your testbench, that brings in the lower two modules
    instantiated within it. You are testing both of those modules together
    within FSM_CorePWM, through the FSM_CorePWM external interface.

    BTW, you can avoid component declarations, configurations, default
    binding, etc. by directly instantiating the entity (and optionally
    specifying the architecture):

    unit: entity work.FSM_CorePWM(HIERARCHICAL) --GENERIC map (PWM_NUM)
    port map (TB_PCLK, TB_PRESET_N, TB_PSEL,
    TB_PENABLE, TB_PWRITE,
    TB_DUTY_CYC, TB_PWM, TB_PRDATA, TB_INT);

    You can do this for any entity/architecture for which you have the
    source code. You cannot do this for primitives, or cores for which you
    do not have vhdl source. For instance, if you do not have the vhdl
    source for the FSM and core_pwm modules, you must use component
    declarations and instantiations like you have done.

    Andy
     
    Andy, Jan 28, 2010
    #5
  6. RaulGonz

    RaulGonz Guest

    Hi Andy, you are correct. FSM_CorePWM is my top level design file and
    it calls on two lower modules instantiated with it. Now, do i have to
    create a testbench for each of the two lower modules in order to
    simulate the design as a whole?

    This is because in the actel libero IDE software project manager, i
    was told that i can set FSM_CorePWM as the root and the modelsim
    simulation can actually be initiated from the libero project manager.
    That brings me to my question... do i have to write individual
    testbench for the two lower modules and then link them up to the top
    level design file (FSM_CorePWM) before i initiated modelsim from
    libero?

    Or from what i understand from your reply, i can just write what i
    want to do with what components/entity (be it the FSM_CorePWM, FSM or
    the corePWM IP) in just a single testbench file?

    Please advise. Thank you so much..

    Andy wrote:
    > On Jan 28, 12:29 am, RaulGonz <> wrote:
    > > Sorry, i mean how can i ADD this fsm_pwmcore to the two
    > > components in testbench format?? Please advise. Thank you.

    >
    > I'm not sure I understand your question, but when you instantiate the
    > FSM_CorePWM in your testbench, that brings in the lower two modules
    > instantiated within it. You are testing both of those modules together
    > within FSM_CorePWM, through the FSM_CorePWM external interface.
    >
    > BTW, you can avoid component declarations, configurations, default
    > binding, etc. by directly instantiating the entity (and optionally
    > specifying the architecture):
    >
    > unit: entity work.FSM_CorePWM(HIERARCHICAL) --GENERIC map (PWM_NUM)
    > port map (TB_PCLK, TB_PRESET_N, TB_PSEL,
    > TB_PENABLE, TB_PWRITE,
    > TB_DUTY_CYC, TB_PWM, TB_PRDATA, TB_INT);
    >
    > You can do this for any entity/architecture for which you have the
    > source code. You cannot do this for primitives, or cores for which you
    > do not have vhdl source. For instance, if you do not have the vhdl
    > source for the FSM and core_pwm modules, you must use component
    > declarations and instantiations like you have done.
    >
    > Andy
     
    RaulGonz, Jan 29, 2010
    #6
  7. RaulGonz

    KJ Guest

    On Jan 28, 8:38 pm, RaulGonz <> wrote:
    > Now, do i have to
    > create a testbench for each of the two lower modules in order to
    > simulate the design as a whole?


    No.

    KJ
     
    KJ, Jan 29, 2010
    #7
  8. RaulGonz

    KJ Guest

    > I usually write self checking testbenches with
    > assertion statements to report failures, and it works well for me.
    >


    Another approach is to write a self checking design. All of that non-
    synthesizable stuff can be included right in the architecture with the
    design itself...safely surrounded by
    -- synthesis translate_off
    -- synthesis translate_on

    Then the testbench itself only generate stimulus. The nice thing here
    is that if you make a change to a widget but don't run the testbench
    for widget, jumping right to the top level testbench instead you've
    still got the same checking code running for you in that environment.

    Alternatively, you can view this as checking code for the widget
    regardless of the test environment since it will always run. When you
    can do this, you've probably got a more robust checker since it is
    will not be dependent on any anomolies, coverage holes or other corner
    cutting that might be implicitly there in the traditional testbench
    approach that generates stimulus and verifies response.

    Testing in more environments is always better from a design
    verification standpoint, putting the checking logic right in the
    design allows you to test in any environment that the widget will ever
    get used.

    KJ
     
    KJ, Jan 29, 2010
    #8
  9. RaulGonz

    RaulGonz Guest

    hi KJ,

    Do u mean that i can just create a testbench and then include whatever
    components/signals, in the two lower modules, to this sole testbench?

    KJ wrote:
    > On Jan 28, 8:38 pm, RaulGonz <> wrote:
    > > Now, do i have to
    > > create a testbench for each of the two lower modules in order to
    > > simulate the design as a whole?

    >
    > No.
    >
    > KJ
     
    RaulGonz, Jan 29, 2010
    #9
  10. KJ wrote:

    > Another approach is to write a self checking design. All of that non-
    > synthesizable stuff can be included right in the architecture with the
    > design itself...safely surrounded by
    > -- synthesis translate_off
    > -- synthesis translate_on


    I can even include simulation libraries in
    my synthesis code the same way.
    This is also a quick way to add some visibility
    for debugging a variable deep in the design.

    -- Mike Treseler
     
    Mike Treseler, Jan 29, 2010
    #10
  11. RaulGonz

    Andy Guest

    So, is this what they mean by "Design For Test"? ;^)

    Seriously, there is nothing like embedding self-checking code in the
    design itself, to provide guidance for future reviewers/maintainers
    about the functionality required of the design.

    I've long advocated a system where we could embed assertion
    statements, perhaps with standardized functions that verify things
    like mutual exclusivity of inputs, etc., such that a synthesis tool
    could use the information to optimize the implementation. In
    simulation, the assertion would verify that the inputs were indeed
    mutually exclusive, thus checking the external interface to that
    module.

    For instance, if I had a function that could take an unconstrained
    array of boolean and return false if more than one element were true,
    I could write an assertion that called it:

    Assert std_mutex(read_enable & write_enable));

    Then if I had code that looked like:

    if read_enable then
    ....
    elsif write_enable then
    ....
    end if;

    then the synthesis tool could recognize that the priority implied by
    the if-elsif statement was not needed and could be optimized out of
    the implementaion.

    We'd get better verification, with better synthesis in the bargain.

    Andy
     
    Andy, Jan 29, 2010
    #11
  12. Andy wrote:

    > For instance, if I had a function that could take an unconstrained
    > array of boolean and return false if more than one element were true,
    > I could write an assertion that called it:
    >
    > Assert std_mutex(read_enable & write_enable));
    >
    > Then if I had code that looked like:
    >
    > if read_enable then
    > ...
    > elsif write_enable then
    > ...
    > end if;
    >
    > then the synthesis tool could recognize that the priority implied by
    > the if-elsif statement was not needed and could be optimized out of
    > the implementaion.
    >
    > We'd get better verification, with better synthesis in the bargain.



    I could collect statistics in a self-checking simulation,
    but I don't follow how I could prove the proposition
    except for a constant array.

    -- Mike Treseler
     
    Mike Treseler, Jan 29, 2010
    #12
  13. RaulGonz

    KJ Guest

    On Jan 29, 3:11 pm, Andy <> wrote:
    >
    > I've long advocated a system where we could embed assertion
    > statements, perhaps with standardized functions that verify things
    > like mutual exclusivity of inputs, etc., such that a synthesis tool
    > could use the information to optimize the implementation.


    And if the assertion statements logically contradict the logic in some
    fashion, which path should the synthesis tool follow?

    - If the synthesis tool followed the path of the written code, it
    would be doing what it does today...which is to ignore all but
    statically verifiable assertions for the purposes of generating logic
    and simply report those assertion failures and stop (at best...some
    tools don't do that).

    - If it followed the path of the assertions, then what makes the line
    of assertion code more likely to be correct than the code for the
    logic? I don't think I'm alone in that every line of code I write is
    a potential to initially be wrong and need fixing. This is true
    whether the line of code is logic for the design or an assertion to
    check that design.

    Kevin Jennings
     
    KJ, Jan 30, 2010
    #13
  14. RaulGonz

    KJ Guest

    On Jan 29, 2:07 pm, Mike Treseler <> wrote:
    > This is also a quick way to add some visibility
    > for debugging a variable deep in the design.
    >


    That's why I keep tellin' ya...use some concurrent assignments and
    signals for a change and cut back on those variables ;)

    Kevin Jennings
     
    KJ, Jan 30, 2010
    #14
  15. KJ wrote:
    > On Jan 29, 2:07 pm, Mike Treseler <> wrote:
    >> This is also a quick way to add some visibility
    >> for debugging a variable deep in the design.
    >>

    >
    > That's why I keep tellin' ya...use some concurrent assignments and
    > signals for a change and cut back on those variables ;)


    Touché.
    I should have said, "register" ;)

    -- Mike Treseler
    (still likes that "printf" debugging)
     
    Mike Treseler, Jan 30, 2010
    #15
  16. RaulGonz

    Evan Lavelle Guest

    Kevin and Andy are correct, of course, but there is a much simpler way
    to write a testbench. I don't know anything about your design but
    let's assume, for the sake of argument, that:

    1 - PRESET_N is an active-low reset
    2 - PWM is the output waveform
    3 - PWM is split into 8 slots
    4 - DUTY_CYC is the count of 0 slots
    5 - (8-DUTY_CYCLE) is the count of high slots

    In this case, the Maia code below tests your design. It applies all 3
    combinations of DUTY_CYCLE to your DUT, and then checks the low and
    high periods. It runs for 72 cycles and reports any failures in your
    code.

    disclaimer #1: I work for Maia EDA. You can currently get a free
    compiler at www.maia-eda.net; it creates a testbench, and you'll need
    a simulator to run the testbench.

    disclaimer #2: The current version produces only Verilog output.
    You'll need a dual-language simulator if your DUT is in VHDL (the
    compiler driver automates all of this).

    -Evan

    // -------------------------------------
    // Maia testbench code:
    DUT {
    module FSM_CorePWM(
    input PCLK, PRESET_N, PSEL, PENABLE, PWRITE,
    input [2:0] DUTY_CYC,
    output PWM, INT,
    output [7:0] PRDATA);
    [PRESET_N, PCLK, DUTY_CYC] -> [PWM];
    create_clock PCLK;
    }

    main() {
    int3 dcycle;
    int i,j;

    for all dcycle { // all 8 values: 0->7
    [0, .C, .X] -> [0]; // reset
    for(i=0; i<dcycle; i++)
    [1, .C, dcycle] -> [0];
    for(j=0; j<8-dcycle; j++)
    [1, .C, dcycle] -> [1];
    }
    }
     
    Evan Lavelle, Feb 1, 2010
    #16
  17. RaulGonz

    Andy Guest

    Does it really make a difference whether the assertion (or any other
    kind of verification code) is located in the design module or in the
    testbench? Is it any less likely to be correct because you put it in a
    place where synthesis could take advantage of it? And if it is
    incorrect, but synthesis could not take advantage of it, does not the
    same assertion still have to be fixed?

    Perhaps we simply give the synthesis tool the ability to do the
    following:

    By writing "assert one_hot(inputs);"

    We are saying that any f(inputs) is "don't care" iff one_hot(inputs)
    is false?

    Conditions could also be put on/around the assertion or its expression
    to limit the scope to e.g. rising edges of the clock, when not in
    reset, etc., either by including those conditions in the assertion
    expression, or by the location and therefore conditional execution of
    the assertion statement itself.

    I see your point WRT design behavior in off-nominal cases, but that is
    just as big an issue everytime we enable synthesis optimizations for
    one-hot state machines, etc.

    Andy
     
    Andy, Feb 1, 2010
    #17
  18. RaulGonz

    KJ Guest

    On Feb 1, 12:56 pm, Andy <> wrote:
    > Does it really make a difference whether the assertion (or any other
    > kind of verification code) is located in the design module or in the
    > testbench?


    See my post from Jan 28 in this thread for an advantage that one may
    gain by putting the verification in the design rather than the
    testbench.

    > Is it any less likely to be correct because you put it in a
    > place where synthesis could take advantage of it?


    Nope, nor did I suggest that it would.

    > And if it is
    > incorrect, but synthesis could not take advantage of it, does not the
    > same assertion still have to be fixed?


    Only if the incorrect assertion can be found, can it be fixed.

    A simulation that runs to completion without failing an assert, no
    matter how well thought out, does not imply that all of those
    assertions are actually correct and match the logic under every
    condition. To prove that they do match, one would have to use a
    formal logic checker of some sort, not a simulator.

    But none of that has to do with the point that I was making. My point
    was along the lines of which path should be followed by a synthesis
    tool if it used non-static assertions to guide how it formed the logic
    and there was a logical difference between what was asserted and what
    the written code actually said.

    Kevin Jennings
     
    KJ, Feb 2, 2010
    #18
  19. RaulGonz

    Andy Guest

    On Feb 1, 10:53 pm, KJ <> wrote:
    > But none of that has to do with the point that I was making.  My point
    > was along the lines of which path should be followed by a synthesis
    > tool if it used non-static assertions to guide how it formed the logic
    > and there was a logical difference between what was asserted and what
    > the written code actually said.


    Sorry, I misinterpreted your point.

    But since you clarified it...

    I think the (synthesis-aware) assertions would have to be implemented
    like a subsequent conditional assignment of "don't care", and that way
    their interference with the otherwise coded logic is controlled and
    (somewhat) predictable.

    Not all assertions are explicitly coded; some are built-in.

    For example, if I have a decoder as follows:

    variable address : natural range 0 to 15;
    variable decode : std_logic_vector(7 downto 0);
    ....
    decode := (others => '0');
    decode(address) := '1';

    What should the synthesis tool do if address is outside of
    decode'range?

    1. Should (or can) decode remain (others => '0')?

    2. Should (or can) decode be (address mod 8 => '1', others => '0')?

    3. Should (or can) decode be (others => '-')?

    My opinion is that any of these options (and probably others) is
    perfectly acceptable, but the #3 is a more accurate option, which
    would be typically optimized to #2.

    Is this example any different than manually adding an assertion that
    address is between 0 and 7 inclusive? And would not the #3 option be
    the same as a subsequent conditional assignment to (others => '-')?

    By using the assertion, you are not telling the synthesis tool that
    the implementation has to do something else, you are merely giving it
    permission to do something else, especially if it is more efficient.

    The same thing happens when an integer counter under/over-flows in
    synthesis. The implementation will simply roll over, probably because
    that is the most efficient thing to do.

    Andy
     
    Andy, Feb 2, 2010
    #19
  20. Andy wrote:

    > Not all assertions are explicitly coded; some are built-in.
    > For example, if I have a decoder as follows:
    > variable address : natural range 0 to 15;
    > variable decode : std_logic_vector(7 downto 0);
    > ...
    > decode := (others => '0');
    > decode(address) := '1';
    >
    > What should the synthesis tool do if address is outside of
    > decode'range?


    I guess I like the vhdl rules as is.

    I will assume this 'decode' is a vector:
    decode := (others => '0');

    And this 'decode' is an f(vector) returns std_ulogic:
    decode(address) := '1';

    If the decode vector is constrained,
    I would expect a synthesis error.
    If the decode vector is not constrained,
    I am not following my design rules.


    -- Mike Treseler
     
    Mike Treseler, Feb 2, 2010
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Richard Erlacher

    file i/o in testbench

    Richard Erlacher, Sep 30, 2003, in forum: VHDL
    Replies:
    4
    Views:
    1,090
    Mike Treseler
    Oct 7, 2003
  2. Markus Meng
    Replies:
    1
    Views:
    1,403
    Mike Treseler
    Jan 15, 2004
  3. Taras_96
    Replies:
    2
    Views:
    4,896
    Taras_96
    Aug 3, 2005
  4. ZHIQUAN

    How to write a testbench

    ZHIQUAN, Apr 23, 2007, in forum: VHDL
    Replies:
    3
    Views:
    1,031
    Mike Treseler
    Apr 24, 2007
  5. zj82119
    Replies:
    0
    Views:
    2,053
    zj82119
    Oct 21, 2008
Loading...

Share This Page