An I2C verification environment, which uses
memories and VPI (c code) to
drive and monitor data to/from DUT, will be described in this work.
-
In this site many verification environments have been presented, using,
specman
,
VHDL
etc....
The main page of this work is accessed with the following
link.
The verilog code of the project, contains a BFM and also
controls the operation of c code.
This page describes how APB transaction buffers are prepared by the
c code
and stored into
a read only memory buffers in the verilog test-bench for farther
use of its BFM.
-
The c code main stimuli is an array and its main element structure has
three fields namely: Address,
write/read expected data and a two bit control array (containing last
entry and write
indication):
typedef struct t_mem_init {
int addr;
int wdat;
int ctrl; //pkt_end pwrite
} t_mem_init;
t_mem_init a_mem_init[] = {
//write transactions
{0x000000e0, 0x000000fa, 0x1},
{0x000000e0, 0x000000c8, 0x1},
{0x000000e4, 0x00000000, 0x1},
//read transactions
{0x000000e0, 0x000000fa, 0x0},
{0x00000000, 0x00000000, 0x2} //end entry
};
...
-
The data extraction from the stimuli c code array to the read only
test-bench memory buffers, is controlled by two global variables:
int mem_ix;
enum t_mem_field {t_addr, t_wdat, t_ctrl};
enum t_mem_field mem_field=t_addr;
-
The verilog test-bench invokes the c-code three times. The c code first
writes to address array, second to the write data and last to the control.
...
stim_sz=sizeof(a_mem_init)/sizeof(t_mem_init);
...
for(mem_ix=0; mem_ix < stim_sz; mem_ix++) {
h3 = vpi_handle_by_index(argh, ix_addr);
ar_da.format = vpiIntVal;
...
vpi_printf("C: current mem_field %d \n", (int)mem_field);
switch (mem_field) {
case t_addr:
data_to_a.value.integer=a_mem_init[mem_ix].addr;
break;
case t_wdat:
...
ix_addr++;
if(ix_addr > right_addr) {
vpi_printf("C: ERROR ix_addr is too large %x %x %x\n", left_addr, right_addr, ix_addr);
}
} //for
...
//move filed pointer
switch (mem_field) {
case t_addr: mem_field=t_wdat; break;
case t_wdat: mem_field=t_ctrl; break;
...
Note that if the user specified a stimuli array too large (more than what
is defined in the verilog test-bench) an
ERROR is printed. In that case the simulation should be stopped
as soon as possible. This is because writing outside an array boundaries
may lead to unpredictable results.
To stop a simulation from within the c code, I selected the
finish command.
ix_addr=left_addr;
for(mem_ix=0; mem_ix < stim_sz; mem_ix++) {
...
if(ix_addr > right_addr) {
vpi_printf("C: ERROR ix_addr is too large %x %x %x\n", left_addr, right_addr, ix_addr);
vpi_control(vpiFinish, 1);
break;
}
The importance of the break command in the c code:
If the
break command is not included, the c code will continue
till it
ends its current for loop, than returns control to the
simulator,
which finally do the finish command as opposed to the ASAP stop, due
memory overrun.
-
The verilog test-bench sends messages to c code to instruct it of
which APB buffers to prepare (DUT register initialization, data ready
poll, etc...). This is explained in the following
link.
|