Fact-checked by Grok 2 weeks ago

Verilog

Verilog is a standardized as IEEE 1364, serving as a formal notation for modeling electronic systems at various abstraction levels, including behavioral, register-transfer level (RTL), and gate-level descriptions. It is both machine-readable and human-readable, enabling its use across all phases of electronic system development, such as design specification, verification, , synthesis, testing, and maintenance. Developed with a syntax inspired by , Verilog facilitates the description of digital circuits and their timing behaviors, supporting both for validation and synthesis into hardware implementations like field-programmable gate arrays (FPGAs) and application-specific integrated circuits (ASICs). The language originated in 1984 when engineers at Gateway Design Automation, including Phil Moorby and Prabhu Goel, created it as a proprietary tool for their Verilog-XL logic simulator, marking a shift from schematic-based design to textual RTL modeling that revolutionized integrated circuit design. Gateway was acquired by Cadence Design Systems in 1990, which opened the language in 1991 to promote industry adoption. It became an IEEE standard in 1995 as IEEE Std 1364-1995, with subsequent revisions in 2001 (adding features such as generate constructs and signed data types) and 2005 (primarily clarifications and minor enhancements). In 2009, Verilog was merged into SystemVerilog (IEEE 1800), under which it is maintained as a subset, with the latest revision being IEEE 1800-2023. By the early 21st century, Verilog had become the dominant HDL, used by approximately 80% of global integrated circuit design teams by 2018, often alongside its successor, SystemVerilog. Verilog's key strengths include its concise syntax for concurrent processes, support for event-driven simulation, and extensibility through programming language interfaces (PLI) for integrating with software tools. It excels in describing combinational and sequential logic, finite state machines, and testbenches for verification, making it essential for modern digital system-on-chip (SoC) designs. While it lacks some high-level abstractions found in newer languages, its simplicity and tool ecosystem ensure widespread application in academia, industry prototyping, and production hardware development.

Introduction

Overview

Verilog is an IEEE-standardized (HDL) for modeling electronic systems at the behavioral, (RTL), and gate levels of abstraction. As a formal notation that is both machine-readable and human-readable, it provides a means to describe the structure and behavior of digital hardware in a way that supports multiple phases of electronic system development. The core purpose of Verilog is to enable the specification of hardware designs for simulation, verification, and synthesis into physical implementations, such as application-specific integrated circuits (ASICs) and field-programmable gate arrays (FPGAs). Its key characteristics include event-driven simulation semantics, which model hardware responsiveness to changes, support for concurrent execution to represent parallel operations inherent in digital circuits, and a concise text-based syntax similar to the C programming language. Originating in the through development by Gateway Design Automation, Verilog was formalized as IEEE Standard 1364 in 1995 and has evolved within broader standards frameworks. In contemporary usage, it is predominantly employed alongside its extension, (IEEE 1800), to facilitate and workflows in complex digital systems.

Purpose and Applications

Verilog serves as a foundational hardware description language (HDL) in digital integrated circuit (IC) design, enabling register-transfer level (RTL) modeling that describes the behavior and structure of digital systems for subsequent synthesis into gate-level implementations. This RTL abstraction allows designers to specify concurrent operations and data flows, which synthesis tools then map to optimized logic gates and interconnects, facilitating efficient hardware realization. Additionally, Verilog supports the creation of testbenches—self-contained environments that simulate input stimuli and monitor outputs—to verify design functionality through behavioral simulation, ensuring correctness before physical fabrication. Gate-level netlists generated from Verilog descriptions are further used in timing analysis to assess signal propagation delays and meet performance constraints across the chip. In industry applications, Verilog is extensively employed in (ASIC) and (FPGA) development within the sector, powering complex designs at companies like and . For instance, Intel utilizes Verilog for state machine modeling in FPGA architectures, and is used by companies like AMD in SoC designs. Beyond core semiconductors, Verilog extends to systems, where it models custom hardware accelerators and interfaces, and SoC integration, combining multiple IP cores into unified chips for applications in automotive, telecommunications, and . These uses underscore Verilog's role in scalable hardware development, from prototyping to production. Verilog integrates seamlessly into (EDA) workflows, where it interfaces with tools for simulation to perform behavioral verification, synthesis to convert high-level descriptions into gate nets, and to mathematically prove design properties like equivalence between and gate levels without exhaustive test vectors. This integration supports end-to-end design flows, from specification to validation. Among its advantages, Verilog enables the development of reusable (IP) blocks through modular descriptions, promotes high-level via behavioral constructs, and accelerates agile design iterations by allowing rapid simulation-based prototyping and refinement. However, as a standalone language, Verilog has limitations in advanced verification capabilities, such as constrained-random testing and coverage metrics, often necessitating its extension with for handling the complexity of modern, large-scale designs.

History

Origins and Early Development

Verilog was developed in late 1983 at Gateway Design Automation, a startup founded by Prabhu Goel in 1983 to advance electronic design automation tools. The language was primarily created by Phil Moorby, a simulation expert, and Chi-Lai Huang, a logic synthesis specialist, with Goel's oversight as the company leader. Their goal was to produce a hardware description language capable of modeling complex digital integrated circuits for simulation, fault analysis, and early synthesis support, addressing the growing demands of VLSI design in the mid-1980s. The motivations for Verilog stemmed from the limitations of existing tools, such as analog simulators like SPICE, which were ill-suited for efficiently handling the behavioral and structural complexity of digital VLSI systems at scale. By adopting a syntax inspired by C for its procedural constructs—enabling familiar, readable code for hardware behavior—and elements from Fortran for event-driven simulation semantics, Verilog provided a more accessible and powerful alternative for digital logic modeling. This C-like approach allowed engineers to describe hardware at higher abstraction levels, facilitating faster iteration in design verification compared to gate-level netlists or analog-focused simulations. Gateway released the first commercial version of Verilog in 1985 alongside a basic simulator, followed by the more advanced Verilog-XL in 1987, which became the de facto reference implementation. Verilog-XL incorporated proprietary extensions beyond the core language, optimizing for high-performance event scheduling and mixed behavioral-gate simulations, though these features varied across tools until later standardization efforts. The company's growth led to its acquisition by Cadence Design Systems in October 1989 for approximately $72 million, integrating Verilog into Cadence's ecosystem and paving the way for broader industry adoption. In 1990, Cadence open-sourced the base language specification, accelerating its integration into diverse EDA tools while retaining proprietary simulator enhancements.

Standardization and Revisions

The standardization of Verilog was undertaken by the IEEE 1364 working group, established in 1993 under the IEEE Design Automation Standards Committee to address the growing need for among (EDA) tools from various vendors. This effort formalized Verilog as an , moving it away from proprietary implementations and enabling consistent use across the industry. The first IEEE standard, IEEE 1364-1995 (also known as Verilog-95), defined the core syntax and semantics of the language, including modules, primitive gates, and simulation semantics, based on the widely used Verilog 2.0 implementation without introducing new features. It focused on documenting the language as it was already employed in practice, providing a stable foundation for hardware description and verification. This standardization removed ambiguities from earlier proprietary versions and promoted vendor-neutral tool development. Subsequent revisions enhanced Verilog's capabilities while maintaining . IEEE 1364-2001 (Verilog-2001), ratified in 2001, introduced support for signed nets via the signed keyword for reg and net types, generate constructs including generate/endgenerate blocks, genvar, and localparam for scalable structural modeling, and expanded file I/O tasks such as $fgetc and $fscanf with support for up to 2^30 open s. These additions improved synthesizability and design reuse, particularly for deep submicron integrated circuits and (IP) blocks. IEEE 1364-2005 (Verilog-2005), published in 2005, made minor refinements, including additional tasks like $fstrobe, $dist_chi_square for probabilistic distributions, and $clog2 for integer logarithms, alongside C-style formatting enhancements in tasks such as $sformat with specifiers like %d and %h to boost code readability. It also clarified ambiguous semantics from prior versions and resolved inconsistencies. Overall, these standards facilitated the creation of interoperable EDA tools, accelerating Verilog's adoption in both academic research and flows by ensuring designs could be simulated, synthesized, and verified across multiple vendor ecosystems without modification. Further evolution beyond 2005 involved integration with extensions.

Merger with SystemVerilog and Recent Updates

In 2009, the IEEE merged the Verilog standard (IEEE 1364-2005) with the extensions (IEEE 1800-2005) to form IEEE 1800-2009, creating a unified , and where Verilog serves as a proper . This integration consolidated syntax and semantics into a single document, eliminating the need for separate Verilog maintenance while ensuring all prior Verilog constructs remained valid and supported within environments. The IEEE 1800-2012 revision built on this foundation by providing clarifications and enhancements to key language elements, including improved support for assertions to aid design verification and refined constructs for better communication modeling. It also addressed minor compatibility issues arising from the merger, ensuring seamless integration of legacy Verilog code without breaking existing tools or designs. Subsequent updates in IEEE 1800-2017 focused on refinements to capabilities, with enhancements to constrained random for more effective in testbenches and strengthened coverage mechanisms to improve functional metrics. Backward compatibility with Verilog was explicitly maintained, allowing pure Verilog designs to compile and simulate unchanged in SystemVerilog-compliant simulators. The most recent revision, IEEE 1800-2023, incorporates errata fixes, clarifications to ambiguous specifications, and formalization of previously tool-specific features to support larger-scale designs and advanced data handling, while preserving full compatibility with Verilog s. No major alterations to core Verilog elements were introduced, reinforcing its role as a foundational . These developments have significant implications for hardware design practices: existing Verilog code continues to execute correctly in modern SystemVerilog tools, but the addition of advanced verification features—such as object-oriented programming and constrained random testing—has driven a widespread shift toward SystemVerilog for new projects, particularly in complex SoC development. Since the 2009 merger, no independent Verilog standard has been maintained, with all evolution occurring under the IEEE 1800 umbrella. The IEEE P1800 working group, sponsored by the Design Automation Standards Committee, ongoingly maintains and revises the standard through periodic reviews, issue resolutions, and community input to address evolving needs in electronic system design and .

Core Language Constructs

Modules and Ports

In Verilog, modules serve as the primary building blocks for describing hardware designs, encapsulating functionality and providing a clear through ports for in hierarchical structures. Each defines a self-contained unit that can represent anything from a simple to a complex subsystem, promoting modularity and reusability in digital system modeling. A module is declared using the module keyword, followed by the module name and an optional list of ports enclosed in parentheses, with the declaration concluding with endmodule. Ports specify the and include direction keywords such as input for signals entering the module, output for signals exiting, and inout for bidirectional connections. For example, a basic module might be declared as follows:
module adder (input [3:0] a, b, output [3:0] sum);
    // Internal logic here
endmodule
This syntax allows ports to be declared directly in the port list, where the data types (such as bit widths for vectors) can be specified inline. Directionality rules enforce that input ports receive data from external sources, output ports drive data outward, and inout ports support tri-state or bidirectional flow, ensuring unambiguous signal propagation without conflicts in simulations. Ports are associated with types that determine their usage: wire (the default net type) for structural connections and continuous assignments, representing physical wires without storage, and reg for variables that hold values assigned in procedural blocks, providing storage capability. While input and inout ports default to wire, output ports can explicitly be declared as reg if they require procedural updates. These types, detailed further in data types documentation, ensure ports align with the module's intended signal behavior. Modules are instantiated within other modules to form hierarchical designs, using the module name, an optional instance identifier, and connections that link internal signals to the parent module's nets. can be positional (matching port order) or explicit (using dot notation for named associations), with the latter preferred for clarity in designs. For instance, instantiating a full adder submodule might look like:
full_adder fa1 (.sum(s), .carry(c), .a(a), .b(b));
This approach allows multiple instances of the same , each potentially connected differently, to build larger systems. To support configurability, modules can include declared with the parameter keyword, defining compile-time constants that influence aspects like bit widths or delays. For example:
[parameter](/page/Parameter) WIDTH = 8;
wire [WIDTH-1:0] data;
can be overridden during using a directive like #(WIDTH=16), enabling a single definition to adapt to varying requirements without code duplication. By treating modules as black boxes—exposing only ports while hiding internal details—Verilog facilitates in large-scale designs, allowing engineers to manage complexity through layered hierarchies where higher-level modules compose lower-level ones via instantiations and net connections. This encapsulation supports scalable and processes in hardware development.

Data Types and Variables

Verilog provides two primary categories of data types: nets and variables, which model structural connections and storage elements, respectively. Nets represent continuous signal paths driven by external sources, such as module outputs or continuous assignments, while variables hold values updated through procedural code and are essential for behavioral modeling. These types support scalar (single-bit) and vector (multi-bit) declarations, enabling representation of both simple signals and bus structures.

Nets

Nets are the default for modeling and interconnections in Verilog designs. The most common net type is wire, which serves as the implicit default and represents a physical connection that holds the value driven by a single source or resolves multiple drivers through wired logic. For example, a wire declaration appears as wire [7:0] bus;, where the optional range specifies a vector of 8 bits. Specialized net types include and , which implement wired-AND and wired-OR resolution functions for multiple drivers, respectively. In a wand net, the resolved value is 0 if any driver asserts 0, otherwise taking the value of the strongest non-zero driver; wor behaves similarly but with OR logic. These types are declared similarly, such as wand reset; or wor [3:0] control;, and default to high-impedance (z) when undriven. Other net variants like tri, triand, and trior extend wire with tri-state capabilities, but wire remains the standard for most continuous assignments.

Variables

Variables in Verilog are used within procedural blocks to store and manipulate values, simulating sequential or combinational behavior. The primary variable type is reg, which can represent either registers or wires in contexts but holds its value across cycles until explicitly updated. A reg declaration might be reg [31:0] counter;, allowing it to model a 32-bit element. Regs support four-state (0, 1, x, z) and default to unknown (x). Additional variable types cater to non-hardware modeling: provides a 32-bit signed value for general computations, declared as integer count;; time is a 64-bit unsigned type for tracking simulation time, such as time timestamp;; and real handles double-precision floating-point numbers, declared as real voltage;, defaulting to 0.0. These types are particularly useful in testbenches for algorithmic tasks rather than direct hardware synthesis.

Vectors

Verilog data types can be extended to vectors by specifying a bit range in the declaration, allowing multi-bit signals like buses. The syntax [msb:lsb] defines the width, where msb (most significant bit) and lsb (least significant bit) are constant expressions, and the vector is treated as unsigned by default. For instance, wire [7:0] data_bus; creates an 8-bit vector, with bits accessible via selects like data_bus[3]. Signed vectors were introduced in IEEE Std 1364-2001, declared using the signed keyword, such as reg signed [15:0] value;, which interprets the msb as a for operations. Alternatively, the system function $signed() can cast an expression to signed during use. Vectors can have a width of up to at least 65,536 bits, as required by the standard.

Arrays

Arrays in Verilog organize multiple instances of scalars, vectors, or even other arrays into multi-dimensional structures, commonly used for modeling. Declarations specify packed dimensions (bit width) followed by unpacked dimensions (array indices), such as reg [7:0] mem [0:255];, which defines a 256-byte where each element is an 8-bit vector. Multi-dimensional arrays like wire [31:0] bus_array [0:15][0:15]; support up to at least 16,777,216 elements. Access to array elements requires full index specification, e.g., mem[addr] = 8'hFF;, and indices must be constant expressions for declaration but can be variables for runtime access. Arrays of nets or variables follow the same rules as single elements, enabling compact representation of lookup tables or in designs.

Declaration Rules

All data types must be declared within a , task, or before use, using the general form net_type [range] identifier; for nets or variable_type [range] identifier; for variables. Nets are typically declared outside procedural blocks to model structural , while variables appear inside modules or blocks for behavioral assignments. Initial values are optional and supported only for variables (e.g., reg [3:0] state = 4'b0000;), defaulting to x for regs/integers/time and z for nets. Declarations cannot overlap names across nets, variables, or parameters in the same scope, ensuring unique identifiers. In contexts, types like wire or reg are explicitly specified to match interfaces, such as input wire clk;. Implicit net declarations are possible if the default_nettype is not set to none, but explicit declarations are recommended for clarity.

Operators and Expressions

Verilog provides a rich set of operators for performing , logical, bitwise, relational, and operations within expressions, enabling the modeling of behaviors at various levels. These operators operate on operands such as nets, variables, and literals, with results influenced by the system (0, 1, X, Z) inherent to the language. Expressions formed by these operators evaluate according to defined precedence rules, ensuring predictable computation in both continuous and procedural assignments. Arithmetic operators in Verilog include binary addition (+), (-), (*), (/), and (%), which perform standard operations with toward zero for and results; division or by zero yields an indeterminate value (X). The power operator (**) computes , producing a if any is real, or an indeterminate value (bx) if the base is zero and the exponent is negative. These operators handle unknown (X) and high-impedance () values by propagating indeterminacy in the result, such as treating Z as X in computations. For example, the expression 4'b1010 + 4'b0011 evaluates to 4'b1101. Logical operators facilitate conditional evaluations with && for logical AND, || for logical OR, and ! for logical NOT, each yielding a single-bit unsigned result of (true), (false), or X (ambiguous) based on operand truth values—where is false and non-zero is true. These operators are particularly useful in procedural blocks for , though their evaluation short-circuits in some contexts. Bitwise operators, including & (AND), | (OR), ^ (XOR), ~ (NOT), and ^~ or ~^ (XNOR), perform bit-by-bit operations on vectors or scalars, preserving the width of the widest . Reduction operators, such as &bus for AND reduction, collapse a multi-bit into a single bit by applying the operation across all bits; for instance, &4'b1010 results in . Relational operators compare operands and return a single-bit result: == for equality, != for inequality, > for greater than, < for less than, >= for greater than or equal, and <= for less than or equal, with comparisons treating X or Z as producing X outcomes to reflect uncertainty. Case equality (===) and case inequality (!==) extend these by explicitly matching X and Z states, making them essential for verifying unknown or tri-state conditions without indeterminacy. For example, 4'b10xz === 4'b10xz evaluates to 1, whereas == would yield X. Operator precedence follows a standard hierarchy to resolve expression evaluation order without ambiguity: unary operators (!, ~, unary +, unary -) have the highest precedence, followed by multiplicative operators (*, /, %), additive operators (+, -), relational operators (<, <=, >, >=, ==, !=, ===, !==), logical operators (&&, ||), and the (?:) at the lowest, with most associating left-to-right except for ?: (right-to-left). Parentheses can override this order, as in (a + b) * c. Signed and unsigned operands influence comparison semantics, with applied as needed based on data types. Concatenation operators enable bit-stream construction using curly braces {} to join expressions, such as {a, b} which appends the bits of b to a, resulting in a of combined width; this cannot appear on the left-hand side of assignments. Replication extends this with {n{expr}}, repeating expr n times, as in {3{2'b10}} yielding 6'b101010. These constructs are fundamental for building wider signals from narrower ones in structural modeling.
Operator CategoryExamplesKey Behaviors
Arithmetic+, -, *, /, %, **Truncates toward zero; X/Z propagation; = X.
Logical&&, `
Bitwise & Reduction&, `, ^, ~, &bus`
Relational==, !=, >, <, ===, !==1-bit comparison; case variants handle X/Z exactly.
Concatenation & Replication{a,b}, {n{a}}Builds s; replication for multiples.

Behavioral and Concurrent Modeling

Procedural Blocks: Initial and Always

Procedural blocks in Verilog provide a mechanism for describing sequential behavior within modules, allowing designers to model both initialization tasks and ongoing hardware activities. These blocks, specifically initial and always, execute procedural statements in a sequential manner, contrasting with the concurrent nature of structural descriptions. They are essential for behavioral modeling, where the focus is on the functional operation rather than gate-level details. The initial block executes exactly once at the beginning of simulation, typically at time 0, making it ideal for setting up initial conditions, generating stimuli, or configuring testbenches. For instance, it can initialize variables or create a clock signal that persists throughout the simulation. A common example is clock generation:
initial begin
    clk = 0;
    forever #5 clk = ~clk;
end
This block starts with clk set to 0 and then toggles it every 5 time units indefinitely using the forever loop, providing a periodic stimulus without repeating the entire block. Once the statements within an initial block complete or suspend indefinitely (as in the case of forever), the block terminates and does not restart. Multiple initial blocks in a module execute concurrently but each only once, enabling parallel one-time setups. In contrast, the always block executes continuously throughout the simulation, repeating its procedural statements in response to specified events or indefinitely, which suits modeling persistent hardware behaviors like combinational logic, sequential elements, or state machines. It begins execution at time 0 and loops until the simulation ends, triggered by changes in a sensitivity list or timing controls. For sequential logic, such as a flip-flop, the block might be written as:
always @(posedge clk) begin
    q <= d;
end
Here, the block activates on the rising edge of clk (denoted by posedge), scheduling the value of d to update q. For combinational logic, like a multiplexer or gate, an always block with inferred sensitivity can be used:
always @(*)
    y = a ? b : c;
The @(*) automatically includes all variables read within the block in the sensitivity list, ensuring the block re-evaluates whenever any input changes, mimicking combinational behavior. Sensitivity lists support edge detection with posedge for rising edges and negedge for falling edges, or level-sensitive events, allowing precise control over block activation. Comma-separated lists, such as @(posedge clk or negedge reset), enable multi-event triggering. Assignments within procedural blocks use either blocking or non-blocking operators, which affect execution order and simulation accuracy. Blocking assignments (=) update the target variable immediately and sequentially, blocking further execution until complete; they are appropriate for combinational logic where immediate propagation is desired, as in the multiplexer example above. Non-blocking assignments (<=) schedule updates to occur at the end of the current time step or in the next delta cycle, allowing parallel evaluation across multiple blocks; this is crucial for sequential logic to model hardware concurrency correctly and avoid race conditions, as seen in the flip-flop example. Mixing assignment types within a block can lead to unintended ordering, so consistent use—blocking for combinational paths and non-blocking for clocked processes—is recommended. For blocks containing multiple statements, the begin...end keywords group them into a single procedural unit, enabling structured sequencing. Nesting is supported within named blocks (e.g., begin : label), allowing hierarchical organization of complex behaviors, such as conditional initialization or looped operations inside an always block. This structure facilitates readable, multi-line descriptions without implicit single-statement limitations.

Concurrency with Fork-Join

In Verilog, the fork-join construct enables the modeling of concurrent processes within procedural blocks, allowing multiple statements or tasks to execute in parallel during simulation. This mechanism is essential for representing hardware behaviors where multiple events occur simultaneously, such as independent signal generations or parallel testbench stimuli. The basic syntax involves a fork keyword followed by one or more procedural statements, tasks, or blocks enclosed within begin...end pairs, and terminated by a join statement that suspends execution until all forked processes complete. For instance, the structure fork: label begin statement1; statement2; end join initiates parallel execution of the statements, with the label providing an optional identifier for later reference. These constructs are confined to procedural contexts, such as within always or initial blocks, and cannot be used at the module level. Early termination of forked processes is supported via the disable fork statement, which aborts all processes under a named fork label when invoked, facilitating controlled simulation scenarios like error handling in test environments. A practical example illustrates concurrent task execution:
always begin
    fork
        task1();  // Generates clock signal
        task2();  // Applies reset sequence
    join
end
Here, task1 and task2 run simultaneously, modeling parallel hardware initialization, with the always block waiting for both to finish before proceeding. This is particularly useful in verification for simulating multiple independent stimuli, such as driving inputs to a digital circuit concurrently. Although powerful for simulation-based verification, fork-join constructs do not imply true hardware parallelism during synthesis, as they are interpreted as sequential event scheduling in the target netlist; thus, they are primarily simulation constructs for behavioral modeling rather than synthesizable logic generation.

Race Conditions and Event Scheduling

Verilog employs an event-driven simulation model based on a stratified event queue, as defined in IEEE Std 1364, to manage the execution of concurrent processes without advancing simulation time for zero-delay events. This model divides each time step into distinct regions where events are processed in a specific order to simulate hardware concurrency, but the arbitrary ordering within certain regions can introduce nondeterminism. The simulation begins at time t=0, where events are scheduled into queues, and delta cycles—virtual time steps of infinitesimal duration—allow multiple iterations within the same timestamp until no new events are triggered. The core simulation regions in Verilog, per IEEE 1364 semantics, include the active region, inactive region, non-blocking assign (NBA) region, and observed (or monitor) region. In the active region, blocking assignments (=) and immediate events, such as those triggered by procedural blocks like initial or always, are evaluated and executed in an arbitrary order, potentially leading to race conditions if multiple processes update shared variables simultaneously. The inactive region handles events scheduled with zero delay (#0), such as those from continuous assignments or certain procedural delays, processed after the active region but still within the same time step. Updates from non-blocking assignments (<=), evaluated in the active or inactive regions, are deferred to the NBA region, ensuring that right-hand-side expressions are sampled before left-hand-side updates occur, which promotes more predictable sequential logic modeling. The observed region executes last, handling system tasks like display and monitor after all updates, to provide a consistent view of signal states at the end of the time step. Race conditions arise primarily from the undefined execution order within the active region, particularly at simulation time t=0, where the execution order of initial and always blocks is indeterminate and simulator-dependent, or when #0 delays cause intermingling of events across blocks. For instance, two always blocks assigning to the same register using blocking assignments can yield simulator-dependent results due to arbitrary process ordering. These races are exacerbated in concurrent structures like fork-join, where parallel processes may schedule events nondeterministically into the event queue. A primary solution is the use of non-blocking assignments in clocked always blocks, which schedule updates in the NBA region, decoupling evaluation from update and mimicking flip-flop behavior to avoid races in sequential designs. Blocking assignments remain suitable for combinational logic but require careful ordering to prevent races. Verilog's event model operates as a two-phase mechanism within each time slot—combining active and inactive regions for event evaluation followed by NBA for updates—contrasting with SystemVerilog's expanded model that enhances predictability for verification by separating design and testbench events more distinctly. This Verilog approach, while efficient for synthesis, can lead to simulation-synthesis mismatches if races are not addressed. For debugging such issues, system tasks like monitor and strobe are invaluable, as they execute in the observed region after NBA updates, ensuring output reflects final values free of intra-time-step races. monitor continuously tracks specified variables and prints on changes at the time step's end, while strobe provides a one-time print of updated states, both aiding in verifying intended ordering without simulator-specific artifacts.

Logic and Simulation Semantics

Four-Valued Logic

Verilog employs a four-valued logic system to model digital circuit behavior accurately during simulation, incorporating states beyond binary 0 and 1 to represent real-world uncertainties and hardware conditions. The four values are 0, denoting a logic low or false state; 1, denoting a logic high or true state; X, representing an unknown or undefined state; and Z, indicating a high-impedance or undriven state. These values apply to nets, variables, and expressions, enabling the simulation of tri-state logic and initialization issues without assuming perfect binary conditions. The value 0 corresponds to a low voltage level, while 1 corresponds to a high voltage level, forming the basis for standard digital operations. X models scenarios such as uninitialized signals, conflicting assignments, or simulation uncertainties, ensuring conservative verification by propagating doubt through the design. Z is essential for high-impedance states, where a net is not actively driven, such as in tri-state buffers or bidirectional buses, allowing multiple drivers to share a net without constant assertion. In practice, nets default to Z if undriven, while variables like reg default to X if unassigned, highlighting the distinction between wire-like connectivity and storage elements. Propagation of these values follows deterministic rules in logic gates and expressions, preserving Z and X where applicable to reflect hardware realities. For instance, in an AND operation, 1 & Z yields Z, 0 & X yields 0, and X & X yields X, as Z acts like a non-contributing high-impedance and X introduces uncertainty that dominates unless resolved by a definitive 0. Similar rules apply to OR, where 0 | Z yields Z, 1 | X yields X, and Z | Z yields Z, ensuring Z propagates through undriven paths. The NOT operator inverts 0 to 1 and 1 to 0 but leaves X as X and Z as Z, maintaining their special semantics. The following table summarizes propagation for binary AND and OR gates, including interactions with X and Z (based on combinational primitive definitions):
Input AInput BAND ResultOR Result
0000
0101
1001
1111
0X0X
0Z0Z
1XX1
1ZZ1
X00X
X1X1
XXXX
XZXX
Z00Z
Z1Z1
ZXXX
ZZZZ
For NOT: 0 → 1, 1 → 0, X → X, Z → Z. In nets, particularly buses, Z enables tri-state logic by allowing segments to float without interference, while X arises from contention—such as multiple drivers asserting conflicting 0 and 1—or uninitialized conditions, signaling potential design flaws. This is resolved during simulation via net resolution functions, where equal-strength conflicts produce X. X propagation significantly impacts simulation semantics, providing conservative analysis by treating unknowns as potentially erroneous; for example, in an adder, 1 + X results in X, alerting designers to incomplete initialization or undefined paths. This behavior extends to arithmetic and bitwise operations, where any X operand yields an X result, promoting robust verification. While the core four values suffice for most digital modeling, Verilog supports optional strength levels to approximate analog effects, such as strong0 (high drive low), weak1 (low drive high), pull0, pull1, and supply levels, with highz (0) for Z. These strengths resolve driver conflicts hierarchically—stronger drives override weaker ones—but the basic 0, 1, X, Z system remains fundamental for logic propagation.

System Tasks and Built-in Functions

Verilog includes a set of predefined system tasks and built-in functions that facilitate simulation control, data output, file operations, randomization, and utility calculations, typically invoked within procedural blocks like initial or always. These elements are essential for debugging, logging, and managing simulation flow in hardware description and verification environments. Defined in the IEEE 1364 standard, they operate non-synthesizably during simulation, interacting with the event scheduler to produce observable behaviors.

Display Tasks

Display tasks enable formatted output of simulation values to the console or monitors. The $display task outputs a formatted string followed by a newline character, executing immediately at the current simulation time and supporting C-style format specifiers such as %b for binary or %d for decimal representations of arguments. In contrast, $write performs similar formatted output but omits the trailing newline, allowing concatenation of multiple outputs on the same line. The $strobe task schedules output to occur at the end of the current time step (post-delta cycle), ensuring that displayed values reflect stable signal states after all updates within that timestep, and it appends a newline like $display. These tasks handle expressions, strings, and escape sequences, making them invaluable for real-time monitoring during simulation runs. For example, the syntax $display("Value of a: %d", a); prints the decimal value of variable a followed by a newline.

Timing Tasks

Timing-related system tasks and constructs manage simulation progression and time queries. The $time system function returns the current simulation time as a 64-bit integer value, scaled according to the prevailing timescale directive in the module (e.g., 1 ns / 1 ps). Delay statements, denoted by #delay within procedural blocks, suspend the executing process for the specified duration—where delay can be a constant, variable, or real number—and reschedule it as an event in the future or inactive queue, adhering to the event-driven simulation semantics. Such delays are crucial for modeling temporal behaviors but are ignored during synthesis.

File I/O Tasks

File input/output tasks support persistent logging and data storage during simulations. The $fopen task opens a specified file and returns a 32-bit file descriptor (positive integer) for subsequent operations, or zero if the open fails; an optional mode string (e.g., "w" for write) can specify access type, and multichannel descriptors allow multiple files under one handle. $fwrite, analogous to $write, directs formatted output to the file identified by the descriptor, enabling structured logging without console interference. To conclude operations, $fclose releases the descriptor, closes the file, and terminates any associated monitoring tasks like $fmonitor. These tasks are particularly useful for generating simulation waveforms or reports in large-scale designs.

Randomization Tasks

Randomization tasks generate pseudo-random values for stimulus creation in testbenches. $random produces a signed 32-bit integer, with an optional seed argument to initialize the generator for reproducible sequences across runs. Introduced in the IEEE 1364-2001 revision, $urandom yields an unsigned 32-bit integer without seeding support, simplifying generation of non-negative random numbers for applications like input vector randomization. Both tasks rely on a linear congruential generator algorithm inherent to the simulator.

Simulation Control Tasks

Simulation control tasks govern the runtime lifecycle of the Verilog simulator. $finish terminates the simulation immediately, optionally accepting a status code (0 for normal completion, 1 for error, 2 for conversion from interactive mode) that may influence diagnostic reporting in the tool. $stop halts execution at the current point, suspending all processes and entering an interactive debugging mode, with an optional level argument (0-2) to control verbosity of the pause message. The $reset task, while less uniformly specified, resets the simulation state—including time to zero and variables to their initial values—though its exact behavior depends on the simulator implementation. These tasks ensure controlled execution in complex verification scenarios.

Built-in Functions

Built-in functions offer compile-time or elaboration-time computations for design utilities, with several added in the IEEE 1364-2001 standard. $clog2 computes the ceiling of the base-2 logarithm of its positive integer argument (returning 0 for input 0), effectively determining the minimum bit width required to represent values up to that argument, and it treats the input as unsigned. For instance, $clog2(10) yields 4, as $2^4 = 16 \geq 10. These functions enhance code portability and are often used in synthesizable contexts for address calculations or array sizing.

Interfaces and Extensions

Definition and Use of Constants

In Verilog, constants are essential for enhancing design reusability and readability by allowing fixed values to parameterize modules without altering the core code structure. The parameter keyword declares compile-time constants that define module attributes, such as data widths or timing values, and these can be overridden at the point of module instantiation to customize behavior across hierarchies. For instance, the declaration parameter CLK_PERIOD = 10; sets a default clock period in time units, which can be adjusted when instantiating the module, such as #(.CLK_PERIOD(20)) my_module(...);, enabling scalable simulations or syntheses without code modifications. This overridability makes parameters particularly valuable for creating generic components like bus interfaces or counters, where the exact configuration varies by application. A related construct, localparam, defines constants that are confined to the module's scope and cannot be overridden from outside, providing protection against unintended modifications while still supporting internal parameterization. The syntax is localparam ADDR_WIDTH = 32;, which might specify a fixed address bus width derived from higher-level parameters, ensuring consistency within the module without exposing it for external changes. Unlike standard parameters, localparams are resolved at elaboration time and are ideal for derived constants, such as computing array sizes based on module inputs, promoting robust and error-resistant designs. Verilog also supports constants via the `define macro directive, which performs text substitution at compile time, effectively replacing the macro name with its defined value throughout the design file or compilation unit. For example, `define TRUE 1'b1 allows simple boolean flags to be used consistently, but this global scope can lead to name clashes if the same macro is redefined elsewhere. Macros are preprocessor directives, lacking the type safety and hierarchical scoping of parameters, and are best limited to non-synthesizable code like testbenches due to potential simulation-synthesis mismatches. Constants find practical application in expressions for conditional logic, delay specifications, and especially in scalable designs enabled by Verilog-2001's generate constructs, where parameters drive loop iterations to instantiate repetitive hardware. Consider a parameterized adder module:
module adder #(parameter WIDTH = 8) (
    input [WIDTH-1:0] a, b,
    output [WIDTH:0] sum
);
    assign sum = a + b;
endmodule
This allows instantiation as adder #(16) wide_adder(...); for a 16-bit version, demonstrating how parameters facilitate width-independent designs. In generate-for loops, parameters control the number of instances, such as generating a shift register chain:
genvar i;
generate
    for (i = 0; i < DEPTH; i = i + 1) begin : shift_stages
        if (i == 0) assign out[0] = in;
        else assign out[i] = out[i-1];
    end
endgenerate
Here, parameter DEPTH = 8; scales the structure dynamically, a feature introduced in IEEE Std 1364-2001 to support procedural generation of hardware. Best practices emphasize using parameters and localparams for synthesizable, hierarchical code to leverage scoping and overridability, while reserving `define for global, non-hierarchical substitutions like debug flags to minimize risks of clashes or debugging challenges. Parameters should be declared with meaningful defaults and documented overrides, ensuring designs remain flexible yet predictable across tools and flows.

Program Language Interface (PLI)

The Programming Language Interface (PLI) provides an application programming interface (API) for bidirectional communication between a Verilog simulator and external programs, typically written in C or C++, enabling the extension of Verilog with custom system tasks and functions. This interface allows external code to access and modify simulation data structures, such as nets, registers, and parameters, during runtime, facilitating advanced verification and simulation control. Originally defined in IEEE Std 1364-1995, PLI has evolved to support applications like custom debugging, waveform dumping, and integration with external hardware or CAD tools. Custom system tasks and functions are invoked from Verilog using the $ prefix, such as $my_task or $get_vector, with tasks allowing time delays and multiple input/output arguments, while functions return a single value without delays. These are registered in external code via routines like vpi_register_systf(), which specifies callbacks for size determination (sizetf), syntax checking (compiletf), and execution (calltf). During execution, the tf_doit routine or equivalent VPI handles perform the core operations, with arguments accessed on demand to support efficient simulation. Access routines enable reading and writing of Verilog data, with deprecated TF routines like tf_getpvalue retrieving values from variables (e.g., nets or parameters) and tf_putpvalue assigning values to them, supporting formats such as scalar (single-bit logic), vector (multi-bit binary strings), strength (drive levels from 0-7), and others including TF_BIN (binary), TF_HEX (hexadecimal), TF_OCT (octal), and TF_DEC (decimal). Modern equivalents in VPI, such as vpi_get_value and vpi_put_value, use structures like s_vpi_value for similar operations, accommodating formats including vpiBinStrVal (binary string), vpiIntVal (integer), vpiRealVal (floating-point), and vpiVectorVal (multi-bit vector), while supporting delay options like vpiNoDelay or vpiInertialDelay. Additional routines like vpi_get_delays and vpi_put_delays manage timing information using s_vpi_delay and s_vpi_time structures. The Verilog Procedural Interface (VPI), introduced as an object-oriented extension in IEEE Std 1364-2001, supersedes earlier TF and ACC routines by providing a hierarchical model for accessing the design via handles (vpiHandle) and iterators (vpi_iterate, vpi_scan). It enables tree traversal of the design hierarchy, allowing navigation through modules, nets, and other objects using properties like vpiSize, vpiName, and vpiLibrary, along with new routines such as vpi_control for simulation management and vpi_register_cb for event callbacks (e.g., cbValueChange for net monitoring). PLI and VPI find applications in custom debugging (e.g., dynamic net value display), acceleration through dynamic link libraries (DLLs), test vector generation, delay annotation, and integration with other languages or hardware interfaces for co-simulation. For instance, external C code can read signal values via tf_getpvalue in hexadecimal format for waveform dumping or write values to inject stimuli during verification. While powerful, PLI's TF and ACC routines were deprecated in IEEE Std 1364-2005 in favor of VPI, and the interface as a whole has been largely superseded by SystemVerilog's Direct Programming Interface (DPI) for simpler C/C++ integration. VPI remains foundational and is extended in SystemVerilog standards.

Synthesis and Implementation

Synthesizable Constructs

In Verilog, synthesizable constructs refer to the language subset that can be mapped to hardware gates and flip-flops by synthesis tools, as defined by the IEEE 1364.1 standard for register-transfer level (RTL) synthesis. This standard specifies the syntax and semantics of IEEE Std 1364 (Verilog HDL) elements suitable for uniform interpretation across compliant tools, ensuring predictable hardware generation without simulation-specific behaviors. Key synthesizable elements include continuous assignments using the assign statement for combinational logic, such as assign out = a & b;, which directly models wire-level connections. Always blocks are central for procedural descriptions: for combinational logic, always @(*) with blocking assignments (=) infers gates like multiplexers, as in always @(*) if (sel) y = a; else y = b;; for sequential logic, always @(posedge clk) with non-blocking assignments (<=) infers flip-flops, exemplified by always @(posedge clk) q <= d;. Basic gate-level primitives, such as and (out, in1, in2);, are also fully supported for structural modeling. Supported data types in synthesizable RTL code are limited to wire and reg (including vectors like reg [7:0] data;), which map to nets and storage elements, respectively. Arithmetic and logical operators (e.g., +, &, >) are permitted for bit-level operations, but types like real, time, and integer are avoided in RTL as they do not correspond to synthesizable hardware and may lead to simulation-synthesis mismatches. Hardware inference from these constructs enables efficient design: always blocks model multiplexers via conditional statements and flip-flops via clocked processes, while generate statements replicate structures (e.g., genvar i; generate for (i=0; i<4; i=i+1) begin : gen_block assign out = in ^ 1; end endgenerate), and parameters provide generics like module adder #(parameter WIDTH=8) (...);. Non-synthesizable constructs include initial blocks, which are simulation-only and cannot be mapped to hardware except in limited reset scenarios handled via always blocks; procedural delays (e.g., #10), which imply timing not present in static hardware; and system tasks like $display, which are ignored or unsupported in synthesis. Synthesis tools adhere to the IEEE 1364 subset, issuing warnings for potential issues like incomplete sensitivity lists in combinational always blocks, which can infer unintended latches instead of gates. Procedural blocks from behavioral modeling, when restricted to synthesizable forms, directly influence hardware mapping in this context.

Simulation and Synthesis Tools

Verilog simulation tools enable the verification of hardware designs by executing Verilog code to model circuit behavior over time. Commercial simulators dominate the industry due to their advanced features and support for large-scale designs. Cadence Xcelium Logic Simulator offers high-performance simulation for SystemVerilog, VHDL, and mixed-signal environments through parallel processing. Synopsys VCS provides multicore parallelism and comprehensive coverage analysis for functional verification, supporting UVM-based testbenches. Siemens Questa One Sim integrates faster engines with built-in power-aware simulation and enhanced debugging capabilities for ASIC and FPGA verification. Open-source alternatives provide cost-effective options for smaller projects or academic use. Icarus Verilog is an interpreted simulator that implements IEEE 1364-1995 standards with support for mixed-language designs, suitable for gate-level and behavioral simulations. Verilator, developed by Veripool, compiles Verilog to C++ for cycle-accurate simulation, often outperforming commercial tools in speed for synthesizable subsets while enabling multithreaded execution. Synthesis tools transform Verilog RTL code into gate-level netlists or FPGA configurations, optimizing for area, timing, and power. Commercial RTL synthesizers include Synopsys Design Compiler, which performs timing-driven optimization and supports low-power techniques for ASIC flows. Cadence Genus Synthesis Solution delivers up to 5x faster turnaround times through machine learning-based optimizations and unified RTL-to-physical synthesis. For FPGA implementation, AMD Vivado Design Suite integrates synthesis with place-and-route, supporting Verilog for adaptive SoCs and high-level design entry. Intel Quartus Prime provides similar end-to-end tools for FPGA synthesis, including timing analysis and resource optimization. Mixed tools facilitate co-simulation and debugging across simulation and synthesis flows. Aldec Riviera-PRO supports high-performance mixed-language simulation (VHDL/Verilog/SystemVerilog) with advanced waveform viewing and integration for FPGA/SoC verification. Synopsys Verdi serves as a waveform viewer and debug platform, automating regression management and providing AI-driven analysis for post-simulation insights. Key features across these tools include cycle-accurate simulation for timing verification, linting to check synthesizability against Verilog subsets, and coverage analysis for functional completeness. These capabilities ensure designs meet performance targets before fabrication. Recent trends emphasize cloud-based EDA for scalable verification, with cloud platforms providing scalable EDA workflows to reduce hardware costs (as of 2024 predictions). Integration with CI/CD pipelines enables automated verification farms, accelerating regression testing for complex SoCs. Open-source tools are gaining traction to address commercial licensing gaps. Yosys Open Synthesis Suite offers Verilog-2005 RTL synthesis with logic optimization algorithms, often paired with nextpnr for FPGA flows. GTKWave provides a versatile waveform viewer for VCD and other formats, supporting open-source simulation debugging. These tools foster accessible hardware design, particularly in research and prototyping.

Practical Examples

Basic Gate-Level Example

Gate-level modeling in Verilog represents digital circuits by instantiating primitive logic gates, such as AND, OR, and , which are built-in components defined in the . This approach emphasizes structural description, where the design hierarchy mirrors the physical interconnections of gates, facilitating direct mapping to hardware implementations. A classic example is a 1-bit full adder, which computes the sum and carry-out for three binary inputs: two bits (A and B) and a carry-in (CIN). The module uses primitive gates to realize the sum () and carry-out (majority function of A, B, and CIN). The following Verilog code defines a 1-bit full adder module using primitive gates, structured hierarchically with submodules for sum and carry generation.
verilog
module fulladder (A, B, CIN, S, COUT);
    input A, B, CIN;
    output S, COUT;
    sum S1 (S, A, B, CIN);
    carry C1 (COUT, A, B, CIN);
endmodule

module sum (S, A, B, CIN);
    input A, B, CIN;
    output S;
    wire t1;
    xor X1 (t1, A, B);
    xor X2 (S, t1, CIN);
endmodule

module carry (COUT, A, B, CIN);
    input A, B, CIN;
    output COUT;
    wire a1, a2, a3;
    and A1 (a1, A, B);
    and A2 (a2, B, CIN);
    and A3 (a3, A, CIN);
    or O1 (COUT, a1, a2, a3);
endmodule
In this implementation, the top-level fulladder module declares input and output ports as single-bit scalars, adhering to Verilog's port syntax for gate-level designs. Internal wires, such as t1 in the sum submodule and a1, a2, a3 in the carry submodule, connect gate outputs to inputs, representing netlist interconnections. Gate instantiations, like xor X1 (t1, A, B);, specify the primitive type, instance name, and port connections in positional order, enabling explicit wiring without behavioral assignments. This structural style promotes reusability through hierarchy and aligns with synthesis tools that target gate libraries. To verify functionality, a simple testbench can apply stimuli using an initial block to cycle through input combinations and monitor outputs. The testbench instantiates the full adder and drives inputs sequentially with delays.
verilog
module test_fulladder;
    reg A, B, CIN;
    wire S, COUT;
    fulladder fa (A, B, CIN, S, COUT);
    initial begin
        $monitor("A=%b, B=%b, CIN=%b -> S=%b, COUT=%b", A, B, CIN, S, COUT);
        A = 0; B = 0; CIN = 0; #10;
        B = 1; #10;
        A = 1; B = 0; #10;
        B = 1; CIN = 0; #10;
        CIN = 1; B = 0; #10;
        A = 0; B = 1; CIN = 1; #10;
        $finish;
    end
endmodule
Key learning outcomes include mastering structural modeling for bottom-up design and leveraging Verilog's primitive library, which includes like and, or, xor, nand, nor, xnor, and not for basic logic operations. These primitives support (0, 1, x, z) and are synthesizable to ASIC or FPGA targets. The yields the full adder's , confirming correct behavior:
ABCINSCOUT
00000
01010
10010
11001
00110
01101
10101
11111
For scalability, Verilog-2001 introduced the generate construct to replicate gate-level structures for multi-bit designs, such as an . This for-loop generates instances and wires dynamically, as shown in the following parameterized module where SIZE defines the bit width.
verilog
module Nbit_adder (co, sum, a, b, ci);
    [parameter](/page/Parameter) SIZE = 4;
    output [SIZE-1:0] sum;
    output co;
    input [SIZE-1:0] a, b;
    input ci;
    wire [SIZE:0] c;
    genvar i;
    assign c[0] = ci;
    assign co = c[SIZE];
    generate
        for (i = 0; i < SIZE; i = i + 1) begin : addbit
            wire n1, n2, n3;
            xor g1 (n1, a[i], b[i]);
            xor g2 (sum[i], n1, c[i]);
            and g3 (n2, a[i], b[i]);
            and g4 (n3, n1, c[i]);
            or g5 (c[i+1], n2, n3);
        end
    endgenerate
endmodule
This variation extends the 1-bit design by chaining full adders via the carry wire vector, with unique hierarchical names (e.g., addbit{{grok:render&&&type=render_inline_citation&&&citation_id=0&&&citation_type=wikipedia}}.g1) for each generated block, enhancing modularity for larger circuits.

Behavioral Description Example

A behavioral description in Verilog uses procedural blocks, such as the always construct, to model higher-level functionality like sequential logic without specifying individual gates. This approach abstracts the hardware implementation, allowing designers to focus on the intended behavior, such as state transitions or arithmetic operations triggered by events like clock edges. According to IEEE Std 1364-2005, procedural assignments within these blocks can infer flip-flops or latches based on the sensitivity list and assignment types, enabling concise descriptions of complex circuits. Consider a simple 4-bit up-counter module that increments on each positive clock edge unless is asserted. The module counter declares inputs for clock (clk) and active-low (rstn), with a 4-bit output out of type reg to hold the count value. The core logic resides in an always block sensitive to the rising edge of the clock, using a non-blocking assignment (<=) to update the register: if is active (!rstn), the output is set to 4'b0000; otherwise, it increments by 1. This sensitivity list @(posedge clk) ensures the block executes only on clock edges, modeling synchronous behavior and inferring edge-triggered flip-flops during synthesis. Non-blocking assignments schedule updates to occur after all evaluations in the time step, preventing race conditions in simulations.
verilog
module counter (
    input clk,
    input rstn,
    output reg [3:0] out
);

always @(posedge clk) begin
    if (!rstn)
        out <= 4'b0000;
    [else](/page/The_Else)
        out <= out + 1;
end

endmodule
To verify this design, a testbench instantiates the and generates stimuli using an initial block. The clock is toggled every 5 time units for a 10-unit period, while is asserted low at time 0, deasserted at 20, and reasserted at 100 before simulation ends at 200. uses $monitor to print output changes, capturing the counter's response to clock and reset events. The reg type for out allows procedural updates, and the initial block provides one-time initialization without implying hardware.
verilog
module tb_counter;

reg clk;
reg rstn;
wire [3:0] out;

[counter](/page/Counter) dut (.clk(clk), .rstn(rstn), .out(out));

always #5 clk = ~clk;

initial begin
    clk <= 0;
    rstn <= 0;
    #20 rstn <= 1;
    #80 rstn <= 0;
    #50 rstn <= 1;
    #20 $finish;
end

initial begin
    $monitor("Time: %0t | rstn: %b | out: %b", $time, rstn, out);
end

endmodule
A typical trace demonstrates the resetting to 0x0, incrementing from 0x0 to 0x8, and responding to by returning to 0x0 on the next clock edge, then resuming incrementing. For instance:
Time (ns)rstnout (hex)Description
00Initial
251First increment after deassert
1000rstn asserted low
1050Reset on clock edge
1551Resume incrementing post-reset
This trace confirms inference, with updates occurring on posedge clk and resets taking effect on the clock edge when rstn is low. Key to this behavioral style is the use of non-blocking assignments (<=) in clocked always blocks, which models the parallel nature of hardware registers and avoids simulation races where multiple blocks update shared variables in unpredictable orders. Blocking assignments (=) would instead serialize updates, potentially leading to incorrect inferred latches or combinational paths. By specifying only the desired behavior, this equates to an array of four D flip-flops with increment logic but is far more concise than an equivalent gate-level of AND/OR gates and flip-flop primitives.

References

  1. [1]
    IEEE 1364-2001 - IEEE SA
    The Verilog(R) Hardware Description Language (HDL) is defined in this standard. Verilog HDL is a formal notation intended for use in all phases of the creation ...
  2. [2]
    Verilog HDL and its ancestors and descendants - ACM Digital Library
    Jun 12, 2020 · This paper describes the history of the Verilog hardware description language (HDL), including its influential predecessors and successors.
  3. [3]
    [PDF] Verilog Fundamentals
    Feb 9, 2007 · • Verilog can model hardware at three levels of abstraction: gate level, register transfer level, and behavioral. • Understanding the Verilog ...
  4. [4]
    IEEE Standard for Verilog Hardware Description Language
    Verilog HDL is a formal notation intended for use in all phases of the creation of electronic systems. Because it is both machine-readable and human-readable, ...
  5. [5]
    Verilog Tutorial - ChipVerify
    Verilog is widely used for design and verification of digital and mixed-signal systems, including both application-specific integrated circuits (ASICs) and ...Introduction to Verilog · Verilog Syntax · Verilog Examples · SystemVerilog Tutorial
  6. [6]
    The Simulation Semantics of Synthesisable Verilog - arXiv
    Feb 26, 2025 · In short, the semantics is reactive and event driven: it is driven by concurrent processes that create and react to events, such as a clock tick ...<|control11|><|separator|>
  7. [7]
    [PDF] Verilog
    Verilog is a “concurrent” language, different than a “procedural” language like C or Java. Verilog is the most widely used HDL industry today, but VHDL is ...Missing: key | Show results with:key
  8. [8]
    Verilog Manual - University of Texas at Austin
    This manual will cover all aspects of the Verilog language that you will need to be familiar with. 2. Syntax. Verilog uses a C-like syntax. It is case sensitive ...
  9. [9]
    History Of Verilog - ASIC World
    Verilog started as a proprietary language around 1984, became open in 1991, and became an IEEE standard in 1995. It was acquired by Cadence in 1990.
  10. [10]
    SystemVerilog Tutorial - ChipVerify
    SystemVerilog is an extension of Verilog with verification features, used to verify hardware designs with complex testbenches and random stimuli.SystemVerilog Threads · SystemVerilog Assertions · SystemVerilog Interview Set 1
  11. [11]
    What is Electronic Design Automation (EDA)? – How it Works
    Verification tools examine either the logical or physical representation of the chip to determine if the resultant design is connected correctly and will ...<|separator|>
  12. [12]
    Hardware Description Languages: VHDL vs Verilog, and Their ...
    Mar 17, 2022 · VHDL vs Verilog ; More natural in use. More of a hardware modeling language ; Wordy. Succinct ; Non-C-like syntax. Similarities to the C language.
  13. [13]
    Verilog - Semiconductor Engineering
    Verilog is a Hardware Description Language (HDL) invented in 1984, named from VERIfy and LOGic. It was released with a logic simulator.
  14. [14]
    1.6.4.2. Verilog HDL State Machines - Intel
    Mar 28, 2022 · To ensure proper recognition and inference of Verilog HDL state machines, observe the following additional Verilog HDL guidelines. Refer to your ...
  15. [15]
    Types of HDLs Explained - Cadence PCB Design & Analysis
    Dec 18, 2024 · However, Verilog has a superior grasp on hardware modeling as well as a lower level of programming constructs. Verilog is not as wordy as VHDL, ...Key Takeaways · Three Most Popular... · All About Verilog
  16. [16]
    IEEE Standard for SystemVerilog—Unified Hardware Design ...
    Dec 11, 2009 · Abstract: This standard represents a merger of two previous standards: IEEE Std 1364™-2005. Verilog hardware description language (HDL) and ...<|separator|>
  17. [17]
    Verilog HDL and its ancestors and descendants (HOPL IV - Papers)
    Verilog HDL is a hardware description language. Since its creation in 1984 and first sale in 1985, Verilog has completely revolutionized the design of hardware.
  18. [18]
    COMPANY NEWS; Cadence to Buy Gateway Design
    Oct 5, 1989 · Cadence Design Systems Inc. agreed to buy the Gateway Design Automation Corporation of Lowell, Mass., for stock valued at more than $72 million.Missing: 1990 | Show results with:1990
  19. [19]
    IEEE 1364-Verilog - Semiconductor Engineering
    In mid-2004 the IEEE 1364 committee was disbanded, and maintenance of the standard transferred to the IEEE 1800 working group. The final version is 1364-2005.
  20. [20]
    [PDF] The IEEE Verilog 1364-2001 Standard What's New, and Why You ...
    standard, and, in 1995, IEEE 1364-1995 became the official Verilog standard. It is important to note that for Verilog-1995, the IEEE standards working group ...
  21. [21]
    IEEE 1364-1995 - IEEE SA
    Verilog HDL is a formal notation intended for use in all phases of the creation of electronic systems. Because it is both machine readable and human readable, ...
  22. [22]
    Verilog HDL: Hardware Description Language
    Apr 23, 2024 · In 1995, Verilog HDL was officially standardized as IEEE 1364-1995 by the IEEE Standards Association, allowing widespread adoption and ...
  23. [23]
    [PDF] IEEE Standard for Verilog Hardware Description Language
    The Verilog hardware description language (HDL) became an IEEE standard in 1995 as IEEE Std 1364-. 1995. It was designed to be simple, intuitive, and effective ...
  24. [24]
    IEEE 1364-2005 - IEEE SA
    Verilog HDL is a formal notation intended for use in all phases of the creation of electronic systems. Because it is both machine-readable and human-readable, ...
  25. [25]
    IEEE 1800-2009 - IEEE SA
    Dec 11, 2009 · Merging the base Verilog language and the SystemVerilog extensions into a single standard provides users with all information regarding ...
  26. [26]
  27. [27]
    IEEE Standards Association
    ### Abstract and Key Changes in IEEE 1800-2017
  28. [28]
    IEEE 1800-2023 - IEEE SA
    Feb 28, 2024 · IEEE Standard for SystemVerilog--Unified Hardware Design, Specification, and Verification Language ; Superseding: 1800-2017 ; Board Approval: 2023 ...<|separator|>
  29. [29]
    2023 Standard Available Through IEEE GET Program - Accellera
    Mar 4, 2024 · IEEE Std. 1800™-2023 includes support for modeling hardware at the behavioral, register transfer (RTL), and gate abstractions, and for writing ...Missing: partitioning data
  30. [30]
  31. [31]
    Verilog Scheduling Semantics - ChipVerify
    Verilog scheduling involves update and evaluation events, managed in event queues. The flow is: active region, inactive region, nonblocking assignments, then ...Missing: IEEE 1364 observed reactive
  32. [32]
    [PDF] SystemVerilog Event Regions, Race Avoidance & Guidelines
    SystemVerilog event regions reduce race conditions between verification code and designs, facilitating race-free Assertion Based Verification (ABV).
  33. [33]
    Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill
    Jan 21, 2015 · SystemVerilog Event Regions, Race Avoidance & Guidelines. Article. Full-text available ; The Fundamentals of Efficient Synthesizable Finite State ...
  34. [34]
    Verilog System Functions | The Octet Institute
    Sep 23, 2021 · Thus the value of variable printed using $strobe will always be free of any race condition. $monitor. This function, like the strobe ...
  35. [35]
    [PDF] Verilog-2001 Quick Reference Guide - Sutherland HDL
    type_of_block is either initial or always. • initial blocks ... The IEEE 1364 Verilog standard defines a number of standard system task and system functions.
  36. [36]
    [PDF] The Verilog Golden Reference Guide
    The logic values L and H in these tables represent results which have a partially unknown value. L is either 0 or Z, and H is either 1 or Z. and. 0. 1. X. Z.
  37. [37]
    Verilog Parameters - ChipVerify
    Parameters are Verilog constructs that allow a module to be reused with a different specification. For example, a 4-bit adder can be parameterized to accept ...
  38. [38]
    Parameters Example (Verilog) - 2025.1 English - UG901
    A Verilog parameter allows to control the width of an instantitated block describing register logic.
  39. [39]
    Verilog `define Macro - ChipVerify
    Verilog macros allow you to define a piece of code that can be reused throughout your design. When a macro is invoked, it gets replaced by its defined content ...
  40. [40]
    Define vs. parameter - difference - SystemVerilog
    May 1, 2020 · `define` is a compile-time text substitution, while `parameter` is a constant resolved at elaboration time, and can be overridden per instance.Define vs. parameter - difference - #3 by dave_59 - SystemVerilogDefine vs. parameter - difference - #4 by J_M - SystemVerilogMore results from verificationacademy.comMissing: practices | Show results with:practices
  41. [41]
    IEEE 1364.1-2002 - IEEE SA
    To develop a standard syntax and semantics for Verilog RTL synthesis. This standard shall define the subset of IEEE 1364 (Verilog HDL) which is suitable for ...Missing: summary | Show results with:summary
  42. [42]
    IEEE 1364.1-Verilog RTL Synthesis - Semiconductor Engineering
    The purpose of this standard is to define a syntax and semantics that can be used in common by all compliant RTL synthesis tools to achieve uniformity of ...Missing: summary | Show results with:summary
  43. [43]
    Verilog Constructs - 2025.1 English - UG901
    The following table lists the support status of Verilog constructs in Vivado synthesis. Table 1. Verilog Constructs. Verilog Constants, Support Status. Constant.
  44. [44]
    Synthesis Constructs in Verilog: Guide for Designers
    Jun 30, 2025 · Blocking assignments ( = ) are used in combinational logic within always blocks, where statements execute sequentially. 1. 2. 3. 4. always @(*) ...
  45. [45]
    Lesson 6: Synthesizable vs. Non-Synthesizable Code - Nandland
    Jun 30, 2022 · The most fundamental non-synthesizable piece of code is a delay statement. The FPGA has no concept of time, so it is impossible to tell the FPGA to wait for 10 ...Missing: initial | Show results with:initial
  46. [46]
    Synthesizable and Non-Synthesizable Verilog constructs
    They are synthesizable as long as they are running for a fixed number of times but not a dynamic value.
  47. [47]
    Xcelium Logic Simulation - Cadence
    Cadence Xcelium Logic Simulator provides best-in-class core engine performance for SystemVerilog, VHDL, SystemC, e, UVM, mixed-signal, low power, and X- ...Missing: Synopsys VCS Siemens Questa
  48. [48]
    VCS: Functional Verification Solution - Simulation - Synopsys
    Discover Synopsys VCS for advanced functional verification with industry-leading performance, multicore parallelism, and comprehensive coverage analysis.Missing: commercial Xcelium Siemens Questa
  49. [49]
    Questa One Sim | Siemens Software
    Questa One Sim is an evolution of the functional simulator. Questa One Sim brings Faster Engines, enables Faster Engineers using Fewer Workloads.Why Questa One Sim? · Built-In Pss Capabilities · Enhanced Debugging...Missing: commercial Cadence Xcelium Synopsys VCS
  50. [50]
    Icarus Verilog download | SourceForge.net
    Rating 5.0 (9) · Free · Design/GraphicsOpen-source interpreted Verilog simulator with a feature set and performance similar to Verilog-XL. Implements all IEEE 1364-1995 features along with some ...
  51. [51]
    Welcome to Verilator - Veripool
    Verilator has typically similar or better performance versus closed-source Verilog simulators ... Visit Veripool for open-sourced Verilog and EDA software.
  52. [52]
    Design Compiler: Timing, Area, Power, & Test Optimization | Synopsys
    Design Compiler offers best-in-class RTL synthesis, enabling fast timing, small area, low power, and high test coverage within short design cycles.Missing: Cadence Genus
  53. [53]
    Genus Synthesis Solution - Cadence
    Genus Synthesis Solution is a next-generation RTL synthesis and physical synthesis tool; 10X better RTL design productivity; 5X faster turnaround times.
  54. [54]
    AMD Vivado™ Design Suite
    AMD Vivado is the design software for AMD adaptive SoCs and FPGAs. It includes: Design Entry, Synthesis, Place and Route, Verification/Simulation tools.Standard Edition Free · More Details · Versal Features · High Level DesignMissing: Intel Quartus
  55. [55]
    3.1. Hardware and Software Tools for FPGA Design - Intel
    The Intel® Quartus® Prime Pro Edition software provides tools similar to those found in the Xilinx* Vivado* software.Missing: Verilog | Show results with:Verilog
  56. [56]
    Riviera-PRO - Functional Verification - Aldec, Inc
    Riviera-PRO is an advanced verification platform for FPGA and SoC devices, enabling high-performance simulation and advanced debugging.Missing: Synopsys Verdi
  57. [57]
    Verdi Automated Debug System | Synopsys
    Verdi is a debug and verification platform that streamlines design, debug, and verification, using AI to automate steps and manage regressions.Missing: Aldec Riviera- PRO
  58. [58]
    EDA Tools in the Cloud: 2024 Predictions | Synopsys Blog
    Feb 28, 2024 · We can expect that in 2024, adoption of cloud-based, AI-driven EDA solutions will continue to rise.Missing: Verilog CI/ CD farms
  59. [59]
    Yosys Open SYnthesis Suite :: About - YosysHQ
    Yosys is a framework for Verilog RTL synthesis. It currently has extensive Verilog-2005 support and provides a basic set of synthesis algorithms for various ...
  60. [60]
    GTKWave
    GTKWave is a fully featured GTK+ based wave viewer for Unix, Win32, and Mac OSX which reads LXT, LXT2, VZT, FST, and GHW files as well as standard Verilog VCD/Missing: synthesis Yosys
  61. [61]
    [PDF] EGC220 - Digital Logic Fundamentals
    At the structural level, the levels of abstraction are at the module level, the gate level, the switch level (transistor) or the circuit level. ... RTL Verilog.
  62. [62]
    [PDF] 1 Objective 2 Verilog–I — Modeling Digital Hardware
    A full-adder takes 1-bit inputs a, b, carryIn, and generates 1-bit outputs sum (sum = a + b + carryIn) and carryOut. It is the basic building block for the 32- ...
  63. [63]
    4-bit counter - ChipVerify
    The module counter has a clock and active-low reset (denoted by n) as inputs and the counter value as a 4-bit output. The always block is always executed ...
  64. [64]
    [PDF] Nonblocking Assignments in Verilog Synthesis; Coding Styles That ...
    According to the IEEE Verilog Standard, the two "always" blocks can be scheduled in any order. If the first always block executes first after a reset, both ...