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.

VHDL: Default Record for generic type

Status
Not open for further replies.

_MW_

Newbie level 3
Joined
Apr 3, 2020
Messages
4
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
44
Hi,

I am currently trying to implement the VHDL-2008 construct Generic Package. For this I have a generic type, which I want to initalize with a default record. Does anyone know if an if so how this is possible?
I would like the colored part of the code to be similar even though it obviously does not work exactly like this.

Code:

Code:
package GenericPkg is
  generic (
    type myType [COLOR="#0000CD"]is record 
        myValue : integer ;
    end record [/COLOR];
  ) ;

  ...

end GenericPkg ;


Thanks a lot!
 

This is not how generic types work.

a generic list can have a type as a generic. But internally you do not have any knowledge of that type. Hence you cannot get access to the default value, because it doesnt exist.


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
package record_pkg is
  type myType is record
    myValue : integer;
  end record;
end package;
 
package GenericPkg is
  generic (
    type some_type   -- the user will specify the type when the package is instantiated
  )
end package GenericPkg;
 
package MyNewPkg is new GenericPkg generic map (some_type => work.myType );

 

I'm aware of that. I may have expressed myself a little unclearly.
The passed record is generic but always contains a fixed attribute and optionally others. This fixed attribute must be accessed in the GenericPkg.The GenericPkg is also passed a function that returns the record data type. Unfortunately, due to backwards compatibility reasons, the function cannot be converted into a procedure with two outputs, one with the fixed attribute and one generic record without the fixed attribute. I was hoping that it would be possible to set a default type for the generic datatype and then access the fixed attribute in the GenericPkg.
I had already expected that it probably wouldn't work, but I still wanted to draw on the collective knowledge of this forum before I stopped my efforts and instead chose a simpler but also suboptimal way for my specific case.
 

I am still confused, particularly as the code in your original post is syntactically incorrect and makes little sense, as specifying a type in a generic is not generic (you cannot even supply a default for a generic type). It might be easiest to post the actual code?
Other parts of your post make me think you're talking about unconstrained types rather than generic types? these are two different things.
A generic type can still be assigned an unconstrained type, but you cannot use any array attributes of a generic type because you have no visibility of the type.

There is a good discussion here as to why getting the initial value of a generic type is not possible:

TL:DR - how can you have an INIT_VAL attribute for an unconstrained type?

So, I think the answer you are looking for is that no, its not possible, but I suspect you are trying to do things in the wrong way.
 

The actual code looks like this:

Code:
package GenericPkg is
  generic (
    type complex_data_type;
    function Match( A, B : complex_data_type ) return boolean;
    function Print( obj : complex_data_type ) return string;
  );

  procedure Check( A, B : in complex_data_type ); 
end GenericPkg;

package body GenericPkg is
  procedure Check( A, B : in complex_data_type ) is
    variable row : line;
  begin
    if not Match( A, B ) then
      write(row, Print(A));
      write(row, Print(B));
    end if;
  end procedure;
end GenericPkg;


package my_functions_pkg is
  function my_match ( A, B : my_complex_data_type ) return boolean;
  function my_print ( obj : my_complex_data_type ) return string;
end my_functions_pkg;

package body my_functions_pkg is
  function my_match ( A, B : my_complex_data_type ) return boolean is
  begin
     if(...) then
       return false;
     end if;
     return true;
  end function my_match

  function my_print ( obj : my_complex_data_type ) return string;
  begin
    return ("Informations stored in obj"...);
  end function my_print;
end my_functions_pkg;

package my_Pkg is new GenericPkg
  generic map (
    complex_data_type  => my_complex_data_type,
    Match              => my_match,
    Output             => my_print
  );

But I want more information from the match function. If it is not matched I want to know what exactly it failed and display it in the print function.
So I want to add an additional data_type as output of the match function and input of the print function to display more detailed info. But as functions can only have one output in VHDL, I have the possibility to store it in one record (but then i need to access the boolean value inside this record, which seems not to be possible) or I change the match function into a procedure with to outputs - the boolean and the information data type- this second way would work perfectly, but has been considered as too different from the previous version.
 

Looks like you're trying to get more information out of the OSVVM Scoreboard package :)

You can do what you want, as Ive done it. The trick is to compare everything as a string. Because you've already written a to_string function. so you can just compare the two results as strings char by char, giving you a char by char matching that you can then have reported in the log. What mine also does is allow you to put 'X' in the expected string to force a match with the actual value. This is useful when, for example, you have byte enables and you only want to check the "valid" bytes in the bus.

So, here is what I do. First off, have a "match_string" function, that returns a string that comapres two strings char by char, and returns a string that has 'X' where there is a missmatch between the two string:


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
--------------------------------------------------------------------------------------------
-- Takes 2 strings and produces another strings that marks missmatches
--------------------------------------------------------------------------------------------
function match_string(s1, s2          : string;
                      match_char      : character := ' ';
                      missmatch_char  : character := 'X';
                      s1_ignore       : string    := "";
                      s2_ignore       : string    := "" ) return string is
 
  variable ret      : string(s1'range);
  variable s1_local : string(s1'range) := s1;
  variable s2_local : string(s2'range) := s2;
begin
  assert (s1'length = s2'length)
    report "match_string: S1 and S2 lengths must match" & LF
          & "S1 = " & s1 & LF
          & "S2 = " & s2
      severity FAILURE;
 
  for i in s1'range loop
    ----------------------------------------------------------------------------
    -- Force a match on ignore chars
    ----------------------------------------------------------------------------
    for j in s1_ignore'range loop
      s1_local(i) := s2_local(i) when s1_local(i) = s1_ignore(j);
    end loop;
 
    for j in s2_ignore'range loop
      s2_local(i) := s1_local(i) when s2_local(i) = s2_ignore(j);
    end loop;
 
    ret(i) := match_char when (s1_local(i) = s2_local(i)) else missmatch_char;
  end loop;
 
  return ret;
end function match_string;



then a procedure that does what you suggested - returns the matching string (with Xs in it) and whether it was a complete match or not


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
procedure match_string( constant s1, s2          :       string;
                        constant match_char      :       character := ' ';
                        constant missmatch_char  :       character := 'X';
                        constant s1_ignore       :       string    := "";
                        constant s2_ignore       :       string    := "";
 
                        variable match_str       : inout line;
                        variable matched         :   out boolean )   is
begin
  DEALLOCATE(match_str);
  matched       := false;
  match_str     := new string'( match_string(s1, s2, match_char, missmatch_char, s1_ignore, s2_ignore) );
 
  -- return missmatch on any missmatch char
  for i in s1'range loop
    if match_str(i) = missmatch_char then return; end if;
  end loop;
 
  matched       := true;
end procedure;



then finally, the magic match_X_generic function that can take any data type so you can plug it directly to the scoreboard package of osvvm


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
function match_X_generic generic ( type data_t;
                                   function to_string(d : data_t) return string is <> )
                         parameter( act, exp    : data_t )
                         return boolean is
  variable matched    : boolean;
  variable match_str  : line;
begin
  match_string( s1          => to_string(act),
                s2          => to_string(exp),
                s2_ignore   => "X-"          ,
                match_str   => match_str     ,
                matched     => matched        );
 
  if not matched then
    -- Dont Use Alert, as this will come in Scoreboard
    log(TBTOOLS_ALERT_ID, "act: " & to_string(act), ALWAYS);
    log(TBTOOLS_ALERT_ID, "exp: " & to_string(exp), ALWAYS);
    log(TBTOOLS_ALERT_ID, "     " & match_str.all , ALWAYS);
  end if;
 
  DEALLOCATE(match_str);
 
  return matched;
end function match_X_generic;



so then, in your log, you can get output like this every time the scoreboard performs a check:

Code:
%% Log   ALWAYS  in testbench_tools_pkg, act: tid: 0x00 tdata: 0x9B3EC00E13ECBA2E tuser: 0xXXXXA5420F6560 tkeep: 0xFF tlast: 0  at 5570 ns
%% Log   ALWAYS  in testbench_tools_pkg, exp: tid: 0x00 tdata: 0xFFFFFFFFFFFFFFFF tuser: 0xXXXXA5420F6560 tkeep: 0xFF tlast: 0  at 5570 ns
%% Log   ALWAYS  in testbench_tools_pkg,                         XXXXXXXXXXXXXXXX                                               at 5570 ns
%% Alert ERROR   in Filtered Packet Checker,    Received: tid: 0x00 tdata: 0x9B3EC00E13ECBA2E tuser: 0xXXXXA5420F6560 tkeep: 0xFF tlast: 0    Expected: tid: 0x00 tdata: 0xFFFFFFFFFFFFFFFF tuser: 0xXXXXA5420F6560 tkeep: 0xFF tlast: 0    Item Number: 1 at 5570 ns
 
Last edited:

That's exactly what I want to do. :)
And it looks like I can use some of your code for my case.
But unfortunately I compare data packets with a length of up to 1500 bytes. So I do not want to output the whole data, but only the number of the first erroneous byte and the stored values in actual and expected.
In my case I verify an packet-based network which routes the packet to the corresponding output stored in the address bits.
I know that I could push and check each byte separately, but then it would become very chaotic if a hole packet would be routed to a wrong port.
 

In my case, all packets are sent on an AXIS bus, and I generate whole ethernet packets and break them into AXIS transactions, and compare on the AXI bus. I do this because I have an AXIS interface I can send the packets to and do the checking for me. If I had N checkers (for each endpoint) I can check each packet transaction by transaction. But like you say you can copy some of my ideas if you want to check at a higher level.

I hope you get what you need working. Am always willing to help.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top