vhdl - How to solve a 'protected_enter(2)' error in GHDL -


i'm trying implement vhdl-08 version of our poc.simulation helper package.

the original package uses shared variables track simulation status:

  • pass: asserts passed
  • stop: stop processes

there several functions , procedures using internal state. example tbgenerateclock() procedure used create clock signal.

in vhdl-08 version, i'm using protected types shared variable. implemented several 'methods' (what correct terminus that?), using or modifying internal state variable.

ghdl compiles sources , throws error @ runtime: c:\tools\ghdl\0.33dev\bin\ghdl.exe:internal error: protected_enter(2) c:\tools\ghdl\0.33dev\bin\ghdl.exe:error: simulation failed

is ghdl internal error or using protected types in wrong way?

i created (hopefully) minimal example (download gist) has 2 procedures: generateclock, stopsimulation.

there tb* wrapper procedures ensure compatible interface vhdl-93 implementation.

library ieee; use     ieee.std_logic_1164.all;  package simulation   type tsimstatus protected     procedure stopsimulation;     procedure generateclock(signal clock : out std_logic; constant clockperiod : time; enable : boolean := true);   end protected;   -- stop simulation processes   procedure tbstopsimulation;   -- generate clock waveform simulation   procedure tbgenerateclock(signal clock : out std_logic; constant clockperiod : time; enable : boolean := true); end;  package body simulation   type tsimstatus protected body     variable stop : boolean := false;      procedure stopsimulation     begin       stop := true;     end procedure;      procedure generateclock(signal clock : out std_logic; constant clockperiod : time; enable : boolean := true)       constant high_time  : time  := clockperiod / 2;       constant low_time    : time  := clockperiod / 2;     begin       clock <= '1';       while not stop loop         while enable , not stop loop           clock <= '1';           wait high_time;           clock <= '0';           wait low_time;         end loop;         wait until (enable = true) or (stop = true);       end loop;     end procedure;   end protected body;    shared variable status : tsimstatus;    procedure tbstopsimulation   begin     status.stopsimulation;   end procedure;    procedure tbgenerateclock(signal clock : out std_logic; constant clockperiod : time; enable : boolean := true)   begin     status.generateclock(clock, clockperiod, enable);   end procedure;   end package body;  library ieee; use      ieee.std_logic_1164.all; use      work.simulation.all;  entity tb end entity;  architecture test of tb   constant clock_period : time := 10 ns;    signal clock    : std_logic;   signal reset    : std_logic    := '0'; begin   -- clock process   process   begin     tbgenerateclock(clock, clock_period, true);   end process;    -- stimuli process   process   begin     wait until rising_edge(clock);      reset    <= '1';     wait until rising_edge(clock);      reset    <= '0';     wait until rising_edge(clock);      tbstopsimulation;     wait;   end process; end; 

solution:

  1. move clock generation code tbgenerateclock procedure
  2. add function protected type internal stop-state
  3. mark function impure

here modified simulation package:

package simulation   type tsimstatus protected     procedure stopsimulation;     impure function getstate return boolean;   end protected;   -- stop simulation processes   procedure tbstopsimulation;   -- generate clock waveform simulation   procedure tbgenerateclock(signal clock : out std_logic; constant clockperiod : time; enable : boolean := true); end;  package body simulation   type tsimstatus protected body     variable stop : boolean := false;      procedure stopsimulation     begin       stop := true;     end procedure;      impure function getstate return boolean     begin       return stop;     end function;   end protected body;    shared variable status : tsimstatus;    procedure tbstopsimulation   begin     status.stopsimulation;   end procedure;    procedure tbgenerateclock(signal clock : out std_logic; constant clockperiod : time; enable : boolean := true)     constant high_time  : time  := clockperiod / 2;     constant low_time   : time  := clockperiod / 2;   begin     clock <= '1';     while not status.getstate loop       while enable , not status.getstate loop         clock <= '1';         wait high_time;         clock <= '0';         wait low_time;       end loop;       wait until (enable = true) or (status.getstate = true);     end loop;   end procedure;   end package body; 

protected types supported in ghdl-0.31 command line flag --std=02 (for -2002 standard revision) , gives same error.

there's release candidate 0.32, you're taking life in own hands 0.33dev represent revision in source tree beyond 0.32rc1.

questions on ghdl internals more addressed ghdl-discuss mail list , capable of addressing them , participating on stackoverflow don't windows.

i used c shell alias

find . -iname \*.ad\[bs\] -exec grep -h !* \{\} \; 

to find protected_enter in ghdl source tree.

in ghdl's source grt/grt-processes.adb, procedure ghdl_protected_enter1 see comments -- protected object locked. , -- should locked current process. associated protected_enter(2) internal error.

you presumably have 2 separate processes seeking access status.

these clock process , stimuli process (and have used labels).

ieee std 1076-2002, 12.5 dynamic elaboration:

b) execution of subprogram call involves elaboration of parameter interface list of corresponding subprogram declaration; involves elaboration of each interface declaration create corresponding formal parameters. actual parameters associated formal parameters. next, if subprogram method of protected type (see 3.5.1) or implicitly declared file operation (see 3.4.1), the elaboration blocks (suspends execution while retaining state), if necessary, until exclusive access object denoted prefix of method or file object denoted file parameter of file operation is secured. ...

method tbgenerateclock calls procedure status.generateclock never returns unless stop true, status locked , stop``true depends on stimuli process blocked.

the way out of appears to add argument method tbgenerateclock , procedure generateclock eliminating method tbstopsimulation , procedure stopsimulation.

you're operating status.generateclock if concurrent procedure call in place sequential procedure call should applicable. loops while waiting on either input values or passage of time. tbgenerateclock wrapper around procedure call status.generateclock masks issue (and there no prohibition can find in standard).

it seem ghdl complaint valid albeit lack of discernible diagnostic messages notable.

further if @ notes in 12.5:

2—if 2 or more processes access same set of shared variables, livelock or deadlock may occur. is, may not possible ever grant exclusive access shared variable outlined in item b), above. implementations allowed to, not required to, detect and, if possible, resolve such conditions.

the resolution appears have been produce unfathomable error message in lieu of allowing simulation time reach time'high, ending simulation time after board load of clock transitions.

personally i'd imagine ghdl quite clever figuring out there deadlock here.

i know of no documentation can here other reading ghdl source noted above or developing thorough understanding standard. (along lines of 'for experienced programmer errors obvious').

there no guarantee vhdl implementation indicate in form deadlock has occurred, it's optional.

the behavior might expect in case long simulation , seeing message effect simulation stopped reaching time'high, without tbstopsimulation procedure call in stimuli process ever having completed.

you'd have less information have ghdl (again, 'for experienced programmer errors obvious').

and know protected_enter (and protected_leave) messages associated blocking access protected methods more 1 process in ghdl. (and had find out hard way too.)

with paebbels solution

moving access stop outside procedure generating clock using protected method access stops value allows multiple processes access shared data provided protected type, giving exclusive access shared variable status long enough complete 2 methods (tbstopsimulation , impure function (method) getstate).

it allows multiple processes read or update stop giving each exclusive access long enough complete respective method.

i'd use signal share information between processes in case still need equivalent of protected method update stop should have multiple processes in elaborated design able stop simulation stopping clock.

there potential issue of portability based on concurrency (a simulation cycle stop both read , updated).

you have accuracy of 1 clock because there's no guarantee of execution or resuming order processes calling methods. if paebbels using pass/fail mechanism evaluate result of testing won't problem, , that's common solution.

so testbench tb change:

tb testbench solution png (clickable)

is you'll find in unlabelled process comment

-- stimuli process 

Comments

Popular posts from this blog

c++ - No viable overloaded operator for references a map -

java - Custom OutputStreamAppender not run: LOGBACK: No context given for <MYAPPENDER> -

java - Cannot secure connection using TLS -