What is Verilog?Verilog is a Hardware Description Language; a textual format for describing electronic circuits and systems. Applied to electronic design, Verilog is intended to be used for verification through simulation, for timing analysis, for test analysis (testability analysis and fault grading) and for logic synthesis. The Verilog HDL is an IEEE standard - number 1364. The first version of the IEEE standard for Verilog was published in 1995. A revised version was published in 2001; this is the current version. The IEEE Verilog standard document is known as the Language Reference Manual, or LRM. This is the complete authoritative definition of the Verilog HDL. A further revision of the Verilog standard is expected to be published in 2005. Accellera - the organisation that oversees developments in the Verilog language - has also published the SystemVerilog extensions to Verilog, which is also expected to become an IEEE standard in 2005. See the appropriate Knowhow section for more details about SystemVerilog. IEEE Std 1364 also defines the Programming Language Interface, or PLI. This is a collection of software routines which permit a bidirectional interface between Verilog and other languages (usually C). Note that VHDL is not an abbreviation for Verilog HDL - Verilog and VHDL are two different HDLs. They have more similarities than differences, however. A Brief History of VerilogThe history of the Verilog HDL goes back to the 1980s, when a company called Gateway Design Automation developed a logic simulator, Verilog-XL, and with it a hardware description language. Cadence Design Systems acquired Gateway in 1989, and with it the rights to the language and the simulator. In 1990, Cadence put the language (but not the simulator) into the public domain, with the intention that it should become a standard, non-proprietary language. The Verilog HDL is now maintained by a non profit making organisation, Accellera, which was formed from the merger of Open Verilog International (OVI) and VHDL International. OVI had the task of taking the language through the IEEE standardisation procedure. In December 1995 Verilog HDL became IEEE Std. 1364-1995. A revised version was published in 2001: IEEE Std. 1364-2001. This is the current version, although a futher revision is expected in 2005. Accellera have also been developing a new standard, SystemVerilog, which extends Verilog. SystemVerilog is also expected to become an IEEE standard in 2005. For more details, see the Systemverilog section of KnowHow There is also a draft standard for analog and mixed-signal extensions to Verilog, Verilog-AMS. Design Flow using VerilogThe diagram below summarises the high level design flow for an ASIC (ie. gate array, standard cell) or FPGA. In a practical design situation, each step described in the following sections may be split into several smaller steps, and parts of the design flow will be iterated as errors are uncovered.
System-level VerificationAs a first step, Verilog may be used to model and simulate aspects of the complete system containing one or more ASICs or FPGAs. This may be a fully functional description of the system allowing the specification to be validated prior to commencing detailed design. Alternatively, this may be a partial description that abstracts certain properties of the system, such as a performance model to detect system performance bottle-necks. Verilog is not ideally suited to system-level modelling. This is one motivation for SystemVerilog, which enhances Verilog in this area. RTL design and testbench creationOnce the overall system architecture and partitioning is stable, the detailed design of each ASIC or FPGA can commence. This starts by capturing the design in Verilog at the register transfer level, and capturing a set of test cases in Verilog. These two tasks are complementary, and are sometimes performed by different design teams in isolation to ensure that the specification is correctly interpreted. The RTL Verilog should be synthesizable if automatic logic synthesis is to be used. Test case generation is a major task that requires a disciplined approach and much engineering ingenuity: the quality of the final ASIC or FPGA depends on the coverage of these test cases. For today's large, complex designs, verification can be a real bottleneck. This provides another motivation for SystemVerilog - it has features for expediting testbench development. See the SystemVerilog section of Knowhow for more details. RTL verificationThe RTL Verilog is then simulated to validate the functionality against the specification. RTL simulation is usually one or two orders of magnitude faster than gate level simulation, and experience has shown that this speed-up is best exploited by doing more simulation, not spending less time on simulation. In practice it is common to spend 70-80% of the design cycle writing and simulating Verilog at and above the register transfer level, and 20-30% of the time synthesizing and verifying the gates. Look-ahead SynthesisAlthough some exploratory synthesis will be done early on in the design process, to provide accurate speed and area data to aid in the evaluation of architectural decisions and to check the engineer's understanding of how the Verilog will be synthesized, the main synthesis production run is deferred until functional simulation is complete. It is pointless to invest a lot of time and effort in synthesis until the functionality of the design is validated. Levels of AbstractionVerilog descriptions can span multiple levels of abstraction i.e. levels of detail, and can be used for different purposes at various stages in the design process.
At the highest level, Verilog contains stochastical functions (queues and random probability distributions) to support performance modelling. Verilog supports abstract behavioural modeling, so can be used to model the functionality of a system at a high level of abstraction. This is useful at the system analysis and partitioning stage. Verilog supports Register Transfer Level descriptions, which are used for the detailed design of digital circuits. Synthesis tools transform RTL descriptions to gate level. Verilog supports gate and switch level descriptions, used for the verification of digital designs, including gate and switch level logic simulation, static and dynamic timing analysis, testability analysis and fault grading. Verilog can also be used to describe simulation environments; test vectors, expected results, results comparison and analysis. With some tools, Verilog can be used to control simulation e.g.
setting breakpoints, taking checkpoints, restarting from time 0,
tracing waveforms. However, most of these functions are not included in
the 1364 standard, but are proprietary to particular simulators. Most
simulators have their own command languages; with many tools this is
based on Tcl, which is an industry-standard tool language. See the
Knowhow section on Tcl/Tk for more details. Scope of VerilogVerilog can be used at different levels of abstraction as we have already seen. But how useful are these different levels of abstraction when it comes to using Verilog? Design processThe diagram below shows a very simplified view of the electronic system design process incorporating Verilog. The central portion of the diagram shows the parts of the design process which will be impacted by Verilog.
System levelVerilog is not ideally suited for abstract system-level simulation, prior to the hardware-software split. This is to some extent addressed by SystemVerilog. Unlike VHDL, which has support for user-defined types and overloaded operators which allow the designer to abstract his work into the domain of the problem, Verilog restricts the designer to working with pre-defined system functions and tasks for stochastic simulation and can be used for modelling performance, throughput and queueing but only in so far as those built-in langauge features allow. Designers occasionally use the stochastic level of abstraction for this phase of the design process. DigitalVerilog is suitable for use today in the digital hardware design process, from functional simulation, manual design and logic synthesis down to gate-level simulation. Verilog tools provide an integrated design environment in this area. Verilog is also suited for specialized implementation-level design verification tools such as fault simulation, switch level simulation and worst case timing simulation. Verilog can be used to simulate gate level fanout loading effects and routing delays through the import of SDF files. The RTL level of abstraction is used for functional simulation prior to synthesis. The gate level of abstraction exists post-synthesis but this level of abstraction is not often created by the designer, it is a level of abstraction adopted by the EDA tools (synthesis and timing analysis, for example). AnalogBecause of Verilog's flexibility as a programming language, it has
been stretched to handle analog simulation in limited cases. There is a
draft standard – Verilog-AMS – that addresses analog and
mixed signal simulation. Synthesizing VerilogHow do you write good synthesisable Verilog code to give you the hardware you want?
Synthesis is a broad term often used to describe very different tools. Synthesis can include silicon compilers and function generators used by ASIC vendors to produce regular RAM and ROM type structures. Synthesis in the context of this tutorial refers to generating random logic structures from Verilog descriptions. This is best suited to gate arrays and programmable devices such FPGAs. Synthesis is not a panacea! It is vital to tackle High Level Design using Verilog with realistic expectations of synthesis. The definition of Verilog for simulation is cast in stone and enshrined in the Language Reference Manual. Other tools which use Verilog, such as synthesis, will make their own interpretation of the Verilog language. There is an IEEE standard for Verilog synthesis (IEEE Std. 1364.1-2002) but no vendor adheres strictly to it. It is not sufficient that the Verilog is functionally correct; it must be written in such a way that it directs the synthesis tool to generate good hardware, and moreover, the Verilog must be matched to the idiosyncrasies of the particular synthesis tool being used. We shall tackle some of these idiosyncracies in this Verilog tutorial. There are currently three kinds of synthesis:
There is some overlap between these three synthesis domains. We will concentrate on RTL synthesis, which is by far the most common. The essence of RTL code is that operations described in Verilog are tied to particular clock cycles. The synthesised netlist exhibits the same clock-by-clock cycle behaviour, allowing the RTL testbench to be easily re-used for gate-level simulation. Designing Hardware using VerilogA Simple DesignA design is described in Verilog using the concept of a module. A module can be conceptualised as consisting of two parts, the port declarations and the module body. The port declarations represent the external interface to the module. The module body represents the internal description of the module - its behaviour, its structure, or a mixture of both. Let's imagine we want to describe an and-or-invert (AOI) gate in Verilog.
Verilog: an AOI gate module// Verilog code for AND-OR-INVERT gate OK, that's the code. Let's dissect it line by line... Comments// Verilog code for AND-OR-INVERT gate Like all programming languages, Verilog supports comments. There are two types of comment in Verilog, line comments and block comments; we will look at line comments for now. Comments are not part of the Verilog design, but allow the user to make notes referring to the Verilog code, usually as an aid to understanding it. Here the comment is a “header” that tells us that the Verilog describes an AOI gate. It is no more than an aide de memoire in this case. A Verilog compiler will ignore this line of Verilog. Two forward slashes mark the start of a line comment, which is ignored by the Verilog compiler. A line comment can be on a separate line or at the end of a line of Verilog code, but in any case stops at the end of the line. Module and Port declarationsmodule AOI (input A, B, C, D, output F); The name of the module is just an arbitrary label invented by the user. It does not correspond to a name pre-defined in a Verilog component library. module is a Verilog keyword. This line defines the start of a new Verilog module definition. All of the input and output ports of the module must appear in parentheses after the module name. The ordering of ports is not important for the module definition per se, although it is conventional to specify input ports first. A port may correspond to a pin on an IC, an edge connector on a board, or any logical channel of communication with a block of hardware. The port declarations include the names of the ports ( e.g., A, B ), and the direction that information is allowed to flow through the ports (input, output or inout). Endmoduleendmodule The module definition is terminated by the Verilog keyword endmodule. FunctionalityWell, that's the interface to the module taken care of, but what about it's functionality? assign F = ~((A & B) | (C & D)); In this module body, there is but one statement, and all the names referenced in this statement are in fact the ports of the design. Because all of the names used in the module body are declared in the module header and port declarations, there are no further declarations for internal elements required in the module body. assign is a Verilog keyword. It denotes a concurrent continuous assignment, which describes the functionality of the module. The concurrent assignment executes whenever one of the four ports A, B, C or D change value. The ~, & and | symbols represent the bit-wise not, and and or operators respectively, which are built in to the Verilog language. That's it! That's all there is to describing the functionality of an AOI gate in Verilog. // end of Verilog code Another Verilog comment, and that's the end of a Verilog description for an AOI gate. Verilog 1995The above example is written using Verilog-2001 syntax. Many people continue to use the 1995 syntax, which is still allowed in Verilog-2001. In Verilog-1995 the module header would look like this: module AOI (A, B, C, D, F); Note that the port names are listed after the module name, and
declared as inputs and outputs in separate statements. The port
declarations must repeat the names of the ports in the module header. WiresThe module shown on the “Modules” page, was simple enough to describe using a continuous assignment where the output was a function of the inputs. Usually, modules are more complex than this, and internal connections are required. To make a continuous assignment to an internal signal, the signal must first be declared as a wire. A Verilog wire represents an electrical connection.
Verilog: Internal signals of an AOI gate module// Verilog code for AND-OR-INVERT gate OK, that's the code. Let's examine it a little more closely... Wire Declarationswire AB, CD, O; This is the syntax for a wire declaration. A wire declaration looks like a Verilog-1995 style port declaration, with a type (wire), an optional vector width and a name or list of names. You can create separate wire declarations if you wish, for example: wire AB, CD; is an alternative way of creating wire declarations. Note that ports default to being wires, so the definition of wire F in the Verilog code is optional. Continuous Assignmentsassign AB = A & B; In this module body, there are four continuous assignment
statements. These statements are independent and executed concurrently.
They are not necessarily executed in the order in which they are
written. This does not affect the functionality of the design. Suppose assign AB = A & B; changes value. This causes B to be evaluated. If AB changes as a result then assign O = AB | CD; is evaluated. If O changes value then assign F = ~O; will be evaluated; possibly the output of the module will change due to a change on B. Wire AssignmentsA wire can be declared and continuously assigned in a single statement - a wire assignment. This is a shortcut which saves declaring and assigning a wire separately. There are no advantages or disadvantages between the two methods other than the obvious difference that wire assignments reduce the size the the text. Later on we will discuss delays on assignments and wires. A delay in a wire assignment is equivalent to a delay in the corresponding continuous assignment, not a delay on the wire. Thus it could be necessary to separate the wire declaration from the continuous assignment to put the delay onto the wire rather than the assignment. Note that this is a subtle point that you are unlikely to encounter in practice!
Verilog: Using wire assignments to describe an AOI gate module// Verilog code for AND-OR-INVERT gate So in this sample code, each of the wire declarations and its corresponding assign statement are effectively merged into one wire assignment. Note the use of a block comment in the Verilog code, rather than the
line comments we have seen so far. A block comment may span several
lines of code. Block comments may not be nested. A Design HierarchyModules can reference other modules to form a hierarchy. Here we see a 2:1 multiplexer with an inverting data path consisting of an AOI gate and a pair of inverters.
Module InstancesThe MUX_2 module contains references to each of the lower level modules, and describes the interconnections between them. In Verilog jargon, a reference to a lower level module is called a module instance. Each instance is an independent, concurrently active copy of a module. Each module instance consists of the name of the module being instanced (e.g. AOI or INV), an instance name (unique to that instance within the current module) and a port connection list. The module port connections can be given in order (positional mapping), or the ports can be explicitly named as they are connected (named mapping). Named mapping is usually preferred for long connection lists as it makes errors less likely. Verilog: 2-input multiplexer module// Verilog code for 2-input multiplexer Yes, it's time to dissect the code line by line again, but we'll concentrate on the new lines as the module interface has been covered before (see A Simple Design). Implicit Wires// wires SELB and FB are implicit The wires used in continuous assignments MUST be declared. However, one-bit wires connecting component instances together do not need to be declared. Such wires are regarded as implicit wires. Note that implicit wires are only one bit wide, if a connection between two components is a bus, you must declare the bus as a wire. Module InstancesAOI G2 (SELB, A, SEL, B, FB); In a module instance, the ports defined in the module interface are connected to wires in the instantiating module through the use of port mapping. For the instance of AOI, the first wire in the port list is SELB. In the module header for the AOI gate, A is the first port in the port list, so SELB is connected to A. The second port in the module header is B, the second wire in the port list is A, thus the wire A in MUX2 is connecyted to the port B of the AOI gate instance. INV G3 (.A(FB), .F(F)); The second INV instance, G3, uses named mapping rather than
positional mapping. In the port list for the G£ instance, the
wire FB is connected to the input port, A, of the INV instance. The
period character is followed by the name of the module header port; in
brackets following the formal port, the name of the wire is entered. Test BenchesTest benches help you to verify that a design is correct. How do you create a simple testbench in Verilog?
Let's take the exisiting MUX_2 example module and create a testbench for it. We can create a template for the testbench code simply by refering to the diagram above. module MUX2TEST; // No ports! Initial StatementIn this code fragment, the stimulus and response capture are going to be coded using a pair of initial blocks. An initial block can contain sequential statements that can be used to describe the behaviour of signals in a test bench. In the Stimulus initial block, we need to generate waveform on the A, B and SEL inputs. Thus: initial // Stimulus Once again, let's look at each line in turn. SEL = 0; A = 0; B = 0; This line contains three sequential statements. First of all, SEL is set to 0, then A, then B. All three are set to 0 at simulation time 0. #10 A = 1; In terms of simulation, the simulator now advances by 10 time units and then assigns 1 to A. Note that we are at simulation time = 10 time units, not 10 ns or 10 ps! Unless we direct the Verilog simulator otherwise, a Verilog simulation works in dimensionless time units. #10 SEL = 1; These two lines are similar to the one above. 10 time units after A is set to 1, SEL is set to 1. Another 10 time units later (so we are now at simulation time = 30 time units), B is set to 1. The diagram below shows how the initial block has created a waveform sequence for the three signals.
We shall look at the use of the initial block to capture the MUX_2's response in the next section of the tutorial. Response CaptureIn the previous section of the tutorial, we looked at describing stimuli in Verilog to test our 2-input multiplexer. So next, we’ll look at how to capture the response of our device under test.
Remember from the module template that we are using initial blocks to code up the Stimulus and Response blocks. module MUX2TEST; // No ports! The Response initial block can be described very easily in Verilog as we can benefit from a built-in Verilog system task. Thus: initial // Response Once again, let's look at each item in turn. $monitor(); $monitor is a system task that is part of the Verilog language. Its mission in life is to print values to the screen. The values it prints are those corresponding to the arguments that you pass to the task when it is executed. The $monitor task is executed whenever any one of its arguments changes, with one or two notable exceptions. $time $time is a system function (as opposed to a system task). It returns the current simulation time. In the above example, $time is an argument to $monitor. However, $time changing does not cause $monitor to execute - $monitor is clever enough to know that you wouldn't really want to print to the screen the values of all of the arguments every time the simulation time changed. , , , The space at position 2 in the argument list ensures that a space is printed to the screen after the value of $time each time $monitor is executed. This is a simple method of formatting the screen output. SEL, A, B, F Finally we come to the signal arguments themselves. Each time one of these signals changes value, $monitor will execute. When $monitor executes it will print all of the argument values to the screen, including $time. This is the output created by $monitor in our MUX2 testbench: 0 0000 This is simply a tabular listing of the waveforms that would be generated during simulation (if we had a waveform viewer, that is!).
It's amazing what you can learn from two lines of code, isn't it? We'll look at more elaborate output formatting soon. RTL VerilogRemember this?
Now we are going to look at the principles of RTL coding for synthesis tools. Most commercially available synthesis tools expect to be given a design description in RTL form. RTL is an acronym for register transfer level. This implies that your Verilog code describes how data is transformed as it is passed from register to register. The transforming of the data is performed by the combinational logic that exists between the registers. Don't worry! RTL code also applies to pure combinational logic - you don't have to use registers. To show you what we mean by RTL code, let's consider a simple example. module AOI (input A, B, C, D, output F); Yes! The AOI gate that we have used as an example so far has actually been written in RTL form. This means that continuous assignments are a valid way of describing designs for input to RTL synthesis tools. What other code techniques can we use? How about: module MUX2 (input SEL, A, B, output F); Module instances are also examples of synthesizable RTL statements. However, one of the reasons to use synthesis technology is to be able to describe the design at a higher level of abstraction than using a collection of module instances or low-level binary operators in a continuous assignment. We would like to be able to describe what the design does and leave the consideration of how the design is implemented up to the synthesis tool. This is a first step (and a pretty big conceptual one) on the road to high-level design. We are going to use a feature of the Verilog language that allows us to specify the functionality of a design (the ‘what') that can be interpreted by a synthesis tool. Always blocksAlways blocks are akin to the initial blocks that you have met already in Test Benches. Initial blocks are procedural blocks that contain sequential statements. Initial blocks execute just once. Always blocks on the other hand are always available for execution. This means that the statements inside an always block are executed up until the closing end keyword: always But then they can be executed again! This means that a way of controlling execution through an always block is required. In describing synthesizable designs, a sensitivity list is often used to control execution (we shall see other approaches later). always @(sensitivity-list) The sensitivity list consists of one or more signals. When at least one of these signals changes, the always block executes through to the end keyword as before. Except that now, the sensitivity list prevents the always block from executing again until another change occurs on a signal in the sensitivity list. The statements inside the always block describe the functionality of the design (or a part of it). Let's reconsider the AOI gate: always @(sensitivity-list) Instead of a continuous assignment, we now have a procedural assignment to describe the functionality of the AOI gate. Notice that the sensitivity list isn't valid Verilog code. We need to create a meaningful sensitivity list. How do we decide when to execute the always block? Perhaps a better question is what do we need to do in order to have F change value. Answer: F can only change when at least one of a, b, c or d changes. After all, these are the four inputs to the AOI gate. That's our sensitivity list: always @(a or b or c or d) Verilog-2001 introduced additional syntax for describing sensitivity lists. always @(a, b, c, d) always @(*) always @* In the first of these, we have simply replaced the word or with a comma. The other two are equivalent and create an implicit sensitivity list that contains all the signals whose values are read in the statements of the always block. In this example @* or @(*) are equivalent to @(a,b,c,d). When describing combinational logic, it is important to make sure that sensitivity lists are complete; this syntax helps to ensure that this is holds. Now for the MUX_2 design. In the above code snippet, we simply replaced the continuous assignment with an equivalent always block. We can do the same with the module instances in the MUX_2 design - strip away each instance and replace it with the equivalent always block. always @(sel) But we can do better than this. Let's merge the three always blocks together remembering that in the process (a pun for the VHDL'ers amongst you!) the sensitivity list of the resulting one always block contains only those signals that cause F to change value. always @(sel or a or b) When writing RTL code, “think functionality, think inputs” is a useful aide memoire in terms of bridging the gap between concept and code. Well, we have already taken care of the inputs as the sensitivity list now consists of only the MUX_2 input ports. For the functionality, let’s get conceptual. If sel is a logic 1, a is routed through to the f output. On the other hand if sel is a logic 0, b is routed through to the f output. Rather than think about routing one of the inputs through to the output let's think about the output getting one of the inputs, and let's write the text on separate lines depending upon whether we are making a decision or performing an action (sometimes referred to as pseudo-code): if sel is logic 1 This can be translated into Verilog code: if (sel == 1) Now before we go any further, we'll just take this code snippet a line at a time. if (sel == 1) The Verilog language allows for many different kinds of sequential statement. The procedural assignment is one you have already come across not only on this page but also in test benches (assignments to SEL, A and B in the stimulus initial block, if you remember). Here's another: the if statement. Actually this line is part of the if-else statement that is the entire code snippet. if is a Verilog keyword. After the if keyword you have a conditional expression, in this case (sel == 1) - does sel have the value logic 1? If so... f = a; f gets the value on the a input. Or in Verilog jargon, a procedural assignment. But what if sel is not logic 1? else Otherwise (assume sel is logic 0 - more on this assumption later)... f = b; f gets the value on the b input. So, as it turns out, we have described the funcionality of the MUX_2 design using a single procedural statement, the if-else statement. In each branch of this if-else statement, there is an additional procedural statement, either assigning a to f, or b to f, depending upon the value of sel. But we have to remember that this procedural statement lives inside an always block, so... always @(sel or a or b) This now enables us to describe a design using a list of continuous assignments, a hierarchy of designs or an always block. Compare the 3 approaches for yourself: // continuous assignments // a hierarchy of designs // always block And of course you can mix'n'match coding styles if you wish. On a simple design, such as a MUX_2 it is perhaps not apparent how succinct the use of always blocks is in general compared to module instances and continuous assignments. But you can readily appreciate that the use of just one always block in this design is enabling us to describe the design in terms of its functionality without regard to the implementation. You can describe what you want without having to worry about how you are going to implement the design (because you don't have to - that's the synthesis tool's job!). Go on! Read the MUX_2 design into your synthesis tool and have a play. If statementIn the last section, we looked at describing hardware conceptually using always blocks. What kind of hardware can we describe? What are the limitations? What kinds of Verilog statement can be used in always blocks to describe hardware? Well, we have already seen the use of an if statement to describe a multiplexer, so let's dwell on if statements in this section. always @(sensitivity-list) // invalid Verilog code! The code snippet above outlines a way to describe combinational logic using always blocks. To model a multiplexer, an if statement was used to describe the functionality. In addition, all of the inputs to the multiplexer were specified in the sensitivity list. reg f; Variable declarationIt is a fundamental rule of the Verilog HDL that any object that is assigned a value in an always statement must be declared as a variable. Hence, reg f; // must be declared before it is used in a statement The term variable was introduced in the verilog-2001 standard. Previously, the term used was register. This was confusing, because a Verilog variable (register) does not necessarily imply that a hardware register would be synthesised. hence the change of terminology. Combinational logicIt transpires that in order to create Verilog code that can be input to a synthesis tool for the synthesis of combinational logic, the requirement for all inputs to the hardware to appear in the sensitivity list is a golden rule. Golden Rule 1: Altogether there are 3 golden rules for synthesizing combinational logic, we will address each of these golden rules over the next couple of sections in this tutorial. If statementThe if statement in Verilog is a sequential statement that conditionally executes other sequential statements, depending upon the value of some condition. An if statement may optionally contain an else part, executed if the condition is false. Although the else part is optional, for the time being, we will code up if statements with a corresponding else rather than simple if statements. In order to have more than one sequential statement executed in an if statement, multiple statements are bracketed together using the begin..end keywords, reg f, g; // a new reg variable, g If statements can be nested if you have more complex behaviour to describe: reg f, g; Notice that the code is beginning to look a little bit confusing! In the code above, begin..end blocks have only been used where they must be used, that is, where we have multiple statements. It is probably a good idea to use begin..end blocks throughout your Verilog code - you end up typing in a bit more Verilog but it's easier to read. Also, if you have to add more functionality to an always block later on (more sequential statement), at least the begin..end block is already in place. So, reg f, g, h; // yes, an extra reg variable, h Note that the order of assignments to f, g and h has been played around with (just to keep you on your toes!). Synthesis considerationsIf statements are synthesized by generating a multiplexer for each
variable assigned within the if statement. The select input on each mux
is driven by logic determined by the if condition, and the data inputs
are determined by the expressions on the right hand sides of the
assignments. During subsequent optimization by a synthesis tool, the
multiplexer architecture may be changed to a structure using and-or-invert gates as surrounding functionality such as the a & b and the ~a can be merged into complex and-or-invert gates to yield a more compact hardware implementation. Synthesizing LatchesIn the last section, if statements were used to describe simple combinational logic circuits. Synthesizing the Verilog code produced multiplexing circuits, although the exact implementation depends upon the synthesis tool used and the target architecture of the device. As well as enabling the creation of multiplexers, if statements can also be used to implement tristate buffers and transparent latches. In this article we will look at how transparent latches are synthesized from if statements and how to avoid the inadvertent creation of latches when you meant to create combinational logic circuits from Verilog code containing if statements. If StatementsIn the processes that have been coded up so far, if-else statements rather than simple if statements have been used. Let's use a simple if statement rather than an if-else statement in an example you have already seen: reg sel, a, b; always @ (sel or a or b) becomes... reg sel, a, b; always @ (sel or a or b)
Note that the behaviour being described is the same. In the pure_if always block, f initially gets b. Only if sel is active HIGH does f get a. This is perhaps a slightly odd way to describe a multiplexing circuit but it is accepted by all synthesis tools. Synthesis tools expect to create circuits responding to binary values. As far as a synthesis tool is concerned if sel is 1 a is routed through to f. If sel is not 1 it must be 0 and thus sel being 0 leaves f being driven by the initial assignment from b. Let's lose the b input to the always block so that we have: reg sel, a; always @ (sel, a) Incomplete AssignmentNow analyze the behaviour of the code. If sel is 1, f gets a. But what happens when sel is 0? Well, very simply, nothing! f does not and can not change. When sel is fixed at 0, we can change a as much as we like, f will not be assigned the value of a. If we suppose that an if statement synthesises to a multiplexer, then we must be able to configure the multiplexer such that f only gets the value of a when sel is 1. This can be achieved by feeding back the multiplexer f output back to the 0 input; in hardware terms this is a transparent latch and this is exactly the hardware synthesized by a synthesis tool given this Verilog code.
If the target architecture does not contain transparent latches the synthesis tool will generate multiplexer circuits that employ combinational feedback in order to mimic the latching behaviour required. Now, this is very well but what's really happening here? One minute if statements create multiplexers, the next they create latches. Well, it's not the if statements, but the process as a whole that counts. If it is possible to execute an always block without assigning a value to a signal in that always block, the reg variable will be implemented as a transparent latch. This is known as incomplete assignment. Golden Rule 2: Simplifying code analysisSuppose you are creating an always block to describe combinational logic. This always block consists of nested if-else statements as follows: reg f, g; Will you get transparent latches on the f and g outputs? Not easy is it? If you look carefully you will see that in fact, g is latched when sel is 0, sel_2 is 0 and sel_3 is 0. The ‘oops!' comment should help you to see where the complete assignment is NOT made. Default AssignmentFortunately, it is possible to save yourself the bother of scouring through the always block code to locate possible incomplete assignments by setting variables to default values at the start of the always block. Using this approach you may get undesired functionality if you have missed out an assignment (which should be easy to fix) as opposed to unwanted transparent latches. For our current example, always @ (sel or sel_2 or sel_3 or a or b) Useful Verilog TipsTop-down Design and Synthesis Issues for Sequential Always BlocksWe are going to look at using structured design of synthesizable always blocks to implement sequential logic. The circuit under consideration is an 8 bit synchronous counter, with an enable, a parallel load, and an asynchronous reset. The counter loads or counts only when the enable is active. When the load is active, Data is loaded into count. The counter has two modes: binary and decade. In binary mode, it is an 8 bit binary counter. In decade mode, it counts in two 4 bit nibbles, each nibble counting from 0 to 9, and the bottom nibble carrying into the top nibble, such that it counts from 00 to 99 decimal. The truth table of the counter is as follows (- means don't care): Reset Clock Enable Load Mode Count and this is the Verilog module declaration: module COUNTER (input Clock, Reset, Enable, Load, Mode, So, how do you apply top-down design principles, a knowledge of synthesizable Verilog constructs and good coding finesse to this problem? Let's have a look... It is important to understand that conceptually, a counter is a register with the output fed back to the input via an incrementer. Hence the Verilog code will reflect this concept. For example, // inside a procedure The design process introduces some key Verilog coding aspects that need to borne in mind for synthesis. The most fundamental is the use of the classic asynchronous-reset-plus-clock single-procedure style of Verilog code. always @ (posedge Clock or negedge Reset) The essence of the code structure is that the clock and reset need to be in the sensitivity list; the appropriate event on either signal will cause one of the two ‘if' branches to execute. Note that the always statement must execute only on the rising edge of the clock and the falling edge of the reset, hence we must have posedge Clock and negedge Reset as the timing control of the always statement. Now that we have defined the basic structure of the procedure, we will go on to fill in the two ‘if' branches. The reset branch is very simple: // inside a procedure The clock branch needs to contain the functionality of the other four truth table entries; the code reflects the priority of those inputs directly. The enable signal has the highest priority, with nothing happening when it is high; next in priority is the load signal. Hence inside the enable block we will have, // inside a procedure For the actual increment statement (remember, Q <= Q + 1;), it is desirable to combine this functionality for either mode to ensure that only one piece of incrementer hardware is synthesised. So far, the detailed structure of the process has been derived from the truth table in a top-down design manner. Now we need to code the Verilog with a view to its implementation. // inside a procedure Although we are only providing a structure for the detail of the Verilog code in the above code snippet, it is notable that the word ‘increment' appears only twice and that it applies to nibbles - the code is structured to synthesise two 4-bit incrementers. This is a subtle point - you are relying on a synthesis tool's resource sharing capabilities to optimize the Verilog unless you write the code as presented above. If your synthesis tool doesn't support resource sharing, you have to write the code as shown above! OK, let's fill out the detail of the code structure presented so far in order to generate a model solution. This is given at the end of the section. So, filling out the detail, // inside a clocked procedure In summary, we have applied top-down design principles to create a synthesizable Verilog architecture containing a single procedure. The detailed code implementation was produced with the pitfalls of synthesis clearly borne in mind. The rest of this section gives a model solution: // counter Think Before You CodeWe are going to extend the sequential counter to implement a Gray code sequence rather than a simple linear increment. The sequence we will implement is as follows:
which yields the following always block for a Gray code counter, derived directly from the above truth table: always @(negedge reset or posedge clock) Obviously, the Verilog code doesn't look like a normal counter always block. Perhaps more worrying is that this approach to coding is going to take a long time for a counter > 3 or 4 bits. Yes, the code space increases as O(2N). In the same way that we try to avoid algorithms whose complexity creates execution times or whose output data sets increase at anything greater than O(N3/2), it's also wise to avoid such algorithms from a coding standpoint. As an example of algorithm choice, consider the options for sorting a set of data. Various algorithms exist, ye olde BubbleSort, Williams' HeapSort and Hoare's QuickSort spring to mind. The HeapSort algorithm executes in time O(Nlog2N), whereas BubbleSort executes in time O(N2). QuickSort is generally faster than HeapSort by about 25% on typical (< 100 items) random data sets providing the data set is not already ordered. As an aside, if you don't know how to code the BubbleSort algorithm don't bother, go straight to the HeapSort algorithm (do not pass GO, but do collect 200 coding Brownie points!). I know, we'll do a HeapSort model as next month's Model of the Month... So let's find a way to code the Gray code sequence in as succinct a way as possible. By examining the sequence in the table, we can see that as we increment through each step bit N+1 inverts the value of bit N when 1. This looks just like an XOR operation and so it proves. Note, that this inversion rule applies because the sequence is incrementing and thus an incrementer is required too. Thus, the horrid case statement in our first code snippett becomes somewhat simpler: q <= q + 1; -- the incrementer and for the inversion, q_gray = {q[3], q[3]^q[2], q[2]^q[1], q[1]^q[0]};
so the Verilog code now becomes: always @(negedge reset or posedge clock) Yes, we took advantage of Verilog's unary XOR operator to make the code even shorter, but well, that's what I thought it was there for! So a summary of the key points,
One final point, if the code looks neat from a coding, performance
(execution and real-time) and data set perspective, you're probably not
going to do much better. Unless, of course, you use a better algorithm... Other Verilog ResourcesVerilog Example ModelsAnalog-to-Digital ConverterOK. We've had a few requests for a Verilog Model of the Month, so here it is. This month we'll present a model of an ADC. You might remember that we modelled an ADC in our April Model of the Month, so this allows us to contrast VHDL coding with Verilog coding. The example we present is for a 16-bit ADC, but you can easily modify the digital output wordlength for any desired accuracy of ADC. The 16-bit ADC model is built around a function, ADC_16b_10v_bipolar. Note there are no conversion operators in this code as there was with the VHDL code - Verilog simply doesn't need them due to its absence of data typing. Note that we must specify a range for the returned value from the function in Verilog, in VHDL, a range constraint is not mandatory. Real-valued ports are not allowed in Verilog so we must use a 64-bit input port to maintain an accurate representation of the analogue signals. All of the required Verilog code is here, there are no references to other external code modules (there are eight referenced packages in the VHDL code). In the VHDL model there are frequent references to conversion functions, in the Verilog code we can use the built-in $rtoi function. The charge_ovr reg is intended to be accessed hierarchically from the testbench in order to determine whether reset_charge needs to be re-activated. A note for VHDL coders; hierarchical naming is allowed in Verilog - remember that in VHDL you always have to use ports and generics to allow hierarchy traversal. You are welcome to use the source code we provide but you must keep the copyright notice with the code (see the Notices page for details). // 16-bit Analogue-Digital ConverterTo download the Verilog source code for this month's Model of the Month, click here. Shift RegisterWell, not just a shift register. This month's model is used to highlight the creation of parameterisable components and the modelling of bidirectional ports. The bidirectional port is modelled as a separate block from the main shifter function as a conditional continuous assignment. Notice that the high impedance state is modelled as {Length{1'bz}} rather than the more obvious Length'bz. This is because a parameter cannot be used as the vector width in Verilog. Ho hum! However, 'bz is quite legal... The shifter function is modelled as a clocked always block The >> operator is used to present more succinct code than using concatenation would allow. The Length parameter is used to parameterise the Data bidirectional port and the Reg register. Note that Reg is legitimate as a reg object name as Verilog is case-sensitive. But Reg is not a good name for a reg object, a better name would be shift_reg, perhaps. So, one shift register. Parameterisable. Bidirectional. And synthesisable. Your mission, should you choose to accept it, is to modify the Verilog code to create a completely parameterisable, bidirectional shift register. Yes, bidirectional shift (shift left, as well as shift right) in addition to bidirectional I/O. This Web page will NOT self-destruct in five seconds! You are welcome to use the source code we provide but you must keep the copyright notice with the code (see the Notices page for details). // Shifter To download the Verilog source code for this month's Model of the Month, click here. Simple RAM ModelThis month, a simple RAM model, written in Verilog. Following on from last month's introduction to parameterisation, the RAM model presented here is parameterisable in terms of memory depth and wordlength. Memory depth is parameterised using the AddressSize parameter, whilst WordSize is used to parameterise the wordlength. The declaration, reg [WordSize-1:0] Mem [0:1<<AddressSize]; defines the size of the memory block. Note the use of the << operator to provide a convenient mechanism for implementing 2N; there is no exponentiation operator in Verilog as there is in VHDL. Just like the shift register model from November, the parameterisable bidirectional port is modelled as a conditional assignment. This assignment effectively models the read process from the RAM. The first always block models the write process. The second provides a simple simultaneous read-write check. Note that it is not possible address individual bits in the memory block using two-dimensional addressing as in VHDL. In Verilog, you need to create a temporary reg object for the memory word and then access a bit or a bit-select from that temporary reg object. Oh, yes. How about a timing diagram?
You are welcome to use the source code we provide but you must keep the copyright notice with the code (see the Notices page for details). // RAM Model To download the Verilog source code for this month's Model of the Month, click here. Universal Asynchronous Receiver (UAR)Many thanks to Gerard Blair at the University of Edinburgh for allowing us to use his UAR model for February's Model of the Month. Gerard's home page is http://www.ee.ed.ac.uk/~gerard/. If you have a model that you are willing to have advertised on these pages, please drop us a line by clicking here. OK, on with this month's Model...
The above figure shows a simplified picture of an asynchronous serial interface of the type commonly used to transfer data in computer and communications systems. The data transfer is referred to as `asynchronous' because the spacing between the characters may be of any length. In contrast, the timing of the bits within the character is well defined (and is related to the baud rate of the interface). The Tx clock and Rx clock signals are nominally of the same frequency, but are generated locally at each end of the transmission link and therefore cannot be assumed to be ‘locked' together. The design of a suitable transmitter circuit is not difficult, but the receiver must be able to detect the start of an incoming character and then store the value of each data bit, despite the fact that the relative frequency and phase of the Tx and Rx clocks may vary.
As shown in the data diagram above, the beginning and end of each character is delimited by a start bit whose value is always 0, and a stop bit whose value is always 1. In between characters, the transmitter outputs a constant value of 1. In operation, the receiver continually samples the input data. Following a 1 -> 0 data input transition, the eight data bits must be stored, and this is where a problem may occur, since for maximum reliability we wish to sample the data bits in the centre of their bit times and not close to either edge, so that small differences between the Tx and Rx clocks can be accommodated. This may be accomplished by using an Rx clock frequency which is a multiple of the data bit rate. In this exercise we shall assume that the Rx clock signal is eight times the bit rate. Following the detection of a start bit, the stop bit should be detected 76 clock cycles later. If so, the Data Available output is set high; if not, the Framing Error output is set. Both status outputs are reset low by the detection of the next start bit. There is thought to be a danger of spikes on the communication channel falsely starting the receiver. This means that a momentary LOW on the input to the receiver would be seen as a one-to-zero transition where-as it is really just noise. To counter this, the specification is changed as follows:
Thus you will have to update your design for detectng a valid start bit. Note:- the flexibility of 3-4-5 clock periods is to allow you to implement whichever is simplest - BUT there is no definition of what value is on the input at the sample AFTER the one-to-zero transition: this is to avoid problems associated with signal bounce. Well, that's the specification for a UAR model. Here is a design based on sound synchronous design principles. The following Verilog code has five major sub-modules:
As with all good synchronous modules, a global_reset signal is included so that the registers can be put into a known state at the start of testing. You are welcome to use the source code we provide but you must keep the copyright notice with the code (see the Notices page for details). // Universal Asynchronous Receiver To download the Verilog source code for this month's Model of the Month, click here. 8-bit x 8-bit Pipelined MultiplierBriefly interrupting the Built-in Self Test (BIST) theme, this month we present a synthesizable model of an 8-bit x 8-bit pipelined multiplier in Verilog. Although the design is synthesizable as is, a synthesis tool with a re-timing capability is required in order to create a pipelined multiplier with the pipeline registers evenly distributed throughout the design. You can of course remove the pipeline_stages always block and use the un_pipelined_output assignment. You are welcome to use the source code we provide but you must keep the copyright notice with the code (see the Notices page for details). `timescale 1ns/1ps Here is a skeleton testbench architecture that can be used for testing purposes. `timescale 1ns/1psTo download the Verilog source code for this month's Model of the Month, click here. Verilog FAQ
What is the difference between Verilog and VHDL? |

















