Analog Tutorial 5: Verilog-A


Table of Contents

Overview

About Verilog-A

Using the Modelwriter Wizard

Simulation of ADC

Writing Verilog-A for an Inverter

About Verilog-A

From the Cadence Verilog-A Language Reference Manual: "The Verilog-A language is a high-level language that uses modules to describe the structure and behavior of analog systems and their components. With the analog statements of Verilog-A, you can describe a wide range of conservative systems and signal-flow systems, such as electrical, mechanical, fluid dynamic, and thermodynamic systems."

Overview

This tutorial describes how to create Verilog-A code for an analog to digital converter (ADC) using the Modelwriter wizard. The tutorial also steps through the simulation of the symbol created from the Verilog-A code of the ADC. At the end of the tutorial, there are instructions on writing Verilog-A code for an inverter.

Using the Modelwriter Wizard

To begin with, let's build an analog to digital converter. We'll do this by using a wizard called Modelwriter. The wizard allows you to select from a group of devices and then choose the parameters for that device. Then, Modelwriter will create verilog-a code based on the characteristics of the device that you set.

First, start the Cadence tools by typing "icfb &" from your cadence directory in a shell window. In the Library Manager window, after highlighting your library, select File -> New -> Cell View ... Enter "adc" or something similar in the "Cell Name" field. In the "Cell View" field, enter "veriloga". That tool should automatically change to the Verilog-A Editor.

After selecting OK, the Invoke Modelwriter window will appear. Select OK.

Then, the Cadence Modelwriter window will appear and you can select a variety of components. Feel free to see what is available. For this tutorial, select the "Analog to Digital Converter" device in the "Interface" folder. Then, select Next>.

The next window includes all of the parameters of the analog to digital converter. Change the "Number of Bits" to 4 and the "Max. Input Voltage" and the "Min. Input Voltage" to 5 V and 0 V, respectively. Leave everything else as is. Select Next>.

The window below contains the verilog-a code generated by the wizard. Scroll through the code and try to understand the functions used. Select Save Generated Code at the bottom right corner of the screen. Then, select Finished! Exit in the same place.

You will be prompted about creating a symbol. Select Yes.

The Symbol Generation Options window will appear. All of the default settings should be fine. Therefore, go ahead and select OK.

The symbol for the ADC will appear in the Virtuoso Symbol Editing window. Make any changes desired to the shape to the symbol shape. Move "[@instanceName]" so that it is above the symbol and change the name of "[@partName]" to something like "ADC". After all changes have been made, select Design -> Check and Save or select F8 and then close the Virtuoso Symbol Editing window.

Simulation of ADC

In order to simulate the ADC, a schematic view needs to be created. In the Library Manager window, after highlighting your folder, select File -> New -> Cell View. Name the Cell "adcsim" or something alike and make sure that the View is "schematic" and the Tool is "Composer-Schematic".

To test out the ADC, the first simulation should be a ramp. With using a ramp, the output of the ADC can be checked to see if it corresponds to the correct input voltage. Place the ADC symbol you created in the middle of the Virtuoso Schematic Editing window. Next, connect a "vpwl" voltage source to the "vin" pin and a "vpulse" voltage source to the "clk" pin of the ADC. Make an output bus (type 'W') from the "dout<3:0>" output of the ADC. Make four smaller wires (type 'w') attached to the bus and connect pins to them, named "dout<3>", "dout<2>", "dout<1>", and "dout<0>". Name the bus "dout<3:0>" and the small wires the same names that you gave their respective pins.

Next, the parameters need to be changed for the voltage sources. You do not want the voltage sources to operate at the same frequency because then, you will always clock in the same data to the ADC. Therefore, change the following parameters:

vpwl

vpulse

When your test schematic is complete, it should look something like the picture below.

Check and save your schematic by typing the "F8" key and select Tools -> Analog Environment. The Cadence Analog Design Environment window will appear. Verify that the simulator is "spectreS". If it is not, then you can change the simulator by selecting Setup -> Simulator/Directory/Host ... To test the ADC, we will run a transient simulation.

To properly set up the transient simulation, select Analyses -> Choose ... Select the "tran" Analysis and enter a Stop Time of 5ms. Select OK.

Select Outputs -> To Be Plotted -> Select On Schematic and then select the two inputs and the output bus in the Virtuoso Schematic Editing window.

Run the simulation by selecting the green traffic light icon in the Cadence Analog Design Environment window. The waveforms of the simulation should appear in the Waveform Window. Select the Switch Axis Mode icon (second icon from bottom) in the Waveform Window.

Pick a few points on vin and verify that the 4-bit ADC is accurate (determine the 4-bit binary value at this point by viewing the dout pins to see if they are high or low). Verify that the output is changing on the rising edge of the clock. To change the ADC so the output changes on the falling edge, go to the Library Manager window and select the veriloga cell view of the adc. Find the following line of code:

@(cross ( V(clk)-vth, 1, slack, clk.potential.abstol)) begin

Change the '1' to a '-1'. This argument determines whether or not the ADC will change on the rising or falling edge of the clock. Save your file and then rerun the simulation from the Cadence Analog Design Environment window. In the Waveform Window, verify that the output is different from the previous simulation, with the output changing on the falling edge of the clock. Also, verify that the digital output is consistent with the analog input.

Writing Verilog-A for an Inverter

In this part of the tutorial, we will write some Verilog-A code for an inverter, instead of having the Modelwriter wizard do it for us. This tutorial will cover a few important concepts that need to be included in Verilog-A coding.

To begin, create a new cell called "inverter2" with a "veriloga" cell view. When the Invoke Modelwriter window appears, select Cancel to manually type up your own Verilog-A code.

Your default text editor should open after selecting cancel. Depending on how you set it up, your text editor is probably Emacs or VI.

The file that opens will appear with the following text.

      // VerilogA for ECEn445, inverter2, veriloga

      `include "constants.h"
      `include "discipline.h"

      module inverter2;

      endmodule

The line at the top beginning with "//" is a comment line. Any time you want to add comments (text that won't effect your code), just add "//" at the beginning of the line or before wherever you want to comment. All of your code will go between the module and endmodule commands. "module inverter2" indicates that inverter2 is the name of the module. This line is like a function header. We would like to have 2 arguments for our inverter: an input and an output. Let us call them "vin" and "vout". The arguments of the module can be indicated by placing them inside parenthesis next to "inverter2".
      module inverter2(vin, vout);
The next part of the code that we will define is all of the initializations. In other words, we need to define what vin, vout, and any other arguments are. To define inputs and outputs, use the commands input and output, respectively.
      input vin;
      output vin;
We also need to define these pins as electrical ports.
      electrical vin, vout;
We want the inverter to change as the input crosses a certain threshold. We will define this parameter as "vtrans". We also want to define delay, rise, and fall time characteristics of the inverter. These parameters will be called "tdelay", "trise", and "tfall". To incorporate these factors of an inverter, we will use the transition filter for the output. The transition filter will be explained later in this tutorial. For now though, let us define these parameters using the "parameter real" statement. Also, each of these statements need to have a time period where their value holds true. In other words, following the definition, the statement "from (0:inf)" (from 0 to infinity) needs to be included in order to define the specific value from 0 to infinity seconds.
      parameter real vtrans = 1.4;
      parameter real tdelay = 0 from [0:inf);
      parameter real trise = 2n from (0:inf);
      parameter real tfall = 2n from (0:inf);

The last parameter we need to define is the output value that we want the output of the inverter to transition to using the parameters above.
      real vout_val;

Now that we have defined everything, we need to set up the main equations (the meat of the code). This part of the code needs to lie within the analog block. Since we will need more than one line to write the main equations, a begin and end statement are needed.
      analog begin
      // Main equations here
      end

A function that we should use to define the transition of the inverter is the "cross" function. This function takes a minimum of two arguments. The first argument required is the threshold point of the input that indicates when the output should change, and the second is the edge where this threshold point is located. A '1' is indicated for a rising edge and a '-1' for a falling egde. A '0' indicates any crossing, rising or falling. In this case, we want to set up two cross statements; one for the rising of the input and one for the falling. When we detect a rising edge of the input, we want the output to fall to 0 volts. When we detect a falling edge of the input to 0 volts, we want the output to rise to 5 volts. The cross event is expressed by "@ cross()", followed by a statement that should result from the cross event occuring. Think of it like a if-then statement. "If the waveform crosses at these certain conditions, then the following will occur".
      @ (cross(V(vin) - vtrans, 1))  vout_val = 0;
      @ (cross(V(vin) - vtrans, -1)) vout_val = 5;

The last thing we need to do is use the transition filter. "With the transition filter, you can control transitions between discrete signal levels by setting the rise time and fall time of signal transitions" (Ref. Manual, Transition Filter). We will use the branch contribution statement (<+) to define the voltage of the output.
      V(vout) <+ transition(vout_val, tdelay, trise, tfall);

The transition filter will help make the inverter seem more realistic, without instantaneous rises and falls. All of the major parts have been covered, so the Verilog-A code is complete.
      // VerilogA for ECEn445, inverter2, veriloga

      `include "constants.h"
      `include "discipline.h"


      module inverter2(vin, vout);
      input vin;
      output vout;
      electrical vin, vout;
      parameter real vtrans = 1.4;
      parameter real tdelay = 0 from [0:inf);
      parameter real trise = 2n from (0:inf);
      parameter real tfall = 2n from (0:inf);

      real vout_val;
      analog begin

            @ (cross(V(vin) - vtrans, 1))  vout_val = 0;
            @ (cross(V(vin) - vtrans, -1)) vout_val = 5;

      
            V(vout) <+ transition( vout_val, tdelay, trise, tfall);

      end
      endmodule

Save your text file and close it. You will be prompted to create a symbol. Select Yes.

All of the default settings should be fine, so select OK in the Symbol Generation Options window.

The Virtuoso Symbol Editing window will appear. Make any necessary changes to the shape of the symbol. Name the inverter by selecting "Property" (type 'q') and then selecting "[@partName]". Refer to Analog Tutorial 2: Simulating an Inverter for instructions on executing a transient simulation of the inverter. If there are any errors in your Verilog-A code, the simulation will not work.