RSS .92| RSS 2.0| ATOM 0.3
  • Home
  • About Us
  • Resources
  • Services
  •  

    Construction Work

    April 29th, 2008

    Think Verification website is being upgraded these days… sorry for any inconvenience you might experience.

    Share This Post

    Progressive Coverage

    April 21st, 2008

    Dear readers, the time has come for me to coin a new term - “Progressive Coverage”.

    No, it’s not a new musical genre… although it would have sounded kind of neat: “Progressive Coverage set by DJ Yaron Ilani”, but really it’s been a long time since I had anything to innovate in the field of electronic music (my latest contributions to the music industry may be found here).

    So by “Progressive Coverage” I’m referring to a specific approach to coverage collection which is highly applicable in communication devices, but may as well be applied elsewhere. Now before I start to babble about my philosophy on coverage collection let me just give you an example ok?

    Let’s recall our beloved struct from the previous post - “packet” - and make it a bit more interesting:

    struct packet {
        %header: byte;
        %payload: list of byte:
        packet_valid: bool;
        header_crc_ok: bool;
        payload_crc_ok: bool;
    };

    Our sample packet can now have various types of errors. First off, it may be invalid (as indicated by the packet_valid field). If the frame is valid,  it might have a corrupt header (header_crc_ok == FALSE), in which case it would be impossible to parse the payload because whoever receives this packet doesn’t know what kind of packet it is. But that’s not all folks, the plot thickens. Even if the header is ok, the payload itself might still contain errors, in which case the payload_crc_ok would be FALSE. Got it?

    Ok, so now we want to write a reference model for the Receiver part which - how surprisingly - receives packets of that particular type, tries to parse them and then do something with them - not so important. What I’d like to focus on today is the coverage collection within the reference model.

    So let’s get started!
    Roughly, the reference model will look something like this:

    unit rx_ref_model {
        !curr_pkt: packet; // currently processed packet
        event cover_curr_pkt; // coverage event
        // method port that receives a packet from somewhere
        receive_packet: in method_port of packet_type is instance;  
        // implementation of the receiving method
        receive_packet(pkt: packet) is {
            curr_pkt = pkt; // copy pkt to be used locally
            if pkt.packet_valid then { process_header(); };
        };
        process_header() is {
            // do something and then
            if pkt.header_crc_ok then { process_payload() };
        };
        process_payload() is {
            // do something
            if pkt.payload_crc_ok then { // do something; };
        };
    };

    So this is the skeleton of the reference model, and the important thing to notice is that the nature of the processing is progressive - you first process the packet as a whole, then the header, and last - the payload. And now ladies and gentlemen, we must add some coverage. We’ll make it really simple and assume we want coverage on the header value, and the payload size.

    extend rx_ref_model {
        cover cover_curr_pkt is {  
            item header;
            item payload_size: uint = payload.size(); 
            receive_packet() is also {
                emit cover_curr_pkt;
            };    
    };

    So now we cover all we want upon receipt of each packet in the reference model. But is that all?  Of course not. What’s the point of covering the payload size if the header is invalid? So let’s use the WHEN command to make sure we only cover items when relevant.

    item header using when = packet_valid and header_crc_ok;
    item payload_size using when=packet_valid and header_crc_ok and payload_crc_ok;

    Now the coverage will only be collected when relevant. Great! we’re finished with the introduction. Phew…

    In modern network devices we might bump into packets or frames that are a bit more complicated than this one, and may have more than one layer of information in them. Try to imagine how easy it would be to come up with the appropriate WHEN expression…. It might get really ugly guys. But, and there’s always a “but”, the solution is just a minute away.
    Time to unveil the curtain - “Progressive Coverage” is all about avoiding WHEN commands, and instead - using multiple coverage events. So in our sample reference model we’ll do this: 

    unit rx_ref_model {
        !curr_pkt: packet;
    // currently processed packet
        event cover_curr_pkt; // coverage event
        event cover_header; // coverage event
        event cover_payload; // coverage event

        // method port that receives a packet from somewhere
        receive_packet: in method_port of packet_type is instance;  
        // implementation of the receiving method
        receive_packet(pkt: packet) is {
            curr_pkt = pkt; // copy pkt to be used locally
            if pkt.packet_valid then {
                process_header();  
                emit cover_curr_pkt;
            };
         };
        process_header() is {
            // do something and then
            if pkt.header_crc_ok then { 
                process_payload();
                emit cover_header;        
             };
        };
        process_payload() is {
            // do something
            if pkt.payload_crc_ok then {
                // do something
                emit cover_payload;
           
    };
        };
        // now we’ll add the dedicated coverage groups
        cover cover_curr_pkt is {   
            // cover something, but not header nor payload
        };
        cover cover_header is {   
            item header // don’t need when :-)     };
        cover cover_payload is {   
            item payload_size: uint = payload.size() // don’t need when :-)     };
    };


    So we got rid of the WHENs, and created a sequence of coverage events, that either occur or not, according to the parsing progress - hence the term “Progressive Coverage”. The nice thing about it is that in large systems it really makes life easier to deal only with the coverage items that are relevant to the current phase. The alternative - complicated WHEN expressions - is not only harder to write, but also more error-prone so that you might end up with missing coverage buckets, or God forbid - false ones.
    Share This Post

    Ignorance is a bliss

    April 16th, 2008

    There is a rather confusing feature in Specman’s coverage engine that I would like to share with you today. I’ve met several people (including myself) who had been struggling to understand what was going on there and gave up… Recently I was called to the rescue again with the same problem so I guess it’s a good opportunity to tell you guys about it…

    So imagine you have a struct called packet. And in the packet you have a length field which could be anything from 0 to 255. You’re doing a lot of things with this packet in your environment and you also want to add some coverage. Let’s see some code:

    struct packet {
        length: byte;
        event cover_me;
        cover cover_me is {
            item length;
         };
    };

    Very simple so far. Next we want to limit the coverage spectrum of this item because we’re not interested in values over 100. We will use the ignore command for that:

     item length using ignore = length > 100; 

    For the less experienced guys out there - note that the coverage commands ignore and when may look as two alternatives for limiting the coverage collection, but in fact they are fundamentaly different from each other and should be used for different purposes. The ignore command is used to narrow down the coverage spectrum while the when command is used to narrow down the number of coverage collection occurrences.

    Back to our business, after we’ve narrowed down the coverage spectrum to values below 100 only, we want to have an additional limitation, and ignore values under 90.  Let’s do this:

     item length using ignore = length > 100, ignore = length < 90;

    You think this is going to work? Not really. The code will compile and run successfully but the coverage engine will only take into consideration the last ignore command. Really disappointing. This problem typically arises with more complex items such as cross items.

    Now for the good news: the workaround is to write all your ignores in one (long) line… Not so comfortable with complex items, but it’s the only way it will work. Also, make sure to use “or” (and not “and”) as a separator between adjacent ignore conditions because we’re dealing with inverse logic here.

    So let’s conclude with the full example again, and a few lines of code that demonstrate it (you’re gonna have to open the coverage window to see this). Here we go:

    <’
    struct packet {
        length: byte;
        event cover_me;
        cover cover_me is {
            item length using 
                // the 2 lines below will NOT do the job
                //ignore = length > 100, // this ignore will be ignored !!
                //ignore = length < 90;
                // the line below WILL do the job 
                ignore = length > 100 or length < 90;
        };
    };

    extend sys {
        !packet: packet;
        run() is also {
            for i from 1 to 100 {
                gen packet; 
                emit packet.cover_me;
            };
        };
    };

    ‘>

    Share This Post