Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
16556 Discussions

Can you force synthesis of registers?

SparkyNZ
New Contributor II
2,218 Views
bit [ 11 : 0 ] colorRGB[ 7 : 0 ];
bit [ 11 : 0 ] tempRGB;
..
tempRGB = colorRGB[ dataH ];
..
dataR = tempRGB[ 11 : 8 ];

When the above  code is synthesized, tempRGB does not appear in the RTL Viewer. It has been optimized/removed from the synthesized design.

Is there a way to force Quartus into synthesizing registers? ie. Is there a keyword I can use so that tempRGB must appear in my design?

0 Kudos
1 Solution
KhaiChein_Y_Intel
2,029 Views

Hi,


You may change to below:

     if( ( hcount >= hdat_begin ) && ( hcount <= hdat_last ) )

     begin

       

      if( hcount[ 0 ] == 0 )

      begin

       tempRGB <= colorRGB[ dataH ];


      end

      else

      begin

       tempRGB <= colorRGB[ dataL ];

      end


      dataR <= tempRGB[ 11 : 8 ];

      dataG <= tempRGB[ 7 : 4 ];

      dataB <= tempRGB[ 3 : 0 ];

     end


Thanks

Best regards,

KhaiY


View solution in original post

21 Replies
sstrell
Honored Contributor III
1,998 Views

Use the "preserve" or "keep" synthesis attributes to prevent logic from being optimized away.  See the built-in help for the appropriate syntax.

SparkyNZ
New Contributor II
1,986 Views

Thanks for that.

wire keep_wire /* synthesis keep */;
reg reg1 /* synthesis preserve */;

Oh my goodness - what an awful language hack - a directive inside a comment.

Shame Verilog didn't support #pragma directives like C.

0 Kudos
ak6dn
Valued Contributor III
1,972 Views

The 'comment' form is only one way to do it. There are others. See:

https://www.intel.com/content/www/us/en/programmable/quartushelp/17.0/hdl/vlog/vlog_file_dir.htm

for what Quartus accepts.  The   (* directive *)   form to add attributes to a declaration won't be mistaken as a generic comment.

0 Kudos
SparkyNZ
New Contributor II
1,966 Views

I don't get it. I must be doing something wrong. I have tried all 3 forms below:

bit [ 11 : 0 ] tempRGB  /* synthesis keep */;
bit [ 11 : 0 ] tempRGB  /* synthesis preserve */;
(* preserve *) bit [ 11 : 0 ] tempRGB;

tempRGB still doesn't appear in the "Signal Tap: pre-sythesis" or RTL Viewer after I recompile. It compiles

I cannot find any references to tempRGB in the System/Processing compiler output tabs either.

I am using a SystemVerilog (.sv) file as opposed to a standard Verilog (.v) file.

I definitely reference tempRGB in the code as well:

            if( hcount[ 0 ] == 0 )
            begin
              tempRGB = colorRGB[ dataH ];

            end
            else
            begin
              tempRGB = colorRGB[ dataL ];
            end

            dataR = tempRGB[ 11 : 8 ];
            dataG = tempRGB[  7 : 4 ];
            dataB = tempRGB[  3 : 0 ];

What's going on here?

0 Kudos
SparkyNZ
New Contributor II
1,964 Views

I've attached my project if anyone is keen to help. I have looked through the various nodes of the Compilation Report and I cannot find tempRGB anywhere.

Can someone please help me - I may not be looking for the right error/warning messages but I thought I would have found a reference to tempRGB somewhere.

0 Kudos
ak6dn
Valued Contributor III
1,958 Views

Well, it is because tempRGB is never instantiated as a real register. You use it as a temp variable only.

So tempRGB is a memoryless construct that basically maps to a 2:1 mux because of the '=' (blocking assignment).

If you want to map to a physical register, add another definition as tempRGB1 and insert this in the block as I indicate.

(* preserve *) bit [11:0] tempRGB1;

always (posedge iClk)
    begin

    if( hcount[ 0 ] == 0 )
        begin
        tempRGB = colorRGB[ dataH ];
        end
    else
        begin
        tempRGB = colorRGB[ dataL ];
        end

    tempRGB1 <= tempRGB;       // <<<============= ADD THIS

    dataR = tempRGB[ 11 : 8 ];
    dataG = tempRGB[ 7 : 4 ];
    dataB = tempRGB[ 3 : 0 ];

    end

 

 

SparkyNZ
New Contributor II
1,953 Views

@ak6dnThanks for the quick response. It's still not working for me though. Are you sure there isn't something else required?

I did a full recompile and it isn't appearing in the Signal Tap Node Finder or RTL Viewer. I wonder if I should be declaring tempRGB1 as 'logic' or 'reg' instead?

bit [ 11 : 0 ] tempRGB;
(* preserve *) bit [ 11 : 0 ] tempRGB1;
...
            if( hcount[ 0 ] == 0 )
            begin
              tempRGB = colorRGB[ dataH ];

            end
            else
            begin
              tempRGB = colorRGB[ dataL ];
            end

            tempRGB1 <= tempRGB;    // Here it is
            
            dataR = tempRGB[ 11 : 8 ];
            dataG = tempRGB[  7 : 4 ];
            dataB = tempRGB[  3 : 0 ];

 

 

0 Kudos
SparkyNZ
New Contributor II
1,948 Views

I gave this a try as well:

bit [ 11 : 0 ] tempRGB;
(* preserve *) reg [ 11 : 0 ] tempRGB1;

assign tempRGB1 = tempRGB;

This time I got the warning 'object "tempRGB1" assigned a value but never read'. Unfortunately I didn't get the opportunity to read it either from Signal Tap since it still can't be found in the Node Finder.

0 Kudos
ak6dn
Valued Contributor III
1,935 Views

Well that won't work for sure, as you can only assign to a wire type, not a reg type.

I have used Verilog as the language with the (* preserve *) attribute on a reg type and it has worked.

reg vs bit in system verilog is just the difference between a 4state ZX01 vs 2state 01 data storage.

Since I have not used SystemVerilog in Quartus, it may be something to do with the language support.

IDK.

0 Kudos
SparkyNZ
New Contributor II
1,927 Views

I just converted my VGAController.sv module into Verilog -removed all the SystemVerlog bits, renamed to a .v file and it still won't work.

The Verilog module is still functioning the same as the SystemVerilog version - complete with it's bug.

Guess I'll have to find another way to debug this.

0 Kudos
ak6dn
Valued Contributor III
1,918 Views

Well, I did a simple test in one of my designs.

I changed a source file to this:

 (* preserve *) reg [7:0] spi_prescale;	// spi clock prescale counter
 (* preserve *) reg [7:0] spi_divisor;	// spi clock prescale divide value
 (* preserve *) reg 	  spi_enable;	// set to 1 to send a bit

And then the DESIGN.map.rpt file changed to this. Where some bits previously of the spi_prescale reg were removed and replaced by constants (and listed in the Registers Removed by Synthesis table), they now all exist and are 'protected' (I wish the code boxes had a horizontal scrolling option ... Intel are you listening?

+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
; Registers Protected by Synthesis                                                                                                                                                             ;
+------------------------------------------------------------------------------+------------------------------------------------------------------+--------------------------------------------+
; Register Name                                                                ; Protected by Synthesis Attribute or Preserve Register Assignment ; Not to be Touched by Netlist Optimizations ;
+------------------------------------------------------------------------------+------------------------------------------------------------------+--------------------------------------------+
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_enable      ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_prescale[0] ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_prescale[1] ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_prescale[2] ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_prescale[3] ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_prescale[4] ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_prescale[5] ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_prescale[6] ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_prescale[7] ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[0]  ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[1]  ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[2]  ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[3]  ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[4]  ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[5]  ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[6]  ; yes                                                              ; yes                                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[7]  ; yes                                                              ; yes                                        ;
+------------------------------------------------------------------------------+------------------------------------------------------------------+--------------------------------------------+


+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
; Registers Removed During Synthesis                                                                                                                                             ;
+-----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------+
; Register name                                                                           ; Reason for Removal                                                                   ;
+-----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------+
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|dualport:mem|r_addr_b[7,8] ; Stuck at GND due to stuck port data_in                                               ;
; mm8e_memory:mem|ext_ce_l                                                                ; Stuck at GND due to stuck port data_in                                               ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_rdwr_block[14..31]                                ; Merged with rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_rdwr_block[13]                     ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|err[1,2,6]                                           ; Merged with rx8e_ctlr:rx|rx0n_drive:rx0n_drive|err[0]                                ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sts[3,4]                                             ; Merged with rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sts[1]                                ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|cmd_arg[23..29,31]         ; Merged with rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|cmd_arg[22] ;

 

0 Kudos
ak6dn
Valued Contributor III
1,917 Views

Ha! My bad. The horizontal scrolling boxes show up in the final display, but not when entering/editing!!

ALSO: Can you PLEASE bring back the capability to EDIT past posts? Why was it removed???????

ak6dn
Valued Contributor III
1,914 Views

For reference, here is the .map.rpt prior to adding the (*preserve*) attribute on those registers. Note that the Registers Preserved section no longer exists, and some spi_divisor[] bits were removed.

+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
; Registers Removed During Synthesis                                                                                                                                                ;
+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+
; Register name                                                                           ; Reason for Removal                                                                      ;
+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|dualport:mem|r_addr_b[7,8] ; Stuck at GND due to stuck port data_in                                                  ;
; mm8e_memory:mem|ext_ce_l                                                                ; Stuck at GND due to stuck port data_in                                                  ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[4]             ; Merged with rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[2] ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[7]             ; Merged with rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[3] ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_rdwr_block[14..31]                                ; Merged with rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_rdwr_block[13]                        ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|err[1,2,6]                                           ; Merged with rx8e_ctlr:rx|rx0n_drive:rx0n_drive|err[0]                                   ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sts[3,4]                                             ; Merged with rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sts[1]                                   ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|cmd_arg[23..29,31]         ; Merged with rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|cmd_arg[22]    ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[1]             ; Merged with rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[0] ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[3]             ; Merged with rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[2] ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[6]             ; Merged with rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[5] ;
; rx8e_ctlr:rx|rx0n_drive:rx0n_drive|sd_card_ctlr:sd_card_ctlr|spi_divisor[2]             ; Stuck at GND due to stuck port data_in                                                  ;
; kl8e_async:serdisk|uart:uart|rxperr                                                     ; Stuck at GND due to stuck port data_in                                                  ;
; kl8e_async:serterm|uart:uart|rxperr                                                     ; Stuck at GND due to stuck port data_in                                                  ;

 

 

KhaiChein_Y_Intel
2,030 Views

Hi,


You may change to below:

     if( ( hcount >= hdat_begin ) && ( hcount <= hdat_last ) )

     begin

       

      if( hcount[ 0 ] == 0 )

      begin

       tempRGB <= colorRGB[ dataH ];


      end

      else

      begin

       tempRGB <= colorRGB[ dataL ];

      end


      dataR <= tempRGB[ 11 : 8 ];

      dataG <= tempRGB[ 7 : 4 ];

      dataB <= tempRGB[ 3 : 0 ];

     end


Thanks

Best regards,

KhaiY


SparkyNZ
New Contributor II
1,851 Views

Wow. That was the culprit!

I know everyone keeps saying "use non blocking assignments" but I didn't think blocking assignments  would cause me this much trouble.

I will definitely be making notes about this. As soon as I changed my code as you'd suggested @KhaiChein_Y_Intel , tempRGB appeared in the RTL Viewer.

Thanks @ak6dn for the additional info. I had a look at my .map.rpt file and tempRGB was nowhere to be found - so it was getting removed long before with no evidence that it had been removed whatsoever.

It's really difficult trying to debug what has gone wrong in the process when there is no track record. @KhaiChein_Y_Intel , if possible could we make a suggestion to the developers to log something in the report for cases such as this? If you attach my project to a ticket, I am sure they will find it easy to recreate. Any message would do such as 'Removed "tempRGB" because you keep using blocking assignments'

So I have a solution, thank you - but I still don't know why was removed (without a trace).

0 Kudos
ak6dn
Valued Contributor III
1,607 Views

It was removed because it never really existed as a physical register.

In coding verilog, you can use register variables to simplify computations WITHOUT ever creating a real register.

thus:

wire W1,W2,W3,W4;
reg R1,R2,R3;
always @(posedge clk)
    begin
    R1 = W1+W2;
    R2 = W3+W4;
    R3 = R1+R2;
    end

will only create a single real register R3. R1 and R2 don't really need to exist, they are transient. It is really the same as if you wrote:

wire W1,W2,W3,W4;
reg R1,R2,R3;
always @(posedge clk)
    begin
    R3 = (W1+W2)+(W3+W4);
    end

 But this will be very different:

wire W1,W2,W3,W4;
reg R1,R2,R3;
always @(posedge clk)
    begin
    R1 <= W1+W2;
    R2 <= W3+W4;
    R3 <= R1+R2;
    end

because R1 and R2 will be computed in time state 'N', but R3 won't get the sum until time state 'N+1'.

0 Kudos
ak6dn
Valued Contributor III
1,850 Views

That solution is NOT going to produce the exact same result however.

Changing the assignment from blocking (=) to non-blocking (<=) is going to cause a one-clock pipeline delay to occur.

tempRGB will be assigned in clock state 'N+0'

dataR/DataG/dataB will get that value in clock state 'N+1'

This may or may not be significant, depending on the desired behavior.

SparkyNZ
New Contributor II
1,847 Views

@ak6dn, yeah its 7pm and my brain is too flat to try it out but I hear you. I would have thought the blocking assignments would have required more clock cycles.. or do you mean that because it's "continuous" now that it may take an extra cycle to stabilise, so to speak?

I've never felt comfortable with using non-blocking assignments in conjunction with if() statements because they don't behave the same as a software if() statement (and I'm a software developer).

Still, there are 3 things here:

1) I need to be able to see values in SignalTap so I can make sense of my bugs

2) I need to understand what Quartus does to help and what it does to hinder

3) I should get my design working properly - but that can wait until the weekend

and possible 4) I really need to get my brain around how non-blocking assignments and if() statements work. Any tutorial material I find seems contradictory or poorly written for my brain to absorb. I kind of got the impression that non-blocking assignments are effectively evaluated at the end of the clock cycle.. but then that does that mean that the if() conditions use the value at the start of the clock cycle.. or are the if() statements themselves continuous in nature like any logic gate would be?

0 Kudos
SparkyNZ
New Contributor II
1,845 Views

It's possibly also work mentioning that tempRGB now appears in RTL Viewer even without "keep" and "preserve".

0 Kudos
Reply