To count as a "functional verification" language, you have to handle temporal assertions, stimulus generation, and coverage. However, these are of little or no use unless the language can also handle the basics of any language that you'd use for high-level coding. The most basic of these would probably be dynamic list handling, and everything that entails for memory management (allocation and garbage collection). This isn't an arbitrary choice - when creating stimulus you frequently create lists of generatable items. You could approach this with something low-level and general-purpose, like the C++ STL, which covers all bases, or something which is compact, focussed, and high-level, like an e list (which is 'high-level' in the sense that the user has to write less code to do some interesting things). There are various other things you'd need to add before moving on to whether you want OOP/AOP/whatever; the basic stuff is nor dependent on this choice. Coverage -------- As for the FV features, temporal assertions are already covered by PSL. Of the other two, coverage is much the easiest. Coverage is the mechanism by which the user tells the system what needs to be recorded about (a) the stimulus applied to the DUT, or (b) about the responses produced by the DUT. The need for (b) is obvious, since you don't know in advance what the DUT will produce, and you need to find out. So, you need to specify a mechanism which is coded in the testbench, or in your temporal assertion constructs, which tells the system which datapoints to record ("increment bin X if the DUT toggles pin Y 3 cycles after an interrupt was received when pin Z was high", and so on). This very quickly gets complicated. The need for (a) is less obvious. If your DUT is so simple that you can test it by applying all possible input stimulus combinations, then you don't need it. Otherwise, you need to get smart (see generation below). In this case, you need a record of what you actually generated. What you end up with at the end of simulation is a coverage database. The database tells you how what the 'holes' in your stimulus were, what your coverage was, and how close you are to being "finished". Coverage analysis ----------------- But, is it good enough just to give the user a raw database? No. The user needs tools to analyse the database, but this is beyond the scope an LRM, so it would have to be vendor-specific. On the other hand, the database needs to be defined in a standard way. The next problem is that a database, by itself, isn't much use. Manual intervention is required to analyse the database, and to modify the stimulus generation to reach your coverage goals. You can help here by providing an API which allows the user to query the database during a simulation run, and to modify their stimulus on-the-fly to attempt to fill holes and increase coverage. Stimulus generation ------------------- Stimulus generation is a much more difficult problem than coverage. To start with, don't confuse stimulus generation and "randomisation". You need a high-level way to generate stimulus. There (quickly) comes a point where the DUT is so complex that you can't supply all possible stimulus to it, and you need to supply only an interesting subset. At this point, you start constraining your stimulus so you only produce the interesting cases, such as corner points. At some point, you may start randomising part of your input in the vague hope of hitting a problem. In some cases, however, randomisation is fundamental - when testing a processor, your stimulus generator produces an instruction stream. The stream must be very heavily constrained, to made it a valid program, but the instructions themselves otherwise need to be "random" instructions. At some point in the instruction stream, you will need to put in special instructions. The instruction at the end of the test region must be a branch, for example. You need to write a constraint to ensure that the instruction in this location is a branch, and that it branches backwards, to somewhere between the start and end locations, to the start of a valid instruction. You might also require the other instructions in the test region to be composed of a mix which includes, for example, 15% branches. These branches must also be constrained so that they branch within the test region. In short, stimulus generation is about specifying and applying a set of constraints which between them make the stimulus valid, interesting, or both. Stimulus generation isn't about creating random numbers. It's almost always about creating complex structures, possibly in a hierarchy, with interactions - constraints - between different fields in the structure or different structures in the hierarchy. The structures may even be variable-length. A 'generate' instruction will generally have to carry out recursive generation, solving multiple constraints, and taking into accout how important these constraints are (a 'hard' constraint can't be broken, but a 'soft' constraint can be broken if it conflicts with a previous constraint, for example). Generation has to fail gracefully if the user constraints can't be met. In a simple case, you might want to produce an Ethernet packet. Your structure would then contain a size field, which is first generated as a random number with an emphasis towards smaller packets; the generator then moves on to producing a variable-size list which is given this length; it then moves on to filling in the data, and then calls a CRC function, passing in the newly-generated list; and so on. Everything has to be done in the right order, and the user needs a syntax which allows this to be specified, and which doesn't create something which is unimplementable. Finally, the language needs a concept of packing and unpacking these structures, so that they can actually be applied to the DUT. All this is closely related to the recursive generation of class objects, so it makes some sense to start with some concept of classes and class initialisation. However, the constraints mechanism makes it much more complicated. In some (very real) sense, a functional verification language is simply an infrastructure on top of a stimulus generator. The big hole in all this, of course, is that it only handles the input (stimulus) side of the problem. Temporal assertions give you a limited mechanism to verify the DUT output, but they're not general enough to verify against a specification.