diff --git a/Makefile.in b/Makefile.in index b4c45bde6..4c4ca6481 100644 --- a/Makefile.in +++ b/Makefile.in @@ -763,6 +763,7 @@ GENHTML_OPT += --rc branch_coverage=1 GENHTML_OPT += --rc genhtml_hi_limit=100 GENHTML_OPT += --ignore-errors negative GENHTML_OPT += --ignore-errors inconsistent +GENHTML_OPT += --ignore-errors empty ifeq ($(COVERAGE_REF_BASE),) GENHTML_OPT += --header-title "Code coverage for Verilator $(shell git describe --dirty)" else diff --git a/include/verilated_std.sv b/include/verilated_std.sv index 4d3f04e92..88122610b 100644 --- a/include/verilated_std.sv +++ b/include/verilated_std.sv @@ -99,46 +99,6 @@ package std; endfunction endclass - // IEEE 1800-specified standard "semaphore" - class semaphore; - protected int m_keyCount; - protected int m_nextKeyCount = '1; - protected longint unsigned m_ticket = 0; - protected longint unsigned m_nextTicket = 0; - - function new(int keyCount = 0); - m_keyCount = keyCount; - endfunction - - function void put(int keyCount = 1); - m_keyCount += keyCount; - endfunction - - task get(int keyCount = 1); -`ifdef VERILATOR_TIMING - longint unsigned ticket; - // Fast path: take if keys fit AND either no one is queued, or - // the head still doesn't fit (so we're not stealing its keys). - if (m_keyCount >= keyCount && m_nextKeyCount > m_keyCount) begin - m_keyCount -= keyCount; - return; - end - ticket = m_nextTicket++; - wait (m_ticket == ticket); - m_nextKeyCount = keyCount; - wait (m_keyCount >= keyCount); - m_keyCount -= keyCount; - m_ticket++; -`endif - endtask - - function int try_get(int keyCount = 1); - if (m_keyCount < keyCount) return 0; - m_keyCount -= keyCount; - return 1; - endfunction - endclass - // IEEE 1800-specified standard "process" class process; typedef enum { @@ -243,6 +203,56 @@ inline bool VlClassRef<`systemc_class_name>::operator<(const VlClassRef<`systemc endfunction endclass + // IEEE 1800-specified standard "semaphore" + class semaphore; + typedef struct { + process proc; + int reqKeys; + } procKeys; + procKeys m_queue[$]; + protected int m_keyCount; + + local task dropKilled; + // Drop killed processes from the queue +`ifdef VERILATOR_TIMING + while (m_queue.size() > 0 && m_queue[0].proc.status() == process::KILLED) m_queue.pop_front(); +`endif + endtask + function new(int keyCount = 0); + m_keyCount = keyCount; + endfunction + + function void put(int keyCount = 1); + m_keyCount += keyCount; + endfunction + + task get(int keyCount = 1); +`ifdef VERILATOR_TIMING + dropKilled(); + // Fast path: take if keys fit AND either no one is queued, or + // the head still doesn't fit (so we're not stealing its keys). + if (m_keyCount >= keyCount && (m_queue.size() == 0 || m_queue[0].reqKeys > keyCount)) begin + m_keyCount -= keyCount; + return; + end + m_queue.push_back('{process::self(), keyCount}); + while (m_queue[0].proc != process::self()) begin + wait (m_queue[0].proc.status() == process::KILLED || m_queue[0].proc == process::self()); + dropKilled(); + end + wait (m_keyCount >= keyCount); + m_keyCount -= keyCount; + m_queue.pop_front(); +`endif + endtask + + function int try_get(int keyCount = 1); + if (m_keyCount < keyCount) return 0; + m_keyCount -= keyCount; + return 1; + endfunction + endclass + // IEEE 1800-specified standard "std::randomize" function int randomize(); randomize = 0; diff --git a/test_regress/t/t_covergroup_array_bins.out b/test_regress/t/t_covergroup_array_bins.out index c3d0a77e9..f2d20a87d 100644 --- a/test_regress/t/t_covergroup_array_bins.out +++ b/test_regress/t/t_covergroup_array_bins.out @@ -22,6 +22,6 @@ cg7.cp.rev[0]: 1 cg7.cp.rev[1]: 0 cg8.cp.w[0]: 0 cg8.cp.w[1]: 1 -cg9.__cross7.ok_x_lo [cross]: 1 +cg9.__cross8.ok_x_lo [cross]: 1 cg9.cpA.ok: 1 cg9.cpB.lo: 1 diff --git a/test_regress/t/t_covergroup_cross.out b/test_regress/t/t_covergroup_cross.out index 16d4ad5a4..88ffe002d 100644 --- a/test_regress/t/t_covergroup_cross.out +++ b/test_regress/t/t_covergroup_cross.out @@ -169,10 +169,10 @@ cg_trans.cp_v.v5: 2 cg_trans.cp_v.v6: 1 cg_trans.tx.t01_x_v5 [cross]: 1 cg_trans.tx.t01_x_v6 [cross]: 0 -cg_unnamed_cross.__cross8.a0_x_read [cross]: 1 -cg_unnamed_cross.__cross8.a0_x_write [cross]: 0 -cg_unnamed_cross.__cross8.a1_x_read [cross]: 0 -cg_unnamed_cross.__cross8.a1_x_write [cross]: 1 +cg_unnamed_cross.__cross9.a0_x_read [cross]: 1 +cg_unnamed_cross.__cross9.a0_x_write [cross]: 0 +cg_unnamed_cross.__cross9.a1_x_read [cross]: 0 +cg_unnamed_cross.__cross9.a1_x_write [cross]: 1 cg_unnamed_cross.cp_a.a0: 1 cg_unnamed_cross.cp_a.a1: 1 cg_unnamed_cross.cp_c.read: 1 diff --git a/test_regress/t/t_covergroup_iff.out b/test_regress/t/t_covergroup_iff.out index a0b982b1e..ea7118969 100644 --- a/test_regress/t/t_covergroup_iff.out +++ b/test_regress/t/t_covergroup_iff.out @@ -18,7 +18,7 @@ cg_cross_coverpoint_iff.cross_ab.one_x_one [cross]: 1 cg_cross_iff.cp_a.one: 3 cg_cross_iff.cp_b.one: 3 cg_cross_iff.cross_ab.one_x_one [cross]: 1 -cg_cross_iff_unnamed.__cross7.one_x_one [cross]: 1 +cg_cross_iff_unnamed.__cross8.one_x_one [cross]: 1 cg_cross_iff_unnamed.cp_a.one: 2 cg_cross_iff_unnamed.cp_b.one: 2 cg_default_iff.cp.def [default]: 1 diff --git a/test_regress/t/t_debug_emitv.out b/test_regress/t/t_debug_emitv.out index a0d89a90b..3b07952ea 100644 --- a/test_regress/t/t_debug_emitv.out +++ b/test_regress/t/t_debug_emitv.out @@ -1228,64 +1228,9 @@ package Vt_debug_emitv___024unit; disable label3; end endfunction - string __Venumtab_enum_name34[1:0]; + string __Venumtab_enum_name36[1:0]; endpackage package Vt_debug_emitv_std; - class Vt_debug_emitv_semaphore; - int signed m_keyCount; - int signed m_nextKeyCount; - m_nextKeyCount = 32'hffffffff; - longint m_ticket; - m_ticket = 64'h0; - longint m_nextTicket; - m_nextTicket = 64'h0; - function new; - input int signed keyCount; - m_keyCount = keyCount; - endfunction - task put; - input int signed keyCount; - m_keyCount = (m_keyCount + keyCount); - endtask - task get; - longint __Vincrement1; - input int signed keyCount; - longint ticket; - begin : label4 - ticket = /*CRESET*/; - if (((m_keyCount >= keyCount) && (m_nextKeyCount - > - m_keyCount))) begin - begin - m_keyCount = (m_keyCount - - keyCount); - disable label4; - end - end - __Vincrement1 = m_nextTicket; - m_nextTicket = (m_nextTicket + 64'h1); - ticket = __Vincrement1; - wait((m_ticket == ticket)); - m_nextKeyCount = keyCount; - wait((m_keyCount >= keyCount)); - m_keyCount = (m_keyCount - keyCount); - m_ticket = (m_ticket + 64'h1); - end - endtask - function try_get; - input int signed keyCount; - begin : label5 - try_get = /*CRESET*/; - if ((m_keyCount < keyCount)) begin - try_get = 'sh0; - disable label5; - end - m_keyCount = (m_keyCount - keyCount); - try_get = 'sh1; - disable label5; - end - endfunction - endclass class Vt_debug_emitv_process; typedef enum int signed{ FINISHED = 32'h0, @@ -1297,12 +1242,12 @@ package Vt_debug_emitv_std; VlProcessRef m_process; function self; Vt_debug_emitv_process pVt_debug_emitv_process; - begin : label6 + begin : label4 self = /*CRESET*/; p = new(); $c(p.m_process = vlProcess;); self = p; - disable label6; + disable label4; end endfunction task set_status; @@ -1310,10 +1255,10 @@ package Vt_debug_emitv_std; $c(m_process->state(s);); endtask function status; - begin : label7 + begin : label5 status = /*CRESET*/; status = ($c(m_process->state())); - disable label7; + disable label5; end endfunction task kill; @@ -1385,12 +1330,12 @@ package Vt_debug_emitv_std; ???? // SYSTEMCSECTION function get_randstate; string s; - begin : label8 + begin : label6 get_randstate = /*CRESET*/; s = string'($c(0)); $c(s = m_process->randstate();); get_randstate = s; - disable label8; + disable label6; end endfunction task set_randstate; @@ -1400,6 +1345,85 @@ package Vt_debug_emitv_std; function new; endfunction process::FINISHEDprocess::KILLEDprocess::RUNNINGprocess::SUSPENDEDprocess::WAITINGendclass + class Vt_debug_emitv_semaphore; + typedef struct { + Vt_debug_emitv_process proc; + int signed reqKeys; + } procKeys; + struct { + Vt_debug_emitv_process proc; + int signed reqKeys; + } m_queue[$]; + int signed m_keyCount; + task dropKilled; + while (((m_queue.size() > 'sh0) && (status() + == + process:: + KILLED))) begin + m_queue.pop_front(); + end + endtask + function new; + input int signed keyCount; + m_keyCount = keyCount; + endfunction + task put; + input int signed keyCount; + m_keyCount = (m_keyCount + keyCount); + endtask + task get; + input int signed keyCount; + begin : label7 + dropKilled(); + if (((m_keyCount >= keyCount) && (( + m_queue.size() + == + 'sh0) + || (m_queue.at( + 'sh0).reqKeys + > + keyCount)))) begin + begin + m_keyCount = (m_keyCount - + keyCount); + disable label7; + end + end + m_queue.push_back( + ???? // CONSPACKUORSTRUCT + + ???? // CONSPACKMEMBER + self() + ???? // CONSPACKMEMBER + keyCount); + while ((m_queue.at('sh0).proc != self())) begin + begin + wait(((status() == process:: + KILLED) || (m_queue.at( + 'sh0).proc + == self()))); + dropKilled(); + end + end + wait((m_keyCount >= keyCount)); + m_keyCount = (m_keyCount - keyCount); + m_queue.pop_front(); + end + endtask + function try_get; + input int signed keyCount; + begin : label8 + try_get = /*CRESET*/; + if ((m_keyCount < keyCount)) begin + try_get = 'sh0; + disable label8; + end + m_keyCount = (m_keyCount - keyCount); + try_get = 'sh1; + disable label8; + end + endfunction + endclass function randomize; randomize = 'sh0; endfunction diff --git a/test_regress/t/t_semaphore_killed_proc.py b/test_regress/t/t_semaphore_killed_proc.py new file mode 100755 index 000000000..6fe7d000c --- /dev/null +++ b/test_regress/t/t_semaphore_killed_proc.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of either the GNU Lesser General Public License Version 3 +# or the Perl Artistic License Version 2.0. +# SPDX-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=["--binary"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_semaphore_killed_proc.v b/test_regress/t/t_semaphore_killed_proc.v new file mode 100644 index 000000000..af6dfdb78 --- /dev/null +++ b/test_regress/t/t_semaphore_killed_proc.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + +module t; + semaphore sem = new(0); + process first_waiter; + process second_waiter; + bit acquired; + + initial begin + fork + begin + first_waiter = process::self(); + sem.get(1); + $stop; + end + begin + second_waiter = process::self(); + sem.get(1); + acquired = 1; + end + join_none + + wait (first_waiter != null && second_waiter != null); + #1; + first_waiter.kill(); + sem.put(1); + + #1; + if (!acquired) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_vlcov_covergroup.annotate.out b/test_regress/t/t_vlcov_covergroup.annotate.out index b49b34d0f..28b8f84c7 100644 --- a/test_regress/t/t_vlcov_covergroup.annotate.out +++ b/test_regress/t/t_vlcov_covergroup.annotate.out @@ -444,13 +444,13 @@ -000001 point: type=covergroup comment= hier=cg_unnamed_cross.cp_c.read -000001 point: type=covergroup comment= hier=cg_unnamed_cross.cp_c.write %000001 cross cp_a, cp_c; // no label: reported under the default cross name --000001 point: type=covergroup comment= hier=cg_unnamed_cross.__cross8.a0_x_read +-000001 point: type=covergroup comment= hier=cg_unnamed_cross.__cross9.a0_x_read // cross: [a0, read] --000000 point: type=covergroup comment= hier=cg_unnamed_cross.__cross8.a0_x_write +-000000 point: type=covergroup comment= hier=cg_unnamed_cross.__cross9.a0_x_write // cross: [a0, write] --000000 point: type=covergroup comment= hier=cg_unnamed_cross.__cross8.a1_x_read +-000000 point: type=covergroup comment= hier=cg_unnamed_cross.__cross9.a1_x_read // cross: [a1, read] --000001 point: type=covergroup comment= hier=cg_unnamed_cross.__cross8.a1_x_write +-000001 point: type=covergroup comment= hier=cg_unnamed_cross.__cross9.a1_x_write // cross: [a1, write] endgroup