This document discusses the limitations of using object-oriented programming (OOP) for hardware verification. Specifically, it examines an issue called "layering" where verification tasks require combining models at different levels of abstraction in a way that does not map cleanly to OOP constructs. While OOP is commonly used, verification often requires additional design patterns and techniques. The document argues hardware verification languages should support constructs beyond OOP to better enable reuse in verification which differs from software domains.
This document discusses the limitations of using object-oriented programming (OOP) for hardware verification. Specifically, it examines an issue called "layering" where verification tasks require combining models at different levels of abstraction in a way that does not map cleanly to OOP constructs. While OOP is commonly used, verification often requires additional design patterns and techniques. The document argues hardware verification languages should support constructs beyond OOP to better enable reuse in verification which differs from software domains.
Matan Vax Cadence Design Systems, Inc. 8 Hamelacha St., Rosh Ha'ain, 48091, Israel matan@cadence.com and stimuli spaces. As the discipline matures, reuse of ABSTRACT libraries and verification IPs becomes ubiquitous and crucial Functional verification requires, among other things, for the success of projects. dedicated programming constructs and mechanisms. Such are accessible to a wide community of verification engineers With the adoption of coverage-driven methods existing today more than in the past thanks to the SystemVerilog programming languages were no longer sufficient for language. Along with many verification specific constructs it testbench development, as they lacked the means to express features object-oriented programming (OOP) framework. constraints on stimuli generation and functional coverage OOP has been extremely successful in facilitating reuse in definitions. So languages dedicated for the task emerged – many software application domains. This observation hardware verification languages (HVLs). The most widely suggests that it should serve just as well for reuse in the used public domain HVLs today are e [6], SystemVerilog verification domain. The present paper critically examines [7], and SystemC/SCV [13].2 All three languages support a this supposition. It demonstrates issues with the naive rich set of verification specific constructs to express application of object-oriented mechanisms, and how they are constraints, coverage points, temporal properties, hardware partially overcome by more sophisticated design techniques. interfaces, and more. However, they differ in the basic Still these techniques don't scale well and increase code modularization mechanisms they provide. complexity. The same needs are shown to be met more naturally with modularization mechanisms that go beyond Developing testbenches for hardware devices is in many strict OOP. This analysis leads to an interesting observation senses a software engineering task. In order to exercise the on the nature of reuse in verification. It turns out to differ design under test (DUT) and check its behavior the testbench substantially from that of classical software application needs to emulate the behavior of the environment in which domains. If hardware verification languages are to address the device is embedded, as well as the device's own the challenges of creating reusable verification code, they operation, at various levels of abstraction. This essentially must accommodate for its unique character. involves models, algorithms, and data structures naturally expressed in high-level programming languages. Advanced Categories and Subject Descriptors testbenches are, in this sense, large scale software systems. B.6.3 [Logic Design]: Design Aids—Verification; D.3.3 Much of the code of a testbench, if built well, may live for [Programming Languages]: Language Constructs and years and be reused across the hardware project's Features – Classes and Objects, Patterns. proliferations, various different projects, and even different companies. A different and more elementary dimension of General Terms reuse in verification is that between the numerous tests in a Languages, Verification. single project's test suite [5]. This kind of reuse has no obvious counterpart in general software systems, but is Keywords somewhat reminiscent of the variability found in software Object-Oriented Design, Hardware Verification Languages. product lines. In any case, verification engineers nowadays must draw upon state-of-the-art software engineering 1. INTRODUCTION methods to meet the challenge of effective code reuse. Simulation-based functional verification of hardware The dominant programming paradigm in the industrial designs1 has established itself in recent years as an software world is object-oriented programming. OOP makes engineering discipline in its own right. It has its own use of the notion of class as the primary unit of dedicated languages, tool set, methodologies, library eco- systems, and body of knowledge. The turning point in the evolution of the discipline was the adoption of coverage- 2 These languages are not exclusively used for verification. driven methods in conjunction with constrained-random SystemVerilog is also a hardware design language, and stimuli generation [11, 16]. Replacing traditional approaches SystemC is primarily used for hardware modeling. that were either strictly directed or fully randomized, it deals SystemC is referred to as a language, although it is actually more systematically with the explosion of simulation state a C++ library compiled with standard C++ compilers. Vera and OpenVera are still used in the industry, but are proclaimed to be superseded by SystemVerilog. There are 1 Henceforth I shall use the unqualified term 'verification' in many proprietary verification languages and language this sense. extensions mostly developed in-house by chip makers. modularization, and relies on class inheritance as its main addr. The verification environment should provide the signal abstraction mechanism. In so far as verification is ultimately level logic for actually driving a packet into the DUT, as in: about writing software, it is only natural to expect that OOP would serve just as well for verification needs. Indeed this class packet_env; expectation is echoed in all three leading languages. ... task drive_packet(packet p); However, in practice even with object-oriented mechanisms // write packet onto DUT signals in place the design of testbenches does not resemble all that endtask much mainstream software design. This is manifested in the endclass extensive use of certain design patterns and auxiliary design constructions. Similar techniques are applied in other Consider a very simple test on top of this environment that domains, but never in such sweeping manner. This drives 20 packets having lower-end addresses into the DUT. phenomenon was observed before but the present paper Here is its code: proposes a generalized analysis for it under the title – the layering problem. The main contribution of the paper is in class low_addr_packet extends packet; suggesting what it is about the task of verification that does constraint low_addr { addr <= 'hFF; } not lend itself naturally to classic object-oriented design. The endclass answer has to do with the unique form that code reuse must take in this domain. program test1; packet_env env; The remainder of the paper is organized as follows: Section 2 presents a design situation encountered regularly in initial begin verification, known as "layering", and explains why it does env = new(); not map directly to object-oriented constructs. Section 3 random_scenario(); surveys and evaluates techniques to address layering within end OOP. Section 4 shows how the required relationship can be captured directly with a different set of language constructs. task random_scenario(); Section 5 builds on previous observations and tries to address int i; the main question framed above. Work related to this kind for (i = 0; i < 20; i++) begin analysis is surveyed in section 6, and section 7 concludes. low_addr_packet p = new(); assert(p.randomize()); 2. THE LAYERING PROBLEM env.drive_packet(p); The constrained-random verification flow is essentially about end running a multitude of tests, each focusing on some specific endtask feature, condition, or aspect of the DUT. There may be endprogram hundreds or even thousands of such tests in a regression suite, and each test is executed multiple times with different Now imagine another test that drives 20 upper-end address random seeds. The verification environment is the common packets into the DUT, and yet another that drives random infrastructure for test execution for a given DUT, or simply packets with addresses distributed in some other way. These put, the code that is shared between all tests. tests share the base packet definition and the driving logic. However, they have in common also the scenario code that 2.1. Layering Constraints generates 20 packets, with the sole difference being the It would be instructive to open the exposition of the problem additional constraint. Unfortunately this code cannot be through an example. Let us consider a testbench for a shared between them because the new operator considers switching device that interfaces through some packet only the static type of its operand. If the code of task protocol. Here is a simplistic definition of packet data type in random_scenrio above had used class packet instead of SystemVerilog:3 low_addr_packet randomization would have ignored lower_addr constraint. Note that using inline constraints (the class packet; randomize with operator) may obviate the subclasses of rand bit[15:0] addr; packet, but the recurrence of generation code in all three tests rand bit[7:0] data[]; would still remain. constraint addr_range {addr >= 'h10;} In this trivial example the loop that generates and drives endclass packets is obviously not worth the trouble of factoring out This class has two randomized member variables (fields): a and reusing. But it so happens that the structure of legitimate 16 bit address and an array of data bytes. It also has one transaction streams may involve some of the most intricate member constraint restricting the range of values for variable logic of the protocol. Ideally most tests would reuse this logic and entirely abstract from it. When constructing a testbench for a device that interacts through a USB port, for example, 3 For simplicity, all code examples in this section and the the environment may wish to hide the complex packet next are in SystemVerilog. The same issues arise in handshaking flows while letting the test merely affect the SystemC/C++ and e so far as standard object-oriented data packets delivered. But this is rendered impossible using inheritance is used. the language's constructs in this naive manner. 2.2. Layering Behavior The main tasks of the environment are decomposed into The above situation is often referred to as the layering separate objects classified by their function. Different problem – the test writer needs to layer some property on top methodologies differ in details and terminology, but are alike of the environment's data type. This problem is by no means in spirit with respect to this classification. They name entities restricted to constraints. To illustrate, imagine that in the such as monitors, drivers, sequencers, collectors, loggers, above testbench some legality check is implemented for generators, etc. These are composed together to form agents packets and is invoked after a packet has been read off the or transactors, and multiple agents are further grouped in DUT interface. Here is this aspect of the environment: module and system environments. All these objects function as software components in the sense that they are created and class packet; configured during environment setup and live throughout the ... simulation. Other kinds of components, such as scoreboards, virtual function void check_length(); abstract scenario libraries, register file models, and // perform check behavioral "golden" models, may also be instantiated in the endfunction same environment and interconnected. endclass The architecture of a large scale testbench may become rather complex. Fortunately, it remains constant (perhaps class packet_env; with minor variations) for the entire test suite since it ... corresponds to the structure of the DUT. It is unrealistic to task monitor(); expect that a test would construct and configure the entire packet p; component hierarchy for itself just to be able to control the forever begin actual type of some specific monitor or driver. After all, this collect_packet(p); structure is exactly the kind of non-trivial definition that p.check_length(); should be abstracted from and reused. So for purposes of test ... writing, inheritance of component classes in its simple form end is out of the question. endtask Finally it should be stressed that the layering problem is not task collect_packet(output packet p); restricted to tests. Standalone module-level environments can p = new(); be reused as verification IPs by integrating them into // read packet off DUT signals different system environments. The large scale environment endtask will typically need to customize the verification IP and adapt endclass it to its needs. This is done in much the same way as tests would, since the IP logic that needs to be reused involves If a test writer needs to refine the check in some way, she instantiation of its own object model. Packaged IP code is cannot expect to achieve this just by overriding function usually not open for integrators to edit even if they wanted, check_length in a derived class. This is again because task and they rarely do. collect_packet allocates packets by new-ing the base type. Editing the code of class packet_env may not be an option, as the source code for this part of the environment is not 3. DESIGN PATTERNS FOR necessarily available (as in the case of commercial IPs, for LAYERING example). But even if it were, the decoupling of test and 3.1. Layering with Factories environment would be sacrificed. Inheriting packet_env and In object-oriented languages virtual method calls are bound overriding collect_packet is impractical for reasons that shall dynamically, that is, dispatched based on the actual type of be discussed next. Note also that non trivial behavioral the receiver object. The new operator, on the other hand, extensions often require auxiliary member variables and determines the type of the object in the first place and so functions and may affect more than one class. must be bound statically with some class. The way to work around this is seemingly straightforward – use another object 2.3. Layering on top of Components for the instantiation and leverage its polymorphic behavior. So far we focused on layering properties or behavior on top This auxiliary class is known as a factory. In this way objects of data item classes provided by the verification can be created in multiple places using an abstract factory environment. However, most checks and coverage points are interface, while the actual class being thus instantiated is defined outside the data model, and so are some aspects of determined by the type of a concrete factory object. This is stimuli such as timing and error injection. Here too actually an old technique that was named a design pattern in individual tests may need to intervene with the environment's the famous Gang-of-Four book [3]. operation in certain respects to hit corner cases or observe specific DUT behavior correctly. The naive object-oriented If we apply the pattern to the example in section 2.1 above, approach would be again to subclass the environment's we would need to replace all explicit uses of the new classes that handle these tasks and make the required operator with calls to a virtual method create() of an abstract adaptations. But in itself this move is futile, because just like factory class. The test would then only have to instantiate a in the case of the data model, instantiation of these classes is concrete factory once, and it in turn will affect the behavior something the test cannot take over. Here is why. of the entire environment. Leaving out much of the detail, the environment code may now look thus: class packet_factory; Imagine a test with another variant of packet, call it virtual function packet create(); round_addr_packet, which gives more weight to 4-byte // by default create a packet aligned addresses. It may make sense to apply this property create = new(); also in conjunction with the low_addr property defined endfunction above to create a third test. But since a different class is used endclass to define each of the variants and both derive from packet they cannot be applied together to the same instances. class packet_env; Conversely, if round_addr_packet explicitly derives from packet_factory pfact; low_addr_packet it cannot be applied separately. ... packet p = pfact.create(); With multiple inheritance, as in SystemC (C++), this kind of ... reuse can be achieved by deriving a third class from both packet p = pfact.create(); subclasses of packet. This way each test could choose ... between the base class, one of the two subclasses, or the third endclass class that combines the two. However, this still requires explicit definition of the combination as a separate class. So This way layering additional properties or refined behavior the two definitions are not truly pluggable independently in a on top of the basic packet definition does not require any test. The situation gets worse with more independent intrusive editing of the environment code. A test can simply properties, of which arbitrary subsets may be used in define a factory subclass and register its instance with the different tests. The number of explicit classes that need to be environment class, as follows: created and maintained grows exponentially with the number of such independent properties. class test1_packet_factory extends packet_factory; A related requirement on the part of test writers has to do virtual function packet create(); with leveraging existing abstractions of the data model. Tests low_addr_packet p = new(); may need to layer a property on top of an abstract class so as return p; to affect all its subclasses equally. Consider a protocol that endfunction defines several variants of its basic data item which have endclass some properties in common and others not. For example, in an environment for USB interface it would be natural to program test1; define data packet, token packet, and handshake packet, as packet_env env; separate classes, all deriving from an abstract packet class. Now some tests may need to layer an additional constraint on initial begin; top of all three subclasses. Ideally the new property would be // factory registration associated with the common base class, rather than test1_packet_factory pf; duplicated for each concrete class. The test writer in this case pf = new(); need not even be aware of the subclasses. But even if env.pfact = pf; factories have been used to instantiate these classes ... throughout the environment, deriving a new class from the end base class would not help. The new class does not "blend in" endprogram with any of the existing. A utility library can reduce the coding overhead of the Here too multiple inheritance can be used to overcome the abstract factory pattern for both environment developer and reuse issue. But this is, again, a very lean sense of reuse. It is test writer. The OVM-SV library, for example, includes a achieved at the price of explicitly crossing the new property very sophisticated version of the Abstract Factory pattern with every existing subclass. The number of synthetic classes [10]. It involves global type registry and bookkeeping code generated by this cross may be large, causing significant encapsulated in base classes and in preprocessor macros. So coding and maintenance overhead. Moreover, the test writer the environment developer needs to derive from a common cannot remain agnostic of the concrete data model. base class, and use a factory method for creation supplied by the library rather then new. The test writer simply needs to 3.3. Behavioral Extensions with Callbacks call a library function to "override" all allocations of some We turn now to discuss another well known object-oriented class with that of a subclass. Neither test nor environment technique to tackle the layering problem. It involves using need to explicitly define or instantiate a factory class. "listeners" or callback objects, and is akin to Command and Observer design patterns [3]. We shall use the term 'callback', 3.2. Limitations of Factories as it is more commonly used in this context. The use of factories solves the layering problem in its simple The principle is simple. The environment declares an abstract form. However, often when tests are defined as refinement class with one or more virtual functions that are called at layers on top of an existing object model, useful tests may be designated points in the execution. The classic observer is obtained by composing two or more such refinements. This intended to monitor state changes within some model, but cannot be done with the Abstract Factory pattern, at least not any kind of occurrence can be monitored just as well. The in a single inheritance language such as SystemVerilog. key here is that a single occurrence may trigger the notification of multiple callbacks. In its simplest form, the 3.4. Advantages and Limitation of idea may be implemented in the environment thus: Callbacks class env_callback; First it should be noted that callback objects can only virtual task execute(); implement behavioral extensions. If structural properties endtask // does nothing by default need to be added to an existing class, such as constraints, endclass fields, or new methods, other techniques must be applied, such as factories.4 class packet_env; Callbacks require upfront design of extension points and are // callback queue only as good as the preparation they have in the environment env_callback pre_drive_cbs[$]; code. Unlike factories, they cannot be used to apply unanticipated modifications to a class. In particular, callbacks task drive_packet(packet p); cannot completely override existing functionality, unless // invoke all registered callbacks explicit preparation for this has been made. It could be for (int i = 0; argued that this restriction is actually an advantage, as it i < pre_drive_cbs.size(); i++) enforces more disciplined usage. Perhaps this position is pre_drive_cbs[i].execute(); valid in other domains, but often turns out to be too rigid for real life situations in verification (see a case for this claim in ... // do the actual driving [12]). A related issue with callbacks is the fact that they endtask encapsulate the extension code in a separate class, while it is endclass often tightly coupled with the extended class. Here the environment triggers all callbacks registered in On the other hand, callbacks are much more flexible with pre_driver_cbs queue right before actually driving a packet respect to layer composition. Any number of independent into the DUT. A test that needs to modify the driving callback objects can be registered to monitor the same event, behavior in this sense can simply define its own callback as long as it has the required preparation. In fact, callbacks object and register it. The following test utilizes the above are independent in a way that does not allow one to affect preparation to force random delay before each packet: another, even when this is needed. Further techniques can be applied to implement more sophisticated notification class my_delay_cb extends env_callback; semantics. In particular, Chain of Responsibility pattern [3] virtual task execute(); can be used to enable control flow variability between the int unsigned delay; calls. With more flexibility comes more complication of delay = $urandom_range(10); flow, which impedes readability and understandability of the #(delay); // wait 0..10 time units code. endtask endclass 4. FROM DESIGN PATTERNS TO program test1; NATIVE CONSTRUCTS packet_env env; Limitations of specific design patterns can usually be my_delay_cb my_cb; overcome with yet more sophisticated techniques. But the one inherent down side of design patterns is their very initial begin existence in the code. They put both cognitive and coding // ... overhead on the programmer, even when reduced to the minimum using utility libraries, and have negative impact on // regiester callback with the env traceability and understandability of the code [2]. The my_cb = new(); compiler and other development tools remain ignorant of the env.pre_drive_cbs.push_back(my_cb); design intent expressed in these terms. The pain grows with end density and variety of patterns applied. It seems that with endprogram advanced object-oriented verification methodologies this becomes a serious issue. Different observer classes (and queues) may be used to encapsulate different function signatures. Conversely, several Gamma et al. readily admitted that design patterns are a callback functions may be grouped together in a single matter of point of view – "One person's pattern can be abstract callback class to encapsulate the handling of related another person's primitive building block" [3]. The difference events. between two such persons may simply be the programming Just like in the case the Abstract Factory pattern, it is worthwhile to encapsulate pattern related services in a utility 4 It should be s,//tressed that neither this section, nor the rest library. The Verification Methodology Manual (VMM), for of the paper, attempts a comparison of OVM and VMM. example, recommends a very wide application of callbacks, Both include more concepts and services that bear on the and provides related services encapsulated in library base considerations raised here. The intention is merely to classes and macros [1, 15]. These handle registration, evaluate the two design techniques per se with respect to unregistration, and the actual invocation of callback objects. the needs outlined previously. language they use. Bosch writes "... design patterns are part 4.2. Applying Class Extensions in Layering of the software engineer’s paradigm and it is the task of the The constraint layering example from section 2.1 above programming language to represent the concepts in the could be rewritten in e such that a generic random scenario is paradigm as accurate as possible" [2]. Gil and Lorentz call defined in the environment using the new operator directly. design patters "puppy language features" and argue that in The e equivalent of the environment's definition for class many cases they compensate in one language for capabilities packet would be: that already exist in other languages [4]. This is evident, for example, with aspect-oriented languages such as AspectJ that struct packet { have the Observer collaboration (as in the callback pattern) addr: uint(bits:16); as their prototypical application [9]. data: list of byte; The e language has unconventional features with direct keep addr_range is { addr >= 0x10; } bearing on the design requirements described above. This }; should come as no surprise, as they were devised from the The code of test1 would consist simply of an extension to outset to tackle exactly these challenges. They are class packet with the additional constraint thus: inheritance-like mechanisms on top of the standard single inheritance – class extensions and "when" subtyping. Both have been presented previously in [6]. Their affinity to key extend packet { keep addr < 0xFF; aspect-oriented concepts, namely advice and introductions, has been analyzed in [12, 14]. In this chapter we shall explain }; very briefly these two mechanisms, leaving details out, and The reader can appreciate the way the extend construct demonstrate their application to the layering problem. The expresses the intention of the test in a concise and intuitive main purpose of this is to substantiate the claim that design way without the need for auxiliary definitions. If defining the techniques discussed above indeed compensate for limited same class in multiple locations should seem strange at first expressive power of strict object-oriented languages.5 glance, it may be just because we disregard the fact that this is in fact what we try to achieve here, and what the patterns 4.1. Class Extensions discussed above try to emulate. In e a class is initially declared with the struct or unit keyword,6 optionally deriving from another class in the Moreover, the limitations listed in section 3.2 do not plague standard object-oriented sense. Within the scope of the class' this mechanism. Consider another property defined in some initial definition new members can be defined, and existing other test, for example: members can be overridden. extend packet { Having been initially defined in this way, a class may be keep data.size() in [2,4,8]; extended elsewhere using the keyword extend. In the scope }; of this construct the class may be further defined in exactly the same manner – new members can be added and existing The two properties thus defined could be loaded together in members can be overridden "in-place" so to speak. New the same session and would then apply equally to all members and new definitions to existing members affect all generated packets, be it within the environment code or instances of that class, including classes inherited from it, outside. Note that this would have been true even if packet just as if they were part of its initial definition. This is was an abstract class in the environment and only subclasses regardless of where the instantiation of (or inheritance from) of it were actually generated. the class occurs in the code. Now consider the example from section 3.3. The same Overriding existing definition in the strict sense is often not approach would apply here just as well. The test only needs required. Subclasses inherited in the standard way, and more to extend class packet_env and refine time-consuming so in-place class extensions, often need to augment existing method drive_packet (e's equivalent of SystemVerilog's definitions rather than replace them altogether. For this member task): purpose e makes available two additive modes of member overriding, or more aptly – refinement. They place the new extend packet_env { definitions after or before the exiting definitions, and are drive_packet() @clock is first { denoted by the key phrases is also and is first var delay: int[0..10] respectively. The standard object-oriented replacement gen delay; semantics is denoted by is only. wait [delay]; }; }; 5 If a number of refinements for the same method are compiled This is not to claim that e's are the only conceivable mechanisms for that purpose, nor even that they are the or loaded in the same session they all get executed upon best ones. every call. The order of execution is determined according to 6 dependency between the modules (source files). The effect The difference between the two corresponds to a distinction thus achieved is similar to that of the use of callbacks. But no made previously between data types and components. For up-front preparation in the base environment is required and present purposes both keywords prefix class definitions. the coding overhead is gone. 4.3. Taking it Further with When Subtypes configuring components, such as buttons, panes, menus etc. A when subtype is simply a class under some condition. These are placed within a window, and behavior is associated Assume that class packet has a field (member variable) with events reported by them. The library provides a pure named kind of an enumerated type, whose possible values are object model for these components while instantiation is left token, data, and handshake. In e these values imply the exclusively to the application. existence of 3 subtypes of packet, namely token packet, data What in verification is analogous to this classic relation packet, and handshake packet. An instance of class packet between library and end-application? Where does the main with field kind equals to token is actually an instance of the "reuse divide" pass? In a single verification project much of type token packet. The phrase token packet represents a logic is common to all tests in a regression suite. Its type for all purposes – declaring variables, casting, etc. When complexity is typically greater than that of any specific test, subtypes may be extended just like any other class type, and so is the effort that goes into its development. But a making the definitions in the extension scope conditional. verification environment is very different in nature from a They apply to an object in as far as it is an instance of that class library, just as tests are very different from GUI subtype, that is, it is an instance of the base class and its applications. corresponding field is of the right value at that time. Section 2 above already outlined what a verification When subtypes are ideal for data modeling where different environment should consist of. It is not merely a set of values of a field correspond to structural differences of the abstract building blocks for writing test. Rather, it is a data item in which it is embedded. This is often the case in concrete and fully operational model simulating in great hardware protocols and processor instruction sets. More details relevant aspects of the environment in which the importantly, with when subtypes it is possible to constrain device is embedded. If built properly a verification and randomize the type of data items. environment could, at least in principle, execute as-is (or In the context of the present discussion when subtypes are a almost as-is) achieving real coverage and possibly way to introduce independent sub-classifications of objects uncovering bugs.7 It obviously makes no sense to expect and thus gain finer control over extensions. A constraint may something of the sort from the average class library. be put on data packet without affecting other kinds of Similarly, individual tests, when distilled to their essentials, packets. Imagine another field of packet indicating whether it don't resemble standalone applications in any way. Tests may is legal or corrupt. This field would expand a sub- need to configure some properties of the environment, classification on an orthogonal dimension. So under corrupt perhaps make slight adaptations to its behavior. But most packet there could be a refined implementation of some commonly tests use constraints and procedural code to guide method, and it would apply to all corrupt packets, regardless random stimuli into the scenario's areas of interest. In this of whether they are data packets or of other kinds. sense tests are merely variations on the environment's This use for when subtypes is very common also in definitions. If fact, test may involve a number of independent customizing components. Bus agents, for example, are variations combined together, where variations themselves typically classified into masters and slaves, a classification may be shared across some (but not all) tests. Interestingly, that may affect both their structure and behavior. From the this mode of reuse is not restricted to tests. It is often testbench point of view some may be active in the sense that manifested also when integrating verification IPs in system- they actually inject synthetic traffic, while others passive, level environments. that is, merely monitoring traffic. These classifications are At the heart of what we identified as the layering problem naturally captured as when subtype extensions to class agent. lies the fact that the model defined by the environment is Any given agent is either a master or a slave, and concrete. Unlike the case with class libraries, the verification independently either active or passive. In all four cases all environment does much, if not all, of the actual instantiation and only the relevant definitions apply. of classes it defines. Generation of data item streams for stimulating the DUT obviously requires instantiation, and so 5. DISCUSSION: THE REUSE MODEL does collection of DUT responses for checking. The IN VERIFICATION construction of environment's component architecture, which The object-oriented programming paradigm emerged in the may become fairly complex, also involves instantiation of 1970's with the development of Smalltalk. One of its first and objects. most distinctive applications was in the design of a graphical There are two basic tasks that a software system needs to user interface (GUI) framework [8]. The language handle – the definition of a model and its instantiation. The mechanisms forged for this purpose, most notably class object-oriented paradigm focuses on modularization of the inheritance and polymorphism, were extremely successful in model's definition prior to its instantiation, and indeed this is capturing the commonalities between library entities, and in where potential for reuse lies in many application domains. supplying useful abstractions to the end application. But in verification the balance between the two tasks is Let us consider the mode of reuse in the context of this different from a reuse point of view. Much of the logic of a classical application for OOP. Reuse here means first and foremost factoring the code-intense definitions of graphical 7 elements into a library so that they can easily be shared In fact, some commercial verification IPs do just that and between many different applications. Applications define even claim to cover significant portions of the verification their custom GUI by specializing, instantiating, and goals relative to a given plan. verification environment involves instantiation, while the constructs. It may well need a suitable programming tests typically just need refine some aspect of the model. This paradigm to supply the right toolbox for modularization, mode of reuse constitutes a different programming paradigm. abstraction, and reuse. As quoted previously, it is the task of the programming language to represent the concepts in the paradigm as 8. ACKNOWLEDGEMENTS accurate as possible. I wish to thank Brett Lammers, Shlomi Uziel, and Zeev Kirshenbaum of Cadence, and JL Gray of Verilab, who 6. RELATED WORK provided valuable feedback on earlier drafts of this paper. Hollander et al. [5] survey the unique mechanisms for separation of concerns of the e language, and their relation to 9. REFERENCES the specific challenges encountered in verification. The 1. Bergeron, J., Cerny, E., Hunter, A., and Nightingale, A. present paper is very much following the lead of hints in their 2005 Verification Methodology Manual for work, in particular in its focus on the special relation between Systemverilog. Springer-Verlag New York, Inc. a verification environments and individual tests in a test suite. However, in their paper Hollander et al. do not discuss 2. Bosch, J. 1998. Design Patterns as Language Constructs. possible solutions within the bounds of object-oriented In Journal of Object-Oriented Programming, vol 11, 18- programming, and their limitations. The present paper 32. attempts exactly this analysis. Here e's mechanisms are 3. Gamma, E., Helm, R., Johnson, R., and Vlissides, J. 1995 mentioned mostly to substantiate the criticism of object- Design Patterns: Elements of Reusable Object-Oriented oriented languages in this respect. Software. Addison-Wesley Longman Publishing Co., Inc. Robinson's book [12] is strongly related to issues discussed 4. Gil, J. and Lorenz, D. H., 1998, Design patterns vs. in the present paper. Apart from being a valuable book for language design. In Proceedings of the 11 th European practitioners, it contains some insights on the very idea of Conference on Object-Oriented Programming, Lecture aspects and AOP. Unlike the present paper, it stresses the Notes in Computer Science, vol. 1241, 9-13. general problem of crosscutting concerns and how AOP promotes better modularization of them. Robinson is surely 5. Hollander, Y., Morley, M., and Noy, A. 2001. The e right in that, being large software systems, testbenches have language: A fresh separation of concerns. In Proceedings crosscutting concerns. He does not stress enough, though, the of the International Conference on Technology of Object- special traits of the verification domain that make these Oriented Languages and Systems (TOOLS 2001 Europe AOP-like mechanisms indispensable. Unlike Robinson, the Conference, Zurich, Switzerland). present paper focuses on problems of reuse in verification 6. IEEE Standard for the Functional Verification Language that are not germane to most other domains. 'e', IEEE Computer Society, IEEE, New York, NY, IEEE Std 1647—2006 7. CONCLUSION This paper presented a software design situation that is 7. IEEE Standard For System Verilog - Unified Hardware ubiquitous when building reusable verification environments. Design, Specification and Verification Language, IEEE It concerns layering properties and behavior on top of a Computer Society, IEEE, New York, NY, IEEE Std model without owning its instantiation. This design situation 1800—2005 does not map naturally to native object-oriented constructs. 8. Kay, A. C. 1993. The early history of Smalltalk. In the Design patterns and techniques are applied across the board Second ACM SIGPLAN Conference on History of by verification methodologies to overcome this shortcoming, Programming Languages (Cambridge, Massachusetts, but these techniques are inherently cumbersome and not United States, April 20 - 23, 1993). HOPL-II. ACM, New wholly satisfactory. Language mechanisms that go beyond York, NY, 69-95. the strict object-oriented paradigm do a much better job in capturing the same design intent. In fact, the object-oriented 9. Kiczales, G., Hilsdale, E., Hugunin, J., Kersten, M., Palm, techniques seem to emulate these very mechanisms. J., and Griswold, W. G. 2001. An Overview of AspectJ. In Proceedings of the 15th European Conference on What makes the programming paradigm that works so well Object-Oriented Programming (June 18 - 22, 2001). J. L. for most complex software systems not right for verification? Knudsen, Ed. Lecture Notes In Computer Science, vol. Some insight can be gained by comparing the mode of reuse 2072. Springer-Verlag, London, 327-353. in classical object-oriented application domains and that of verification environments. In a nutshell, object models make 10. OVM web site. http://ovmworld.org very good candidates for reuse, but construction and generation logic does not. The latter is extremely important 11. Piziali, A. 2007 Functional Verification Coverage in verification, and less so in other domains. Measurement and Analysis. 1st. Springer Publishing Company, Incorporated. The upshot of this discussion is twofold. It reinforces the claim that simulation-based verification is a unique kind of 12. Robinson, D. 2007, Aspect-Oriented Programming with challenge, not reducible in its methods to other engineering the e Verification Language: A Pragmatic Guide for disciplines. From the point of view of language design, there Testbench Developers. Elsevier Inc. is a lesson to be learned too. A domain specific language is 13. SystemC web site. http://www.systemc.org not all about domain specific types, operators, or even 14. Vax, M. 2007. Conservative aspect-orientated 15. VMM web site. http://vmm-sv.org programming with the e language. In Proceedings of the 6th international Conference on Aspect-Oriented 16. Wile, B., Goss, J., and Roesner, W. 2005 Comprehensive Software Development (Vancouver, British Columbia, Functional Verification: the Complete Industry Cycle Canada, March 12 - 16, 2007). AOSD '07, vol. 208. (Systems on Silicon). Morgan Kaufmann Publishers Inc.