Skip to content

Fix large array initialization for I/O ports (#6904)#6918

Draft
neeruuppalapati wants to merge 2 commits intoverilator:masterfrom
neeruuppalapati:fix-issue-6904
Draft

Fix large array initialization for I/O ports (#6904)#6918
neeruuppalapati wants to merge 2 commits intoverilator:masterfrom
neeruuppalapati:fix-issue-6904

Conversation

@neeruuppalapati
Copy link

When you have a large array (>256 elements) with wide elements (>64 bits) on an output port like this:

  output logic [64:0] my_array [257];
  assign my_array = '{default: '0};

Verilator generated broken C++ code that wouldn't compile. The generated code was missing the left-hand side of the assignment, producing something like {{0, 0, ...}}; instead of my_array = {{0, 0, ...}};. I believe this was introduced in commit e2f5854 as mentioned in the GH issue. The problem seems to be that output ports are declared as raw C arrays and the assignment is broken, whilst VLUnpacked does support this. I made the below changes, let me know if this is short sighted, there are bigger things to do, I also added some tests.

  1. V3Slice.cpp: Don't use this optimization for I/O ports - expand them element-by-element instead
  2. V3EmitCFunc.h: Make sure array initializers always emit the left-hand side of the assignment

Neeru Uppalapati added 2 commits January 12, 2026 16:14
When unpacked arrays with >256 elements and >64-bit packed width are
assigned using aggregate initialization, Verilator generated invalid
C++ code with malformed initializers.

Two issues were fixed:
- V3Slice: Don't skip slice expansion for I/O ports since they use raw
  C arrays that don't support aggregate initialization
- V3EmitCFunc: Exclude InitArray from wide assignment optimization to
  ensure proper LHS emission
When unpacked arrays with >256 elements and >64-bit packed width are
assigned using aggregate initialization, Verilator generated invalid
C++ code with malformed initializers.

Two issues were fixed:
- V3Slice: Don't skip slice expansion for I/O ports since they use raw
  C arrays that don't support aggregate initialization
- V3EmitCFunc: Exclude InitArray from wide assignment optimization to
  ensure proper LHS emission
Copy link
Member

@wsnyder wsnyder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appreciate your first pull! Some minor comments:

// Skip optimization if array is too large
// Check if LHS contains I/O ports - they use raw C arrays which can't be assigned with =
const bool hasIO
= nodep->lhsp()->exists([&](const AstVarRef* refp) -> bool { return refp->varp()->isIO(); });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
= nodep->lhsp()->exists([&](const AstVarRef* refp) -> bool { return refp->varp()->isIO(); });
= nodep->lhsp()->exists([&](const AstVarRef* refp) -> bool { return refp->varp()->isPrimaryIO(); });

@@ -0,0 +1,25 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file shouldn't be needed, the driver will make it.

clk
);

input clk;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use 2 spaces per indent level in new files to match edaplayground/verilog-format, thanks.

@wsnyder
Copy link
Member

wsnyder commented Jan 31, 2026

Marking draft for now; I'm hoping you can get back to this & address the comments, once you do & tests pass please mark non-draft and I'll review again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants