Best testbench style for microprocessor bus simulation

Discussion in 'VHDL' started by Doug Miller, Jan 28, 2004.

  1. Doug Miller

    Doug Miller Guest

    I'm looking for suggestions for improving the brevity and clarity of my
    testbenches when I'm simulating software initialization and interrupt
    handling over a microprocessor bus. Currently, I use a pair of processes
    such as the following:

    bus_simplifier: process(addr,din,op)
    begin
    if (op = write) then
    reg_write <= '1';
    reg_read <= '0';
    reg_en <= '1';
    reg_addr <= addr;
    reg_data <= din;
    elsif (op = read) then
    -- etc....
    elsif (op = nop) then
    -- etc....
    end if;
    end process;

    up_stim: process
    variable up_stim_initflag : std_logic := '0';
    begin
    if (up_stim_initflag = '0') then
    -- Startup conditions
    op <= nop;
    int_vector <= (others => 'U');
    wait until reset='1';
    wait until reset='0';

    -- Read from register
    wait until up_clk='1'
    wait for 0.1 ns;
    addr <= "X"FC000000";
    op <= read;
    wait for UP_CLK_PERIOD;
    op <= nop;
    wait for UP_CLK_PERIOD;

    -- Read and write lots more registers...

    up_stim_initflag :='1'; -- Set flag so initialization code only
    executes once

    end if; -- end of initialization

    -- Start of interrupt processing

    wait until interrupt = '1';

    -- Read and write lots of registers to imitate software interrupt
    processing

    end process;

    Can anyone suggest a better way to encapsulate and compact this in a better
    way? Ideally, I'd like to reduce the 7 lines below the "--Read from
    register" line to a single line, while still making the address, data and
    operation type easily readable, so that when I need to initialize lots of
    registers, I can write it efficiently.

    Thanks,
    Doug Miller
     
    Doug Miller, Jan 28, 2004
    #1
    1. Advertising

  2. Doug Miller

    Jim Lewis Guest

    Doug,
    What it sounds like you want is a transaction based
    testbench. Using procedures is a good start:

    -- Baud Rate = 115200. ExtClk = 20 MHz. Divisor = 11
    CpuWrite(CpuRec, UART_DIVISOR_HIGH, X"0000");
    CpuWrite(CpuRec, UART_DIVISOR_LOW, X"000A");

    -- Configure for Even Parity, One Stop Bit, and 8 Data Bits
    CpuWrite(CpuRec, UART_CFG1, X"00" & "00" &
    PARITY_EVEN & STOP_BITS_1 & DATA_BITS_8);
    -- Disable all interrupts (default)
    CpuWrite(CpuRec, UART_RX_INT_MASK, X"0000");
    CpuWrite(CpuRec, UART_TX_INT_MASK, X"0000");

    -- Make it Active and Select EXT CLK
    CpuWrite(CpuRec, UART_CFG2, X"00C0");

    wait for 5 * tperiod_Clk ;
    -- Clear Interrupt Status
    CpuRead (CpuRec, UART_RX_INT_STAT, DataO);
    CpuRead (CpuRec, UART_TX_INT_STAT, DataO);

    . . .

    Want to know more? I am giving a half day tutorial on
    transaction based testbenches at both DesignCon (February)
    and DVCon (March). Details are at:

    DesignCon: http://www.designcon.com/conference/tf2.html
    DVCon: http://www.dvcon.org/tutorial6.html


    Need a more detailed class with labs? SynthWorks is
    offering its 3 Day, VHDL Testbenches and Verification
    class at public locations. The code shown above is
    from the lab files in the class. The next class date
    is Feb 25-27 in Dallas, Tx.
    Description: http://www.synthworks.com/vhdl_testbench_verification.htm
    Public Classes: http://www.synthworks.com/public_vhdl_courses.htm


    Best Regards,
    Jim Lewis
    --
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Jim Lewis
    Director of Training mailto:
    SynthWorks Design Inc. http://www.SynthWorks.com
    800-505-8435 (800-505-VHDL) / 503-590-4787

    Expert VHDL Training for Hardware Design and Verification
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



    Doug Miller wrote:

    > I'm looking for suggestions for improving the brevity and clarity of my
    > testbenches when I'm simulating software initialization and interrupt
    > handling over a microprocessor bus. Currently, I use a pair of processes
    > such as the following:
    >
    > bus_simplifier: process(addr,din,op)
    > begin
    > if (op = write) then
    > reg_write <= '1';
    > reg_read <= '0';
    > reg_en <= '1';
    > reg_addr <= addr;
    > reg_data <= din;
    > elsif (op = read) then
    > -- etc....
    > elsif (op = nop) then
    > -- etc....
    > end if;
    > end process;
    >
    > up_stim: process
    > variable up_stim_initflag : std_logic := '0';
    > begin
    > if (up_stim_initflag = '0') then
    > -- Startup conditions
    > op <= nop;
    > int_vector <= (others => 'U');
    > wait until reset='1';
    > wait until reset='0';
    >
    > -- Read from register
    > wait until up_clk='1'
    > wait for 0.1 ns;
    > addr <= "X"FC000000";
    > op <= read;
    > wait for UP_CLK_PERIOD;
    > op <= nop;
    > wait for UP_CLK_PERIOD;
    >
    > -- Read and write lots more registers...
    >
    > up_stim_initflag :='1'; -- Set flag so initialization code only
    > executes once
    >
    > end if; -- end of initialization
    >
    > -- Start of interrupt processing
    >
    > wait until interrupt = '1';
    >
    > -- Read and write lots of registers to imitate software interrupt
    > processing
    >
    > end process;
    >
    > Can anyone suggest a better way to encapsulate and compact this in a better
    > way? Ideally, I'd like to reduce the 7 lines below the "--Read from
    > register" line to a single line, while still making the address, data and
    > operation type easily readable, so that when I need to initialize lots of
    > registers, I can write it efficiently.
    >
    > Thanks,
    > Doug Miller
    >
    >
     
    Jim Lewis, Jan 29, 2004
    #2
    1. Advertising

  3. "Jim Lewis" <> wrote in message
    news:...

    > What it sounds like you want is a transaction based
    > testbench. Using procedures is a good start:
    >
    > -- Baud Rate = 115200. ExtClk = 20 MHz. Divisor = 11
    > CpuWrite(CpuRec, UART_DIVISOR_HIGH, X"0000");
    > CpuWrite(CpuRec, UART_DIVISOR_LOW, X"000A");

    [...]

    Is it just me, or does anyone else find this pretty clumsy?

    Just to recap, the problem is...
    1.We want these procedures to go in a package, for the sake
    of reusability.
    2.Procedures in a package can't access signals in an architecture
    directly, of course, because those signals aren't visible
    (don't exist!) when the procedure is analyzed.
    3.So whenever we invoke the procedure, we need to provide as
    actual parameters not only the stuff that's unique for this
    call to the procedure (UART_DIVISOR_HIGH, X"0000") but also
    stuff describing the signals that the procedure will activate
    (CpuRec).
    4.Respectable and reliable authors (Bergeron, Lewis, Cohen, even
    our training materials) then advise packaging all these signals
    in a record, so it's easier to change the details and less hassle
    to invoke the procedure.

    So far, so traditional. But I still find it offensive to have to
    name the connections every time I invoke the procedure. Am I alone?

    I like to add one additional layer of encapsulation, adding a
    "wrapper" procedure in the stimulus-generator process...

    -- architecture contains the CPU-interface record CpuRec,
    signal CpuRec: CpuRec_Type;
    -- and this process that does the work...
    CPU_stimulus_generator: process

    -- Wrapper procedure:
    procedure CpuWrite(in REG: Reg_Adrs_Type; in DATA: Data_Type) is
    begin
    CpuWrite(CpuRec, REG, DATA);
    end;

    -- and more procedures for CpuRead, etc, etc

    begin
    ...
    CpuWrite(UART_DIVISOR_HIGH, X"0000");
    CpuWrite(UART_DIVISOR_LOW, X"000A");
    ...
    end process;

    The wrapper procedures simply take general-purpose package
    procedures like CpuWrite(rec, adrs, data) and specialise them
    with the signals that will be used by that specific process.
    There's no loss of portability, and IMHO a great gain in clarity
    of the mainstream stimulus generator code. Even in complicated
    cases, the wrapper procedures are simple and short.

    Criticism welcome!
    --

    Jonathan Bromley, Consultant

    DOULOS - Developing Design Know-how
    VHDL * Verilog * SystemC * Perl * Tcl/Tk * Verification * Project Services

    Doulos Ltd. Church Hatch, 22 Market Place, Ringwood, Hampshire, BH24 1AW, UK
    Tel: +44 (0)1425 471223 mail:
    Fax: +44 (0)1425 471573 Web: http://www.doulos.com

    The contents of this message may contain personal views which
    are not the views of Doulos Ltd., unless specifically stated.
     
    Jonathan Bromley, Jan 29, 2004
    #3
  4. Doug Miller

    Jim Lewis Guest

    VHDL-200X DTA topic hits about the middle of this thread.

    Jim Lewis <> wrote:
    >>What it sounds like you want is a transaction based
    >>testbench. Using procedures is a good start:
    >>
    >> -- Baud Rate = 115200. ExtClk = 20 MHz. Divisor = 11
    >> CpuWrite(CpuRec, UART_DIVISOR_HIGH, X"0000");
    >> CpuWrite(CpuRec, UART_DIVISOR_LOW, X"000A");


    Jonathan Bromley wrote:
    >
    > [...]
    >
    > Is it just me, or does anyone else find this pretty clumsy?
    >


    .... Snip ...

    >
    > I like to add one additional layer of encapsulation, adding a
    > "wrapper" procedure in the stimulus-generator process...
    >
    > -- architecture contains the CPU-interface record CpuRec,
    > signal CpuRec: CpuRec_Type;
    > -- and this process that does the work...
    > CPU_stimulus_generator: process
    >
    > -- Wrapper procedure:
    > procedure CpuWrite(in REG: Reg_Adrs_Type; in DATA: Data_Type) is
    > begin
    > CpuWrite(CpuRec, REG, DATA);
    > end;
    >
    > -- and more procedures for CpuRead, etc, etc
    >
    > begin
    > ...
    > CpuWrite(UART_DIVISOR_HIGH, X"0000");
    > CpuWrite(UART_DIVISOR_LOW, X"000A");
    > ...
    > end process;
    >
    > The wrapper procedures simply take general-purpose package
    > procedures like CpuWrite(rec, adrs, data) and specialise them
    > with the signals that will be used by that specific process.
    > There's no loss of portability, and IMHO a great gain in clarity
    > of the mainstream stimulus generator code. Even in complicated
    > cases, the wrapper procedures are simple and short.
    >
    > Criticism welcome!


    First, I feel your pain. However, since we have
    worked the procedures down to only having one extra
    signal, the record, I don't feel it that much. To
    remove this one signal name, you propose to add the
    clutter of the translation procedures and potential
    simulation inefficiency of the additional layer of
    procedure calls.

    Engineering wise, there is probably a balance point.
    Your suggestion probably works great if there are only
    a few procedures and if no additional procedures will be
    added.

    I think I would always be willing to type the extra
    name. If I was really that concerned about it, I would
    make the record name C.

    The language is up for revision, so rather than argue
    about the merits of the wrapper approach, I would
    prefer to brain-storm on language changes that would
    help this situation.

    The VHDL-200X Data Types and Abstractions (DTA) group
    (headed by Peter Ashenden) is looking at adding generics
    to packages (including type generics). One of the
    things that comes with this is instantiatable
    packages. So I have been wondering, if I instantiate
    a package in a process declaration region, can the
    package see signals in the process environment and
    can procedures in the instantiated package see signals
    by side-effect? This most would solve the same problem.
    Currently it is planned that this feature will be based
    on the SUAVE proposal (but perhaps with some syntax
    changes). For links to the SUAVE work, go to:
    http://www.eda.org/vhdl-200x/vhdl-200x-dta/proposals/proposals.html


    Another problem I have with using a single record is that
    the record must be inout (both the transaction source and
    the BFMs drive elements of the record). This limits the
    record to use of types with a resolution function - and in
    my case I take the easy way out by using the std_logic
    family. Currently there is a fast track proposal to address
    this issue by making it possible to specify modes of record
    elements individually. For more information see:
    http://www.eda.org/vhdl-200x/vhdl-200x-ft/proposals/ft17_composite_interface_mode.txt

    Comments welcome. :)

    More information on the VHDL-200X is at:
    http://www.eda.org/vhdl-200x

    Anyone can participate as an observer. If you are an IEEE member
    and a DASC member you can be a voting member and vote on issues.
    However, do note people do listen and are concerned about the
    issues of observers. Speaking as the team leader of the
    modeling and productivity group and co-team leader of
    fast track, I would welcome people with language skills like
    Jonathan and Mike to contribute to working group proposal
    writing.

    Cheers,
    Jim
    --
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Jim Lewis
    Director of Training mailto:
    SynthWorks Design Inc. http://www.SynthWorks.com
    1-503-590-4787

    Expert VHDL Training for Hardware Design and Verification
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     
    Jim Lewis, Jan 29, 2004
    #4
  5. "Jim Lewis" <> wrote in
    message news:...

    > VHDL-200X DTA topic hits about the middle of this thread.


    I'll try to get back to following VHDL-200X. I've let it
    lapse recently, with other issues taking higher priority -
    SystemV*****g, for example :-(

    [...]

    > > The wrapper procedures simply take general-purpose package
    > > procedures like CpuWrite(rec, adrs, data) and specialise them
    > > with the signals that will be used by that specific process.
    > > There's no loss of portability, and IMHO a great gain in clarity
    > > of the mainstream stimulus generator code. Even in complicated
    > > cases, the wrapper procedures are simple and short.
    > >
    > > Criticism welcome!

    >
    > First, I feel your pain. However, since we have
    > worked the procedures down to only having one extra
    > signal, the record, I don't feel it that much.


    I think I hear what you're saying, but I don't find it
    very convincing. [On a second reading of what I've
    written below, it sounds a bit combative. It's not meant
    to be, and please accept my apologies if it seems so.
    A deadline looms, and I don't have time to polish the
    phrasing of a newsgroup post!]

    > To remove this one signal name, you propose to add...


    VHDL is and will probably remain fairly verbose. I have
    no problem with that, and never have had. The argument
    that says (in parody) productivity=gates/keystrokes is
    a bad joke. No, my motivation is definitely NOT to save
    keystrokes. It's an encapsulation/hiding issue. Within
    the stimulus generator process, I want calls to the BFM
    procedures to be parameterised ONLY ON THE THINGS THAT
    ARE DIFFERENT PER-CALL: the connected signal is not,
    and should be rolled into the procedure.

    Remember partial function application in Pop-II (and
    LISP, I think, and some functional languages)?

    > clutter of the translation procedures


    A fair criticism, but I stand by my position that the
    specialisation wrappers are invariably simple and small.

    > and potential
    > simulation inefficiency of the additional layer of
    > procedure calls.


    BFM procedures are likely to be non-trivial. The
    overhead of one more function call and its associated
    parameter-passing should be negligible in comparison
    with the execution time and memory footprint of the
    procedure. Anyhow, any half-decent compiler should
    be able to inline calls of that kind that simply pass
    on parameters from one procedure to another, especially
    as the wrapper procedure is sure to be local to the
    process that uses it.

    > Engineering wise, there is probably a balance point.
    > Your suggestion probably works great if there are only
    > a few procedures and if no additional procedures will be
    > added.


    I agree that it gives rise to a maintenance issue when
    new BFM procedures are added to the package.

    > I think I would always be willing to type the extra
    > name. If I was really that concerned about it, I would
    > make the record name C.


    AARGH!

    > The language is up for revision, so rather than argue
    > about the merits of the wrapper approach, I would
    > prefer to brain-storm on language changes that would
    > help this situation.


    My wrapper trick is just a fudge to get a reasonable
    compromise between the style I want, the features
    available in VHDL, and the pressing need for re-use.
    I don't want to promote it as a solution for the future.

    The right solution to this problem IMHO is procedural
    entry points into entities (as proposed in OOVHDL, I think).
    This would give you the wonderful ability from Verilog
    of being able to write a BFM module, with procedures to
    invoke its functionality but also with ports to connect
    (permanently) to the signals it will drive/receive.
    The procedure would then be called by an OO-style
    "instancename.BFMprocedure(params)" method call.
    What's more, VHDL could easily make a good, robust job
    of the mutual exclusion problem, which is always a
    major issue when you allow this kind of cross-module
    access; we could borrow the tasks/entries/rendezvous
    mechanism from Ada - it matches this problem beautifully.

    > The VHDL-200X Data Types and Abstractions (DTA) group
    > (headed by Peter Ashenden) is looking at adding generics
    > to packages (including type generics). One of the
    > things that comes with this is instantiatable
    > packages. So I have been wondering, if I instantiate
    > a package in a process declaration region, can the
    > package see signals in the process environment and
    > can procedures in the instantiated package see signals
    > by side-effect? This most would solve the same problem.
    > Currently it is planned that this feature will be based
    > on the SUAVE proposal (but perhaps with some syntax
    > changes). For links to the SUAVE work, go to:
    > http://www.eda.org/vhdl-200x/vhdl-200x-dta/proposals/proposals.html


    Thanks for the link. Again, I'll try to get up to speed with
    it in the next few weeks, as time permits.

    > Another problem I have with using a single record is that
    > the record must be inout (both the transaction source and
    > the BFMs drive elements of the record). This limits the
    > record to use of types with a resolution function - and in
    > my case I take the easy way out by using the std_logic
    > family. Currently there is a fast track proposal to address
    > this issue by making it possible to specify modes of record
    > elements individually.


    This issue is another reason why I tend to prefer NOT using
    records, so that signal-class "port" parameters can be given
    their proper directions - then the "wrapper" trick looks
    even more useful.

    > For more information see:

    http://www.eda.org/vhdl-200x/vhdl-200x-ft/proposals/ft17_composite_interface
    _mode.txt
    > Comments welcome. :)


    Not until I've had a chance to look very much more carefully!

    Thanks for your comments and all the references.
    --

    Jonathan Bromley, Consultant

    DOULOS - Developing Design Know-how
    VHDL * Verilog * SystemC * Perl * Tcl/Tk * Verification * Project Services

    Doulos Ltd. Church Hatch, 22 Market Place, Ringwood, Hampshire, BH24 1AW, UK
    Tel: +44 (0)1425 471223 mail:
    Fax: +44 (0)1425 471573 Web: http://www.doulos.com

    The contents of this message may contain personal views which
    are not the views of Doulos Ltd., unless specifically stated.
     
    Jonathan Bromley, Jan 30, 2004
    #5
    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. Mike Treseler
    Replies:
    1
    Views:
    686
    Jim Lewis
    Jan 29, 2004
  2. Guido
    Replies:
    3
    Views:
    3,229
    Mike Treseler
    Jan 30, 2006
  3. Mr.X
    Replies:
    5
    Views:
    1,135
    radarman
    Apr 9, 2008
  4. M. Norton
    Replies:
    9
    Views:
    1,367
  5. M. Norton
    Replies:
    1
    Views:
    761
Loading...

Share This Page