Verilog blocking statements in always block (SOLVED) - Page 1
Forum section: electronics / general

author: knight
author_rank: Regular Contributor
timestamp: September 29, 2022, 02:37:37 pm
content: 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:always @(posedge clk or negedge rst)beginif (~rst)// initialize all to 0elsefor (i=1;i<8;i++)begina = a[i-1] + constant; // want non-blocking hereendtemp = a + constant; // want non-blocking hereendBut 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:integer i;always @(posedge clk or negedge rst)beginif (~rst | (sample_count == SAMPLE_COUNT))begintemp <= PHASE_WORD;for (i = 0; i < 8; i = i + 1)beginphase_word <= 0;endendelse if (adc_data_in_vld_dly0)beginphase_word = temp;for (i = 1; i < 8; i = i + 1)beginphase_word = phase_word[i-1] + PHASE_WORD;endtemp = phase_word + PHASE_WORD;endendSo 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.

author: BrianHG
author_rank: Super Contributor
timestamp: September 30, 2022, 03:39:35 am
content: 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-L126But 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.

author: KrudyZ
author_rank: Frequent Contributor
timestamp: September 30, 2022, 03:58:12 am
content: 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.

author: pbernardi
author_rank: Contributor
timestamp: September 30, 2022, 04:02:56 pm
content: 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:phase_word <= phase_word + i*PHASE_WORD;couldn´t do the job?

author: knight
author_rank: Regular Contributor
timestamp: October 01, 2022, 04:26:49 am
content: Quote from: pbernardi on September 30, 2022, 04:02:56 pmYes, and temp <= phase_word + 8*PHASE_WORD also worked but still phase_word = 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.

author: hamster_nz
author_rank: Super Contributor
timestamp: October 01, 2022, 08:10:49 am
content: If PHASE_WORD is a constant, then this will be close to optimal:Code:for (i = 0; i < 8; i = i + 1)phase_word = 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:// Update the phase_word[] valuesfor (i = 0; i < 8; i = i + 1)phase_word = temp + offset;temp = temp + offset;// Calculate the values for the next update cycle - Note there are 9 values calculated!for (i = 0; i < 9; i = i + 1)offset = 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.

author: pbernardi
author_rank: Contributor
timestamp: October 02, 2022, 01:02:31 am
content: Quote from: knight on October 01, 2022, 04:26:49 amOk, so instead index 0, use index 7 as referenceYou don´t need temp anymore, just start your for loop with "0" instead "1":Code:(...)else if (adc_data_in_vld_dly0)beginfor (i = 0; i < 8; i = i + 1)beginphase_word <= phase_word + (i+1)*PHASE_WORD;endendNote: not tested.

author: knight
author_rank: Regular Contributor
timestamp: October 02, 2022, 10:36:42 am
content: Quote from: pbernardi on October 02, 2022, 01:02:31 amOh this works good. I tried a similar approach but didn't use last phase_word as a reference and got repeated values. Thanks