Can anyone explain me what a blueprint is?

I have read this in Chris Spear’s book and haven’t understood properly. It would be great if anyone explains it with an example.

In reply to Suhas BV:
A blueprint is defined as a design plan or other technical drawing
In his book SystemVerilog for Verification (a good book BTW), Chris Spear was referring to SystemVerilog classes being blueprints, or templates, that can be used to build many objects. Blueprints are thus templates that contain objects. Blueprints are typically transformed into actual and usable design plans by either having them approved as is, or modified to needs and then approved.

  • Crhis was using a house plan as an example to explain OOP. House blueprint can be momodified (e.g., a different kind of refrigerator, different flooring, roofing material, etc…) and then approved by the city for a building permit, i.e., to be used.
  • In OOP, a class is like a blueprint of an entity that contains variables, functions, and tasks. To be used, a class can be extended, if needed, and then instantiated, and that handle uniquely identifies your desired class object. Note that the building permit that uses the updated house blueprint is also a handle that uniquely identifies your house.
  • In my SVA Handbook 4th Edition I present blueprints for the design of a requirement apec and a verification spec.

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr


In reply to Suhas BV:
There is an example in my book, so this might repeat some of what you have read. Note that there are many ways to write a transaction generator. This is one that I found easy to understand and explain. Or maybe not, as some people still ask for more details!

The goal is to write a generator that can produce objects of a certain flavor, when you don’t know in advance what all the possible flavors could be. And have the generator flexible enough that you don’t have to keep going back and editing it over and over for every variation.

Say you won the contact to provide STOP signs to the highway department. You could make a machine that makes 8 cuts to a piece of steel, then painted an exact pattern of red and white. What happens if the highway department then asks you for YIELD signs. Now you have make a new machine that makes 3 cuts at a new angle and paint a different pattern of red and while. What about speed limit signs, handicap parking, and more? You don’t want to keep making custom machines for these. Instead, buy a stamping machine and an 8-sided die that cuts the STOP sign shape, and a printer that writes “STOP”. Now when you want to make a YIELD sign, just get a new die that cuts triangles, and change your printer to write “YIELD”.

Likewise, in your testbench, don’t try to write code that creates an AXI transaction then tries to tweak every possible field with masks, delays, and errors. Instead, write a generator that copies a “blueprint” object (like the die above) and then randomizes it to set new values.

A key concept is that you need to provide a default blueprint, and then give the user a way to replace it with a new type. For example, the following bad generator builds only one type of transaction that you can’t change - can you see why?

class Bad_Generator;
  AXI_TR tx;              // Handle to an AXI transaction
  task run();
    repeat(5) begin
      tx = new();         // Construct object
      if (!tx.randomize()) $fatal(...);
      $display("%p", tx); // Print the transaction
    end
  endtask
endclass

The problem with this generator is that it constructs an AXI_TR object and immediately randomizes it. What if you want to extend the AXI_TR class to make AXI_TR_ADDR and add a new constraint that set the address to a fixed value? There is no way to inject an AXI_TR_ADDR object in the middle of that run() task between new() and randomize().

The secret is to separate where you construct the object from where you randomize it. Also, following the idea of a steel stamping machine, you are going to start with a die (the blueprint), then stamp out a copy (“clone the blueprint object”), then paint it (randomize the object).


class Generator;
  AXI_TR blueprint, tx;

  function new();
    blueprint = new();        // Construct a default blueprint object
  endfunction

  task run();
    repeat(5) begin
      tx = blueprint.clone(); // Clone the blueprint object
      if (!tx.randomize()) $fatal(1, "randomize() failed");
      $display("%p", tx);     // Print the transaction
    end
  endtask
endclass

When the Generator object is constructed, it constructs an AXI_TR object and store the handle in blueprint. The run() task then makes 5 copies of this default object, randomizes them and sends them out. This generator is instantiated in an test class. Details are in my book, and not shown here.


class Test;
  Generator gen;
  function new();
    gen = new();
  endfunction

  task run();
    gen.run();
  endtask
endclass

Finally, the test class is constructed and run in a top module.


module top;
  Test t;
  initial begin
    t = new();
    t.run();
  end
endmodule

What is in the AXI_TR class? Here is some very simple code. The copy() and clone() methods are described in my book, and any good SystemVerilog / UVM / OVM / VMM course.


class AXI_TR;
  rand bit [7:0] addr, data;

  virtual function void copy(AXI_TR rhs); // "right-hand side"
    this.addr = rhs.addr;
    this.data = rhs.addr;
  endfunction

  virtual function AXI_TR clone();
    clone = new();
    clone.copy(this);
  endfunction
endclass

How can inject a new flavor of transaction into the generator? Just like with the sign example, make a new die pattern and put it into the stamping machine.


class AXI_TR_ADDR extends AXI_TR;
  constraint FIXED_ADDR_100
    {addr == 100; }

  virtual function AXI_TR_ADDR clone(); // Note return type!
    clone = new();
    clone.copy(this);
  endfunction

endclass

Write a new test that replaces the default blueprint with this one.


class Test_ADDR extends Test;
  task run();
    AXI_TR_ADDR tx_addr = new();
    gen.blueprint = tx_addr;
    gen.run();
  endtask
endclass

Lastly, run this test in a new top module:


module top_addr;
  Test_ADDR t;
  initial begin
    t = new();
    t.run();
  end
endmodule

The key concept is that the Generator class remains the same, yet can produce new types of transactions, that are injected by the test. The Generator follows the “blueprint” software pattern.

Run two simulations - one with the AXI_TR, Generator, and Test classes plus top module. This will have random addresses. Next run a second simulation with those classes plus AXI_TR_ADDR, Test_ADDR, and swap top for top_addr module. This one will only have addr:100

Thank you to Janick Bergeron and others who showed me this technique, and my readers who suggested better ways to show these concepts.

  • Chris Spear

Thank you ben and Chris. This clears my doubt. Also Chris, I am very glad that you replayed to me

In reply to chrisspear:

Cannot understand why Bad_Generator code is not working…

class Test;
  Bad_Generator gen;
  //Generator gen;
  
  AXI_TR_ADDR tx_addr;
    
  function new();
    
    gen = new();
    gen.tx = tx_addr; /// <- here we overried the original AXI_TR with AXI_TR_ADDR
                      // So AXI_TR_ADDR constraint should work FIXED_ADDR_100. But NO
                      // WHY??
  endfunction
 
  task run();
    gen.run();
  endtask
enclass 

In reply to haykp:

Use the Generator class as it has a gap between when it constructs the object and then uses it. The blueprint object is constructed in new(), then cloned in run(), allowing you to replace it between those two methods. You can see this in Test_ADDR which constructs AXI_TR_ADDR, assigns it to gen.blueprint, then calls gen.run(). Now when the the Generator clones the blueprint, it is making copies of an AXI_TR_ADDR object.

The problem with the Bad_Generator is that it constructs the object and immediately uses it, so there is no way to inject a different one. Don’t use the Bad_Generator class.