Abstract:
A network layer verification mechanism (NLVM) is inserted between DUTs or between a DUT and the test bench components in order to simulate conditions that can occur in a packetized network connection, such as dropped packets, duplicate packets, corrupted packets out-of-order packets and delayed packets. The NLVM has internal storage and an application programmer interface (API) which can be driven by the test bench and comprises a plurality of methods that allow packets received by the NLVM to be selectively forwarded through the object, temporarily stored in the object or the packet data to be corrupted. The NLVM is implemented as an object with an interface that is independent of the simulation configuration so that verification test benches and tests can be written with no reliance on bus functional models and environment-specific details.

Description:
FIELD OF THE INVENTION  
         [0001]    This invention relates to verification and testing of hardware design simulations, and, in particular, to the construction of automated test benches for verifying hardware designs simulated with convention HDL languages.  
         BACKGROUND OF THE INVENTION  
         [0002]    Modern electronic circuits are increasingly being fabricated with Application Specific Integrated Circuits (ASICs), which are chips that contain custom designed circuits. Increasing chip complexity and size, combined with the rapidly changing technologies and very short time-to-market windows requires that circuitry be designed and tested rapidly. Typically, circuits are designed using computer simulations that model the circuits and permit them to be tested before the circuit is actually committed to fabrication.  
           [0003]    Computer simulations are performed using a Hardware Description Language (HDL) to conceptually model the circuit. The HDL is a text format for describing the inputs, outputs and behavior of electronic circuits and systems. When the HDL text is compiled by a simulation tool, the result is a computer circuit model that performs according to the HDL description. The computer circuit model can be used for verification of the circuit operation through simulation, for timing analysis, for test analysis (testability analysis and fault grading) and for logic synthesis.  
           [0004]    There are several standard HDLs presently in wide use that can be used to simulate electronic circuits. Two of the most popular are Verilog and VHDL. The Verilog HDL is defined by IEEE standard No. 1364 that includes a document known as a language reference manual. This document provides a complete and authoritative definition of the Verilog HDL. IEEE Standard 1364 also defines a programming language interface that is a collection of software routines that permit a bi-directional interface between Verilog and other languages. In the description that follows, the Verilog HDL will be used as an example. However, it would be understood by those skilled in the art that other conventional HDL languages could be used without departing from the spirit and scope of the invention.  
           [0005]    The Verilog HDL can be used to model the circuit being tested, typically called the “design under test” or DUT from a set of design specifications. The model can be specified at a module level with low-level binary operators in a continuous assignment or at a higher conceptual level called a register transfer level (RTL.) When the design is described at using RTL statements, the Verilog code describes how data is transformed by pure combinatorial logic as it passes between conceptual registers.  
           [0006]    Verilog can also be used to generate a testing circuit, called a “test bench” that can generate stimulus patterns which, in turn, can be used to test the DUT. Generally, the DUT simulation and the test bench for that DUT are designed together from the same specifications so that the test bench generates a stimulus pattern specifically for the particular DUT, called a “test scenario”, that mimics all possible real world signal combinations and verifies that the operation of the DUT is correct under all conditions. The test bench also receives outputs generated by the DUT and displays or stores the outputs for later analysis by the circuit designers.  
           [0007]    Often different teams of designers are used for the DUT and the test bench so that the test bench designers have the opportunity to generate test scenarios without a bias introduced by the design effort in designing the DUT. However, the design of a test bench can be just as difficult and time consuming as the design of the DUT. Because HDL was created to model a DUT and not a test bench, it lacks some features that make it efficient for designing test benches. Consequently, designers had been forced to resort to a complicated mixture of HDLs and other languages, such as C, C++ and Perl to create verification code. Consequently, the verification process that was once a minor part of the development cycle was becoming a major part of the design effort.  
           [0008]    Consequently, conventional tools have been developed in order to simplify the test bench design task and reduce the time necessary to completely design a test bench. These tools generally use a specialized hardware verification language (HVL) that has been specifically designed to quickly model test benches. Some verification tools have additional features, such as the ability to automatically monitor results generated by the DUT and the ability to generate additional tests based on the information gathered from the DUT operation.  
           [0009]    Although these automated test bench tools often provide significant advantages in the test and verification of simulated circuits, there are still problems remaining. For example, while the tools provide adequate features and functionality for testing DUTs in isolation, in situations where several DUTs that are connected together, for example by a network, must be tested, the conventional test bench tools cannot adequately control the signals passing between DUTs.  
           [0010]    In addition, test benches developed with the tools are still tightly coupled to the precise simulation for which they were designed, thereby limiting the reusability of the test bench code.  
           [0011]    Therefore, there is a need to enhance existing verification system tools in order to provide the capability of simulating and controlling network layer connections and for providing increased test bench code reusability.  
         SUMMARY OF THE INVENTION  
         [0012]    In accordance with the principles of the present invention, a network layer verification mechanism (NLVM) is inserted between DUTs or between a DUT and the test bench components. The NLVM has internal storage and can be controlled to simulate conditions that can occur in a packetized network connection, such as dropped packets, duplicate packets, corrupted packets and out-of-order packets. The NLVM also has an application programmer interface (API) that can be driven by the test bench and that is independent of the simulation configuration. In this manner, code reuse is promoted.  
           [0013]    In one embodiment, the NLVM is implemented as a specialized object written in an HVL. The object includes internal storage in the form of an associative array and a plurality of methods that allow packets received by the object to be selectively forwarded through the object, temporarily stored in the object or the packet data to be corrupted.  
           [0014]    In another embodiment, the methods in the specialized object form an interface that is independent of the simulation configuration so that verification test benches and tests can be written with no reliance on bus functional models and environment-specific details. 
       
    
    
     BRIEF DESCRIPTION OF THE DRAWINGS  
       [0015]    The above and further advantages of the invention may be better understood by referring to the following description in conjunction with the accompanying drawings in which:  
         [0016]    [0016]FIG. 1 is a block schematic diagram of a conventional test bench connected to a design under test.  
         [0017]    [0017]FIG. 2 is a block schematic diagram of a conventional test bench connected to two interconnected designs under test.  
         [0018]    [0018]FIG. 3 is a block schematic diagram of a test bench connected to two interconnected designs under test and utilizing two NLVMs in accordance with the principles of the invention.  
         [0019]    [0019]FIG. 4 is a block schematic diagram of a test bench connected to a single design under test that also utilizes an NLVM in accordance with the principles of the invention.  
         [0020]    [0020]FIG. 5 is a schematic diagram of the details of an NLVM.  
         [0021]    [0021]FIG. 6 is a flowchart illustrating the steps in a process performed by an NLVM in creating a dropped packet condition.  
         [0022]    [0022]FIGS. 7A and 7B, when placed together, form a flowchart illustrating the steps in a process performed by an NLVM in creating an out-of-order packet condition.  
         [0023]    [0023]FIGS. 8A and 8B, when placed together, form a flowchart illustrating the steps in a process performed by an NLVM in creating a duplicate packet condition.  
         [0024]    [0024]FIGS. 9A and 9B, when placed together, form a flowchart illustrating the steps in a process performed by an NLVM in creating a corrupted packet condition.  
     
    
     DETAILED DESCRIPTION  
       [0025]    As previously mentioned, in order to ensure that a simulated hardware design is functionally correct, tests are written to verify that the simulated hardware design behaves as specified. To accomplish this, the tests apply a stimulus to the DUT simulation, and subsequently check the response of the DUT.  
         [0026]    A conventional ASIC verification environment  100  may be similar to that shown in FIG. 1. It consists of a test bench framework  102  that is being used to verify the operation of a design under test  106 . In this arrangement, the DUT  106  is an RTL model of a particular hardware circuit. As an illustrative example, the circuit to be tested could be an InfiniBand SM  host channel adapter and the DUT  106  might be an RTL model of the hardware portion of the host channel adapter implementing the transport layer and link layer protocols of the specification. The host channel adapter construction and the transport and link layer protocols are described in detail in the InfiniBand Specification Rev 1.0, The InfiniBand SM  Trade Association (2000) which specification is incorporated by reference herein in its entirety. The host channel adapter is used for exemplary purposes only and those skilled in the art would realize that other circuits and designs could be tested using the principles of the invention.  
         [0027]    In order to verify the operation of one or more DUTs  104 , tests are written and executed. The tests can be thought of as abstractions that can be realized by a number of components. In the example illustrated in FIG. 1, these components include the testbench framework  102  and a test scenario  110 .  
         [0028]    The testbench framework  102  is a code base composed of common functions and routines, which facilitate the generation of stimuli  106  and the comparison of the response  108  of the DUT  104  to an expected response. As previously mentioned, the testbench framework  102  can be designed using conventional tools that are optimized for designing testbenches. These conventional tools include the VERA™ System Verifier developed and marketed by Synopsis, Inc., 700 East Middlefield Road, Mountain View, Calif. 94043. The VERA testbench automation system is based on VERA hardware verification language (HVL) that is a high-level, object-oriented programming language developed specifically to meet the unique requirements of functional verification. The VERA system can be used to develop self-checking test benches that automatically generate reactive tests. The VERA system allows verification designers to model the target environment at a high level of abstraction, essentially creating a virtual prototype. From this environment, VERA can automatically generate self-checking tests that mimic the “real-life” stimulus. During simulation, the VERA system monitors coverage points in the simulated design and uses the results to dynamically generate new tests to cover untested areas. In the discussion below, the VERA system will be used for exemplary purposes. However, those skilled in the art would realize that other conventional verification systems could also be used without departing from the spirit and scope of the invention.  
         [0029]    The testbench framework  102  is driven by the test scenario code  110 . The test scenario code  110  controls the testbench framework  102  to generate a set of stimuli  106  that test selected functional areas of the design. A complete verification process may consist of running a large number of test scenarios to provide a high coverage of the total design functionality. The test scenario  110  can also be designed on the aforementioned VERA verification system in a conventional manner.  
         [0030]    In some cases it is necessary to generate stimuli  106  which mimic the behavior of a network in order to test the response of a design to various conditions that occur in design layers that interface with the network. For example, these conditions include dropped data packets, out-of-order data packets, duplicate data packets, corrupted data packets and delayed data packets (increased packet latency). In a standalone environment with a single ASIC, such as that illustrated in FIG. 1, these conditions may be created by the testbench  102  operating under control of an appropriate test scenario  110 .  
         [0031]    However, some simulation configurations require that two DUTs that are interconnected by a network be simultaneously tested and verified. Such an arrangement  200  is shown in FIG. 2. For example, such a simulation may be used to test the network and link layers in two InfiniBand SM  host channel adapters  204  and  205  which are connected by a network  212 . In a multi-chip environment such as shown in FIG. 2, the testbench framework  202  operating under control of the test scenario  210 , can generate stimuli  206  and receive responses  208  from the DUTs  204  and  205 , but it would not be possible to create conditions that occur at the InfiniBand SM  network and link layers, such as dropped packets, out-of-order packets, duplicate packets, corrupted packets and delayed packets with the testbench framework  202 .  
         [0032]    In accordance with the principles of the invention and as shown in FIG. 3, the simulation configuration shown in FIG. 2 is modified to include two network layer verification mechanisms (NLVMs)  316  and  318 . Components in FIG. 3 that correspond to those in FIG. 2 have been given corresponding numeral designations. For example, DUT  304  in FIG. 3 corresponds to DUT  204  in FIG. 2. As with the configuration illustrated in FIG. 2, the testbench framework  302  operating under control of the test scenario  310  can generate stimuli  306  and receive responses  308  from the DUTs  304  and  305 . The NLVMs  316  and  318  provide the ability for the testbench framework  302  and the test scenario  310  to create the conditions that occur in the network, for example, at the InfiniBand SM  network and link layer layers, including dropped packets, out-of-order packets, duplicate packets, and corrupted packets.  
         [0033]    In particular, NLVM  316  is inserted in one network direction and NLVM  318  is inserted in the return direction. NLVM  316  receives data packets from DUT  304  as schematically indicated by arrow  312  and selectively transmits data packets to DUT as schematically indicated by arrow  324 . Similarly, NLVM  318  receives data packets from DUT  305  as schematically indicated by arrow  326  and selectively transmits data packets to DUT  304  as schematically indicated by arrow  314 . As discussed in detail below, NLVM  316  operates under commands generated by testbench framework  302  that are indicated schematically by arrow  320  and NLVM  318  operates under commands generated by testbench framework  302  that are indicated schematically by arrow  322 . In a preferred embodiment, these commands are API calls.  
         [0034]    Some advantages can also be gained by using an NLVM in a standalone ASIC environment. The standalone environment with the single InfiniBand SM  host channel adapter ASIC is shown in FIG. 4 wherein components that correspond to those in FIGS. 2 and 3 have been given corresponding numeral designations. Rather than having two host channel adapters  304 ,  305  as illustrated in FIG. 3, one host channel adapter  305  has been replaced by a verification component  407 . The new component  407  is called an InfiniBand SM  link layer transactor  407 . The code that simulates the transactor  407  receives data packet structures as described by the test scenario  410  and drives the proper data symbols as stimulus to the DUT  404 . By using the transactor component  407 , the test scenarios  410  can target the finer grain functionalities of the InfiniBand SM  Link layer protocol. As depicted in this diagram, NLVM  416  is inserted in one network direction and NLVM  418  is inserted in the return direction. NLVM  416  receives data packets from DUT  404  as schematically indicated by arrow  412  and selectively transmits data packets to transactor  407  as schematically indicated by arrow  424 . Similarly, NLVM  418  receives data packets from transactor  407  as schematically indicated by arrow  426  and selectively transmits data packets to DUT  404  as schematically indicated by arrow  414 . As discussed in detail below, NLVM  416  operates under commands generated by testbench framework  402  that are indicated schematically by arrow  420  and NLVM  418  operates under commands generated by testbench framework  402  that are indicated schematically by arrow  422 . In a preferred embodiment, these commands are also API calls.  
         [0035]    As shown in FIG. 4, NLVMs  416  and  418  can be used in the single ASIC environment to create the InfiniBand SM  network layer conditions, requiring little or no change in the testbench framework  402  or test scenarios  410  from the multi ASIC environment shown in FIG. 3 for creating these conditions. Thus, the testbench code can be reused.  
         [0036]    Each NLVM is an object that is instantiated from a VERA™ HVL class. The following is a simplified class definition of an exemplary NLVM:  
         [0037]    class NetworkLayerVerificationMechanism { 
         [0038]    local lbPacket ib 13 packet_array[ ];  
         [0039]    event packet 13 ingress_event;  
         [0040]    // enable/disable auto packet forwarding  
         [0041]    task enable_auto packet_forwarding( );  
         [0042]    task disable_auto_packet_forwarding( );  
         [0043]    // storing, immediate forward, and transmit stored packets  
         [0044]    function integer store_ingress_packet( );  
         [0045]    task transmit_ingress_packet( );  
         [0046]    task transmit_stored_packet(integer packet_handle);  
         [0047]    // retrieving packets at the ingress and stored packets  
         [0048]    function IbPacket get_ingress_packet( );  
         [0049]    function IbPacket get_stored_packet(integer packet_handle);  
         [0050]    function integer remove_stored_packet(integer packet_handle);  
         [0051]    function integer modify_stored_packet(integer packet_handle, lbPacket packet);  
         [0052]    // returning header information about current packet at ingress  
         [0053]    function integer get_ingress packet_vl( );  
         [0054]    function integer get_ingress_packet_dest_qp( );  
         [0055]    } 
         [0056]    [0056]FIG. 5 shows a schematic view of an NVLM object  500 . This particular object has been designed to create the aforementioned InfiniBand SM  network and link layer condition, but those skilled in the art would recognize that other network layer conditions could easily be simulated with a similar object. The object has a packet ingress section  502 , a processing section  504  and a packet egress section  506 . A preferred embodiment of the invention uses a VERA™ associative array as an IB packet array  526  to store a data packet for later transmission. When a packet arrives at the ingress section  502 , the store_ingress_packet( ) function  520  can store the packet in the array  526  for later transmission or retransmission. An event  528  indicates when there is a packet in the ingress section  502 . This event  528  is triggered by the NLVM when the complete packet has gone through the ingress section. Accordingly, this operation creates a start up time cost, as a packet will not egress from the NLVM until the complete packet has arrived at the ingress section  502 . However, after the first packet has arrived, packets can be pipelined so that, as packets arrive at the ingress section, other packets are forwarded to the egress section  506  simultaneously. However, if there are packet size differences, then there will be added latency. In addition, latency will be introduced as packets are stored and later retransmitted, if the packets should be immediately forwarded to the egress section  506 .  
         [0057]    Automatic packet forwarding can also be enabled as indicated schematically by arrow  510 , which cause the transmit_ingress_packet( ) function  514  to immediately forward packets to the egress section  506  as the packets arrive at the ingress section  502 . To enable automatic packet forwarding, the enable_auto_packet_forwarding( ) task would be invoked. Invoking the disable_auto_packet_forwarding( ) task  512  would disable the function.  
         [0058]    Two functions  534  and  536  are provided to obtain information about a packet that has arrived at the ingress section  502 , which may be used, for example, to make a decision to forward or store the packet. The get_ingress_packet_vl( ) is used to obtain the virtual lane number and the get_ingress_packet_dest_qp( ) function obtains the destination queue pair number. If a packet that has arrived at the ingress section  502  is to be immediately forwarded, and assuming that automatic packet forwarding is disabled, then the transmit_ingress_packet( ) function  514  must be invoked. If the transmit_ingress_packet( ) function  514  is not invoked a dropped packet condition is created.  
         [0059]    Alternatively, if the packet is to be stored, the store_ingress_packet( ) function  520  is invoked. This latter function returns a “packet handle”, which is a unique identifier used to retrieve the packet at a later time. The packet is stored in the associative array  526 . Both the store_ingress_packet( ) function  520  and the transmit_ingress_packet( ), function can be invoked on the same ingress packet. This double invocation has the effect of storing the packet as well as immediately forwarding the packet. This operation may be used to create duplicate packets.  
         [0060]    A stored packet may be transmitted by invoking the transmit_stored_packet(packet_handle) function  528 . When this function is invoked, the packet handle must be supplied through the task parameter list. The store_ingress_packet( ) function  520  and the transmit_stored_packet(packet_handle) function  528  can be used together to introduce a varying amount of latency in transmission of packets through the NLVM object  500 . In particular, the store_ingress_packet( ) function  520  can be used to stored incoming packets that can be transmitted after waiting the desired latency time with the transmit_stored_packet( packet_handle) function  528 . Bursts of packets can also be sent this way as well.  
         [0061]    There are additional functions to retrieve packets located in the ingress section  502  or packets that have been stored in the associative array  526 . The function get_ingress_packet( )  532  returns the packet at the ingress section  502 . The get_stored_packet(packet_handle) function  530  returns a stored packet; the packet handle to the packet in the associative array must be supplied when calling this function.  
         [0062]    The remove_stored_packet(packet_handle) function  538  removes a previously stored packet from the associative array  526 . A packet handle must also be supplied to this function when it is invoked.  
         [0063]    Finally, to corrupt a packet, the packet must first be obtained by invoking the get_ingress_packet( ) function  532 . The packet contents can then be modified.  
         [0064]    Finally, the modified packet is stored by invoking the modify_stored_packet(packet_handle, packet) function  524 . The second function parameter (packet) is the newly modified packet. The stored packet can then transmitted with the transmit_stored_packet(packet_handle) function  528 .  
         [0065]    The following flowcharts and code example demonstrate how to create the four aforementioned InfiniBand SM  network layer conditions. In accordance with InfiniBand SM  protocol, data packets travel on “virtual lanes” established through a switch fabric. For a detailed discussion of InfiniBand SM  switch fabric and virtual lanes, see the InfiniBand SM  specification referred to above. In the following flowcharts and example, packets on virtual lane (VL)  1  are used to demonstrate the creation of a dropped packet condition. Packets on VL  2  are used to demonstrate the creation of an out-of-order packet condition. Packets on VL  3  demonstrate the creation of a duplicate packet condition, and packets on VL  4  are used to demonstrate corrupted packet conditions.  
         [0066]    [0066]FIG. 6 is a flowchart that illustrates use of the NLVM API to create a network layer condition in which packets are dropped. This procedure starts in step  600  and proceeds to step  602  where the process watches for packets at the ingress section  502  of the NLVM by monitoring the packet-ingress-event mechanism. When a packet has been detected, the process proceeds to step  604  where the ingress packet virtual lane is obtained by invoking the get_ingress_packet_vl( ) function.  
         [0067]    Next, in step  606 , a determination is made whether the virtual lane is equal to one. If not, the process returns to step  602  to watch for additional packets. Alternatively, if, in step  606 , it is determined that the packet has arrived on virtual lane  1 , then the packet is dropped by printing a message in step  608  rather than transmitting the packet. The process then terminates in step  610 .  
         [0068]    An example of a process that creates out-of-order packets is shown in FIGS. 7A and 7B. This process starts in step  700  and proceeds to step  702  where a packet count variable is set to 0. Next, in step  704 , the process watches for the presence of packets at the NLVM ingress section  502  by monitoring the aforementioned packet_ingress_event mechanism. When a packet is detected, the routine proceeds to step  706  in which the ingress packet virtual lane is obtained by using the get_ingress_packet_vl( ) function.  
         [0069]    If, in step  708 , it is decided that the virtual lane is not equal to 2, then the process proceeds back to step  704  to watch for additional packets. Alternatively, if in step  708 , a determination is made that the packet has arrived on virtual lane  2 , then, in step  710 , the packet count variable is checked to determine whether it is equal to 0. A packet count variable equal to 0 indicates that the received packet is first packet that has been received on virtual lane  2 . If so, the process proceeds to step  714  where, instead of transmitting the packet, the packet is stored in the packet array  526 . The process then proceeds back to step  704  to watch for additional packets.  
         [0070]    Alternatively, if in step  710 , it is determined that the packet count variable is not equal to 0 and, thus, the received packet is not the first packet received on virtual lane  2 , the packet is transmitted in step  715  and process proceeds, via off-page connectors  718  and  724 , to step  728 .  
         [0071]    In step  728 , a determination is made as to whether the packet count is equal to 3. If not, the process proceeds back, via off-page connectors  722  and  716 , to step  704  to watch for additional packets. When the third packet on virtual lane  2  is received as indicated by a positive outcome in step  728 , the process proceeds to step  732  and transmits the stored packet. Since this packet was the first packet stored, the first and second packets are now out of order. The process then finishes in step  734 .  
         [0072]    [0072]FIGS. 8A and 8B illustrate a process for creating duplicate packets. In particular, the process starts in step  800  and proceeds to step  802  where a packet count variable is set equal to 0. Next, in step  804 , the process watches for packets at the NLVM ingress section  502  by monitoring the packet_ingress_event mechanism as previously described.  
         [0073]    When a packet has been detected, the process proceeds to step  806  where the ingress packet virtual lane is obtained using the get_ingress_packet_vl( ) function. If the virtual lane is not equal to 3, the process does not operate to duplicate the packets. In particular, the process proceeds back to step  804  to watch for additional packets. Alternatively, if, in step  808 , it is determined that the virtual lane is equal to  3  and therefore the process is to duplicate packets, the process proceeds to step  810  in which the packet is transmitted. Then the process proceeds, via off-page connectors  816  and  822 , to step  826 .  
         [0074]    In step  826 , the packet count variable is checked to see whether it is 0, indicating that the transmitted packet is the first packet received on virtual lane  3 . If so, the packet is stored in step  828 . Then, the process proceeds to return, via off-page connectors  820  and  814 , to step  804  to watch for additional packets.  
         [0075]    Alternatively, if, in step  826 , it is determined that the packet count is not equal to 0, indicating that the received packet is not the first packet received, the process proceeds to step  830  in which a determination is made whether the packet count is equal to 3. If not, the process proceeds via off-page connectors  820  and  814  back to step  804  to watch for additional packets.  
         [0076]    Alternatively, if in step  830  it is determined that the packet count is equal to 3, then the routine proceeds to step  834  where the stored packet is transmitted creating a duplicate packet transmission and then the routine finishes in step  836 .  
         [0077]    [0077]FIGS. 9A and 9B illustrate a process in which packets are corrupted as described above. This process starts in step  900  and proceeds to step  902  where a watch is conducted for packets received at the ingress section by monitoring the packet_ingress_event mechanism. When a packet is determined to have reached the ingress section, the process proceeds to step  904  where the ingress packet virtual lane is obtained using the get_ingress_packet_vl( ) function. Next, in step  906 , a determination is made as to whether the virtual lane is equal to 4 and that packets are to be corrupted. If not, the routine proceeds back to step  902  where the process watches for additional packets.  
         [0078]    Alternatively, if, in step  906 , it is determined that the virtual lane of the packet is 4 and thus the packets are to be corrupted, the process proceeds to step  908  where the packet is stored in the packet array  526 . Next, in step  912 , a packet is retrieved from the ingress section  502  using the get_ingress_packet( ) function. The routine then proceeds, via off-page connectors  914  and  918 , to step  922  where the packet data is corrupted in a known manner. The routine then proceeds to step  924  where the modified packet is saved in the packet array  526  using the modify_stored_packet(packet_handle — 4,packet — 4) function. Next, in step  926 , the modified packet is transmitted using the transmit_stored_packet(packet_handle_ 4 ) function. The routine then finishes in step  928 .  
         [0079]    An exemplary code fragment, which illustrates the foregoing processes and which is coded in VERA™ HVL code as follows:  
         [0080]    program main { 
         [0081]    NetworkLayerVerificationMechanism nlvm=new( );  
         [0082]    // temporary variables (packet_handles_x, packet_x) declaration and initialization.  
         [0083]    //code here to setup packets to be sent from one HCA to the other HCA.  
         [0084]    // code example for dropping packets  
         [0085]    fork { 
         [0086]    while(1){ 
         [0087]    // watch for packets at the ingress  
         [0088]    sync(ALL, nlvm.packet_ingress_event);  
         [0089]    // for virtual lane 1 packets, we want to create dropped packet conditions  
         [0090]    if (nlvm.get_ingress_packet_vl( )==1) { 
         [0091]    // don&#39;t invoke transmit_ingress_packet( )  
         [0092]    printf(“Dropping vl 1 packet\n”);  
         [0093]    break;  
         [0094]    } 
         [0095]    } 
         [0096]    } join none  
         [0097]    // code example for creating out-of-order packets  
         [0098]    fork { 
         [0099]    while(1){ 
         [0100]    // watch for packets at the ingress  
         [0101]    sync(ALL, nIvm.packet_ingress_event);  
         [0102]    // for virtual lane 2 packets, we want to create out-of-order packet conditions  
         [0103]    if (nlvm.get_ingress_packet_vl( )==2) { 
         [0104]    // don&#39;t invoke transmit_ingress_packet( )  
         [0105]    // store the current packet at the ingress if first packet on vl 2  
         [0106]    if (vl2_packet_count==0)  
         [0107]    packet_handle — 2=nlvm.store_ingress_packet( );  
         [0108]    else nvlm.transmit_ingress_packet( );  
         [0109]    // transmit on 3rd vi 2 packet  
         [0110]    if (vl2_packet_count++==3 ) { 
         [0111]    nlvm.transmit_stored_packet(packet_handle — 2);  
         [0112]    break;  
         [0113]    } 
         [0114]    } 
         [0115]    } 
         [0116]    } join none  
         [0117]    // code example for creating duplicate packets  
         [0118]    fork { 
         [0119]    while (1) { 
         [0120]    // watch for packets at the ingress  
         [0121]    sync(ALL, nlvm.packet_ingress_event);  
         [0122]    // for virtual lane 3 packets, we want to create duplicate packet conditions  
         [0123]    if (nlvm.get_ingress_packet_vl( )==3) { 
         [0124]    // transmit the current ingress packet  
         [0125]    nlvm.transmit_ingress_packet( );  
         [0126]    // store the current packet at the ingress if first packet on vl 3  
         [0127]    if (vl3_packet_count==0)  
         [0128]    packet_handle — 3=nlvm.store_ingress_packet( );  
         [0129]    // retransmit on 3rd vl 3 packet  
         [0130]    if (vl3_packet_count++==3) { 
         [0131]    nlvm.transmit_stored_packet(packet_handle — 3);  
         [0132]    break;  
         [0133]    } 
         [0134]    } 
         [0135]    } 
         [0136]    } join none  
         [0137]    // code example for creating corrupt packets  
         [0138]    fork { 
         [0139]    while (1) { 
         [0140]    // watch for packets at the ingress  
         [0141]    sync(ALL, nlvm.packet_ingress_event);  
         [0142]    // for virtual lane 4 packets, we want to create duplicate packet conditions  
         [0143]    if (nlvm.get_ingress_packet_vl( )==4) { 
         [0144]    // store the current packet at the ingress  
         [0145]    packet_handle — 4=nlvm.store_ingress_packet( );  
         [0146]    // get packet and corrupt packet  
         [0147]    packet — 4=nlvm.get_ingress_packet( 0 );  
         [0148]    // . . . code for corrupting the packet  
         [0149]    // saved modified packet  
         [0150]    nlvm.modify_stored_packet(packet_handle — 4, packet — 4);  
         [0151]    // transmit modified packet  
         [0152]    nlvm.transmit_stored_packet(packet_handle — 4);  
         [0153]    // done  
         [0154]    break;  
         [0155]    } 
         [0156]    } 
         [0157]    } join none  
         [0158]    fork{ 
         [0159]    // watch for packets at the ingress  
         [0160]    synch(ALL, nlvm.packet_ingress_event);  
         [0161]    // catch the packet if the vl is not 1, 2, 3, 4 for the example,  
         [0162]    // then transmit it through the egress.  
         [0163]    if (nlvm.get_ingress_packet_vl( )!=1 &amp;&amp;  
         [0164]    nlvm.get_ingress_packet_vl( )!=2 &amp;&amp;  
         [0165]    nlvm.get_ingress_packet_vl( )!=3 &amp;&amp;  
         [0166]    nlvm.get_ingress_packet_vl( )!=4)  
         [0167]    nlvm.transmit_ingress_packet( );  
         [0168]    } join none  
         [0169]    // wait for all threads to complete  
         [0170]    wait_child( );  
         [0171]    } 
         [0172]    Although an exemplary embodiment of the invention has been disclosed, it will be apparent to those skilled in the art that various changes and modifications can be made which will achieve some of the advantages of the invention without departing from the spirit and scope of the invention. For example, it will be obvious to those reasonably skilled in the art that, in other implementations, different arrangements can be used for the work queue entries. Other aspects, such as the specific process flow, as well as other modifications to the inventive concept are intended to be covered by the appended claims