Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Array indexed by enumerated type results in '-' or 'u' signal #1143

Open
McSherry opened this issue Jan 22, 2025 · 0 comments
Open

Array indexed by enumerated type results in '-' or 'u' signal #1143

McSherry opened this issue Jan 22, 2025 · 0 comments

Comments

@McSherry
Copy link

I'm using nvc 1.14.2.

I have a signal that is an array of arrays, where the first level is indexed by an enumerated type:

type reg_e is (
    I2CCFG,
    I2CCON,
    I2CDR,
    -- ...and so on
);
    
type   read_port_t is array(reg_e range reg_e'high downto reg_e'low) of std_ulogic_vector(apb_prdata_o'range);
signal read_port     : read_port_t;

This signal is connected to the output of the block (which is an APB completer) through a pipelined mux tree block:

prdata_mux: entity work.mux
generic map(
    Ports          => reg_e'pos(reg_e'right) + 1,
    Width          => apb_prdata_o'length,
    InputRegister  => false,
    SelectRegister => false,
    OutputRegister => true,
    Stages         => 2
)
port map(
    clk_i => clk_i,
    sel_i => address_as_select,
    in_i  => read_port_to_slm2(read_port),
    out_o => apb_prdata_o
);

Here, address_as_select is a function that boils down to a case statement that translates the APB PADDR signal into a reg_e value, and the function read_port_to_slm2 is a trivial copy to a similarly-shaped type we use common across our IP cores:

type std_ulogic_matrix2 is array(natural range <>) of std_ulogic_vector;

impure function read_port_to_slm2(rp : read_port_t) return std_ulogic_matrix2 is
    variable rv : std_ulogic_matrix2(reg_e'pos(reg_e'right) downto 0)(apb_prdata_o'range);
begin
    for reg in reg_e'left to reg_e'right loop
        rv(reg_e'pos(reg)) := rp(reg);
    end loop;

    return rv;
end function read_port_to_slm2;

Arranged like this, in simulation with nvc, the output on apb_prdata_o is constant at a partially don't-care, partially undefined value. The way the block is defined, whether or not an APB read is ongoing, the apb_prdata_o signal has the value of the currently-addressed register on it, so it should not remain constant. Here is a waveform showing this behaviour (five APB writes followed by an APB read):

I initially thought this might be an issue with the pipelined mux tree. The first two APB writes set up a strobe generator, and the two strobes_g rows near the bottom of the image come from that strobe generator through another instantiation of the same mux tree component. As these work fine, it suggests that the mux tree is not the issue.

I thought from there it might be an issue with using an enumerated type as an index, so I changed the definition of read_port so that it used a to range instead of a downto to see if it made a difference:

type read_port_t is array(reg_e range reg_e'left to reg_e'right) of std_ulogic_vector(apb_prdata_o'range);

(I also changed read_port_to_slm2 to use to ordering as well)

While this didn't solve the issue, it did change the observed behaviour—the constant-but-wrong output on apb_prdata_o is now different:

To me, this suggests it's something with how nvc is handling the read_port_t type.

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

No branches or pull requests

1 participant