Author Topic: Verilog blocking statements in always block (SOLVED)  (Read 1228 times)

0 Members and 1 Guest are viewing this topic.

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Verilog blocking statements in always block (SOLVED)
« on: September 29, 2022, 02:37:37 pm »
I need to perform an addition inside an always block (with clock) but one of the operands depends on the previous value, hence I cannot use non-blocking statements as all variables/registers/wires will have same values.

The expression is basically of the form: a = a[i-1] + constant;

So, I code it like this and it works fine.
Code: [Select]
always @(posedge clk or negedge rst)
begin
    if (~rst)
        // initialize all to 0
    else
        for (i=1;i<8;i++)
            begin
                a[i] = a[i-1] + constant;  // want non-blocking here
            end
        temp = a[7] + constant;            // want non-blocking here
end
But it creates a lot of combinational logic as there is one more always block which is performing the similar operation and thus limiting the maximum frequency of operation. Is there any way I can use non-blocking statements.

Actual code:
Code: [Select]
integer i;
    always @(posedge clk or negedge rst)
        begin
            if (~rst | (sample_count == SAMPLE_COUNT))
                begin
                    temp <= PHASE_WORD;
                    for (i = 0; i < 8; i = i + 1)
                        begin
                            phase_word[i] <= 0;
                        end   
                end
            else if (adc_data_in_vld_dly0)
                begin
                    phase_word[0] = temp;
                    for (i = 1; i < 8; i = i + 1)
                        begin
                            phase_word[i] = phase_word[i-1] + PHASE_WORD;
                        end
                    temp = phase_word[7] + PHASE_WORD; 
                end       
        end
So basically adding phase word and storing the last value in temp register. For example, if PHASE_WORD is 3 then, in the same clock cycle, phase_word should be [3,6,9,12,15,18,21,24] and next clock cycle it begins with 24+3=27, so 27,30,33......

Now all this works fine using "=" blocking statement at the expense of huge combinational blocks.

I was wondering if this can be done using non-blocking statements as it would greatly enhance frequency of operation. Thanks.
« Last Edit: October 06, 2022, 03:27:05 am by knight »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7660
  • Country: ca
Re: Verilog blocking statements in always block
« Reply #1 on: September 30, 2022, 03:39:35 am »
Here is a hint to 1 possible method.
I cannot offer you any other help.
https://github.com/BrianHGinc/YM2149_PSG_system/blob/9cce2dba1c873c40461d01b75e1cb5be9262e5ed/BHG_audio_filter_mixer.sv#L73-L126
But this method takes multiple clock cycles to give a final result.
During these clock cycles, the inputs must be held until the final result is reached.
« Last Edit: September 30, 2022, 03:43:36 am by BrianHG »
 
The following users thanked this post: knight

Offline KrudyZ

  • Frequent Contributor
  • **
  • Posts: 274
  • Country: us
Re: Verilog blocking statements in always block
« Reply #2 on: September 30, 2022, 03:58:12 am »
It seems like you could easily unroll the loop.
The output vector is simply the last word of the previous clock cycle plus 1, 2, 3, 4, etc. times your constant.
If it is truly a constant then the numbers get computed at synthesis time, else you will get a set of multipliers which depending on your FPGA architecture could get expensive.
 
The following users thanked this post: knight

Offline pbernardi

  • Contributor
  • Posts: 15
  • Country: br
Re: Verilog blocking statements in always block
« Reply #3 on: September 30, 2022, 04:02:56 pm »
So basically adding phase word and storing the last value in temp register. For example, if PHASE_WORD is 3 then, in the same clock cycle, phase_word should be [3,6,9,12,15,18,21,24] and next clock cycle it begins with 24+3=27, so 27,30,33......

something like:

Code: [Select]
phase_word[i] <= phase_word[0] + i*PHASE_WORD;
couldn´t do the job?
 
The following users thanked this post: knight

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: Verilog blocking statements in always block
« Reply #4 on: October 01, 2022, 04:26:49 am »
So basically adding phase word and storing the last value in temp register. For example, if PHASE_WORD is 3 then, in the same clock cycle, phase_word should be [3,6,9,12,15,18,21,24] and next clock cycle it begins with 24+3=27, so 27,30,33......

something like:

Code: [Select]
phase_word[i] <= phase_word[0] + i*PHASE_WORD;
couldn´t do the job?
Yes, and temp <= phase_word[0] + 8*PHASE_WORD also worked but still phase_word[0] = temp needs to be blocking. |O

According to Verilog coding guideline, we should not mix blocking and non-blocking in same always block so I just kept it blocking for now until I find a way to assign phase_word[0].
« Last Edit: October 01, 2022, 04:29:15 am by knight »
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: Verilog blocking statements in always block
« Reply #5 on: October 01, 2022, 08:10:49 am »
If PHASE_WORD is a constant, then this will be close to optimal:

Code: [Select]
                    for (i = 0; i < 8; i = i + 1)
                phase_word[i] = temp + i*PHASE_WORD;

Any decent synthesizer will unroll the loop and propagate the constants, leaving just an addition.

If PHASE_WORD isn't a constant, performance will still be pretty good. The multiplication by a small constant number will get implemented with bitshifts and addition, and the bitshifts are essentially free in an FPGA.

If speed is a problem then you are at the edge of what your FPGA can do at that clock rate. Then you want to precompute the phase offsets the cycle before they are used to minimize how much work you do each cycle:

Code: [Select]
                    // Update the phase_word[] values
                    for (i = 0; i < 8; i = i + 1)
                phase_word[i] = temp + offset[i];
                    temp               = temp + offset[8];

                    // Calculate the values for the next update cycle - Note there are 9 values calculated!
                    for (i = 0; i < 9; i = i + 1)
                        offset[i] = i*PHASE_WORD;

Once that goes through the logic optimizer, a lot of the perceived overhead will be stripped out - most of the registers in 'offset' can be merged or removed.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 
The following users thanked this post: knight

Offline pbernardi

  • Contributor
  • Posts: 15
  • Country: br
Re: Verilog blocking statements in always block
« Reply #6 on: October 02, 2022, 01:02:31 am »
Yes, and temp <= phase_word[0] + 8*PHASE_WORD also worked but still phase_word[0] = temp needs to be blocking. |O

According to Verilog coding guideline, we should not mix blocking and non-blocking in same always block so I just kept it blocking for now until I find a way to assign phase_word[0].

Ok, so instead index 0, use index 7 as reference

You don´t need temp anymore, just start your for loop with "0" instead "1":

Code: [Select]
(...)
            else if (adc_data_in_vld_dly0)
                begin
                    for (i = 0; i < 8; i = i + 1)
                        begin
                            phase_word[i] <= phase_word[7] + (i+1)*PHASE_WORD;
                        end
                end

Note: not tested.
 
The following users thanked this post: knight

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: Verilog blocking statements in always block
« Reply #7 on: October 02, 2022, 10:36:42 am »
Yes, and temp <= phase_word[0] + 8*PHASE_WORD also worked but still phase_word[0] = temp needs to be blocking. |O

According to Verilog coding guideline, we should not mix blocking and non-blocking in same always block so I just kept it blocking for now until I find a way to assign phase_word[0].

Ok, so instead index 0, use index 7 as reference

You don´t need temp anymore, just start your for loop with "0" instead "1":

Code: [Select]
(...)
            else if (adc_data_in_vld_dly0)
                begin
                    for (i = 0; i < 8; i = i + 1)
                        begin
                            phase_word[i] <= phase_word[7] + (i+1)*PHASE_WORD;
                        end
                end

Note: not tested.
Oh this works good. I tried a similar approach but didn't use last phase_word[7] as a reference and got repeated values. Thanks :-+
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf