Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

(Beginner VHDL) How to write test bench code to learn about records?

Status
Not open for further replies.

TimTamSlam

Newbie level 2
Joined
May 23, 2017
Messages
2
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
33
I am using GHDL and GTKWAVE to help with simulation

Thanks for looking at my post. I am learning vhdl and attempting to look into using records. I have been reading the article https://www.gaisler.com/doc/vhdl2proc.pdf, which preaches the ease of use and importance of using records to pass data, keep code reusable, and make it easily readable (sounds nice right). Well so I can understand vhdl I have been practicing by first trying to make a simple vhdl entity then an associated testbench. I could not figure out how to write the associated test bench for the vhdl in the article but looked for some simple examples on the web and came across this article at nand land https://www.nandland.com/vhdl/examples/example-record.html. I then tried writing a testbench for this entity like so:

Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.example_record_pkg.all;

entity Records_Ex_tb is

end Records_Ex_tb;

architecture behavior of Records_Ex_tb is
 
	component example_record 
	port(
		i_clk : in std_logic;
		i_fifo : in t_FROM_FIFO;
		o_fifo : out t_TO_FIFO := c_TO_FIFO_INIT	
		);
	end component;

	-- signals
	signal i_clk : std_logic;
	signal i_fifo : t_FROM_FIFO;
	signal o_fifo : t_TO_FIFO;



	
	
begin

	uut : example_record port map (i_clk => i_clk, i_fifo => i_fifo, o_fifo => o_fifo);

	clk_proc : process
	begin
		i_clk <= '0';
		wait for 1 ns;
		i_clk <= '1';
		wait for 1 ns;
	end process;

	
	stim_proc : process
	begin
	wait for 10 ns;
	
	
	
	assert false report "end of test";
	wait;
	i_fifo.wr_full <= '1';
	end process;

end behavior;

which does not complain when analyzed or run, the only problem is that when I go into GTKwave I only see my clock signal or the signal
Code:
 r_WR_DATA
. I was thinking that I would see my records also in GTKwave, is this wishful thinking or am I missing something.
 

r_WR_DATA is not shown in your code - so I have no idea what it is.
Also, GHDL and GTKWave are open source simulators - they probably should work but not many people use them, and are out of date (little/no 2008 support for example). I suspect the problem you have is a setup issue, rather than code issue.
You'll be much better served using the free version of modelsim (provided by altera) or Vivado.
 

You're going to need to include use example_record_pkg

Also some fundamental points to be raised here!

Code VHDL - [expand]
1
2
wait;
i_fifo.wr_full <= '1';



You will NEVER do the assignment i_fifo.wr_full <= '1'; because the simulator is stuck at the wait command above. You need to understand when something happens sequentially and concurrently in vhdl.
 

The idea is actually pretty interesting. Placing the state machine and the outputs generated from the state machine in the same record allows the benefits of the two-process state machine while limiting verbosity.

The article is probably written for an experienced developer. For example, the usefulness of loops is overstated. It isn't clear what the author considers "iterative algorithms" to be. Loops tend to be limited to special cases -- the bit reversal has only routing cost for the code inside the loop. any-set/all-set/odd-set work because they are simple reductions. priority encoder is fine. polynomial evaluation is a bit ambitious though and inner-product might rely on retiming to be practical.

VHDL2008 adds unconstrained members for records. SystemVerilog has interfaces in addition to structs and unions. It also has classes, but these can't be synthesized because they are forced to be dynamically constructed.

The main downside to this style is that you will never get hired if you use this as code samples.
 

#4, I'm contracting in space and we're pushing to go down this route in the company I'm at.

Take the following

Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
U14 : entity work.TIMER 
  port map(
    RST                                 => MSS_nREADY_S,
    CLK                                 => CLK,
 
    PPS_IN                              => PPS_S,
 
    ARM_WR_GPS_TIME_START               => ARM_WR_GPS_TIME_START_S,      -- from arm reg
    ARM_WR_GPS_TIME_ABORT               => ARM_WR_GPS_TIME_ABORT_S,      -- from arm reg
    ARM_WR_GPS_TIME                     => ARM_WR_GPS_TIME_S,            -- from arm reg
    ARM_WR_GPS_SELECT                   => ARM_WR_GPS_SELECT_S,          -- from arm reg
    ARM_WR_PAYLOAD_START_TIME           => ARM_WR_PAYLOAD_START_TIME_S,  -- from arm reg
    ARM_WR_PAYLOAD_STOP_TIME            => ARM_WR_PAYLOAD_STOP_TIME_S,   -- from arm reg
    ARM_RD_PAYLOAD_COUNTDOWN            => ARM_RD_PAYLOAD_COUNTDOWN_S,   -- to arm reg
    ARM_RD_PAYLOAD_TIME_WINDOW          => ARM_RD_PAYLOAD_TIME_WINDOW_S, -- to arm reg
    ARM_IRQ_PAYLOAD_EOCT                => ARM_IRQ_PAYLOAD_EOCT_S,
    ARM_IRQ                             => ARM_IRQ_PPS_S(0),
    ARM_PPS_IRQ                         => ARM_IRQ_PPS_S(1),
 
    PAYLOAD_START                       => PAYLOAD_START_S,
    PAYLOAD_STOP                        => PAYLOAD_STOP_S,
 
    UNIX_TIME                           => UNIX_TIME_S,                  -- to arm
    UNIX_TIME_LATCH                     => UNIX_TIME_LATCH_S,            -- to arm
    UNIX_TIME_LATCH_EN                  => UNIX_TIME_LATCH_EN_S          -- from arm
  ) ;



Becomes


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
type to_timer_t is record
    ARM_WR_GPS_TIME_START     : (whatever type)
    ARM_WR_GPS_TIME_START     : (whatever type)
    ARM_WR_GPS_TIME_ABORT     : (whatever type)
    ARM_WR_GPS_TIME           : (whatever type)
    ARM_WR_GPS_SELECT         : (whatever type)
    ARM_WR_PAYLOAD_START_TIME : (whatever type)
    ARM_WR_PAYLOAD_STOP_TIME  : (whatever type)
    UNIX_TIME_LATCH_EN        : std_logic;
  end record;
  
  type timer_t is record
    too   : to_timer_t; -- to is a keyword duh
    from  : from_timer_t;
  end record
  
  type bus_t is record
    something  : some_t;
    something1 : some1_t;
    timer      : timer_t;
  end record;
  
  signal my_bus : bus_t;
  
U14 : entity work.TIMER 
  port map(
    RST                                 => MSS_nREADY_S,
    CLK                                 => CLK,
 
    PPS_IN                              => PPS_S,
    from_timer                          => my_bus.timer.from,     -- here you have your structural reductions to 
    to_timer                            => my_bus.timer.too,       -- the verbosity of the code
    ARM_IRQ_PAYLOAD_EOCT                => ARM_IRQ_PAYLOAD_EOCT_S,
    ARM_IRQ                             => ARM_IRQ_PPS_S(0),
    ARM_PPS_IRQ                         => ARM_IRQ_PPS_S(1),
 
    PAYLOAD_START                       => PAYLOAD_START_S,
    PAYLOAD_STOP                        => PAYLOAD_STOP_S,
  ) ;



Note I haven't had a change to test this, but the concept stands!
 
Last edited:

We use records for all our AXI infrastructure. If you wrote it all in VHDL 2008 you could use package generics to then define all the different sized axi busses, but support for that is only just arriving.
It is a very large package, with all types for all directions defined, along with utility functions like

record_to_slv(a : my_record_t) return std_logic_vector;
slv_to_record(a : std_logic_vector) return my_record_t;

And default values for each record - as it is much cleaner just assigning:

a <= MY_RECORD_T_DEFAULT;

then remembering to assign everything in a reset or testbench input.

Also - a big note: there are a couple of big issues I have seen recently using records across language:

1. SV has no understanding of 0 length arrays. Our original axi packages had tuser set to 0 bits wide, but it didnt work with SV, so we just had to remove them from the package.
2. Cadence Incisive has a big issue mapping VHDL records in SV. It will only work with single layer records (so no records within records) and all fields must be a std_logic(_vector). It took a while to find, as the simulation ran, but the simulator just passed junk data over the interface.
 

Ah, ok. using records for interfaces is fine and is common enough. At one point I had a python script that automated the to_slv and to_record conversion functions. This prevented the off-by-one errors that come up.
 

Thanks Guys,

It looks like I have a couple of takeaways:

- I need to get more experience with coding (work on examples that show the difference between concurrent and sequential)
- That Records are not ubiquitous in the VHDL industry, but are mainly used when talking to peripheral buses
- That developing a test bench and showing the entity responses is not well supported in the ghdl gtkwave combo.

My goal for right now is to create a sandbox of reference codes that I can learn about different topics in vhdl. I usually like to start with something simple like a half adder or some flip flops, but the examples I have found tend to be for more experienced programmers.
 

For some context here, this article was first written in 1997 and then modified in 2000. As a result, some of the comparisons are not correct. For example, almost no one uses the verbose dataflow style to the level that there is a process per logic element. Such designs would only come from university students as it is more similar to the structural design style taught by some universities.

The primary issues with the design style listed in the article is that a higher level of abstraction makes it harder to estimate how complex a circuit will be. It also makes some tools like explicit pipelining more difficult. The second issue is that the style doesn't translate into Verilog.

--edit: using records for ports is fine though. that should only affect the way a bus is represented and not infer any logic on its own.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top