Design and Verification of a PCI Based System using SystemC

1.3. Testbench

Testbenches are used to provide stimulus to a design under test and check design results. The testbench can be implemented in a number of ways. In the current testbench stimulus are generated by one process (Driver) and results checked by another (Monitor). The stimulus is generated by a thread which runs as long as all the conditions given by it are tested and the results are obtained. The results are checked by another process which is sensitive to the events which are triggered by the slave whenever any transactions take place. The data sent and received at the driver end are stored in an array. The same is done at the monitor end. At the end of all the transactions both the arrays are compared. This is to verify whether the transaction were successful or not.

1.3.1 Driver :

Driver is a part of the test bench, which is used to send stimulus to the DUT module. Initially a THREAD process sends the stimulus to configure all the slaves base address register. This process initializes all the Base Address Register of all the six slaves, in the configuration Base Address Register (BAR). Once the configuration is over, the driver sends the various PCI commands to each master by calling the function testbench (). The testbench function sends the slave address, data, command number, and data length to the master of the current transaction.

The send function sets the corresponding master bit and writes the information packet to the master through the channel. The Driver informs the master whether to read the packet or to transmit the received data from the slave using the read and write bits. If the read bit is set then the master sends the data to the driver or if write bit is set then master reads the packet.
The Driver contains an array to store the received data during the read transaction, and during the write transaction the sent data is stored in this array.

1.3.2 Monitor :

Monitor is a part of the test bench, which is used to display the result of the transaction. The Monitor contains an array to store the received data during the write transaction, and during the read transaction the sent data is stored in this array. The Driver’s array and the Monitor’s array are compared at the end of the each transaction, and if both arrays are not equal then an “ERROR” message is displayed.

Monitor contains destination memory space. This space is split into memory and I/O space, where all the data of corresponding transaction are stored.

1.3.3 Testcases :

Test cases are used to check the system performance for the different PCI commands. These test cases are sent from the driver to the master, to carry out required transaction. The test case is defined in the test bench function. If an invalid test case is sent then no master claims the information packet.

Code description:

2.1 Interfaces :

2.1.1. inter1 interface :

The inter1 interface is used to connect Channel1 to the master and driver module. The interface functions move information packets through the channel. It also contains the functions which sets and updates the status bits in the channel. These functions are defined as follows :

2.1.1.1 void write(struct Packet*);
The above function writes the address of the structure Packet into the channel. This address is given to another structure pointer present in the channel. And also updates the status bits in the channel to tell which of the three masters the pointer should be sent to.

2.1.1.2 struct Packet* read(void);
This function is used to read the address of the struct Packet from the channel.

2.1.1.3 struct Status status(void);
This function is used to read the status of the channel. It returns the structure status.

2.1.1.4 void Status_update(struct Status);
This function is used to update the status bits present in the channel.

2.1.2. inter2 interface :

The inter2 interface is used to connect Channel2 to the monitor and the slave. The interface functions are used to exchange data between the slave and the monitor.

2.1.2.1 void write(struct m_status*);
This function is used to write the address of the structure m_status into the channel. The function doesn’t return anything.

2.1.2.2 struct m_status* read(void);
This function returns the address of the structure m_status from the channel. This function is used to read the status bits and other data that had been updated to the channel.
The codes are in files Channel1.h, Channel1.cpp, Channel2.h and Channel2.cpp

2.2 Structures :

2.2.1. struct Packet {
int cmd_def;
int address;
int data[30];
int length;
int master;
};

The above structure was used to pass the information from the driver to the master. In our program, this structure is owned by the master and its pointer is sent to the master via the channel for it to access the required information.

2.2.2. struct Status {
bool read;
bool write;
bool m1;
bool m2;
bool m3;
int wait;
};

This structure is used to copy and update the status bits in Channel1.

2.2.3. struct m_status {
bool w;
bool r;
int data;
int s_no;
int abort;
int Add;
};

The above structure is used to transfer data as well as to read and update the status bits in Channel2. This structure is owned by the slave.

2.3 Design under test (DUT) :

2.3.1.Master module :

The master is responsible to initiate and carry the transaction. Each master is given unique priority which is assigned to it during instantiation.
There are eight input/output port in which two are of type int named as AD and C_BE, six are of type bool named as FRAME, PAR, IRDY, TRDY, STOP, DEVSEL, two output ports are of type bool named as REQ, IDSEL, one input port is of type bool named as GNT, one clock port clock and one port of type inter1 named as mast.

There are eight events: frame_a, frame_d, irdy_a, irdy_d, req_a, req_d, ad and cd.

This module consists many functions and processes which help it carry out its task, they are listed below :

1.1 void master(void);
This function is registered as SC_METHOD process and is sensitive to the positive edge of the clock. This function is mainly responsible for most of the tasks that are performed by the master module. It uses switch case for executing the required transaction.

1.2 void rem_req(void);
This function is registered as SC_METHOD process and is sensitive to IRDY# as well as STOP#. It is responsible for deasserting REQ#. It also resets the status bits in Channel1 telling the driver that the master has finished with all the transactions so that it ends the simulation.

1.3 void Abort(void);
This function is registered as SC_METHOD process and is sensitive to DEVSEL#. It sets a condition indicating that a slave has been selected. If this condition is not set then the master end the transaction when the timer runs out.

1.4 void done_reading(int );
This function is used to set and update the status bits present in Channel1. These bits tell the driver whether any masters have pending transactions.

1.5 void parity_fun(void);
This function is SC_METHOD process and is sensitive to the event par . This function is used to generate the parity of the data/command and byte enable/command definition. Depending on the parity thus generated, it asserts or deasserts PAR.

1.6 void parity_check(void);
This function is used to check the parity of the receives data. The decisions regarding whether or not a parity error has occurred is taken by the process – void master(void).

1.7 void set(void);
This function is simply used to set all the initial conditions. It is registered as SC_PROCESS but is not sensitive to any events. It is executed once just before the simulation starts.

1.8 void f_a (void);
This function is registered as SC_METHOD process and is sensitive to the event frame_a. It asserts FRAME#, sets PAR to 0, write the command definition into the C/BE lines and also resets the latency timer.

1.9 void f_d (void);
This function is registered as SC_METHOD process and is sensitive to the event frame_d. It deasserts FRAME#.

1.10 void i_a (void);
This function is registered as SC_METHOD process and is sensitive to the event irdy_a. It asserts IRDY#.

1.11 void i_d (void);
This function is registered as SC_METHOD process and is sensitive to the event irdy_d. It deasserts IRDY#.

1.12 void r_a (void);
This function is registered as SC_METHOD process and is sensitive to the event req_a. It asserts REQ#.

1.13 void r_d (void);
This function is registered as SC_METHOD process and is sensitive to the event req_d. It deasserts REQ#.

1.14 void address (void);
This function is registered as SC_METHOD process and is sensitive to the event ad. It writes the data into the AD lines and also notifies the event par.

1.15 void p_a (void);
This function is registered as SC_METHOD process and is sensitive to the event par_a. It asserts PAR.

1.16 void p_d (void);
This function is registered as SC_METHOD process and is sensitive to the event par_d. It deasserts .

1.17 void pr_a (void);
This function is registered as SC_METHOD process and is sensitive to the event perr_a. This function asserts the PERR# and sets the condition for target abort.

1.18 void pr_y (void);
This function is registered as SC_METHOD process and is sensitive to the event perr_y. This function is used to create a parity error during verification.

Editorial Team
Editorial Team

We are a group of young techies trying to provide the best study material for all Electronic and Computer science students. We are publishing Microcontroller projects, Basic Electronics, Digital Electronics, Computer projects and also c/c++, java programs.

One thought on “Design and Verification of a PCI Based System using SystemC

Leave a Reply

Your email address will not be published. Required fields are marked *

Get the latest updates on your inbox

Be the first to receive the latest updates from Codesdoc by signing up to our email subscription.

    StudentProjects.in