parent
176e333774
commit
cdfff86c2d
|
|
@ -422,9 +422,11 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
struct RefStrength final {
|
||||
AstNodeVarRef* m_varrefp;
|
||||
VStrength m_strength;
|
||||
RefStrength(AstNodeVarRef* varrefp, VStrength strength)
|
||||
AstDelay* m_delayp; // Explicit delay on the continuous assignment
|
||||
RefStrength(AstNodeVarRef* varrefp, VStrength strength, AstDelay* delayp)
|
||||
: m_varrefp{varrefp}
|
||||
, m_strength{strength} {}
|
||||
, m_strength{strength}
|
||||
, m_delayp{delayp} {}
|
||||
};
|
||||
using RefStrengthVec = std::vector<RefStrength>;
|
||||
using VarMap = std::map<AstVar*, RefStrengthVec*>;
|
||||
|
|
@ -449,6 +451,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
bool m_processedIfaces = false; // Interface modules already processed (interfaces-first pass)
|
||||
VStrength m_currentStrength = VStrength::STRONG; // Current strength of assignment,
|
||||
// Used only on LHS of assignment
|
||||
AstDelay* m_currentDelayp = nullptr; // Delay of assignment currently collecting LHS drivers
|
||||
const AstNode* m_logicp = nullptr; // Current logic being built
|
||||
TristateGraph m_tgraph; // Logic graph
|
||||
// Map: interface AstVar* -> list of per-module (enVarp, outVarp) contribution pairs
|
||||
|
|
@ -635,7 +638,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
AstVar* const key = nodep->varp();
|
||||
const auto pair = m_lhsmap.emplace(key, nullptr);
|
||||
if (pair.second) pair.first->second = new RefStrengthVec;
|
||||
pair.first->second->push_back(RefStrength{nodep, m_currentStrength});
|
||||
pair.first->second->push_back(RefStrength{nodep, m_currentStrength, m_currentDelayp});
|
||||
}
|
||||
|
||||
AstNodeExpr* newEnableDeposit(AstSel* selp, AstNodeExpr* enp) {
|
||||
|
|
@ -854,6 +857,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
AstAssignW* const enLhspAssignp = new AstAssignW{
|
||||
refp->fileline(), new AstVarRef{refp->fileline(), newEnLhsp, VAccess::WRITE},
|
||||
getEnp(refp)};
|
||||
if (it->m_delayp) { enLhspAssignp->timingControlp(it->m_delayp->cloneTree(false)); }
|
||||
UINFO(9, " newenlhspAssignp " << enLhspAssignp);
|
||||
nodep->addStmtsp(new AstAlways{enLhspAssignp});
|
||||
|
||||
|
|
@ -1567,11 +1571,18 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
void visitAssign(AstNodeAssign* nodep) {
|
||||
VL_RESTORER(m_alhs);
|
||||
VL_RESTORER(m_currentStrength);
|
||||
VL_RESTORER(m_currentDelayp);
|
||||
if (VN_IS(nodep->rhsp(), CReset)) return;
|
||||
if (AstAssignW* const assignWp = VN_CAST(nodep, AssignW)) {
|
||||
m_currentDelayp = VN_CAST(assignWp->timingControlp(), Delay);
|
||||
}
|
||||
if (m_graphing) {
|
||||
if (AstAssignW* assignWp = VN_CAST(nodep, AssignW)) {
|
||||
if (assignWp->timingControlp() || assignWp->getLhsNetDelay()) return;
|
||||
addToAssignmentList(assignWp);
|
||||
if (assignWp->getLhsNetDelay()) return;
|
||||
if (assignWp->timingControlp() && !m_currentDelayp) return;
|
||||
// Separate data and enable assignments cannot preserve distinct rise/fall delays.
|
||||
if (m_currentDelayp && m_currentDelayp->fallDelay()) return;
|
||||
if (!assignWp->timingControlp()) addToAssignmentList(assignWp);
|
||||
}
|
||||
|
||||
if (nodep->user2() & U2_GRAPHING) return;
|
||||
|
|
|
|||
|
|
@ -4,26 +4,73 @@
|
|||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__, `__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0)
|
||||
`define check_scalar(exp) do begin `checkh(out_assign, exp); `checkh(out_buf, exp); `checkh(out_net, exp); end while(0)
|
||||
// verilog_format: on
|
||||
|
||||
module t;
|
||||
parameter delay = 0;
|
||||
localparam int TRI_DELAY = 3;
|
||||
|
||||
logic in = 0;
|
||||
logic [3:0] in_vec = 4'h0;
|
||||
logic tri_data = 0;
|
||||
logic tri_enable = 0;
|
||||
wire out_assign;
|
||||
wire out_buf;
|
||||
wire #(5,3.3) out_net;
|
||||
wire out_bufif0;
|
||||
wire out_bufif1;
|
||||
wire out_issue;
|
||||
wire out_nmos;
|
||||
wire out_notif0;
|
||||
wire out_notif1;
|
||||
wire out_pmos;
|
||||
wire #(5, 3.3) out_net;
|
||||
wire [3:0] out_vec_assign;
|
||||
|
||||
assign #(5,3) out_assign = in;
|
||||
buf #(5,3) u_buf (out_buf, in);
|
||||
assign #(5, 3) out_assign = in;
|
||||
buf #(5, 3) u_buf (out_buf, in);
|
||||
bufif0 #(delay) u_bufif0 (out_bufif0, in, 1'b0);
|
||||
bufif1 #(TRI_DELAY) u_bufif1 (out_bufif1, tri_data, tri_enable);
|
||||
bufif1 #(delay) u_issue (out_issue, in, 1'b0);
|
||||
nmos #(delay) u_nmos (out_nmos, in, 1'b1);
|
||||
notif0 #(delay) u_notif0 (out_notif0, in, 1'b0);
|
||||
notif1 #(delay) u_notif1 (out_notif1, in, 1'b1);
|
||||
pmos #(delay) u_pmos (out_pmos, in, 1'b0);
|
||||
assign out_net = in;
|
||||
assign #(5,3) out_vec_assign = in_vec;
|
||||
assign #(5, 3) out_vec_assign = in_vec;
|
||||
|
||||
initial begin
|
||||
#4;
|
||||
`checkh(out_bufif1, 1'bz);
|
||||
tri_enable = 1'b1;
|
||||
#2;
|
||||
`checkh(out_bufif1, 1'bz);
|
||||
#1;
|
||||
`checkh(out_bufif1, 1'b0);
|
||||
tri_data = 1'b1;
|
||||
#2;
|
||||
`checkh(out_bufif1, 1'b0);
|
||||
#1;
|
||||
`checkh(out_bufif1, 1'b1);
|
||||
tri_enable = 1'b0;
|
||||
#2;
|
||||
`checkh(out_bufif1, 1'b1);
|
||||
#1;
|
||||
`checkh(out_bufif1, 1'bz);
|
||||
end
|
||||
|
||||
initial begin
|
||||
#4;
|
||||
`check_scalar(1'b0);
|
||||
`checkh(out_bufif0, 1'b0);
|
||||
`checkh(out_issue, 1'bz);
|
||||
`checkh(out_nmos, 1'b0);
|
||||
`checkh(out_notif0, 1'b1);
|
||||
`checkh(out_notif1, 1'b1);
|
||||
`checkh(out_pmos, 1'b0);
|
||||
`checkh(out_vec_assign, 4'h0);
|
||||
|
||||
// Rise canceled by a fall before the rise delay expires.
|
||||
|
|
|
|||
Loading…
Reference in New Issue