Transactor generator with VMM technology for efficient usage of CPU resources.
Posted by Oded Edelstein on 5th April 2010
Oded Edelstein – Founder and CEO of SolidVer
Background:
Many network designs require an efficient transactor generator
to cover DUT functionality.
In a random test we would like to cover all scenarios,
but also to use the CPU mostly on cases which push the design to its edge.
In this VMM example, I will demonstrate 3 cases, and solutions for a better
usage of CPU resources.
Cases:
Case A – In network designs packet size can vary between 40 Bytes, for small packets
and 10KBytes, for large MTU packets.
A test which is based on the number of packets(Transactions), might be very short
or very long depends on the total size of packets. The long tests scenarios can
be covered in a separate random test.
Case B – Some network designs forward packets to different channels(queues) with
different levels of bandwidth support. Random generation of channel
number does not cover many cases (e.g. filling a certain queue with packets),
since the probability that the same channel will be chosen one after the other,
in a system with many channels is very low.
Case C – In some projects, the transactor generates many packets to all queues
while some queues are randomly configured to a low bandwidth. This causes the
test to be very long, until all packets are being forwarded.
At the beginning of the test, the DUT is very busy – almost every cycle, it gets data.
But after the high bandwidth queues got all packets, the low bandwidth queues
continue slowly to get packets, until all packets have been forwarded.
Now, most of the DUT queues are empty and the DUT is using only a small
portion of its performance ability. That has no added value for coverage.
Solutions:
The following code example, shows a simple solution for the above cases.
The solution is based on the following techniques:
1. Test length is defined based on sum of packets size, instead of the number of
packets(transactions).
2. Add the random test a basic case where a number of packets are send to the same channel
one after the other.
Low probability cases need to be identified and added as case inside
the random test (cases inside directed tests are not good enough for a good coverage).
3. No packets are generated in advance for all queues.
Packets are randomly generated and driven, on the fly, only to available queues.
From my experience, random tests can generate all parameters, and a good coverage can be achieved.
At the same time, a much better coverage can be achieved if idle periods, which consume
CPU during the test are identified and handle correctly.
Code Example:
//——————————————————————————————————
//
// packet.sv
//
//——————————————————————————————————
class packet extends vmm_data;
rand byte payload[];
rand int packet_size;
rand int channel_num;
static int cnt;
constraint c_payload_size { payload.size == packet_size; }
constraint c_pkt_size_dist { packet_size dist { 40:= 20,
[41:200]:= 50,
[200:2000]:= 5,
[2000:10000]:= 1,
10000 := 1};}
`vmm_data_member_begin(packet)
`vmm_data_member_scalar_array(payload, DO_ALL)
`vmm_data_member_scalar(packet_size, DO_ALL)
`vmm_data_member_scalar(channel_numm, DO_ALL)
`vmm_data_member_end(packet)
endclass : packet
//—————————————————————————–
// VMM Macros – Channel and Atomic Generator
//—————————————————————————–
`vmm_channel(packet)
`vmm_atomic_gen(packet, “Packet atomic generator”)
//——————————————————————————————————
// End file packet.sv
//——————————————————————————————————
//——————————————————————————————————
//
// bfm_master.sv
//
//————————————————————————————————————
//
// SUM_PACKETS_SIZE_IN_TEST : The sum of packets size in bytes that the BFM will drive the DUT.
// We used sum of packets size, to define test length, instead of number of packets, since packet
// size distribution could randomly vary between 40 bytes (small packets) – 10KByes (Large MTU packets).
// This could cause for some seeds to be very long, with no significant added value for coverage.
// These long scenarios were tested in a separate random test.
//
`define SUM_PACKETS_SIZE_IN_TEST 10000000 // 10MB
//
// In this example The DUT gets a packet with a channel number.
// The DUT holds a sperate FIFO for every channel.
//
`define MAX_NUMBER_OF_CAHNNELS 16
class bfm_master extends vmm_xactor;
vmm_log log;
// Packet Transaction channels
//
packet_channel packet_chan;
//
// The DUT will send the BFM back pressure signal, separately for every channel,
// when the channel FIFO, inside the DUT is full.
// avail_channel_list – Holds a bit for every channel, The BFM can drive packets only on channels
// which are not back pressured.
//
bit [(`MAX_NUMBER_OF_CAHNNELS-1):0] avail_channel_list;
int done = 0;
extern function new (string instance,
integer stream_id,
packet_channel packet_chan);
extern function int generate_stream_size();
extern function int generate_avail_channel();
extern virtual task main();
extern virtual task drive_packet(packet packet_trans);
endclass: bfm_master
function bfm_master::new(string instance,
integer stream_id,
packet_channel packet_chan);
super.new(“BFM MASTER”, instance, stream_id);
log = new(“BFM MASTER”, “BFM MASTER”);
if (packet_chan == null) packet_chan = new(“BFM MASTER INPUT CHANNEL”, instance);
this.packet_chan = packet_chan;
endfunction: new
//—————————————————————————–
// main() – Main task for driving packets.
//—————————————————————————–
task bfm_master::drive_packet(packet packet_trans);
// drive the packet …
endtask: drive_packet
function int bfm_master::generate_avail_channel();
….
endfunction
function int bfm_master::generate_stream_size();
….
endfunction
task bfm_master::main();
//
// The sum of packets that the BFM will drive the DUT. when this value is
// above SUM_PACKETS_SIZE_IN_TEST the BFM will stop driving packets
//
int sum_packet_data_sent = 0;
//
// The channel on which the DUT will drive packets. This channel should not be back pressured
// while driving packets
//
int channel_num;
//
// packet_stream_size
// The number of packets that will be sent one after the other to the same channel.
// The idea behind this variable is to get a good coverage for cases where number
// of packets are sent to the same channel one after the other, to quickly fill the FIFO.
// Otherwise the BFM will generate statistically every time, a different
// channel. The probability that the same channel will be generated one after the other
// is very low. e.g. Statistically the probability that the same channel will be
// generated 5, 10, or 20 times, one after the other, is 16 power 5, 16 power 10 or
// 16 power 20, which is a very low probability.
//
int packet_stream_size;
// Counter for the number of packets that were driven in the test.
//
int packet_cnt = 0;
int i;
packet packet_trans;
super.main();
while(sum_packet_data_sent < `SUM_PACKETS_SIZE_IN_TEST) begin
// gen random channel from avail_channel_list;
channel_num = generate_avail_channel();
packet_stream_size = generate_stream_size();
for(i = 0; i < packet_stream_size; i++ ) begin
this.wait_if_stopped_or_empty(this.packet_chan);
if(avail_channel_list[channel_num] == 1) begin
packet_chan.get(packet_trans);
packet_trans.channel_num = channel_num;
drive_packet(packet_trans);
sum_packet_data_sent = sum_packet_data_sent + packet_trans.packet_size;
packet_cnt++;
`vmm_note(log, $psprintf(“drive packet = %0d size = %0d channel = %0d stream index = %0d sum = %0d “,
packet_cnt, packet_trans.packet_size, channel_num, i, sum_packet_data_sent));
end
else begin
break;
end
end // for loop
end// end while loop
done = 1;
endtask: main
//——————————————————————————————————
//
// End file bfm_master.sv
//
//——————————————————————————————————
Posted in Automation, Modeling, Optimization/Performance | 1 Comment »
JL Gray

Srinivasan Venkataramanan, CVC