Parameter sets to zero during compilation

Hi,

I have a struct:


typedef struct packed {
        logic [2:0] irq1;
        logic [2:0] irq2;
        logic [2:0] irq3;
        logic irq4;
        logic irq5;
        logic irq6;
} interrupts_struct;    

Then I define this set of parameters:


parameter int IRQ_SERIALIZED_DATA_WIDTH   = 8;
parameter int IRQ_BUS_WIDTH               = $bits(interrupts_struct);
parameter int IRQ_BUS_TRANSMIT_RESIDUE    = IRQ_BUS_WIDTH % IRQ_SERIALIZED_DATA_WIDTH;

The parameter IRQ_BUS_TRANSMIT_RESIDUE can get in some cases zero value.

When this happen, I get compilation error on this code:


if ((IRQ_BUS_TRANSMIT_RESIDUE != 0) & (duration_counter == SERIALIZATION_DURATION-1))
    data[IRQ_BUS_TRANSMIT_RESIDUE-1:0] <= irq_struct_sampled[duration_counter*IRQ_SERIALIZED_DATA_WIDTH +: IRQ_BUS_TRANSMIT_RESIDUE];
else
    data <= irq_struct_sampled[duration_counter*IRQ_SERIALIZED_DATA_WIDTH +:IRQ_SERIALIZED_DATA_WIDTH];

because then the part select don’t make sense. it gets data[-1:0].

Any way I can get it to work?
I mean, without giving up on the $bits that gets the size of struct during compilation.

In reply to yakir_mishli:

If you can separate this code into a generate-if construct, you could write

if (IRQ_BUS_TRANSMIT_RESIDUE != 0)
  always @(posedge clk) if (duration_counter == SERIALIZATION_DURATION-1)
      data[IRQ_BUS_TRANSMIT_RESIDUE-1:0] <= irq_struct_sampled[duration_counter*IRQ_SERIALIZED_DATA_WIDTH +: IRQ_BUS_TRANSMIT_RESIDUE];
    else
      data <= irq_struct_sampled[duration_counter*IRQ_SERIALIZED_DATA_WIDTH +:IRQ_SERIALIZED_DATA_WIDTH];
else 
    always @(posedge clk)
      data <= irq_struct_sampled[duration_counter*IRQ_SERIALIZED_DATA_WIDTH +:IRQ_SERIALIZED_DATA_WIDTH];

Otherwise you could write

parameter int IRQ_SERIALIZED_DATA_WIDTH   = 8;
parameter int IRQ_BUS_WIDTH               = $bits(interrupts_struct);
parameter int IRQ_BUS_TRANSMIT_RESIDUE    = IRQ_BUS_WIDTH % IRQ_SERIALIZED_DATA_WIDTH;
parameter int ADJUSTED_RESIDUE            = IRQ_BUS_TRANSMIT_RESIDUE ? IRQ_BUS_TRANSMIT_RESIDUE : 1;
if ((IRQ_BUS_TRANSMIT_RESIDUE != 0) & (duration_counter == SERIALIZATION_DURATION-1))
    data[ADJUSTED_RESIDUE-1:0] <= irq_struct_sampled[duration_counter*IRQ_SERIALIZED_DATA_WIDTH +: ADJUSTED_RESIDUE];
else
    data <= irq_struct_sampled[duration_counter*IRQ_SERIALIZED_DATA_WIDTH +:IRQ_SERIALIZED_DATA_WIDTH];

In reply to dave_59:

Thanks Dave!

Both options solved the problem.

I took the 2nd because it’s less code lines.

In reply to yakir_mishli:

Can you plz help me to understand why “The parameter IRQ_BUS_TRANSMIT_RESIDUE can get in some cases zero value”?

In reply to Desam:

Sure.

This struct is often changed during development. We add/remove signal and so his size is changing.


typedef struct packed {
        logic [2:0] irq1;
        logic [2:0] irq2;
        logic [2:0] irq3;
        logic irq4;
        logic irq5;
        logic irq6;
} interrupts_struct;   

if, for example, $bits(interrupts_struct) will evaluate to 16,
then IRQ_BUS_TRANSMIT_RESIDUE = 16 % 8 = 0.


parameter int IRQ_SERIALIZED_DATA_WIDTH   = 8;
parameter int IRQ_BUS_WIDTH               = $bits(interrupts_struct);
parameter int IRQ_BUS_TRANSMIT_RESIDUE    = IRQ_BUS_WIDTH % IRQ_SERIALIZED_DATA_WIDTH;

I tried to write my code in a way that changing the struct won’t affect the logic that handle it. For easy scaling. so this is the most elegant way I managed to do it.
The drawback was a specific case that the residue gets zero.
But dave solved this.