Skip to content

[BUG] Verilator Error-BLKLOOPINIT #193

@mgjaggers

Description

@mgjaggers

Hello!

I'm creating a regblock that we'll be using for both VCS and Verilator. With the axi4-lite cpuif, there is an issue on the Verilator side of things. I get this error output when trying to compile it with Verilator v5.044:

%Error-BLKLOOPINIT: regs.sv:175:65: Unsupported: Non-blocking assignment to array with compound element type inside loop
  175 |                     axil_resp_buffer[axil_resp_wptr[0:0]].is_wr <= '0;
      |                                                                 ^~
                    ... For error description see https://verilator.org/warn/BLKLOOPINIT?v=5.044
%Error-BLKLOOPINIT: regs.sv:176:63: Unsupported: Non-blocking assignment to array with compound element type inside loop
  176 |                     axil_resp_buffer[axil_resp_wptr[0:0]].err <= cpuif_rd_err;
      |                                                               ^~
%Error-BLKLOOPINIT: regs.sv:177:65: Unsupported: Non-blocking assignment to array with compound element type inside loop
  177 |                     axil_resp_buffer[axil_resp_wptr[0:0]].rdata <= cpuif_rd_data;
      |                                                                 ^~
%Error-BLKLOOPINIT: regs.sv:180:65: Unsupported: Non-blocking assignment to array with compound element type inside loop
  180 |                     axil_resp_buffer[axil_resp_wptr[0:0]].is_wr <= '1;
      |                                                                 ^~
%Error-BLKLOOPINIT: regs.sv:181:63: Unsupported: Non-blocking assignment to array with compound element type inside loop
  181 |                     axil_resp_buffer[axil_resp_wptr[0:0]].err <= cpuif_wr_err;
      |                                                               ^~
%Error-BLKLOOPINIT: regs.sv:165:43: Unsupported: Non-blocking assignment to array with compound element type inside loop
  165 |                 axil_resp_buffer[i].is_wr <= '0;
      |                                           ^~
%Error-BLKLOOPINIT: regs.sv:166:41: Unsupported: Non-blocking assignment to array with compound element type inside loop
  166 |                 axil_resp_buffer[i].err <= '0;
      |                                         ^~
%Error-BLKLOOPINIT: regs.sv:167:43: Unsupported: Non-blocking assignment to array with compound element type inside loop
  167 |                 axil_resp_buffer[i].rdata <= '0;
      |                                           ^~

The command I used to produce the verilog file is:
peakrdl regblock test_registers.rdl top.rdl -o verilog --cpuif axi4-lite-flat --peakrdl-cfg peakrdl.toml

I'm running a virtual environment with the following requirements.txt:

antlr4-python3-runtime==4.13.2
colorama==0.4.6
git-me-the-url==2.2.0
gitdb==4.0.12
GitPython==3.1.46
Jinja2==3.1.6
Markdown==3.10.2
MarkupSafe==3.0.3
peakrdl==1.5.0
peakrdl-cheader==1.0.0
peakrdl-html==2.12.1
peakrdl-ipxact==3.5.0
peakrdl-python==2.3.0
peakrdl-regblock==1.2.0
peakrdl-systemrdl==1.0.1
peakrdl-uvm==2.4.0
peakrdl_markdown==1.0.3
py-markdown-table==1.3.0
Pygments==2.19.2
python-markdown-math==0.9
smmap==5.0.2
systemrdl-compiler==1.32.1

The culprit is this section of code in cpuif/axi4lite/axi4lite_tmpl.sv:

struct {
    logic is_wr;
    logic err;
    logic [{{cpuif.data_width-1}}:0] rdata;
} axil_resp_buffer[{{roundup_pow2(cpuif.resp_buffer_size)}}];
{%- if not is_pow2(cpuif.resp_buffer_size) %}
// axil_resp_buffer is intentionally padded to the next power of two despite
// only requiring {{cpuif.resp_buffer_size}} entries.
// This is to avoid quirks in some tools that cannot handle indexing into a non-power-of-2 array.
// Unused entries are expected to be optimized away
{% endif %}

logic [{{clog2(cpuif.resp_buffer_size)}}:0] axil_resp_wptr;
logic [{{clog2(cpuif.resp_buffer_size)}}:0] axil_resp_rptr;

always_ff {{get_always_ff_event(cpuif.reset)}} begin
    if({{get_resetsignal(cpuif.reset)}}) begin
        for(int i=0; i<{{cpuif.resp_buffer_size}}; i++) begin
            axil_resp_buffer[i].is_wr <= '0;
            axil_resp_buffer[i].err <= '0;
            axil_resp_buffer[i].rdata <= '0;
        end
        axil_resp_wptr <= '0;
        axil_resp_rptr <= '0;
    end else begin
        // Store responses in buffer until AXI response channel accepts them
        if(cpuif_rd_ack || cpuif_wr_ack) begin
            if(cpuif_rd_ack) begin
                axil_resp_buffer[axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0]].is_wr <= '0;
                axil_resp_buffer[axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0]].err <= cpuif_rd_err;
                axil_resp_buffer[axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0]].rdata <= cpuif_rd_data;

            end else if(cpuif_wr_ack) begin
                axil_resp_buffer[axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0]].is_wr <= '1;
                axil_resp_buffer[axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0]].err <= cpuif_wr_err;
            end
            {%- if is_pow2(cpuif.resp_buffer_size) %}
            axil_resp_wptr <= axil_resp_wptr + 1'b1;
            {%- else %}
            if(axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] == {{cpuif.resp_buffer_size-1}}) begin
                axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] <= '0;
                axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)}}] <= ~axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)}}];
            end else begin
                axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] <= axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] + 1'b1;
            end
            {%- endif %}
        end

        // Advance read pointer when acknowledged
        if(axil_resp_acked) begin
            {%- if is_pow2(cpuif.resp_buffer_size) %}
            axil_resp_rptr <= axil_resp_rptr + 1'b1;
            {%- else %}
            if(axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] == {{cpuif.resp_buffer_size-1}}) begin
                axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] <= '0;
                axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)}}] <= ~axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)}}];
            end else begin
                axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] <= axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] + 1'b1;
            end
            {%- endif %}
        end
    end
end

I did look at the cpuif.resp_buffer_size == 1 section of the jinja template, and it did manage to run without any issue using that. I also modified the output file to remove the struct and just make it plain registers, and that also seems to work. So, the main issue Verilator has with this code is that it's using a struct.

I'll see about creating a pull request with the struct fixed.

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions