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.
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:
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.
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.
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:
phase_word[i] <= phase_word[0] + i*PHASE_WORD;
couldn´t do the job?
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:
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.
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].
If PHASE_WORD is a constant, then this will be close to optimal:
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:
// 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.
Yes, and temp <= phase_word[0] + 8*PHASE_WORD also worked but still phase_word[0] = temp needs to be blocking.
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":
(...)
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.
Yes, and temp <= phase_word[0] + 8*PHASE_WORD also worked but still phase_word[0] = temp needs to be blocking.
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":
(...)
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