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:
- move clock generation code
tbgenerateclock
procedure - add function protected type internal stop-state
- 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 stop
s 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:
is you'll find in unlabelled process comment
-- stimuli process
Comments
Post a Comment