yeap's profileyeap's spaceBlogGuestbookNetwork Tools Help

yeap's space

July 06

Performing SQL operations through Perl from http://www.codeproject.com/KB/perl/perldbi.aspx

Introduction

This article explains on how to perform operations on your database through Perl, using the DBI module. This assumes that you have basic knowledge about Perl/CGI and SQL. We will be making a simple table and performing basic SQL operations on it.

Comments

Like all Perl code, this code too is self explanatory. If you need detailed information, don't hesitate to use the article forums.

Example one

Creating a table.

Collapse Copy Code
#!/usr/local/bin/perl
use DBI;

$username = '';$password = '';$database = '';$hostname = '';
$dbh = DBI->connect("dbi:mysql:database=$database;" . 
   "host=$hostname;port=3306", $username, $password);

$SQL= "create table user(ID integer primary key " . 
  "auto_increment, username text not null," . 
  " password text not null, email text not null)";

$CreateTable = $dbh->do($SQL);

print "Content-type:text/html\n\n\n";
if($CreateTable){
print "Success";
}
else{
print "Failure
$DBI::errstr"; }

Example two

Inserting a record.

Collapse Copy Code
#!/usr/local/bin/perl
use DBI;

$username = '';$password = '';$database = '';$hostname = '';
$dbh = DBI->connect("dbi:mysql:database=$database;" . 
  "host=$hostname;port=3306", $username, $password);

$SQL= "insert into user (username, password, email)" .
  " values('lexxwern', 'password', 'email@host')";

$InsertRecord = $dbh->do($SQL);

print "Content-type:text/html\n\n\n";
if($InsertRecord){
print "Success";
}
else{
print "Failure
$DBI::errstr"; }

Example three

Updating a record.

Collapse Copy Code
#!/usr/local/bin/perl
use DBI;

$username = '';$password = '';$database = '';$hostname = '';
$dbh = DBI->connect("dbi:mysql:database=$database;" .
  "host=$hostname;port=3306", $username, $password);

$SQL= "update user set email = ".
  "'lexxwern@yahoo.com' where username = 'lexxwern'";

$UpdateRecord = $dbh->do($SQL);

print "Content-type:text/html\n\n\n";
if($UpdateRecord){
print "Success";
}
else{
print "Failure
$DBI::errstr"; }

Example four

Deleting a record.

Collapse Copy Code
#!/usr/local/bin/perl
use DBI;

$username = '';$password = '';$database = '';$hostname = '';
$dbh = DBI->connect("dbi:mysql:database=$database;" .
  "host=$hostname;port=3306", $username, $password);

$SQL= "delete from user where ID=1";

$DeleteRecord = $dbh->do($SQL);

print "Content-type:text/html\n\n\n";
if($DeleteRecord){
print "Success";
}
else{
print "Failure
$DBI::errstr"; }

Example five

Viewing all records.

Collapse Copy Code
#!/usr/local/bin/perl
print "Content-type:text/html\n\n";

use DBI;

$username = '';$password = '';$database = '';$hostname = '';
$dbh = DBI->connect("dbi:mysql:database=$database;" .
 "host=$hostname;port=3306", $username, $password);

$SQL= "select * from user";

$Select = $dbh->prepare($SQL);
$Select->execute();

while($Row=$Select->fetchrow_hashref)
{
  print "$Row->{username}
$Row->{email}"; }

Conclusion

Hopefully these examples can give you a neat preview of the capabilities of the DBI module. This site will be of further help. Good luck!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

lexxwern


Member
About
:: a fulltime college student from new delhi, india.

Latest
:: college 1st semester.
Occupation: Web Developer
Location: India India

Talking about perl.com: A Short Guide to DBI from http://www.perl.com/pub/a/1999/10/DBI.html


General information about relational databases

Relational databases started to get to be a big deal in the 1970's, andthey're still a big deal today, which is a little peculiar, because they're a 1960's technology.

A relational database is a bunch of rectangular tables. Each row of a table is a record about one person or thing; the record contains several pieces of information called fields. Here is an example table:

 LASTNAME   FIRSTNAME   ID   POSTAL_CODE   AGE  SEX
        Gauss      Karl        119  19107         30   M
        Smith      Mark        3    T2V 3V4       53   M
        Noether    Emmy        118  19107         31   F
        Smith      Jeff        28   K2G 5J9       19   M
        Hamilton   William     247  10139         2    M

The names of the fields are LASTNAME, FIRSTNAME, ID, POSTAL_CODE, AGE, and SEX. Each line in the table is a record, or sometimes a row or tuple. For example, the first row of the table represents a 30-year-old male whose name is Karl Gauss, who lives at postal code 19107, and whose ID number is 119.

Sometimes this is a very silly way to store information. When the information naturally has a tabular structure it's fine. When it doesn't, you have to squeeze it into a table, and some of the techniques for doing that are more successful than others. Nevertheless, tables are simple and are easy to understand, and most of the high-performance database systems you can buy today operate under this 1960's model.

About SQL

SQL stands for Structured Query Language. It was invented at IBM in the 1970's. It's a language for describing searches and modifications to a relational database.

SQL was a huge success, probably because it's incredibly simple and anyone can pick it up in ten minutes. As a result, all the important database systems support it in some fashion or another. This includes the big players, like Oracle and Sybase, high-quality free or inexpensive database systems like MySQL, and funny hacks like Perl's DBD::CSV module, which we'll see later.

There are four important things one can do with a table:

SELECT
Find all the records that have a certain property

INSERT
Add new records

DELETE
Remove old records

UPDATE
Modify records that are already there

Those are the four most important SQL commands, also called queries. Suppose that the example table above is named people. Here are examples of each of the four important kinds of queries:

 SELECT firstname FROM people WHERE lastname = 'Smith'

(Locate the first names of all the Smiths.)

 DELETE FROM people WHERE id = 3

(Delete Mark Smith from the table)

 UPDATE people SET age = age+1 WHERE id = 247

(William Hamilton just had a birthday.)

 INSERT INTO people VALUES ('Euler', 'Leonhard', 248, NULL, 58, 'M')

(Add Leonhard Euler to the table.)

There are a bunch of other SQL commands for creating and discarding tables, for granting and revoking access permissions, for committing and abandoning transactions, and so forth. But these four are the important ones. Congratulations; you are now a SQL programmer. For the details, go to any reasonable bookstore and pick up a SQL quick reference.

Every database system is a little different. You talk to some databases over the network and make requests of the database engine; other databases you talk to through files or something else.

Typically when you buy a commercial database, you get a library with it. The vendor has written some functions for talking to the database in some language like C, compiled the functions, and the compiled code is the library. You can write a C program that calls the functions in the library when it wants to talk to the database.

Every vendor's library is different. The names of the functions vary, and the order in which you call them varies, and the details of passing queries to the functions and getting the data back out will vary. Some libraries, like Oracle's, are very thin—they just send the query over to the network to the real database and let the giant expensive real database engine deal with it directly. Other libraries will do more predigestion of the query, and more work afterwards to turn the data into a data structure. Some databases will want you to spin around three times and bark like a chicken; others want you to stand on your head and drink out of your sneaker.

What DBI is For

There's a saying that any software problem can be solved by adding a layer of indirection. That's what Perl's DBI (`Database Interface') module is all about. It was written by Tim Bunce.

DBI is designed to protect you from the details of the vendor libraries. It has a very simple interface for saying what SQL queries you want to make, and for getting the results back. DBI doesn't know how to talk to any particular database, but it does know how to locate and load in DBD (`Database Driver') modules. The DBD modules have the vendor libraries in them and know how to talk to the real databases; there is one DBD module for every different database.

When you ask DBI to make a query for you, it sends the query to the appropriate DBD module, which spins around three times or drinks out of its sneaker or whatever is necessary to communicate with the real database. When it gets the results back, it passes them to DBI. Then DBI gives you the results. Since your program only has to deal with DBI, and not with the real database, you don't have to worry about barking like a chicken.

Here's your program talking to the DBI library. You are using two databases at once. One is an Oracle database server on some other machine, and another is a DBD::CSV database that stores the data in a bunch of plain text files on the local disk.

Your program sends a query to DBI, which forwards it to the appropriate DBD module; let's say it's DBD::Oracle. DBD::Oracle knows how to translate what it gets from DBI into the format demanded by the Oracle library, which is built into it. The library forwards the request across the network, gets the results back, and returns them to DBD::Oracle. DBD::Oracle returns the results to DBI as a Perl data structure. Finally, your program can get the results from DBI.

On the other hand, suppose that your program was querying the text files. It would prepare the same sort of query in exactly the same way, and send it to DBI in exactly the same way. DBI would see that you were trying to talk to the DBD::CSV database and forward the request to the DBD::CSV module. The DBD::CSV module has Perl functions in it that tell it how to parse SQL and how to hunt around in the text files to find the information you asked for. It then returns the results to DBI as a Perl data structure. Finally, your program gets the results from DBI in exactly the same way that it would have if you were talking to Oracle instead.

There are two big wins that result from this organization. First, you don't have to worry about the details of hunting around in text files or talking on the network to the Oracle server or dealing with Oracle's library. You just have to know how to talk to DBI.

Second, if you build your program to use Oracle, and then the following week upper management signs a new Strategic Partnership with Sybase, it's easy to convert your code to use Sybase instead of Oracle. You change exactly one line in your program, the line that tells DBI to talk to DBD::Oracle, and have it use DBD::Sybase instead. Or you might build your program to talk to a cheap, crappy database like MS Access, and then next year when the application is doing well and getting more use than you expected, you can upgrade to a better database next year without changing any of your code.

There are DBD modules for talking to every important kind of SQL database. DBD::Oracle will talk to Oracle, and DBD::Sybase will talk to Sybase. DBD::ODBC will talk to any ODBC database including Microsoft Acesss. (ODBC is a Microsoft invention that is analogous to DBI itself. There is no DBD module for talking to Access directly.) DBD::CSV allows SQL queries on plain text files. DBD::mysql talks to the excellent MySQL database from TCX DataKonsultAB in Sweden. (MySQL is a tremendous bargain: It's $200 for commercial use, and free for noncommerical use.)

Example of How to Use DBI

Here's a typical program. When you run it, it waits for you to type a last name. Then it searches the database for people with that last name and prints out the full name and ID number for each person it finds. For example:

 Enter name> Noether
                118: Emmy Noether

        Enter name> Smith
                3: Mark Smith
                28: Jeff Smith

        Enter name> Snonkopus
                No names matched `Snonkopus'.
        
        Enter name> ^D

Here is the code:

 use DBI;

        my $dbh = DBI->connect('DBI:Oracle:payroll')
                or die "Couldn't connect to database: " . DBI->errstr;
        my $sth = $dbh->prepare('SELECT * FROM people WHERE lastname = ?')
                or die "Couldn't prepare statement: " . $dbh->errstr;

        print "Enter name> ";
        while ($lastname = <>) {               # Read input from the user
          my @data;
          chomp $lastname;
          $sth->execute($lastname)             # Execute the query
            or die "Couldn't execute statement: " . $sth->errstr;

          # Read the matching records and print them out          
          while (@data = $sth->fetchrow_array()) {
            my $firstname = $data[1];
            my $id = $data[2];
            print "\t$id: $firstname $lastname\n";
          }

          if ($sth->rows == 0) {
            print "No names matched `$lastname'.\n\n";
          }

          $sth->finish;
          print "\n";
          print "Enter name> ";
        }
          
        $dbh->disconnect;

 use DBI;

This loads in the DBI module. Notice that we don't have to load in any DBD module. DBI will do that for us when it needs to.

 my $dbh = DBI->connect('DBI:Oracle:payroll');
                or die "Couldn't connect to database: " . DBI->errstr;

The connect call tries to connect to a database. The first argument, DBI:Oracle:payroll, tells DBI what kind of database it is connecting to. The Oracle part tells it to load DBD::Oracle and to use that to communicate with the database. If we had to switch to Sybase next week, this is the one line of the program that we would change. We would have to change Oracle to Sybase.

payroll is the name of the database we will be searching. If we were going to supply a username and password to the database, we would do it in the connect call:

 my $dbh = DBI->connect('DBI:Oracle:payroll', 'username', 'password')
                or die "Couldn't connect to database: " . DBI->errstr;

If DBI connects to the database, it returns a database handle object, which we store into $dbh. This object represents the database connection. We can be connected to many databases at once and have many such database connection objects.

If DBI can't connect, it returns an undefined value. In this case, we use die to abort the program with an error message. DBI->errstr returns the reason why we couldn't connect—``Bad password'' for example.

 my $sth = $dbh->prepare('SELECT * FROM people WHERE lastname = ?')
                or die "Couldn't prepare statement: " . $dbh->errstr;

The prepare call prepares a query to be executed by the database. The argument is any SQL at all. On high-end databases, prepare will send the SQL to the database server, which will compile it. If prepare is successful, it returns a statement handle object which represents the statement; otherwise it returns an undefined value and we abort the program. $dbh->errstr will return the reason for failure, which might be ``Syntax error in SQL''. It gets this reason from the actual database, if possible.

The ? in the SQL will be filled in later. Most databases can handle this. For some databases that don't understand the ?, the DBD module will emulate it for you and will pretend that the database understands how to fill values in later, even though it doesn't.

 print "Enter name> ";

Here we just print a prompt for the user.

 while ($lastname = <>) {               # Read input from the user
          ...
        }

This loop will repeat over and over again as long as the user enters a last name. If they type a blank line, it will exit. The Perl <> symbol means to read from the terminal or from files named on the command line if there were any.

 my @data;

This declares a variable to hold the data that we will get back from the database.

 chomp $lastname;

This trims the newline character off the end of the user's input.

 $sth->execute($lastname)             # Execute the query
            or die "Couldn't execute statement: " . $sth->errstr;

execute executes the statement that we prepared before. The argument $lastname is substituted into the SQL in place of the ? that we saw earlier. execute returns a true value if it succeeds and a false value otherwise, so we abort if for some reason the execution fails.

 while (@data = $sth->fetchrow_array()) {
            ...
           }

fetchrow_array returns one of the selected rows from the database. You get back an array whose elements contain the data from the selected row. In this case, the array you get back has six elements. The first element is the person's last name; the second element is the first name; the third element is the ID, and then the other elements are the postal code, age, and sex.

Each time we call fetchrow_array, we get back a different record from the database. When there are no more matching records, fetchrow_array returns the empty list and the while loop exits.

 my $firstname = $data[1];
             my $id = $data[2];

These lines extract the first name and the ID number from the record data.

 print "\t$id: $firstname $lastname\n";

This prints out the result.

 if ($sth->rows == 0) {
            print "No names matched `$lastname'.\n\n";
          }

The rows method returns the number of rows of the database that were selected. If no rows were selected, then there is nobody in the database with the last name that the user is looking for. In that case, we print out a message. We have to do this after the while loop that fetches whatever rows were available, because with some databases you don't know how many rows there were until after you've gotten them all.

 $sth->finish;
          print "\n";
          print "Enter name> ";

Once we're done reporting about the result of the query, we print another prompt so that the user can enter another name. finish tells the database that we have finished retrieving all the data for this query and allows it to reinitialize the handle so that we can execute it again for the next query.

 $dbh->disconnect;

When the user has finished querying the database, they type a blank line and the main while loop exits. disconnect closes the connection to the database.

Cached Queries

Here's a function which looks up someone in the example table, given their ID number, and returns their age:

 sub age_by_id {
          # Arguments: database handle, person ID number
          my ($dbh, $id) = @_;
          my $sth = $dbh->prepare('SELECT age FROM people WHERE id = ?')
            or die "Couldn't prepare statement: " . $dbh->errstr;

 $sth->execute($id) 
            or die "Couldn't execute statement: " . $sth->errstr;

 my ($age) = $sth->fetchrow_array();
          return $age;
        }

It prepares the query, executes it, and retrieves the result.

There's a problem here though. Even though the function works correctly, it's inefficient. Every time it's called, it prepares a new query. Typically, preparing a query is a relatively expensive operation. For example, the database engine may parse and understand the SQL and translate it into an internal format. Since the query is the same every time, it's wasteful to throw away this work when the function returns.

Here's one solution:

 { my $sth;
          sub age_by_id {
            # Arguments: database handle, person ID number
            my ($dbh, $id) = @_;

 if (! defined $sth) {
              $sth = $dbh->prepare('SELECT age FROM people WHERE id = ?')
                or die "Couldn't prepare statement: " . $dbh->errstr;
            }

 $sth->execute($id) 
              or die "Couldn't execute statement: " . $sth->errstr;

 my ($age) = $sth->fetchrow_array();
            return $age;
          }
        }

There are two big changes to this function from the previous version. First, the $sth variable has moved outside of the function; this tells Perl that its value should persist even after the function returns. Next time the function is called, $sth will have the same value as before.

Second, the prepare code is in a conditional block. It's only executed if $sth does not yet have a value. The first time the function is called, the prepare code is executed and the statement handle is stored into $sth. This value persists after the function returns, and the next time the function is called, $sth still contains the statement handle and the prepare code is skipped.

Here's another solution:

 sub age_by_id {
          # Arguments: database handle, person ID number
          my ($dbh, $id) = @_;
          my $sth = $dbh->prepare_cached('SELECT age FROM people WHERE id = ?')
            or die "Couldn't prepare statement: " . $dbh->errstr;

 $sth->execute($id) 
            or die "Couldn't execute statement: " . $sth->errstr;

 my ($age) = $sth->fetchrow_array();
          return $age;
        }

Here the only change to to replace prepare with prepare_cached. The prepare_cached call is just like prepare, except that it looks to see if the query is the same as last time. If so, it gives you the statement handle that it gave you before.

Transactions

Many databases support transactions. This means that you can make a whole bunch of queries which would modify the databases, but none of the changes are actually made. Then at the end you issue the special SQL query COMMIT, and all the changes are made simultaneously. Alternatively, you can issue the query ROLLBACK, in which case all the queries are thrown away.

As an example of this, consider a function to add a new employee to a database. The database has a table called employees that looks like this:

 FIRSTNAME  LASTNAME   DEPARTMENT_ID
        Gauss      Karl       17
        Smith      Mark       19
        Noether    Emmy       17
        Smith      Jeff       666
        Hamilton   William    17

and a table called departments that looks like this:

 ID   NAME               NUM_MEMBERS
        17   Mathematics        3
        666  Legal              1
        19   Grounds Crew       1

The mathematics department is department #17 and has three members: Karl Gauss, Emmy Noether, and William Hamilton.

Here's our first cut at a function to insert a new employee. It will return true or false depending on whether or not it was successful:

 sub new_employee {
          # Arguments: database handle; first and last names of new employee;
          # department ID number for new employee's work assignment
          my ($dbh, $first, $last, $department) = @_;
          my ($insert_handle, $update_handle);

 my $insert_handle = 
            $dbh->prepare_cached('INSERT INTO employees VALUES (?,?,?)'); 
          my $update_handle = 
            $dbh->prepare_cached('UPDATE departments 
                                     SET num_members = num_members + 1
                                   WHERE id = ?');

 die "Couldn't prepare queries; aborting"
            unless defined $insert_handle && defined $update_handle;

 $insert_handle->execute($first, $last, $department) or return 0;
          $update_handle->execute($department) or return 0;
          return 1;   # Success
        }

We create two handles, one for an insert query that will insert the new employee's name and department number into the employees table, and an update query that will increment the number of members in the new employee's department in the department table. Then we execute the two queries with the appropriate arguments.

There's a big problem here: Suppose, for some reason, the second query fails. Our function returns a failure code, but it's too late, it has already added the employee to the employees table, and that means that the count in the departments table is wrong. The database now has corrupted data in it.

The solution is to make both updates part of the same transaction. Most databases will do this automatically, but without an explicit instruction about whether or not to commit the changes, some databases will commit the changes when we disconnect from the database, and others will roll them back. We should specify the behavior explicitly.

Typically, no changes will actually be made to the database until we issue a commit. The version of our program with commit looks like this:

 sub new_employee {
          # Arguments: database handle; first and last names of new employee;
          # department ID number for new employee's work assignment
          my ($dbh, $first, $last, $department) = @_;
          my ($insert_handle, $update_handle);

 my $insert_handle = 
            $dbh->prepare_cached('INSERT INTO employees VALUES (?,?,?)'); 
          my $update_handle = 
            $dbh->prepare_cached('UPDATE departments 
                                     SET num_members = num_members + 1
                                   WHERE id = ?');

 die "Couldn't prepare queries; aborting"
            unless defined $insert_handle && defined $update_handle;

 my $success = 1;
          $success &&= $insert_handle->execute($first, $last, $department);
          $success &&= $update_handle->execute($department);

 my $result = ($success ? $dbh->commit : $dbh->rollback);
          unless ($result) { 
            die "Couldn't finish transaction: " . $dbh->errstr 
          }
          return $success;
        }

We perform both queries, and record in $success whether they both succeeded. $success will be true if both queries succeeded, false otherwise. If the queries succeded, we commit the transaction; otherwise, we roll it back, cancelling all our changes.

The problem of concurrent database access is also solved by transactions. Suppose that queries were executed immediately, and that some other program came along and examined the database after our insert but before our update. It would see inconsistent data in the database, even if our update would eventually have succeeded. But with transactions, all the changes happen simultaneously when we do the commit, and the changes are committed automatically, which means that any other program looking at the database either sees all of them or none.

do

If you're doing an UPDATE, INSERT, or DELETE there is no data that comes back from the database, so there is a short cut. You can say

 $dbh->do('DELETE FROM people WHERE age > 65');

for example, and DBI will prepare the statement, execute it, and finish it. do returns a true value if it succeeded, and a false value if it failed. Actually, if it succeeds it returns the number of affected rows. In the example it would return the number of rows that were actually deleted. (DBI plays a magic trick so that the value it turns is true even when it is 0. This is bizarre, because 0 is usually false in Perl. But it's convenient because you can use it either as a number or as a true-or-false success code, and it works both ways.)

AutoCommit

If your transactions are simple, you can save yourself the trouble of having to issue a lot of commits. When you make the connect call, you can specify an AutoCommit option which will perform an automatic commit operation after every successful query. Here's what it looks like:

 my $dbh = DBI->connect('DBI:Oracle:payroll', 
                               {AutoCommit => 1},
                              )
                or die "Couldn't connect to database: " . DBI->errstr;

Automatic Error Handling

When you make the connect call, you can specify a RaiseErrors option that handles errors for you automatically. When an error occurs, DBI will abort your program instead of returning a failure code. If all you want is to abort the program on an error, this can be convenient:

 my $dbh = DBI->connect('DBI:Oracle:payroll', 
                               {RaiseError => 1},
                              )
                or die "Couldn't connect to database: " . DBI->errstr;

Don't do This

People are always writing code like this:

 while ($lastname = <>) {
          my $sth = $dbh->prepare("SELECT * FROM people 
                                   WHERE lastname = '$lastname'");
          $sth->execute();
          # and so on ...
        }

Here we interpolated the value of $lastname directly into the SQL in the prepare call.

This is a bad thing to do for three reasons.

First, prepare calls can take a long time. The database server has to compile the SQL and figure out how it is going to run the query. If you have many similar queries, that is a waste of time.

Second, it will not work if $lastname contains a name like O'Malley or D'Amico or some other name with an '. The ' has a special meaning in SQL, and the database will not understand when you ask it to prepare a statement that looks like

 SELECT * FROM people WHERE lastname = 'O'Malley'

It will see that you have three 's and complain that you don't have a fourth matching ' somewhere else.

Finally, if you're going to be constructing your query based on a user input, as we did in the example program, it's unsafe to simply interpolate the input directly into the query, because the user can construct a strange input in an attempt to trick your program into doing something it didn't expect. For example, suppose the user enters the following bizarre value for $input:

 x' or lastname = lastname or lastname = 'y

Now our query has become something very surprising:

 SELECT * FROM people WHERE lastname = 'x' 
         or lastname = lastname or lastname = 'y'

The part of this query that our sneaky user is interested in is the second or clause. This clause selects all the records for which lastname is equal to lastname; that is, all of them. We thought that the user was only going to be able to see a few records at a time, and now they've found a way to get them all at once. This probably wasn't what we wanted.

People go to all sorts of trouble to get around these problems with interpolation. They write a function that puts the last name in quotes and then backslashes any apostrophes that appear in it. Then it breaks because they forgot to backslash backslashes. Then they make their escape function better. Then their code is a big message because they are calling the backslashing function every other line. They put a lot of work into it the backslashing function, and it was all for nothing, because the whole problem is solved by just putting a ? into the query, like this

 SELECT * FROM people WHERE lastname = ?

All my examples look like this. It is safer and more convenient and more efficient to do it this way.

July 02

wire and reg (verilog) from http://www.asic-world.com/tidbits/wire_reg.html

Well I had this doubt when I was learning Verilog: What is the difference between reg and wire? Well I won't tell stories to explain this, rather I will give you some examples to show the difference.

space.gif

From the college days we know that wire is something which connects two points, and thus does not have any driving strength. In the figure below, in_wire is a wire which connects the AND gate input to the driving source, clk_wire connects the clock to the flip-flop input, d_wire connects the AND gate output to the flip-flop D input.

space.gif

../images/tidbits/wire.h4.gif

space.gif

There is something else about wire which sometimes confuses. wire data types can be used for connecting the output port to the actual driver. Below is the code which when synthesized gives a AND gate as output, as we know a AND gate can drive a load.

space.gif


 1 module wire_example( a, b, y);
 2   input a, b;
 3   output y;
 4 
 5   wire a, b, y;
 6 
 7   assign y = a & b;
 8 
 9 endmodule
You could download file wire_example.v here

space.gif

SYNTHESIS OUTPUT

space.gif

../images/tidbits/wire_and.gif

space.gif

What this implies is that wire is used for designing combinational logic, as we all know that this kind of logic can not store a value. As you can see from the example above, a wire can be assigned a value by an assign statement. Default data type is wire: this means that if you declare a variable without specifying reg or wire, it will be a 1-bit wide wire.

space.gif

Now, coming to reg data type, reg can store value and drive strength. Something that we need to know about reg is that it can be used for modeling both combinational and sequential logic. Reg data type can be driven from initial and always block.

space.gif

Reg data type as Combinational element

space.gif


  1 module reg_combo_example( a, b, y);
  2 input a, b;
  3 output y;
  4 
  5 reg   y;
  6 wire a, b;
  7 
  8 always @ ( a or b)
  9 begin	
 10   y = a & b;
 11 end
 12 
 13 endmodule
You could download file reg_combo_example.v here

space.gif

SYNTHESIS OUTPUT

space.gif

../images/tidbits/wire_and.gif

space.gif

This gives the same output as that of the assign statement, with the only difference that y is declared as reg. There are distinct advantages to have reg modeled as combinational element; reg type is useful when a "case" statement is required (refer to the Verilog section for more on this).

space.gif

To model a sequential element using reg, we need to have edge sensitive variables in the sensitivity list of the always block.

space.gif

Reg data type as Sequential element

space.gif


  1 module reg_seq_example( clk, reset, d, q);
  2 input clk, reset, d;
  3 output q;
  4   
  5 reg   q;
  6 wire clk, reset, d;
  7 
  8 always @ (posedge clk or posedge reset)
  9 if (reset) begin
 10   q <= 1'b0;
 11 end else begin
 12   q <= d;
 13 end
 14 
 15 endmodule
You could download file reg_seq_example.v here

space.gif

SYNTHESIS OUTPUT

space.gif

../images/tidbits/wire_syn.gif

space.gif

There is a difference in the way we assign to reg when modeling combinational logic: in this logic we use blocking assignments while modeling sequential logic we use nonblocking ones.

June 29

Different between casex and casez from http://www.asic-world.com/verilog/vbehave2.html

space.gif


The Conditional Statement if-else

The if - else statement controls the execution of other statements. In programming language like c, if - else controls the flow of program. When more than one statement needs to be executed for an if condition, then we need to use begin and end as seen in earlier examples.

space.gif

Syntax : if

if (condition)

statements;

space.gif

Syntax : if-else

if (condition)

statements;

else

statements;

space.gif

Syntax : nested if-else-if

if (condition)

statements;

else if (condition)

statements;

................

................

else

statements;

space.gif

../images/main/bulllet_4dots_orange.gif
Example- simple if

space.gif


  1 module simple_if();
  2 
  3 reg latch;
  4 wire enable,din;
  5 
  6 always @ (enable or din)
  7 if (enable) begin
  8   latch <= din;
  9 end  
 10 
 11 endmodule
You could download file simple_if.v here

space.gif

../images/main/bulllet_4dots_orange.gif
Example- if-else

space.gif


  1 module if_else();
  2 
  3 reg dff;
  4 wire clk,din,reset;
  5 
  6 always @ (posedge clk)
  7 if (reset) begin
  8   dff <= 0;
  9 end else  begin
 10   dff <= din;
 11 end
 12 
 13 endmodule
You could download file if_else.v here

space.gif

../images/main/bulllet_4dots_orange.gif
Example- nested-if-else-if

space.gif


  1 module nested_if();
  2 
  3 reg [3:0] counter;
  4 reg clk,reset,enable, up_en, down_en;
  5 
  6 always @ (posedge clk)
  7 // If reset is asserted
  8 if (reset == 1'b0) begin
  9    counter <= 4'b0000; 
 10 // If counter is enable and up count is asserted
 11 end else if (enable == 1'b1 && up_en == 1'b1) begin
 12    counter <= counter + 1'b1;
 13 // If counter is enable and down count is asserted
 14 end else if (enable == 1'b1 && down_en == 1'b1) begin
 15    counter <= counter - 1'b1;
 16 // If counting is disabled
 17 end else begin
 18    counter <= counter; // Redundant code 
 19 end
 20 
 21 // Testbench code 
 22 initial begin
 23   $monitor ("@‰0dns reset=‰b enable=‰b up=‰b down=‰b count=‰b",
 24              $time, reset, enable, up_en, down_en,counter);
 25   $display("@‰0dns Driving all inputs to know state",$time);
 26   clk = 0;
 27   reset = 0;
 28   enable = 0;
 29   up_en = 0;
 30   down_en = 0;
 31    #3  reset = 1;
 32   $display("@‰0dns De-Asserting reset",$time);
 33    #4  enable = 1;
 34   $display("@‰0dns De-Asserting reset",$time);
 35    #4  up_en = 1;
 36   $display("@‰0dns Putting counter in up count mode",$time);
 37    #10  up_en = 0;
 38   down_en = 1;
 39   $display("@‰0dns Putting counter in down count mode",$time);
 40    #8  $finish;
 41 end
 42 
 43 always  #1  clk = ~clk;
 44 
 45 endmodule
You could download file nested_if.v here

space.gif

../images/main/bulllet_4dots_orange.gif
Simulation Log- nested-if-else-if

space.gif

 @0ns Driving all inputs to know state
 @0ns reset=0 enable=0 up=0 down=0 count=xxxx
 @1ns reset=0 enable=0 up=0 down=0 count=0000
 @3ns De-Asserting reset
 @3ns reset=1 enable=0 up=0 down=0 count=0000
 @7ns De-Asserting reset
 @7ns reset=1 enable=1 up=0 down=0 count=0000
 @11ns Putting counter in up count mode
 @11ns reset=1 enable=1 up=1 down=0 count=0001
 @13ns reset=1 enable=1 up=1 down=0 count=0010
 @15ns reset=1 enable=1 up=1 down=0 count=0011
 @17ns reset=1 enable=1 up=1 down=0 count=0100
 @19ns reset=1 enable=1 up=1 down=0 count=0101
 @21ns Putting counter in down count mode
 @21ns reset=1 enable=1 up=0 down=1 count=0100
 @23ns reset=1 enable=1 up=0 down=1 count=0011
 @25ns reset=1 enable=1 up=0 down=1 count=0010
 @27ns reset=1 enable=1 up=0 down=1 count=0001

space.gif

../images/main/bulllet_4dots_orange.gif
Parallel if-else

In the above example, the (enable == 1'b1 && up_en == 1'b1) is given highest priority and condition (enable == 1'b1 && down_en == 1'b1) is given lowest priority. We normally don't include reset checking in priority as this does not fall in the combo logic input to the flip-flop as shown in the figure below.

space.gif

../images/verilog/if_else.gif

space.gif

So when we need priority logic, we use nested if-else statements. On the other hand if we don't want to implement priority logic, knowing that only one input is active at a time (i.e. all inputs are mutually exclusive), then we can write the code as shown below.

space.gif

It's known fact that priority implementation takes more logic to implement than parallel implementation. So if you know the inputs are mutually exclusive, then you can code the logic in parallel if.

space.gif


  1 module parallel_if();
  2 
  3 reg [3:0] counter;
  4 wire clk,reset,enable, up_en, down_en;
  5 
  6 always @ (posedge clk)
  7 // If reset is asserted
  8 if (reset == 1'b0) begin
  9    counter <= 4'b0000; 
 10 end else begin
 11   // If counter is enable and up count is mode
 12   if (enable == 1'b1 && up_en == 1'b1) begin
 13     counter <= counter + 1'b1;
 14   end
 15   // If counter is enable and down count is mode
 16   if (enable == 1'b1 && down_en == 1'b1) begin
 17     counter <= counter - 1'b1;
 18   end 
 19 end  
 20 
 21 endmodule
You could download file parallel_if.v here

space.gif

../images/main/bullet_green_ball.gif
The Case Statement

The case statement compares an expression to a series of cases and executes the statement or statement group associated with the first matching case:

space.gif

  • case statement supports single or multiple statements.
  • Group multiple statements using begin and end keywords.

space.gif

Syntax of a case statement look as shown below.

case ()

< case1 > : < statement >

< case2 > : < statement >

.....

default : < statement >

endcase

space.gif

../images/main/bulllet_4dots_orange.gif
Normal Case

space.gif

space.gif

../images/main/bullet_star_pink.gif
Example- case

space.gif


  1 module mux (a,b,c,d,sel,y); 
  2 input a, b, c, d; 
  3 input [1:0] sel; 
  4 output y; 
  5 
  6 reg y;
  7 
  8 always @ (a or b or c or d or sel) 
  9 case (sel) 
 10   0 : y = a; 
 11   1 : y = b; 
 12   2 : y = c; 
 13   3 : y = d; 
 14   default : $display("Error in SEL"); 
 15 endcase 
 16     
 17 endmodule
You could download file mux.v here

space.gif

../images/main/bullet_star_pink.gif
Example- case without default

space.gif


  1 module mux_without_default (a,b,c,d,sel,y);
  2 input a, b, c, d; 
  3 input [1:0] sel; 
  4 output y; 
  5 
  6 reg y;
  7 
  8 always @ (a or b or c or d or sel) 
  9 case (sel) 
 10   0 : y = a; 
 11   1 : y = b; 
 12   2 : y = c; 
 13   3 : y = d; 
 14   2'bxx,2'bx0,2'bx1,2'b0x,2'b1x,
 15   2'bzz,2'bz0,2'bz1,2'b0z,2'b1z : $display("Error in SEL");
 16 endcase 
 17 
 18 endmodule
You could download file mux_without_default.v here

space.gif

The example above shows how to specify multiple case items as a single case item.

space.gif

The Verilog case statement does an identity comparison (like the === operator); one can use the case statement to check for logic x and z values as shown in the example below.

space.gif

../images/main/bullet_star_pink.gif
Example- case with x and z

space.gif


  1 module case_xz(enable);
  2 input enable;
  3 
  4 always @ (enable)
  5 case(enable)
  6   1'bz : $display ("enable is floating"); 
  7   1'bx : $display ("enable is unknown"); 
  8   default : $display ("enable is ‰b",enable); 
  9 endcase 
 10 
 11 endmodule
You could download file case_xz.v here

space.gif

../images/main/bulllet_4dots_orange.gif
The casez and casex statement

Special versions of the case statement allow the x ad z logic values to be used as "don't care":

space.gif

  • casez : Treats z as don't care.
  • casex : Treats x and z as don't care.

space.gif

../images/main/bullet_star_pink.gif
Example- casez

space.gif


  1 module casez_example();
  2 reg [3:0] opcode;
  3 reg [1:0] a,b,c;
  4 reg [1:0] out;
  5 
  6 always @ (opcode or a or b or c)
  7 casez(opcode)
  8   4'b1zzx : begin // Don't care about lower 2:1 bit, bit 0 match with x
  9               out = a; 
 10               $display("@‰0dns 4'b1zzx is selected, opcode ‰b",$time,opcode);
 11             end
 12   4'b01?? : begin
 13               out = b; // bit 1:0 is don't care
 14               $display("@‰0dns 4'b01?? is selected, opcode ‰b",$time,opcode);
 15             end
 16   4'b001? : begin  // bit 0 is don't care
 17               out = c;
 18               $display("@‰0dns 4'b001? is selected, opcode ‰b",$time,opcode);
 19             end
 20   default : begin
 21               $display("@‰0dns default is selected, opcode ‰b",$time,opcode);
 22             end
 23 endcase
 24 
 25 // Testbench code goes here
 26 always  #2  a = $random;
 27 always  #2  b = $random;
 28 always  #2  c = $random;
 29 
 30 initial begin
 31   opcode = 0;
 32    #2  opcode = 4'b101x;
 33    #2  opcode = 4'b0101;
 34    #2  opcode = 4'b0010;
 35    #2  opcode = 4'b0000;
 36    #2  $finish;
 37 end
 38 
 39 endmodule
You could download file casez_example.v here

space.gif

../images/main/bullet_star_pink.gif
Simulation Output - casez

space.gif

 @0ns default is selected, opcode 0000
 @2ns 4'b1zzx is selected, opcode 101x
 @4ns 4'b01?? is selected, opcode 0101
 @6ns 4'b001? is selected, opcode 0010
 @8ns default is selected, opcode 0000

space.gif

../images/main/bullet_star_pink.gif
Example- casex

space.gif


  1 module casex_example();
  2 reg [3:0] opcode;
  3 reg [1:0] a,b,c;
  4 reg [1:0] out;
  5 
  6 always @ (opcode or a or b or c)
  7 casex(opcode)
  8   4'b1zzx : begin // Don't care  2:0 bits
  9               out = a; 
 10               $display("@‰0dns 4'b1zzx is selected, opcode ‰b",$time,opcode);
 11             end
 12   4'b01?? : begin // bit 1:0 is don't care
 13               out = b; 
 14               $display("@‰0dns 4'b01?? is selected, opcode ‰b",$time,opcode);
 15             end
 16   4'b001? : begin // bit 0 is don't care
 17               out = c;
 18               $display("@‰0dns 4'b001? is selected, opcode ‰b",$time,opcode);
 19             end
 20   default : begin
 21               $display("@‰0dns default is selected, opcode ‰b",$time,opcode);
 22             end
 23 endcase 
 24 
 25 // Testbench code goes here
 26 always  #2  a = $random;
 27 always  #2  b = $random;
 28 always  #2  c = $random;
 29 
 30 initial begin
 31   opcode = 0;
 32    #2  opcode = 4'b101x;
 33    #2  opcode = 4'b0101;
 34    #2  opcode = 4'b0010;
 35    #2  opcode = 4'b0000;
 36    #2  $finish;
 37 end
 38 
 39 endmodule
You could download file casex_example.v here

space.gif

../images/main/bullet_star_pink.gif
Simulation Output - casex

space.gif

 @0ns default is selected, opcode 0000
 @2ns 4'b1zzx is selected, opcode 101x
 @4ns 4'b01?? is selected, opcode 0101
 @6ns 4'b001? is selected, opcode 0010
 @8ns default is selected, opcode 0000

space.gif

../images/main/bullet_star_pink.gif
Example- Comparing case, casex, casez

space.gif


  1 module case_compare;
  2 
  3 reg sel;
  4 
  5 initial begin
  6    #1  $display ("\n     Driving 0");
  7   sel = 0;
  8    #1  $display ("\n     Driving 1");
  9   sel = 1;
 10    #1  $display ("\n     Driving x");
 11   sel = 1'bx;
 12    #1  $display ("\n     Driving z");
 13   sel = 1'bz;
 14    #1  $finish;
 15 end
 16 
 17 always @ (sel)
 18 case (sel)
 19   1'b0 : $display("Normal : Logic 0 on sel");
 20   1'b1 : $display("Normal : Logic 1 on sel");
 21   1'bx : $display("Normal : Logic x on sel");
 22   1'bz : $display("Normal : Logic z on sel");
 23 endcase
 24 
 25 always @ (sel)
 26 casex (sel)
 27   1'b0 : $display("CASEX  : Logic 0 on sel");
 28   1'b1 : $display("CASEX  : Logic 1 on sel");
 29   1'bx : $display("CASEX  : Logic x on sel");
 30   1'bz : $display("CASEX  : Logic z on sel");
 31 endcase
 32 
 33 always @ (sel)
 34 casez (sel)
 35   1'b0 : $display("CASEZ  : Logic 0 on sel");
 36   1'b1 : $display("CASEZ  : Logic 1 on sel");
 37   1'bx : $display("CASEZ  : Logic x on sel");
 38   1'bz : $display("CASEZ  : Logic z on sel");
 39 endcase
 40 
 41 endmodule
You could download file case_compare.v here

space.gif

Simulation Output

space.gif

      Driving 0
 Normal : Logic 0 on sel
 CASEX  : Logic 0 on sel
 CASEZ  : Logic 0 on sel
 
      Driving 1
 Normal : Logic 1 on sel
 CASEX  : Logic 1 on sel
 CASEZ  : Logic 1 on sel
 
      Driving x
 Normal : Logic x on sel
 CASEX  : Logic 0 on sel
 CASEZ  : Logic x on sel
 
      Driving z
 Normal : Logic z on sel
 CASEX  : Logic 0 on sel
 CASEZ  : Logic 0 on sel

X, Z In IF Conditions And CaseX, CaseZ from http://www.see.ed.ac.uk/~gerard/Teach/Verilog/me5cds/me95cdr.html

 

Logic Levels Within Verilog

    0 - logic zero, false condition

    1 - logic one, true condition

    x - unknown logic value

    z - high impedance

An x can be any one of a 1, 0, z or change of state. If a one and a zero are both present at a node with comparable strength, the resultant is unknown (x).

A z represents a high impedance or floating gate condition. It is the weakest level of logic, being very susceptible to change, and primarily occurs when a node is no longer driven.

X, Z in IF and CASE statements

Within an IF statement a zero corresponds to a false condition and any other value to true. However, if an unknown (x) or high impedance (z) are compared the result may evaluate to an x or z, being interpreted as a false condition.

Case expressions may include x's and z's, with the comparison only being successful if there is an exact match between each individual bit (whether it be a 0, 1, x ot z).

X, Z In CASEX, CASEZ

Casex and casez are the two variations of the case statement within Verilog. The syntax is almost identical to the case statement, with the only difference being that case is substituted by either casex or casez. The syntax is as follows:

    case_statement :: =

      | case (expression) case_item {case_item} endcase

      | casez (expression) case_item {case_item} endcase

      | case (expression) case_item {case_item} endcase

    case_item :: =

      expression {,expression} : statement_or_null

      | default [:] statement_or_null

The use of casex and casez allows don't care values to be considered in the comparison. Casez allows for z values to be treated as don't cares, whereas casex allows for both z and x to be treated as don't cares. Only bit values other than the don't care bits are used in the comparison.

An example of the use of x within a casex statement is given below:

    reg [7:0] value_read, value_held;

    always begin

      value_held = 8'bx1xx01x1

      casex (value_read ^ value_held)

        8'bxx1010x0 : statement1;

        8'b00xx01x0 : statement2;

        8'bx001x0x1 : statement3;

        8'bxx1010x0 : statement4;

      endcase

    end

Where the ^ character represents the Exclusive-OR function.

Assuming value_read is given as 11001001 the statement executed is calculated as follows:

    value_held ^ value_read

    = x1xx01x1 ^ 01100110

    = x0xx00x1

Note: when an x is Exclusive-ORed with any value the result is an x.

It can be seen that the only statement the match and therefore the one which is executed is statement3.

 
  • Send a private message
  • Subscribe to RSS feed
  • Tell a friend
  • Add to My MSN
  • Add to Live.com
  • Add to your network
Thanks for visiting!
Please wait...
Sorry, the comment you entered is too long. Please shorten it.
You didn't enter anything. Please try again.
Sorry, we can't add your comment right now. Please try again later.
To add a comment, you need permission from your parent. Ask for permission
Your parent has turned off comments.
Sorry, we can't delete your comment right now. Please try again later.
You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
Complete the security check below to finish leaving your comment.
The characters you type in the security check must match the characters in the picture or audio.