UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Explorer
Explorer
2,361 Views
Registered: ‎07-10-2013

Inferring a ROM using BRAM with unregistered outputs

Jump to solution

UG901 (v2017.4) on p.165 shows an example of inferring a ROM using a BRAM.  The coding shows that the dout output bits are being registered at the rising edge of the input clock.

 

What is recommended way to infer a similar ROM, with the outputs not being registered?

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Explorer
Explorer
3,014 Views
Registered: ‎07-10-2013

Re: Inferring a ROM using BRAM with unregistered outputs

Jump to solution

Mark,

 

Thanks for your comments and suggestions!

0 Kudos
8 Replies
Scholar markcurry
Scholar
2,337 Views
Registered: ‎09-16-2009

Re: Inferring a ROM using BRAM with unregistered outputs

Jump to solution

 

You must have one cycle of latency in order to map to a BRAM.  If you want an asynchronous ROM, then it'll have to map to just LUT cells.  To to this, just follow the same guideline from UG901 - but make the procedural block as purely combinational i.e.

always @*
  case( addr )
      6'd0000000: data = foo;
      6'd0000001: data = bar;
...
   default:
      data = baz;

Or, better yet use a two-dimensional array:

 

reg [ 19 : 0 ] my_romdata[ 0 : 63 ];

always @*
  data = my_romdata[ addr ];


And then use a $readmemh or something similar to initialize my_romdata.

 

Regards,

 

Mark

0 Kudos
Explorer
Explorer
2,329 Views
Registered: ‎07-10-2013

Re: Inferring a ROM using BRAM with unregistered outputs

Jump to solution

@markcurry,

 

It is known and understood that any use of a BRAM would incur (at least) one cycle of latency, which is a non-issue in my application.

 

My desire is to wind up with just a single cycle of latency (i.e., the overhead in getting the address clocked into the BRAM), and not two cycles (i.e., not having the output data be registered).

 

Could a combinatorial always block such as you've outlined be used somehow to infer a non-output-registered BRAM?  Is Vivado keyed to recognize such an inference?

 

 

0 Kudos
Scholar markcurry
Scholar
2,323 Views
Registered: ‎09-16-2009

Re: Inferring a ROM using BRAM with unregistered outputs

Jump to solution

 

 

A BRAM will work fine then.  Just code it as one-cycle latency, and the tool will very likely do the right thing. 

 

I'm away from my desk at the moment - so cannot consult UG901 - but whether you code it as registering the address, or registering the final contents - take a look at the examples in UG901, but likely the tool will do the right thing in either case.

 

Regards,

 

Mark

0 Kudos
Explorer
Explorer
2,317 Views
Registered: ‎07-10-2013

Re: Inferring a ROM using BRAM with unregistered outputs

Jump to solution

Mark,

 

Unfortunately, it's not obvious (to me) how to take the clocked always block example in UG901 p.165 and transform it from registering all BRAM signals (the control inputs and the data outputs), to registering just the control inputs and leaving the data outputs unregistered.

 

It looks like what could help or would be necessary would be to have Vivado define other possibilities for the ROM_STYLE attribute, beyond what's seen there in UG901, namely something like:

 

(*rom_style = "block_unregistered_data" *) reg [19:0] data;

 

Or, the issue might generally just come down to a deficiency in Verilog which I have run into in numerous situations, namely the inability to specify production of combinatorial signals which it would be desirable to "output" (export) from a clocked always block, i.e., without them needing to be registered.

 

0 Kudos
Scholar markcurry
Scholar
2,297 Views
Registered: ‎09-16-2009

Re: Inferring a ROM using BRAM with unregistered outputs

Jump to solution

 

I'm not clear on what's holding you up.

 

The example in UG901 on page 165 shows a ROM being inferred using case statements with a SINGLE cycle of latency.  That solution should meet your requirements.

 

From a design perspective, why does it matter if that one cycle of latency is at the control inputs, or at the data outputs? - It's a single cycle either way.  Of course one solution probably has a better quality of results timing wise (i.e. can run at a higher clock rate).  But how it works with the rest of your interface logic is the same for either solution.

 

It's not a "deficiency in Verilog" either.  The solution is darned near identical in VHDL. 

 

I'd like to help, but I'm not following what's holding you up.

 

Regards,

 

Mark

 

 

0 Kudos
Explorer
Explorer
2,288 Views
Registered: ‎07-10-2013

Re: Inferring a ROM using BRAM with unregistered outputs

Jump to solution

Mark,

 

Upon further review I agree with you; the UG901 coding on p.165 would correspond to use of an unregistered-output BRAM.  My confusion resulted from the fact that, at the primitive level, it is the case that the address (and other control signals) are clocked into the BRAM before any read activity is initiated.  That, together with the use of  non-blocking (<=) assignments in the Verilog to produce the output data, moved my thinking in the wrong direction that that data would be output following the following clock edge.  There was improper mingling of primitive-level and HDL-level considerations going on.

 

Whether a single cycle of latency occurs at the input or at the output, does not matter (logically) of course.

 

FYI, the "Verilog deficiency" I was referring to is not specific to the BRAM question.  It refers to the inability (as far as I am aware) to specify production of combinatorial signals which it would be desirable to "output" (export) from a clocked always block, i.e., without them needing to be registered.

 

This issue typically comes up when Verilog code needs to accept signals in from an instantiated clock-utilizing primitive, and to produce signals to be input back into the primitive.  The code design may be begun under the assumption that the primitive's out-to-in turn-around timing requirements can be accomplished in one or more clock cycles, with a clocked always block then used to produce the needed signals.  It may later turn out that that or related assumptions were incorrect, and that the timing is tighter than thought originally (or has changed from what was okay originally), so that e.g. the output signals needs to be produced in the same clock cycle, necessitating use of combinatorial logic to produce the output signals.

 

Unfortunately, the output signals' production may have "buried" by the coding in layers of if/else (or other) constructs in the clocked always block, so that the logic required to produce combinatorial versions of the output signals is non-obvious, and certainly difficult or error-prone to attempt to separately reproduce using e.g. an assign along with ?: operators.  And, the complex always block logic typically needs to stay intact to handle production of other (registered) output signals.

 

The only approach I've thought of that would always be generally applicable to be able to handle such situations without having to go back and rewrite a bunch of code sometime later on, would be to (always) utilize two always blocks, the first being a combinatorial always block which can legitimately export combinatorial output signals (including to the instantiated primitives that might need access to such unregistered signals), and the second being a clock always block whose only function is to take (various of the) exported combinatorial signals from the first always block and register them into flipflops (some of whose outputs would typically feedback to the first always block).

 

It would seem far simpler and much more elegant if Verilog were simply to allow "export" of combinatorial signals produced in a clocked always block, those signals having been assigned using blocking (=) assignments.

 

0 Kudos
Scholar markcurry
Scholar
2,263 Views
Registered: ‎09-16-2009

Re: Inferring a ROM using BRAM with unregistered outputs

Jump to solution

@chsdkj wrote:

 

The only approach I've thought of that would always be generally applicable to be able to handle such situations without having to go back and rewrite a bunch of code sometime later on, would be to (always) utilize two always blocks, the first being a combinatorial always block which can legitimately export combinatorial output signals (including to the instantiated primitives that might need access to such unregistered signals), and the second being a clock always block whose only function is to take (various of the) exported combinatorial signals from the first always block and register them into flipflops (some of whose outputs would typically feedback to the first always block).


 


 

This is the widely used approach, however it's sometime met with a little (uncalled for) derision.   Search these forums for "two-process state machine" or similar.  Most argue quite strongly that using two process state machines is only done by beginners or the inexperienced.  That argument is wrong. 

 

With respect to two-process "state machines" or more generally as what you're looking for, the only thing to watch out for is coding such that one avoids inferring inadvertent latches.  This is easily achieved by just assigning a "default" value at the beginning of your combinatorial process.  Some examples:

 

module foo(...);

  my_states_t state, next_state;
  reg [ 7 : 0 ] cnt, next_cnt;
  reg [ 63 : 0  ] header, next_header;
  reg header_valid, next_header_valid;

  // All synchronous signals
  always @( posedge clk )
    if( reset )
    begin
      state <= IDLE_STATE;
      cnt <= 0;
      header <= next_header;  // Not a typo - doesn't need a reset
      header_valid <= 0;
   else
   begin
      state <= next_state;
      cnt <= next_cnt;
      header <= next_header;
      header_valid <= next_header_valid;
   end

  // additional combinatorial signals
  reg assert_state_decode_error;
  reg assert_invalid_state;
  reg push_side_band;
  reg [ 31 : 0 ] addr_to_map;

  // Combinatorial decode
  always @*
  begin
    // default assignments - avoids latches, helps define "default" operation
    next_state = state;
    next_cnt = cnt + 1'b1;
    next_header = header;
    next_header_valid = header_valid & ~header_ready_i;
    
addr_to_map = current_pcie_addr; assert_invalid_state = 0; assert_state_decode_error = 0; push_side_band = 0; case( state ) // do state decode .... end endmodule

The key here is the second always block must first assign all variables to a default value at the beginning - before any conditional code is done.  Sometimes the default value is for a register to keep its last value.  Sometimes the default value is to increment.  Sometimes the default can be one-line decoded from a few signals.  Combinational outputs may default to an "idle" like condition. It all depends.

 

Later on within the rest of the decode, one overrides the "default" with a new value - depending on the decode.  This may be done more than once.  It makes exception handling quite nice.  The key here is that the meat of your processing is done in the one place - the second always block - procedurally.

 

I like this style of state machine - and even use it outside state machine coding.  It's nice for me when debugging to have a concrete signal I can probe for both the Q (i.e. cnt), and D (i.e. next_cnt) of the FF.  It also makes coding up assertions quite easy as well.  And due to my style I can quickly see which signals are registered, and which are combinatorial by keying off the "next_" prefix.

 

Some don't like the overhead of the first procedural block and / or extra names for the "next_" signals.  I find it worth this little extra effort. 

 

Regards,

 

Mark

0 Kudos
Highlighted
Explorer
Explorer
3,015 Views
Registered: ‎07-10-2013

Re: Inferring a ROM using BRAM with unregistered outputs

Jump to solution

Mark,

 

Thanks for your comments and suggestions!

0 Kudos