frznchckn
Member level 1
- Joined
- Jul 20, 2010
- Messages
- 36
- Helped
- 4
- Reputation
- 8
- Reaction score
- 4
- Trophy points
- 1,288
- Location
- California
- Activity points
- 1,521
Stimulus : process
begin
reset <= '1';
wait for 20 ns;
reset <= '0';
axi4Write(<address>,<data>);
axi4Write(<address>,<data>);
axi4Write(<address>,<data>);
axi4Write(<address>,<data>);
axi4Write(<address>,<data>);
end process Stimulus;
Code VHDL - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 --------------------------------------------------- --BFM of writing an 8 bit word to the SPI bus --------------------------------------------------- procedure write_spi_word( d : unsigned; signal spim_clk : out std_logic; signal spim_simo : out std_logic ) is begin for i in d'range loop spim_simo <= d(i); spim_clk <= '0'; wait for CLK_PERIOD_SPI/2; spim_clk <= '1'; wait for CLK_PERIOD_SPI/2; spim_clk <= '0'; end loop; end procedure write_spi_word;
Code VHDL - [expand] 1 2 3 4 5 6 for d in 1 to packet_size*2 loop write_spi_word( to_unsigned(stim_gen.get_stim, 8), spim_clk, spim_simo ); end loop;
Code VHDL - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package some_pkg is function do_something(x : integer) return integer; --no definition here, its not allowed procedure bfm(variable a : out integer); end package some_package; package body some_pkg is function do_something(x : integer) return integer is --you can declare another function or procedure here if you want begin --this calculates the awesomeness of PI end function; procedure bfm(variable a : out integer) is --you can declare other functions or procedures here begin --do somethiong end procedure bfm; end package body some_pkg;
Code VHDL - [expand] 1 2 3 4 5 6 7 8 9 10 --inside a process axi4.loadfile("somefile.txt"); while not AXI4.done_all_commands loop AXI4_BFM.do_next_command( --signal interface) end loop; wait;
Thanks for the push. I'll get my ship sailing now.
A quick clarification though... I've used functions before defined in processes, but I thought you could also define them outside of a process? When would you use a function versus a procedure, or did I get functions wrong?
[syntax=vhdl]
package my_tb_package is
procedure Write(
-- Long list of parameters and signals for connecting to the entity under test
... -- Other procedures
package my_tb_package;
package body my_tb_package
procedure Write(
-- This would be the place where you would implement the protocol to perform
-- the requested task, in this case 'Write'
... -- Other procedures
end package my_tb_package;
...
architecture rtl of my_testbench is
-- Alternatively, the procedure mentioned above for the package could be placed here
-- Whether you should put it in a package or not depends on whether you think those
-- procedures have potential future value besides the current project you're working on.
-- If so, put them in the package so you can reuse the procedures in that new project
-- simply with a 'use work...."
begin
process
-- Create shorthand procedures that don't require the use of a long list of signals.
-- The example here is that you want to be able to read and write some registers
-- inside the device being tested.
-- First create read/write procedures that have a simple address/data interface
procedure Write(Address, Data: std_ulogic_vector) is
...
begin
Write(
Addr => Address,
Write_Data => Data,
... -- Long list of signals as required by the write procedure in the package
);
end procedure Write;
impure function Read(Address: std_ulogic_vector) return std_ulogic_vector is
-- You get the idea
end function Read;
-- The above procedures and functions can also be overridden to allow different
-- parameters; maybe you'd like the address and data to be integers or something
-- To do this, you would declare new procedures and functions like the ones above
-- that are in this process, but it's even less work than one might think. Since you
-- now already have a method for writing if the parameters are std_ulogic_vector,
-- then simply cast yourintegers into std_ulogic_vector via the usual functions from
-- numeric_std. Build on what you have, avoid copy/paste whenever possible
-- Now consider that maybe you've defined record types for all of these registers
-- inside your design to define the bit positions of the register. Hopefully those record
-- types have been put into a package...if not you should do so. Let's say that you
-- have a record type called t_MY_CNTL_REG that defines the bit fields of some control
-- register in your design. Let's assume also that you had the foresight to also include
-- a 'To_std_ulogic_vector' and a 'From_std_ulogic_vector' function in the package
-- that contains the t_MY_CNTL_REG definition. These functions convert t_MY_CNTL_REG
-- things to/from std_ulogic_vectors. Given all that, now you could define read and
-- write procedures that have an even simpler interface
procedure Write(Reg: t_MY_CNTL_REG) is
constant Address: integer := xxx; -- The address of the control register
begin
write(Address, To_std_ulogic_vector(Reg));
end procedure Write;
impure function Read return t_MY_CNTL_REG is
constant Address: integer := xxx; -- The address of the control register
variable Reg_Data: std_ulogic_vector(...);
begin
Reg_Data := Read(Address);
return(From_std_ulogic_vector(Reg_Data));
end function Read;
begin
-- Now the fun and easy part. You can read and write addresses by manually entering the correct addresses and data
Write(20, 40); -- Easy, but rather lacking in describing what you're doing
Cntl_Reg := Read(20); -- Easy here, but consider that the address of 20 needs to be manually maintained to be the same
-- A better approach would for the address to be obtained from a constant in the package
Write(CNTL_PORT_ADDRESS, 40);
Cntl_Reg := Read(CNTL_PORT_ADDRESS);
-- Even better approach...the last layer of procedures intentionally removes the address from the interface so that there
-- is no chance of getting the address incorrect in this area of the code
Write(Cntl_Reg);
Cntl_Reg := Read;
end rtl;
[/syntax]
Look at the top of this forum above all of the postings for the instructionsOh also, how did you get your code to look so awesome in the forum?
With what you are doing, you could get a really awesome BFM if you wanted to spend a bit of time on it. You could open a file with the transaction list inside a protected type, and then in your testbench all you would see would be something like this:
Code VHDL - [expand] 1 2 3 4 5 6 7 --inside a process axi4.loadfile("somefile.txt"); while not AXI4.done_all_commands loop AXI4_BFM.do_next_command( --signal interface) end loop; wait;
And then it would be the file, rather than the testbench code, that determined the read/write/other functions. You would only need a single testbench then.
And that entity could be called the testbench.boo, didn't think about that. you could just wrap it inside an entity instead.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?