Tuesday, August 9, 2011

How to calculate the sum of data in a queue of bits in SystemVerilog?


    The built-in array method sum() will return a value according to the type of queue.
    such as:
    bit flags[$];
    ....
    flags.sum() will return 0 or 1 because the type of queue is bit

    Solution

    To actually sum the queue data use:
    mysum = flags.sum() with (int'(item));
    Below is an example for reference:
    module test;
     bit flags[$];
     int mysum;
     initial
     begin
     flags[0] =1;
     flags[1]=1;
     mysum = flags.sum();  //this will return 0 or 1
     $display("%0d",mysum);
     mysum = flags.sum() with (int'(item));  //this will return the total value of every element.
     $display("%0d",mysum);
    end
    endmodule

Thursday, May 5, 2011

Aldec - Events

Aldec - Events

You can observe the Aldec Events in above link

Macros to simplify the Register Write/Read Operations using OVM_RGM Package

The Sequences or macros provided by OVM_RGM can't be used inside the Testcases and those can be used in one of the RGM Sequence only. Also these macros won't allow us to write Field write/read operations.
To avoid this problem in one of our project, our team has come up with a list of some generic Sequences and Macros for OVM_RGM Usage to enable easy Register Operations.

To understand this assume following structure for Register Database for small environment looks like below.


The Register Database will have

  1. Two Register Files with names IEEE and EXTE.
  2. IEEE Register File will have Reg0 and Reg1 Register.
    • Reg0 will have Fields with names F1 and F2.
  3. EXTE Register File will have Reg0.
Generalized Sequence Written for Register Operations:

class Rd_Wr_RGMSequence #(string REGFILENAME = "" ,type REGNAME = ovm_rgm_pkg::ovm_rgm_register_base) extends ovm_rgm_sequence;
  
  rand bit [`OVM_RGM_DWIDTH:0] REQVAL;
  bit [`OVM_RGM_DWIDTH:0] RSPVAL;
  rand ovm_rgm_op_direction_t OP; 
  ovm_rgm_pkg::ovm_rgm_container container; 
  REGNAME rgm_reg;
  string path1,path2;
  ovm_rgm_pkg::ovm_rgm_register_base reg_rsp_var,r;

   `ovm_object_param_utils_begin(Rd_Wr_RGMSequence #(REGFILENAME,REGNAME))   
       `ovm_field_int(REQVAL,OVM_PRINT)
   `ovm_object_utils_end   
   
     function new(string name = "Rd_Wr_RGM RANDOM SEQUENCE");
        super.new(name);
     endfunction  

 task body();
  rgm_reg=REGNAME::type_id::create("SEQRGM");
  path1=rgm_reg.get_type_name();
  path1 = path1.tolower();
  path2 = REGFILENAME.tolower();
  path1 = {path2,".",path1};
  case (OP)
  OP_RD:     begin
            `rgm_read_by_name(rgm_reg,path1)
           get_reg_response(rgm_reg,reg_rsp_var);
             this.RSPVAL=rgm_reg.value;
         end   
  OP_WR:    begin
           `rgm_write_by_name_with(rgm_reg,path1,{value==local::REQVAL;})
                get_reg_response(rgm_reg,reg_rsp_var);
          end  
        endcase  
  ovm_report_info(get_type_name(),"Body of the Rd_WR_RGM sequence ENDING\n");
 endtask
endclass

Macros for different Register Operations:

//
//Macro to perform register read
//usage : regread("IEEE",Reg0,bit[4:0]read,p_sequencer Pointer)
//
`define regread(REGFILENAME,REGNAME,DATAREAD,SEQUENCERREF)\
begin\
  import `RGM_PKG::*;\
  `RGM_PKG::Rd_Wr_RGMSequence #(REGFILENAME,REGNAME) seq;\
  seq = `RGM_PKG::Rd_Wr_RGMSequence #(REGFILENAME,REGNAME)::type_id::create("readrgmsequence");\
  assert(seq.randomize() with {OP==OP_RD;});\
  seq.print();\
  seq.start(SEQUENCERREF);\
  DATAREAD=seq.RSPVAL;\
end


//
//Macro to perform register write
//usage : regwrite("IEEE",Reg0,'h09,p_sequencer Pointer)
//
`define regwrite(REGFILENAME,REGNAME,WRITEDATA,SEQUENCERREF)\
begin\
  import `RGM_PKG::*;\
   bit[`OVM_RGM_DWIDTH:0] writedata;\
  `RGM_PKG::Rd_Wr_RGMSequence #(REGFILENAME,REGNAME) seq;\
  seq = `RGM_PKG::Rd_Wr_RGMSequence #(REGFILENAME,REGNAME)::type_id::create("RD_WR_RGM_SEQUENCE");\
  writedata=WRITEDATA;\
  assert(seq.randomize() with {OP==OP_WR;REQVAL==local::writedata;});\
  seq.print();\
  seq.start(SEQUENCERREF);\
end


//
//Macro to perform register field write
//usage : regfldwrite("IEEE",Reg0,{F1:2'b0},p_sequencer Pointer)
//
`define regfldwrite(REGFILENAME,REGNAME,FIELDS,SEQUENCERREF)\
begin\
 import `RGM_PKG::*;\
  bit[`OVM_RGM_DWIDTH:0] REQVAL;\
  REGNAME regfld;\
  ovm_rgm_fld_props fld_props=new();\
  string path1,path2;\
  ovm_rgm_register_base r; \
  string s;\
  int i=0;\
  integer field_updates [string]=FIELDS;\
  regfld=REGNAME::type_id::create("FLDRGM");\
  s=regfld.get_type_name();\
  path1 = s.tolower();\
  s=REGFILENAME;\
  path2 = s.tolower();\
  path1 = {path2,".",path1};\
  $cast(r,SEQUENCERREF.container.get_reg_by_name(path1,0));\
  while(r.get_field_props(i,fld_props))\
  begin\
  if(field_updates.exists(fld_props.name_))\
  begin\
  $display("i am setting the filed %s with %d",fld_props.name_,field_updates[fld_props.name_]);\
  r.set_field_value(fld_props.name_,field_updates[fld_props.name_]);\
end\
++i;\
   end\
   REQVAL=r.read();\
   `regwrite(REGFILENAME,REGNAME,REQVAL,SEQUENCERREF)\
end

//
//Macro to perform register field read
//usage : regfldread("IEEE",mode_control,int dataread[string],p_sequencer)
//dataread is an Associative array which indicates the required fields interested
`define regfldread(REGFILENAME,REGNAME,DATAREAD,SEQUENCERREF)\
begin\
  import `RGM_PKG::*;\
  bit[`OVM_RGM_DWIDTH:0] REQVAL;\
  REGNAME regfld;\
  ovm_rgm_fld_props fld_props = new();\
  string path1,path2;\
  integer update [string];\
  string s;\
  int i=0;\
  regfld=REGNAME::type_id::create("FLDRGM");\
  s=regfld.get_type_name();\
  path1 = s.tolower();\
  s=REGFILENAME;\
  path2 = s.tolower();\
  path1 = {path2,".",path1};\
  $cast(regfld,SEQUENCERREF.container.get_reg_by_name(path1));\
 `regread(REGFILENAME,REGNAME,REQVAL,SEQUENCERREF)\
 regfld.value=REQVAL;\
 while(regfld.get_field_props(i,fld_props))\
  begin\
  update[fld_props.name_]=regfld.get_field_value(fld_props.name_);\
++i;\
   end\
   DATAREAD=update;\
end

Examples of Usages:
RGM_PKG define will indicate the Chipspecific RGM Package name

To perform the Register Field Read Operation
integer read_data[string];
byte    data;

`regfldread("IEEE",`RGM_PKG::Reg0,read_data,p_sequencer.REG_SEQR)
 data=read_data["F1"];

To perform the Register Field Write Operation
integer fields_write [string];
fields_write = '{"F1":8'h12,"F2":8'h45} ;
`regfldwrite("IEEE",`RGM_PKG::Reg0,fields_write,p_sequencer.REG_SEQR)

Tuesday, April 26, 2011

Killing Sequences on Sequencer Abruptly

Sometimes you may need to drive input until you see come condition or some timer expires. Once you meet that condition, you need to stop generating stimulus. The code for this scenario look like below.


//Test
begin
    fork
    begin
        wait(rtl_linkup == 1);
    end
    begin
       forever
           idles_transmit.start(Sequencer);
    end
  join_any
  disable fork;
end


In the above code we are driving idles until rtl_linkup condition is observed. But here there is a problem, As we are trying kill idles_transmit sequence abruptly when condition is met, this may cause the sequencer to be in intermittent state. This will cause the problem on the next sequences which trigger on the same sequencer. As sequencer is in intermittent state it may not get grant and will wait for for grant forever. To avoid this problem we need to reset the sequencer after killing threads. The code look like below.


//Test
begin
   fork
      begin
        wait(rtl_linkup == 1);
      end
      begin
           forever
              idles_transmit.start(Sequencer);
      end
   join_any
   disable fork;
   Sequencer.stop_sequence();
end


In the above code the stop_sequences call will reset the sequencer variables and won't cause any problem for the next sequences which are triggered on same sequencer. Here also we have another problem with the sequence thread which is killed with disable fork. Sometimes by the time thread is killed request might have been sent to driver. if thread is killed and stop_sequence is called before receiving the item_done, item_done will cause fatal error as request fifo is empty. So we need to kill thread and call of stop_sequence only after receiving item_done from driver. The code will look like below.


//Sequence .
class idles_transmit extends ovm_sequence #(REQ= packet);
    bit received_item_done;
    task body();
       wait_for_grant();
       assert(req.randomize());
       send_req(req);
       received_item_done = 0;
       wait_for_item_done();
       received_item_done = 1;
   endtask
endclass


//Test
begin
    fork
        begin
            wait(rtl_linkup == 1);
        end
        begin
             forever
                  idles_transmit.start(Sequencer);
        end
     join_any
     @(posedge idles_transmit.received_item_done);
     disable fork;
      Sequencer.stop_sequence();
end


In the above code we are trying to kill the thread and reseting sequencer state only after receiving the ite_done for the request sent, which is the idle way to stop thread.

Sunday, April 10, 2011

IT'S NOT HOW GOOD YOU ARE, IT'S HOW GOOD YOU WANT TO BE

IT'S NOT HOW GOOD YOU ARE, IT'S HOW GOOD YOU WANT TO BE - PAUL ARDEN

Everybody will have dreams and want to be Good with Success in Life. In similar lines, I came across above book and found it has beautiful points to follow.
Here is the gist of Book.

1. Nearly all rich and powerful people are not notably talented, educated, charming or good-looking. They become rich and powerful by wanting to be rich and powerful.
2. Your vision of where or who you want to be is the greatest asset you have. Without having a goal it's difficult to score.
3. All creative people need something to rebel against, it's what gives their lives excitement, and it's creative people who make the clients' lives exciting.
4. There is no instant solution, to become good. It is only through experience and mistakes.
5. You can achieve the unachievable. Always aim beyond what you are capable of. Try to do things that you are incapable of.
6. Always dream about how good you want to be.
7. Energy is the 75 % of the job. 
8. Don't seek praise. Seek criticism. So that you can always improve your idea.
9. If You are involved in something that goes wrong, never blame others. Blame no one but yourself. If you accept responsibility, you are in a position to do something about it.
10. Give away everything you know, and more will come back to you.
11. Don't look for the next opportunity. The one you have in hand is the opportunity.
12. Eliminate the Negative.
13. Don't promise what you can't deliver. 
14. Know your client Aims for whom you are working.
15. Always show a client what he want's first, he is then relaxed and is prepared to look at what you want to show him.
16. Don't take No for an answer.
17. When it can't be done, do it. If you don't do it, it doesn't exist.
18. If you can't solve the problem, it's because you are playing by the rules.
19. The person who doesn't make mistakes is unlikely to make anything.
20. It's wrong to be right.
21. Don't be afraid of Silly Ideas.
22. How you perceive yourself is how others will see you.
23. It's not what you know. It is who you know.
24. Don't give a speech. Put on a show.
25. Rough Layouts sell ideas better than polished ones. Show the client a scribble. Explain it to him, talk to him through it, let him use his imagination. Work with him rather than confronting with idea. 
26. If you get stuck, use a different pen.
27. Don't hand over to a team hoping that they will produce the magic. It's for you to lead them along the path of enlightenment.
28. Don't be afraid to work with the best.
29. Don't try to win awards. Be true to your subject and you will be far more likely to create something that is timeless.
30. Success is going from failure to failure with no loss of enthusiasm.
31. The first thing to decide before you walk into any negotiation is what to do if the other fellow says no.
32. Those who lack courage will always find a philosophy to justify it. 
33. If everything seems under control you're not going fast enough.
34. We don't see things as they are. We see them as we are.


Finally at some point we need to draw line somewhere. 

Thursday, March 10, 2011

Comparing Signal Strength in Verilog/Systemverilog


Language doesn’t allow you directly to compare the signal strength. But you can compare strengths by converting the strings. By using the following macro you can achieve the required function.

`define compSigValues(siga, sigb)
  begin
  string sigaStr, sigbStr;
  $sformat(sigaStr, "%v", siga);
  $sformat(sigbStr, "%v", sigb);
  if ( sigaStr == sigbStr )
$display("Signal values %s and %s match", sigaStr, sigbStr);
  else
$display("Signal values %s and %s don't match", sigaStr, sigbStr);
 end

Monday, March 7, 2011

Escaped Identifiers in hierarchical Path usage in Verilog/Systemverilog

An identifier in Verilog and SystemVerilog is the name of some object, such as the name of a module, the name of a wire, the name of a variable, or the name of a function. The legal characters in an identifier are alphabetic characters, numbers, underscore or dollar sign. All other characters, such as +, -, (, ), [ and ], are illegal in an identifier name.
Verilog and SystemVerilog allow these illegal characters to be used in a name by escaping the identifier. A name is escaped by preceding the name with a back slash ( \ ) and terminating the name with a white space character.


module \d-flop (output q, \q~ , input \d[0] ,clk, \rst- ); 
...
endmodule


Note in the above example that a white space character must be used before the commas that separate an escaped identifier from the next item in the list. A white space is also required between the last escaped name, \reset-, and the closing parenthesis.
The gotcha is when an escaped identifier is used as part of a hierarchy path. The escaped identifier must be terminated by a white space. That white space looks like it breaks the hierarchy path into two identifiers, but the terminating white space is ignored, which, in effect, concatenates the two names into one name.


The following examples illustrate the use of white space after references to escaped identifiers. Module chip uses named port connections to escaped port names identifiers. The $display contains a relative hierarchy path that contains an escaped identifier.


module chip (output [7:0] q, input [7:0] d, input clk, rstN); 
\d-flop \d-0 (.q(q[0]), .\q~ (), .\d[0] (d[0]), .clk(clk), .\rst- (rstN));
initial 
begin 
$display(“d = %b”, \d-0.\d[0] );    // Error - As White Space is missing
$display(“d = %b”, \d-0 .\d[0] );   // Correct Usage as White Space is used.
end
endmodule


The Netlist file normally will be using Escaped Identifiers to preserve the hierarchical path of design.

Tuesday, March 1, 2011

Adding Validation support to OVM Agents

OVM Agents need to be developed to support the Validation activity also. Sometimes during validation we will be having requirement to provide the Packets or input data in file format. If OVM Agents has the capability to dump the packet into file at various abstraction levels, that file can be used as Input during validation. Adding this logic may not be overhead to Agent when compared against the advantages.

Monday, February 28, 2011

Duplicate or multiple OVM banners

    When executing vsim on a design containing OVM, two or more OVM banners appear on the screen and/or in the transcript file.
    # ------------------------------------------------- 
    # OVM-2.1.1 
    # (C) 2007-2009 Mentor Graphics Corporation 
    # (C) 2007-2009 Cadence Design Systems, Inc. 
    # ------------------------------------------------- 
    # ------------------------------------------------- 
    # OVM-2.1.1 
    # (C) 2007-2009 Mentor Graphics Corporation 
    # (C) 2007-2009 Cadence Design Systems, Inc. 
    # -------------------------------------------------
    
    
    
    
    The message is printed in method ovm_report_handler::report_header() in src/base/ovm_report_handler.svh
    This is called only from OVM code in method ovm_report_object::report_header() in ovm_report_object.svh
    This too is called only from OVM code in ovm_root::new() in ovm_root.svh

Solution:
All possible causes of multiple printout of this message and suggestions for resolution: 

1. User code has instantiated ovm_root multiple times via multiple calls to ovm_root::new().  This should not be done and will need to be corrected. 

2. User code has extended ovm_root and changed its behavior. This also should be not be done and will need to be corrected.

3. User code calls ovm_report_handler::report_header() directly via an ovm_report_handler object handle.

4. User code calls ovm_report_object::report_header() directly via an ovm_report_object handle or subclass method override calling super.report_header(). 

5. One additional and very likely possibility is that there are multiple ovm_pkg universes compiled separately and integrated at runtime. This can happen in a simulation scripting case, which compiles separate units (e.g. VIPs or testbench bits) each of which correctly does an import ovmpkg::*. Those units are then integrated in to a toplevel testbench by `include instead of by import my_subunit1::*; import my_vip2::* etc 


Don't use `include for this case. Use only `import. Otherwise the outcome is that each package, while called ovm_pkg, is actually a different package namespace with a different ovm_root etc.

Wednesday, February 23, 2011

Virtual Signal Spy...Debugging Made easy

If you are using Questasim, your waveform debugging will be easy if start using Virtual Signal Option. With the help of this option New Signals can be created by applying the expressions on the Existing signals. You can also delay the signals by certain amount when comparing input with output which will be general case many times.



Few examples include:
Create a virtual signal that is the same as /top/signalA except it is delayed by 10 ps. 
  virtual signal -delay {10 ps} {/top/signalA} myDelayedSignalA

Create a three-bit signal, chip.address_mode, as an alias to the specified bits. 
  virtual signal { chip.instruction[23:21] } address_mode

Create a two-bit signal (with an enumerated type) based on the results of the subexpressions. For example, if aold equals anew, then the first bit is true (1). Alternatively, if bold does not equal bnew, the second bit is false (0). Each subexpression is evaluated independently.
  virtual signal {(aold == anew) & (bold == bnew)} myequalityvector

Create signal newbus that is a concatenation of bus1 (bit-reversed) and bus2[7:4] (bit- reversed). Assuming bus1 has indices running 7 downto 0, the result will be newbus[11:0] with the upper 8 bits being bus1[0:7] and the lower 4 bits being bus2[4:7]. 
  virtual signal {(concat_reverse)(bus1 & bus2[7:4])} newbus

I personally felt this option saves lot of time and effort during debugging.
Hope the same for you too...

Tuesday, January 18, 2011

Spare Cells in ASIC

What are spare cells and why the heck do we need them?
Spare cells are basically elements embedded in the design which are not driving anything. The idea is that maybe they will enable an easy (metal) fix without the need of a full redesign.


Sometimes not everything works after tape-out, a counter might not be reseted correctly, a control signal needs to be additionally blocked when another signal is high etc. These kind of problems could be solved easily if “only I would have another AND gate here…”
Spare cells aim to give a chance of solving those kind of problems. Generally, the layout guys try to embed in the free spaces of the floor-plan some cells which are not driving anything. There is almost always free space around, and adding more cells doesn’t cost us in power (maybe in leakage in newer technologies), area (this space is anyhow there) or design time (the processes is 99% automatic).


Having spare cells might mean that we are able to fix a design for a few 10K dollars (sometimes less) rather than a few 100K.

So which spare cells should we use? It is always a good idea to have a few free memory elements, so I would recommend on a few flip-flops. Even a number as low as 100 FF in a 50K FF design is usually ok. Remember, you arenot trying to build a new block, but rather to have a cheap possibility for a solution by rewiring some gates and FFs.

What gates should we through in? If you remember some basic boolean algebra, you know that NANDs and NORs can create any boolean function! This means that integrating only NANDs or NORs as spare cells would be sufficient. Usually, both NANDs and NORs are thrown in for more flexibility. 3 input, or even better 4 input NANDs and NORs should be used.



A small trick is tying the inputs of all NANDs to a logical “1″ and all inputs of the NORs to a logical “0″. This way if you decide to use only 2 of the 4 inputs the other inputs do not affect the output (check it yourself), this in turn means less layout work when tying and untying the inputs of those spare cells.
The integration of spare cells is usually done after the synthesis step and in the verilog netlist basically looks like an instantiation of library cells. This should not done before, since the synthesis tool will just optimize all those cells away as they drive nothing. The layout guy has to somehow by feeling (or black magic) spread the spare cells around in an even way.


I believe that when an ECO (Engineering Change Order) is needed and a metal-fix is considered – this is where our real work as digital designers start. I consider ECOs, and in turn the use of spare cells to solve or patch a problem, as the epitome our usage of skills, experience, knowledge and creativity!