Specman Verification
Verification engineer? Verifigen has the right project for you!
Add color to your UVM environment 
Monday, December 26, 2011, 06:35 AM - Hardcore verification
This is the tiniest contribution ever made to UVM but its usefullness is inverse proportional to its size. It Allows you to color all messages coming from a specific block or environment in your UVM testbench. The colors will be visible in a batch mode run, so you can use it to make log files dumped by regression more readable. In fact, this is exactly what I've created it for. Enjoy!



  |  permalink
DeepChip in the HolyLand!!! - 1st November at Hilton TA 
Tuesday, October 25, 2011, 11:11 AM - Hardcore verification
The moment all Israeli EDA industry have been waiting from has finally arrived. No, I'm not talking about specman-verification's revival...John Cooley, the author of the best industry blog, is coming to give the keynote at the annual Mentor Graphics Expo in Hilton Tel-Aviv on the 1st of November at exactly 09:55. As a Mentor Graphics employee, I have my place guaranteed, but you're not, so go ahead and register now.

(And yes, I'm back to writing, sorry for being away for so long)
  |  permalink
Specman profiler for beginners 
Thursday, November 12, 2009, 01:31 AM - Hardcore verification
We had a small discussion: Pini, my great office-mate claimed that his way of writing e code was more efficient then mine, I had a feeling mine was as good as his, but wouldn't have been ready to place a bet for anything worth more then 5$ to back this up. We had an hour or two on our hands, and we thought that instead of fighting, we could settle our differences in a civilized manner by way an experiment which would also help us freshen up our knowledge on running Specman profiler.

To make our experiment reliable we carried it out with both simulator and Specman in batch mode. The time consumed by GUI related activities such as refreshing screen images simply adds noise to the profiler results, which are not the easiest thing to figure out anyway. In our case, we had a super-simple code that did not include any printouts to the screen or to files, but if you're running the profiler with a normal testbench, you might want to disable as much of these as you can. If you've done things the eRM way, and have used only message/messagef and no out/outf/print, this should be a peace of cake, at least on the testbench side.

The following zip file holds mine and Pini's code (every_clock.e, every_10_clocks.e correspondingly), a small DUT, and the simple magic commands required to compile everything and run the profiler in a Cadence IES environment. It also holds another piece of code (optimized.e) and its corresponding profiler report, which, as you can easily tell from its name, is the optimized version that I created based on the profiler reports for the other two versions. For those of you who detest zip, the competing code snippets and the optimized one can also be found below, and the profiler reports can be viewed here(Pini), here(Avidan) and here(optimized), but try not to look at the optimized version until you've reached the end...

A quick look at the results for my and Pini's code, will give you the impression that our contest ended up more or less in a tie - the difference in the percentage of time consumed by Specman between the two version is only 1.3%, 84.8% in my version compared to 86.1% in Pini's. However, the quick look is misleading in this case, and these 2% are more significant then they would seem. To understand why, think about a case where version A consumes 99% of simulation time, and version B 98%. Assuming the simulator code used with both A and B is identical, the 1% with A reflects the same CPU usage as the 2% with B, which actually means that version B's e code is using 50% less CPU then version A's e code. Since your e code in this case is taking the vast majority of simulation time, it means that B will run almost twice as fast as A! Therefore, if you have two results you want to compare, you might want to use the following formula to calculate the actual performance improvement (this is in fact a very close approximation of the real difference, but we're not doing our A level in Mathematics here):

"Version B will take ((version A's simulator time)/(version B's simulator time))*100 of the time version A takes".

and in our case:

Avidan's version will take 13.86/15.18*100=91% of the time Pini's Version takes.

And this looks already more significant...

I must admit that I'm not an expert figuring out what goes on in the profiler report: Basically, I work my way through it fairly stupidly, looking for the most wasteful parts of my code and trying to recode them, but not always knowing to pinpoint the exact problem, if my recoding will improve it or make it worse, or if there was a problem at all to begin with, or what I see is just a normal behavior. Looking at the reports for my and Pini's code, I could see that his "temporals" section, takes almost as much time as my own "temporals" and "user methods" sections put together. This makes sense because what Pini chose to implement in a temporal expression (i.e. wait till the cnt signal is 10), I have implemented inside the TCM. Basically, our argument was over the question if it is better to make the TCM or the event more complex, and the results seem to indicate that both options are very much equivalent. However, in Pini's report there's an anigmatic item called "scheduling" that takes more then in my report, and probably makes the difference...What can it point to?

I gave this question some thought and the best guess I could come up with was that the difference is probably due to the fact that Pini's code has two parallel processes (the temporal expression and the TCM), while my code has only one (the TCM). I assumed that "scheduling" probably referred to switching between the threads, and since Pini has 2, while I have only 1, his scheduling expenses are higher. To confirm this hypothesis, I replaced the TCM in Pini's code with an "on" construct, thereby removing one of the threads, which resulted in a version that did much better then both mine and Pini's. This was a bit too good, because I was expecting the new version to be more or less equivalent to mine, but I already told you I'm not the biggest profiler expert, right?! If someone can explain the results better, please write me, and I'll put your explanation here, along with the appropriate credit.

BTW, from the pure e perspective, this entry doesn't result in any clear coding guidelines. While "on" seems to be the winner, it has several annoying characteristics that brought it to the verge of extinction in modern day e. To name just two: it can't consume any time, and it can't trigger on an event defined elsewhere. Also, if my assumption is correct and the differences between the versions are just related to the number of threads used in each, then in any reasonable size testbench where you have 10 threads or more, these coding styles should be equivalent.

Thanks to the people who helped me with this entry or corrected mistakes:
Daniel Pörsch
Ronen Ben-Zino


----- Avidan's version - TCM that runs every clock -----


<'
unit env_u {
    clk : in event_port is instance;

    keep bind(clk, external);
    
    cnt : in simple_port of uint (bits:16) is instance;

    keep bind(cnt, external);
        
    !cnt_10s : uint;


    every_clk_tcm() @ clk$ is {
        while(TRUE) {

            if(cnt$ == 10) then {
                cnt_10s+=1;

            };
            wait cycle;
        };
    };
    
    run() is also {

        start every_clk_tcm();
    };
};

extend sys {

    env : env_u is instance;
    keep env.hdl_path() == "~/top";

    keep env.clk.hdl_path() == "clk";

    keep env.cnt.hdl_path() == "cnt";

    
    setup() is also { 
        set_config(run, tick_max, MAX_INT, exit_on, error); 
    }; 

};
    
'>



----- Pini's version - TCM that runs every 10th clock -----


<'
unit env_u {    
    clk : in event_port is instance;

    keep bind(clk, external);
    
    cnt : in simple_port of uint (bits:16) is instance;

    keep bind(cnt, external);
        
    !cnt_10s : uint;

    
    event every_10_clks_e is true(cnt$ == 10) @ clk$;

    every_10_clks_tcm() @ every_10_clks_e is {
        while(TRUE) {

            cnt_10s+=1;
            wait cycle;
        };
    };

        
    run() is also {
        start every_10_clks_tcm();
    };

};

extend sys {
    env : env_u is instance;

    keep env.hdl_path() == "~/top";
    keep env.clk.hdl_path() == "clk";

    keep env.cnt.hdl_path() == "cnt";

    
    setup() is also { 
        set_config(run, tick_max, MAX_INT, exit_on, error); 
    }; 

};
    
'>




----- Optimized version - using "on" -----

<'
unit env_u {    
    clk : in event_port is instance;

    keep bind(clk, external);
    
    cnt : in simple_port of uint (bits:16) is instance;

    keep bind(cnt, external);
        
    !cnt_10s : uint;

    
    event every_10_clks_e is true(cnt$ == 10) @ clk$;

    
    on every_10_clks_e {
        cnt_10s+=1;
    };
};

extend sys {
    env : env_u is instance;
    keep env.hdl_path() == "~/top";

    keep env.clk.hdl_path() == "clk";

    keep env.cnt.hdl_path() == "cnt";

    
    setup() is also { 
        set_config(run, tick_max, MAX_INT, exit_on, error); 
    }; 

};
    
'>




  |  permalink

Next