ASIC Verification: September 2008

Monday, September 29, 2008

Writing test cases using sequences

The simplest way to write a test case is to redefine the behavior of the MAIN sequence by overriding the body() TCM. This is sufficient to create the test case, because the MAIN sequence is started automatically.

extend MAIN usb_sequence_s {
body()@driver.clock is only {

do usb_transaction_s keeping {
.pid == SETUP};
}; // End of do
}; // End of body()
}; // End of MAIN

To create a simple test based on the sequence library is to choose a subset that will be activated in the specific test and then set the weights for each kind using keep soft select.


Tuesday, September 23, 2008

Sequence Implementation

How to implement the various scenarios using the sequence struct?
  • The items and sub-sequences are created inside the pre-defined TCM called "body()" - used to define the behavior of the sequences - using the dedicated "do" action.
  • The body() TCM inside the MAIN sequence is launched automatically by the run() method inside the sequence driver.
  • The body() TCM of any sub-sequence is activated by the "do" action.
  • The body() TCM defines the duration of the sequences.
  • When "do"ing an item, you must emit the event driver.item_done to let the sequence complete the "do" action and inform the driver that the item was processed. Without emitting this event, the sequence cannot continue, and the driver cannot drive more items.
  • The do action can only be activated inside sequences.
How to create the sequence library?

Once you define the sequence struct, you can create various scnearios by creating the sub types of the sequences using kind field.

1. Extend the sequence kind type with the new kind

extend usb_transaction_kind_t : [ SETUP];

2. Extend the new sequence sub type of the kind with either parameters or body().

// SETUP Transaction
extend SETUP usb_sequence_s {
body()@driver.clock is {
do sequence_items keeping {
// The "do sequence_items" will wait until the driver.get_next_item is called and will be
// completed once the driver. packet_done is emitted. Hence the "do sequence_items" and
// driver.get_next_item work in tandem
.pid == SETUP;
}; // End of body()
}; // End of extend

// OUT Transaction
extend usb_transaction_kind_t : [ OUT];
extend OUT usb_sequence_s {
body()@driver.clock is {
do sequence_items keeping {
.pid == OUT;
}; // End of body()
}; // End of extend

// IN Transaction
extend usb_transaction_kind_t : [ IN];
extend IN usb_sequence_s {
body()@driver.clock is {
do sequence_items keeping {
.pid == IN;
}; // End of body()
}; // End of extend

In the next post, we will see how to write the test cases using sequences.

Monday, September 22, 2008

Sequences in Specman

What are the sequences in Specman? What are the significance of sequences? This post explains the way of implementing the sequences in specman.

Introduction: Sequences let you define the streams of data items sent over to the input protocol of the DUT. Before moving on to the details of sequences, let me give you some of the important definitions.

Item : It is a struct that represents the main inputs to the DUT - Basically a USB packet or an CPU instruction.

Sequence : It is a struct that represents the streams of data items generated one after another according to some protocol, say for example, in USB - Out or setup packet is transferred followed by Data packet.

Sequence driver : The SD acts as an agent b/w sequences and the Bus Functional Model (BFM). Basically, a SD takes the generated data items and pass it on to the BFM which in turns convert all your high level data items (Packets or Instruction) into low level data items (bits and bytes).

Basically a TCM which resides in the BFM does the actual transmission of data items. Both the sequence driver and BFM acts as a pair; The sequence driver serves as the interface upward towards the sequnces and the BFM serves as the interface downward towards DUT. Therefore the Sequence driver only interacts with BFM for the purpose of driving data item into the DUT.

How to use sequences?

1. Define the sequence item struct - For an item to be used with sequences, it must have some common functionality.

type usb_pid_t : [SETUP = 0xD, OUT = 0x1 , IN = 0x9];

// Create the sequence item
struct usb_transaction_s like any_sequence_item {
dev_addr : uint (bits : 7);
ep_num : uint (bits:4);
pid : usb_pid_t;
data : list of uint (bits : 8);
};

2. Define the sequence and its driver using the sequence statement

// Define the sequence
sequence usb_sequence_s using

item = usb_transaction_s,
created_driver : usb_transaction_driver_u; // Name of the driver
created_kind : usb_transaction_kind_t; // Various sub types for the sequence

3. Hook up the sequence driver to the environment

Have a BFM that knows how to drive the USB packet to the DUT.

unit usb_bfm {

event usb_clk is rise ('usb_clk_30') @ sim;
drive_packet ( packet : usb_transaction_s) @ usb_clk is {
-------
------
}; // End of drive_packet TCM
}; // End of unit usb_bfm

The BFM is instantiated in the Agent

extend usb_bfm {
driver : usb_transaction_driver_u; // Reference to the sequence driver in the BFM
};

unit usb_agent {
bfm : usb_bfm is instance; };

extend usb_agent {
driver : usb_transaction_driver_u is instance;
keep bfm.driver == driver;
};

connect the pre-defined clock to the BFM clock

extend usb_bfm {
on usb_clk { emit driver.clock }; };

Pull item from driver, process it and inform through done
Instantiate the driver into the Agent

extend usb_bfm {
execute_items () @ clock is {

var sequential_items : usb_transaction_s;
while (TRUE) {
sequential_items = driver.get_next_item();
drive_packet (sequential_item);
emit driver.packet_done;
}; // End of while loop
}; // End of execute_item TCM

run() is also {
start execute_items ();
}; // End of run method
}; // End of usb_bfm

In the next post, we will see how to implemet the sequence library and how to write the test case s using the sequences.


Saturday, September 20, 2008

Increase the operational speed of the circuit

There are numerous design techniques exists to increase the speed of the digital circuit. These design techniques are implemented automatically during synthesis. It also involves the trade-off between the area and speed, means that you have to pay for more area in order to achieve a speed.
  1. Use And-Or-Invert or Or-And-Invert gates wherever possible, since they are economical particularly for both area and speed.
  2. Feed the late arriving signals in your design late into the combinatorial circuit to balance the total gate delay along each path of the combinatorial circuit. To know more about late arriving signals, please go thorough it here.
  3. Use a maximum of 2 inputs on all combinatorial circuits in your design. For example, you can use two numbers of 2 input NAND gates and a 2 input NOR gate instead of using a 4 input AND gate.
  4. The bottom line is, if a boolean function with more than 2 inputs are decomposed into several simple gates, which results in more gates for the same function; but the total delay is reduced. According to the gate delay model, an N-input AND gate contains a branch with N transistors in series, resulting in an increased internal resistance of N*delta. Furthermore, the parasitic capacitance is also increased; therefore the internal delay of an N input AND gate is N(square)*delta. So if the NAND gate with 6 inputs is not decomposed, the internal delay will be rougly 0.7 ns as opposed to 0.42 ns with decomposition.
  5. Use Johnson counters instead of binary counters.
  6. An n-stage johnson counter produces a set of outputs of length 2n, which can be decoded to give a count sequence. The advantage of using this counter is that, having no combinatorial logic between flip-flops, it can be run at the maximum speed permitted by setup and hold time constraints. The disadvantage of a johnson counter is that, for a required count of m, it requires m/2 flip-flops, rather than log2(m) as required by a synchronous binary counter.


Thursday, September 4, 2008

Verilog questions

1. Is this a valid, synthesizable, use of a for loop?

module for_loop();

reg [8:0] A, B;
integer i;
parameter N=8;
always@(B)
begin
for (i=1; i<=N; i=i+1)
A[i-1]=B[i];
A[N] = A[N-1];
end
endmodule

2. Assuming the code above is synthesizable, Which of the following continuous assignment statements would have the closest meaning?

A. assign A = B << 1;
B. assign A = B <<< 1;
C. assign A = B >> 1;
D. assign A = B >>> 1;

3. If the following logic is built exactly as described, which test vector sensitizes a stuck-at-0 fault at "e" and propagates it to the output "g".

module (a, b, c, d, e, f, g);
input a, b, c, d;
output e, f, g;

assign e = a & b;
assign f = c ^ e;
assign g = d | f;

endmodule

A. {a, b, c, d} = 4’b0010;
B. {a, b, c, d} = 4’b1100;
C. {a, b, c, d} = 4’b1111;
D. {a, b, c, d} = 4’b0101;
E. None of the above

4. Consider the following two test fixtures.

// Fixture A
parameter delay1 =
parameter delay2 =
initial
begin
B = 1’b0;
#20 A = 1’b1;
#delay1 A = 1’b0;
#delay2 B = 1'b1;
end

// Fixture B
initial
fork
B = 1’b0;
#20 A = 1’b1;
#40 A = 1’b0;
#60 B = 1’b1;
join

For these two fixtures to produce the same waveforms, delay1 and delay2 have to be set
as follows:

A. delay1 = 40; delay2 = 60;
B. delay1 = 30; delay2 = 20;
C. delay1 = 30; delay2 = 30;
D. delay1 = 20; delay2 = 20;
E. None of these are correct

5. In verification, most of the effort should be applied at the system (complete chip) level. Which of the following statements gives the best reason as to why?

A. Most of the bugs in a design are in the netlist wiring it together.
B. Most of the bugs in a design are due to poorly understood interactions between different modules.
C. This is the fastest way to verify the individual modules that make up the design.
D. Most of the bugs in a design occur because of poorly designed interfaces, e.g. buses.
E. None of the above are remotely a good reason.

6. Consider the following specify block:

specify
specparam A0spec = 1 : 2 : 3;
specparam A1spec = 2 : 3 : 4;
(a => b) = (A0spec, A1spec);
endspecify

This is defining the following:

A. Rising, falling and steady delay from input a to output b of 1, 2, and 3 ns respectively when a is 0, and 2, 3, and 4 ns when a is 1.
B. Minimum, typical and maximum delay from input a to output b of 1, 2, and 3 ns on a rising edge at B, and 2, 3 and 4 ns on a falling edge.
C. Non-blocking assignment of a to b with minimum, typical and maximum delay of 1, 2 and 3ns.
D. Setup time requirements for the flip-flop with output B.