We present a rigorous but transparent semantics definition of SystemVerilog that ... assertions and leave the detailed relationship to the individual steps of the ...
The Formal Simulation Semantics of SystemVerilog Wolfgang Mueller
Martin Zambaldi, Wolfgang Ecker, Thomas Kruse
Paderborn University /C-LAB
Infineon Technologies AG
Fuerstenallee11, 33102 Paderborn
Balanstr. 73, 81541 Munich
ABSTRACT We present a rigorous but transparent semantics definition of SystemVerilog that covers processes with blocking and non-blocking statements as well as their interaction with the simulation scheduler including the management of new SystemVerilog regions. We present our definition in form of distributed Abstract State Machines (ASMs) rules reflecting the view given in the SystemVerilog Language Reference Manual [1]. Our formal semantics is a concise, unambiguous, high-level specification for SystemVerilog-based implementations and for investigation of interoperabilities of SystemVerilog with SpecC, SystemC, and VHDL.
1. INTRODUCTION Since 15 years, Verilog shared the market with VHDL for hardware description, simulation, and synthesis. Where Verilog was more dominant in the US market, VHDL took more shares in Europe. To increase its market share, Verilog was published as IEEE standard IEEE-1364 in 1997. This standard received an update in 2001 [4]. Recently, in the context of the introduction of new system description languages like SpecC and SystemC, Verilog received a major revision and upgrade to SystemVerilog by Accellera in 2003 [1]. However, following the lines of the SystemVerilog Language Reference Manual (LRM), the precise meaning of several parts of the underlying concepts cannot be easily captured since natural language descriptions often lack precision. The authors of LRM already discovered this and introduced a formal semantics of rewrite rules. Nevertheless, the rewrite rules just cover SystemVerilog assertions and leave the detailed relationship to the individual steps of the simulation scheduler open. However, a precise semantics of the main complete behavioural parts of SystemVerilog is mandatory for various applications including simulation, synthesis, and formal verification. If well written, it can be taken as a complementary, unambiguous documentation to significantly help understanding the language. This article presents the formal semantics for SystemVerilog simulation. Our SystemVerilog semantics provides a concise definition of the complete execution semantics of SystemVerilog V 3.1 [1]. This is an important step towards future SystemVerilog-compliant implementations and applications in various fields including formal verification. In synthesis and (co-)simulation, our formal semantics can be used as a sound basis to identify common behavioral concepts for interoperability with Verilog, VHDL, and SystemC. We present a concise and rigorous but yet intuitive semantic definition of SystemVerilog in terms of Gurevich's distributed Abstract State Machines (ASMs) [6]. Our ASM specification follows the terminology and outlines given in the SystemVerilog LRM with focus on LRM Section 12 [1]. Our semantic definition corresponds to the ASM definition style of the VHDL'93 semantics in [2], the SystemC semantics in [9], and SpecC semantics in [8]. We present a mathematical definition of SystemVerilog in terms of a SystemVerilog algebra considering blocking and non-blocking statements and their different priorities given by their region as well as the definition of the SystemVerilog simulation scheduler.
The remainder of this paper is organized as follows. Section 2 discusses related works. Section 3 briefly introduces distributed ASMs before Section 4 outlines basic concepts of the SystemVerilog language and defines its execution semantics by means of ASMs. Section 5 finally closes with a conclusion.
2. RELATED WORKS Over previous years, research in formal semantics in EDA mainly focused on VHDL. There exists numerous works based on temporal logics, functional semantics, denotational semantics, and operational semantics applying Boyer-Moore Logic, Process Algebras, and Petri-Nets etc. [5]. Most of the approaches cover subsets dedicated for application in formal verification. In [2], the simulation semantics of complete behavioral VHDL’93 is introduced by Abstract State Machines [6], which was later extended for VHDL-AMS in [12]. ASMs have already been applied for formal specification in various other domains such as hardware and software architectures, protocols, and programming languages [3]. Furthermore, the ITU standard SDL 2000 is partly underlined by an ASM definition [6]. More recently, the SystemC simulation semantics have been published in [9], which is oriented towards the VHDL'93 definitions in [2]. All those investigations demonstrate that ASMs (i.e., distributed ASMs) have excellent capabilities to capture the behavioral semantics of programming and specification languages. This is particularly true for the specification of underlying virtual machines as required for the formal coverage of the SystemVerilog simulation scheduler. In previous work, Sasaski et al. investigated VHDL-Verilog interoperability by means of ASMs in [11]. Their definitions mainly take up the VHDL definition in [2] and combine them with a very abstract Verilog view, so that no detailed behavioural semantics of Verilog was introduced. Additionally, the most recent SystemVerilog LRM introduces formal semantics in Annex G. Here, just the formal semantics of concurrent assertion statements is given by rewriting rules based on an abstract grammar. The semantics of the simulation scheduler is introduced by the LRM in Section 12 by natural language description combined with an abstract pseudo -algorithm. In this article, we focus our investigations on SystemVerilog 3.1 simulation semantics (i.e., simulation scheduler in combination with blocking and non-blocking statements). Our ASM definition takes the pseudo-algorithm given in Section 12 of the SystemVerilog LRM as a starting point and follows the ASM modelling style of existing VHDL'93 [2], SystemC [9], and SpecC [8] ASM definitions so that future work on interoperability with VHDL, SystemC, and SpecC is simplified.
3. ABSTRACT STATE MACHINES Gurevich initially introduced basic Abstract State Machines (ASMs) in 1991. A revised definition of ASMs with various extensions, commonly known as the Lipari Guide, was published in [7]. Whereas Gurevich originally defined ASMs for considerations in complexity theory, multiple publications have demonstrated the applicability of ASMs for formal specification for various purposes. Examples are hardware architectures, software architectures, communication protocols, and programming languages. An ASM specification is basically a program executed on an abstract machine. The program comes in the form of guarded function updates (rules). Rules are nested if–then–else clauses with a set of function updates in their body. Based on those rules, an abstract machine performs state transitions with algebras as states. Firing a set of rules in one step performs a state transition. Only those rules are fired whose guards (Condition) evaluate to true. Rules are of the form
if Condition then else endif; At each step the guards evaluate to a set of function updates (block) each of the form f(t1, ..., tr) := t0, where ti are terms (including functions). A block is a set of function updates separated by a comma.1 The individual function updates of each block are collected in a so-called update set. The individual updates of the update set are simultaneously executed in one step. That means that all updates in a block are simultaneously executed. Each function update changes a value at a particular location, which is given by the left hand side of the assignment. Functions are considered as global. In the classical ASM definition, two or more simultaneous updates of the same location in one update set define inconsistency and no state transition and no update in the update set is executed. In this chapter, we take a slightly modified ASM definition. In the case of more than one update on the same location we non-deterministically choose one and remove the others from the update set.2 The following example illustrates a guarded update of a block with two update instructions: if Condition then A := B; B := A endif It defines the simultaneous update of the 0-ary functions A and B. Since both updates are simultaneously executed, A becomes the value of B and vice versa. The rule fires when Condition evaluates to true. ASMs distinguish internal and external functions. An internal function has a well-defined signature and mapping. An external function non-deterministically maps to a valid value (i.e., an external function may return different results when given the same arguments). External functions are often used when parts of a system are left unspecified and are typically applied for modelling the system’s environment. ASMs are multi-sorted based on the notion of universes. We assume the standard mathematic universes of Boolean, Integer, List, etc., as well as the standard operations on them without further mentioning. A universe can be dynamically extended with individual objects by extend Universe with v endextend ; where v is a variable which is bound by the extend constructor. The choose constructor defines an arbitrary selection of one element in a universe choose v in Universe endchoose ; where v is non-deterministically selected from the given universe. v is undef when the condition evaluates to false. The var rule constructor defines the simultaneous instantiation of a rule: var v ranges over Universe Executing the var constructor means to spawn and execute the rule for each element in Universe simultaneously (i.e., the constructor basically spawns n rules where n is the number of elements in Universe). The following example demonstrates the application of this constructor. It defines a rule, which specifies that each non-empty l from the universe LIST is replaced by the list’s tail (i.e., deleting the first list element). l refers to any valid instance of LIST. var l ranges over LIST if l ≠∅ then l := tail(l) 1
Note here that Gurevich [7] does not introduce a special symbol for separating updates in a block. We use a comma as an explicit block separator in this paper.
2
This modification has no impact on the theory of ASMs rather than helps us to keep the definition of SystemVerilog simulation scheduler simpler.
The definition of our SystemVerilog semantics is defined by distributed ASMs. Distributed ASMs consist of a collection of autonomously operating agents interacting with each other by reading and writing shared locations of global system states. The underlying semantic model regulates such interactions so that potential conflicts are resolved according to the definition of partially ordered runs. Distributed ASMs partition rules into modules where each module is given by its module nameν. A module is instantiated to execute by setting Mod(a) := ν for an agent a. The symbol Self refers to a after the instantiation.
4. SYSTEMVERILOG 4.1 Basic Concepts A SystemVerilog model is composed of modules, which define nets connected by wires. Nets are composed of processes (threads of executions), which execute •
Blocking assignment statements are sequential statements, which block the process execution until their completion
•
Non-blocking assignment statements are concurrent assignments like implicit assignments to wires as well as all variations of the always statement and statements in a fork…join section.
Assignment statements and PLI calls3 generate events, which are processed by the SystemVerilog simulation scheduler. The scheduler processes those events, determines the invocation of suspended processes, and advances the simulation time. Processes can be in two different states status ∈ {evaluating, suspended}. In status evaluating, when executing a blocking statement they become suspended. The simulation scheduler can invoke them by setting them to evaluating again. Events are structured and have different properties as given in Figure 1.
Figure 1: Structure of an Event Events are managed in a global event queue, which we abbreviate as EventQ. The EventQ linearly orders events by their discrete time (-stamp) and partitions them into regions. Additionally, SystemVerilog distinguishes two event types:
3
•
Update events and
•
Evaluation events.
Function calls by a native programming language through the programming language interface (PLI)
When evaluating statements each (user defined) process generates an update event for each of the currently evaluated statements. The update event of an assignment statement refers to an update request of the left-hand-side object (which is associated with the event) by the expression at the right-hand-side. When executing an update event, the associated object is updated, e.g., by computing the result of the associated right-hand-side expression. Due to their origin, events are separated into preponed, active, inactive, non-blocking4, observed, reactive, and postponed regions. Regions are linearly order by their priority as given in . Considering the priorities of regions, the scheduler performs an iterative selection process over events. That means, preponed region events at current simulation time Tcurrent have highest and postponed region events have lowest priority. Following those priorities, the scheduler first consumes preponed and active region events until no active region events are available at current simulation time slot. Thereafter, inactive region events are considered. If there are inactive events they are reassigned to the active region, where they are executed before continuing to the non-blocking events. When no more events are available at the Tcurrent, the scheduler advances Tcurrent to the next discrete point in time and starts selecting and executing the preponed active events at the new current simulation time Tnext.
Figure 2: Different Regions of Events In the remainder of this section, we first elaborate on SystemVerilog statements and then give an ASM definition of the simulation scheduler.
4.2 SystemVerilog Statements In order to focus on the essential behavioral semantics of SystemVerilog, we assume that the continuation of the control flow of each process is determined by values of the function programCounter, which is initially set to the first statement of each process Self. To express that a user defined process Self can be executed only when it is in status evaluating and the programCounter is assigned to the specific statement, we use the following abbreviation: Self executes = programCounter(Self) = statement ∧ status(Self) = evaluating
4
We use ‘non-blocking’ rather like NBA as given in the LRM since we find it more intuitive and consistent for the outline of the concepts.
Note here, that we consider the abstract representation of a SystemVerilog model as parallel processes. That means, for instance, that a fork…join, which spawns n parallel statements creates n processes. As already introduced, processes evaluate statements, which can be mainly divided into blocking and non-blocking statements. Blocking Statements. Blocking assignments block the execution of a process. They can be without time specifications like a=b; They generate active region update events of type update, which are scheduled to the EventQ at the current simulation time Tcurrent. Blocking assignments with time specifications like #1 a=b;
generate inactive region update events, even if the time is given as a zero delay, like #0. The corresponding event is always scheduled with the current simulation time Tcurrent plus the specified time delay. The ASM specification of a blocking assignment statement is given by the following rule, which becomes active when the corresponding process is in status evaluating and when the program counter points to that statement, i.e., when it is executed. Thus, the ASM definition as given by the following rule is pretty much straight forward. if Self executes then extend EVENT with e EventQ := EventQ ∪ {e}, region (e) : = inactive, type(e) : = update, time (e) : = Tcurrent + time, object(e):= v, associated(v) := associated(v) ∪ {Self}, endextend status(Self) := suspended, programCounter(Self) := nextStmt(Self), endif
When a blocking assignment is executed, an event e is generated and added to the global event queue EventQ. The event is associated with the corresponding region, type, time, and the object for which the update has to be performed by the scheduler. Additionally, the process Self has to be kept in the set of processes associated with the updated object. This is necessary to identify the processes, which have to be invoked in a later step. Non-Blocking Assignments. Non-blocking assignment statements, like always, fork…join, and implicit wire assignment statements, generate non-blocking region update events. In contrast to the blocking assignments with time specification, they are scheduled into the EventQ as of type nonblocking and their status remains unchanged, i.e., the process Self is not set to suspended. Except to those two little changes the corresponding ASM specification is exactly the same as in the previous paragraph, so that we do not need to give further details here.
4.3 SystemVerilog Simulation Scheduler The SystemVerilog simulation scheduler is given in the SystemVerilog LRM in Section 12 by a pseudoalgorithm and performs as follows. After initialization of basic structures, the SystemVerilog simulation scheduler processes events from the global event queue (EventQ) and advances the simulation time starting with the current simulation time
Tcurrent=0. The scheduler consumes all events at Tcurrent before advancing Tcurrent to the next point in time. When consuming events, they are non-deterministically selected from EventQ so that no specific order of event processing is presumed. The next point in time Tnext is assign to Tcurrent by determining the event with the minimum time greater than the current simulation time. Figure 3 gives an overview of the basic event-based simulation flow.
Figure 3: SystemVerilog Simulation Scheduler When all processes are suspended and EventQ is not empty, the scheduler first checks the time and then processes events at the current simulation time along the different regions. First, all current time events of the preponed region are processed. Then, the events of the active and all other regions are consumed, except the postponed ones. The postponed events are the last ones before the simulation time is advanced or the simulation stops when EventQ is empty. We introduce the simulation cycle with different phases, which are controlled by setting the function phases ∈ {advanceTime, preponed, active, others, postponed}. Thus, the main simulation loop of SystemVerilog can be finally given by the following ASM rule. if ∀ p ∈ PROCESS: status(p) = suspended then if (EventQ ≠∅) then AdvanceTime, ExecuteRegion(preponed), ExecuteRegion(active), CheckOtherRegions, ExecuteRegion(postponed) else STOP endif endif
In order to increase the readability of the ASM specification, we use so-called ASM macros for describing the different phases. Macros can be seen as placeholders with or without parameters as they are used in C/C++, where the definitions of the previous macros are given hereafter. The first phase advances the simulation time to the next point in time. AdvanceTime ≡ if phase = advanceTime then Tcurrent := Tnext, phase := preponed endif
In order to check for the next point in time, all time properties of all events in EventQ are considered. The minimum of all time points determines the next simulation time Tnext. Note here that the current simulation cycle is not finished before not all events at the current time are consumed, so that only future events are left at the end of each cycle before advancing Tcurrent. Tnext = min {t | t = time(e) ∧ e ∈ EventQ}
Figure 4 sketches the corresponding event queue and gives an overview over the different orders by time and regions.
Figure 4: The SystemVerilog Event Queue with Regions After advancing the time, all events of the preponed region and of the active region are executed. We specify this with an ASM macro with parameter R, which gives the region and the phase at the same time. For each region R, the event is first removed from the event queue. Due to the different type of the event e ∈ {update, evaluate}, the corresponding object is either first updated and the corresponding processes invoked by setting status(Self) := evaluate. For evaluate events the corresponding processes is invoked without any object update. ExecuteRegion (R) ≡ if phase ∈ {preponed, active, postponed} then if e ∈ EventQ ∧ region(e) = R ∧ time(e) = Tcurrent then EventQ := EventQ – {e}, If type(e) = update then Update(object(e)), var p ranges over PROCESS if p ∈ associated(object(e)) then status(p) := evaluate endif, else var p ranges over PROCESS if p ∈ associated(object(e)) then status(p) := evaluate endif, endif endif, if R = preponed then phase := active endif, if R = active then phase := others endif, if R = postponed then phase := advanceTime endif endif
Finally, dependent on the current phase, the next phase is determined. So, after processing all postponed and active region events, the other regions are checked for pending events at the current time. It has to be noted here, that SystemVerilog only executes events in the regions preponed, active, and postponed and that other events have to be reassigned to become active for execution Thus, after processing all active (region) events, inactive, nonblocking, observed, and reactive regions are checked and iteratively moved to active. After moving all events of a region to active, the scheduler returns to process them in phase executeRegion. After processing them, the scheduler continues to check the other regions again and moves all events of the next region to active etc., which is given by the following ASM rule.
CheckOtherRegions ≡ if phase = others then if ∃ e: region(e) = inactive then allToActive(inactive) elsif ∃ e: region(e) = nonblocking then allToActive(nonblocking; elsif ∃ e: region(e) = observed then allToActive(observed) elsif ∃ e: region(e) = reactive then allToActive(reactive) else phase := postponed endif endif
Note here, that the previous rule preserves the specific order of regions of regions as given in . Moving them to active is simply performed by assigning their region to active as given by the following macro. allToActive (R) ≡ if e ∈ EventQ ∧ region(e) = R then region(e) :=active, phase := active endif
5. CONCLUSIONS This article introduces the simulation semantics of SystemVerilog 3.1 by the means of ASMs. The specification has been defined along the lines given in the Verilog and SystemVerilog language reference manuals [4][1]. Though our ASM specification is not directly executable, we think that it really supports and accelerates the development of software by providing the formal framework to reason about the validity of execution semantics of such systems. Moreover, once an implementation like a simulator is given, the specification really makes already implemented concepts clearer and greatly helps to relate them to the behavioural semantics of other standard hardware description languages like VHDL and SystemC. This is a very important point for the investigation of SystemVerilog synthesis, i.e., for identification of subsets and patterns for the source language and different target languages. Therefore, our future investigations will consider interoperability issues and equivalences between VHDL'93, SpecC, SystemC, and SystemVerilog.
REFERENCES [1] Accellera. SytemVerilog 3.1 - Accellera’s Extensions to Verilog(R). Accellera Organization, Inc., 2003. [2] Börger, E., Glässer, U., and Mueller, W. Formal Definition of an Abstract VHDL’93 Simulator by EA-Machines. In Delgado Kloos, C. and Breuer, P. T., editors, Formal Semantics for VHDL. Kluwer Academic Publishers, Boston/London/Dordrecht, 1995 [3] Börger, E. and Stärk, R.. Abstract State Machines - A Method for High-Level System Design and Analysis. Springer Verlag, Berlin/Heidelberg/New York., 2003. [4] IEEE. Verilog IEEE-1364-2001 Std Language Reference Manual, IEEE, 2001. [5] Delgado Kloos, C. and Breuer, P. T. (1995). Formal Semantics for VHDL. Kluwer Academic Publishers, Boston/London/Dordrecht, 1995.
[6] Glässer, U., Gotzhein, R., and Prinz, A.. Towards a New Formal SDL Semantics Based on Abstract State Machines. In R. Dssouli, G. Bochmann, and Y. Lahav, editors, Proc. of the 9th SDL Forum . Elsevier Science B.V., 1999. [7] Gurevich, Y. Evolving Algebras 1993: Lipari Guide. In Börger, E., editor, Specification and Validation Methods. Oxford University Press, Oxford, 1995. [8] Mueller, W., Dömer, R., and Gerstlauer, A. The Formal Execution Semantics of SpecC. In Proc. O the International Symposium on System Synthesis (ISSS’02), Kyoto, Japan, 2002. [9] Mueller, W., Ruf, J., Hofmann, D., Gerlach, J., Kropf, Th., and Rosenstiel, W. The Simulation Semantics of SystemC. In Proc. of Design, Automation and Test in Europe (DATE’01), Munich, Germany. IEEE CS Press, Los Alamitos, 2001. [10] OSCI. SystemC Version 2.0 Functional Specification. Synopsys Inc, CoWare Inc, Frontier Inc. www.systemc.org, 2002. [11] Sasaki, H. A Formal Semantics for Verilog VHDL Simulation Interoperability by Abstract State Machine. In Proc. of Design, Automation and Test in Europe (DATE’99), Munich, Germany. IEEE CS Press, Los Alamitos, 1999. [12] Sasaki, H., Mizushima, K., and Sasaki, T. Semantic Validation of VHDL-AMS by an Abstract State Machine. In IEEE/VIUF Int. Workshop on Behavioral Modeling and Simulation (BMAS’97), Arlington, USA, 1997.