Electronic – Can a VHDL concurrent assertion reference the LAST_EVENT attribute

vhdl

I'm trying to use a concurrent assertion in an entity declaration to enforce a minimum pulse-width constraint. Everything works as expected if I use a sequential assertion wrapped inside a passive process:

testcase.vhdl

entity testcase is
    port(clk: in bit);
begin
    check: process is
    begin
        -- Require at least 10ns between clock edges
        assert clk'delayed'last_event >= 10 ns;
        wait on clk;
    end process check;
end entity testcase;

-- Keep the compiler happy
architecture empty of testcase is
begin
end architecture empty;

testcase_testbench.vhdl

entity testcase_testbench is
end entity testcase_testbench;

architecture bench of testcase_testbench is
    signal clk: bit;
begin
    dut: entity work.testcase(empty) port map(clk => clk);

    stimulus: process is
    begin
        -- Valid low and high pulses
        clk <= '0';
        wait for 10 ns;
        clk <= '1';
        wait for 10 ns;
        -- Confirm that we're timing events, not transactions
        clk <= '1';
        wait for 5 ns;
        -- Now send a short pulse to make the assertion fire        
        clk <= '0';
        wait for 5 ns;
        -- Assertion should fire here, at 30ns
        clk <= '1';
        wait;
    end process stimulus;
end architecture bench;

Build and test:

$ ghdl -a testcase.vhdl
$ ghdl -a testcase_testbench.vhdl
$ ghdl -e testcase_testbench
$ ghdl -r testcase_testbench
testcase.vhdl:6:16:@30ns:(assertion error): Assertion violation

However, if I try to use a concurrent assertion I get a compiler error from ghdl:

testcase2.vhdl

entity testcase2 is
    port(clk: in bit);
begin
    check: assert clk'delayed'last_event >= 10 ns;
end entity testcase2;

Attempt to analyse:

$ ghdl -a testcase2.vhdl
canon_extract_sensitivity: cannot handle IIR_KIND_LAST_EVENT_ATTRIBUTE (testcase2.vhdl:4:34)

******************** GHDL Bug occured ****************************
Please report this bug on http://gna.org/projects/ghdl
GHDL release: GHDL 0.33 (20150921) [Dunoon edition]
Compiled with GNAT Version: 4.8
In directory: /home/simon/vhdl/
Command line:
/usr/bin/ghdl1-llvm -P/usr/lib/ghdl/v93/std/ -P/usr/lib/ghdl/v93/ieee/ -c -o testcase2.o testcase2.vhdl
Exception TYPES.INTERNAL_ERROR raised
Exception information:
Exception name: TYPES.INTERNAL_ERROR
Message: errorout.adb:63
Call stack traceback locations:
0x4978f2 0x4f055b 0x4f0350 0x4f2513 0x4f4806 0x5597df 0x5afbba 0x46eef6 0x433013 0x7f64f836082e 0x432450 0xfffffffffffffffe
******************************************************************
ghdl: compilation error

I get the same error if I move the concurrent assertion into the architecture body, or if I shorten the expression to clk'last_event >= 10 ns. Other expressions like clk'event or clk'delayed = '1' compile fine, even if they are somewhat pointless.

I'm fairly new to VHDL but my understanding is that my two testcases should be equivalent. If they aren't, why not? And if they are, why does ghdl complain about the second one?

Best Answer

Thank you for taking the effort to make a proper MCVE. My build of ghdl-0.34dev does the same, so there is clearly a ghdl bug here.

If the behaviour is legal, this should work, and if it's illegal, ghdl should exit cleanly with a description of the error.

Instead, ghdl isn't crashing, it has identified a shortcoming, a case where it "cannot handle LAST_EVENT attribute" (applied to another attribute) and shutdown with diagnostics.

I'll leave open the question whether a fine reading of the LRM determines its actual legality or not...

Putting anything at all beyond generics and ports in the entity as opposed to the architecture is rare ... I can't say I've ever seen it in production code - so you are out in the tall grass, though it's a valid thing to do.

In any case, moving this assertion into the architecture yields the same error, so that isn't the problem.

So, I've reporting it on ghdl's development site as https://github.com/tgingold/ghdl/issues/256 and I'll update my answer with any developments.

EDIT : A fix for this issue is now tested, and will be pushed to github following a full regression test.

HOWEVER : due to a subtlety in concurrent asserts, the two forms are not equivalent.

ghdl -r testcase_testbench
testcase.vhd:7:9:@30ns:(assertion error): Assertion violation

ghdl -r testcase_testbench
testcase2.vhd:4:5:@10ns:(assertion error): Assertion violation
testcase2.vhd:4:5:@25ns:(assertion error): Assertion violation
testcase2.vhd:4:5:@30ns:(assertion error): Assertion violation

In the first case, the process triggers on clk as requested. Delete the "wait" and put clk in the sensitivity list, and it does the same.

However, in Testcase2, the concurrent Assert is equivalent to a sensitivity list process, but the sensitivity list is clk'delayed.

As Tristan points out on the issue report (same link as above), clk'delayed is active in more than one delta cycle at 10ns, and so fails the test (because last'event is 0 ns between them!) Put clk'delayed in the sensitivity list for the Testcase process and see.

As "diogratia" points out there, a similar example in "The VHDL Designer's Guide" (Peter Ashenden) has a simple change to Testcase2 avoiding the issue : restrict the Assert to clk events...

entity testcase2 is
    port(clk: in bit);
begin
    check: assert (not clk'event) or clk'delayed'last_event >= 10 ns;
end entity testcase2;

architecture empty of testcase2 is
begin
end architecture empty;

EDIT 2 : As of commit b42069e this is fixed in ghdl-0.34dev. If your workaround using a process doesn't meet your needs, you can update to this version, but it means building ghdl from source.