您的位置:技术中心首页 > 逻辑验证 >> Verilog PLI教程 --- 第五部分 PLI例子

Verilog PLI教程 --- 第五部分 PLI例子

作者:5life   时间:2006-02-19 05:58:23  来自:本站原创  浏览次数:980  文字大小:【】【】【
简   介:本Verilog PLI教程翻译自asic-world网站的Verilog PLI教程,由于译者水平有限,难免会有一些错误,请与译者5life站内联系。原文地址为:http://www.asic-world.com/verilog/pli5.html#PLI_Example

在剩下的教程中,让我们用测试向量发生器,监测器,检验器以及任何用C代码编写的来验证计数器例子。

Testbench将有下列:

  •    C编写的时钟发生器
  •    时钟发生器的HDL wrapper
  •    C编写的测试产生器
  •    测试产生器的HDL wrapper
  •    C编写的监测器和检验器
  •    Mointor Checker HDL wrapper
  •    在verilog中的DUT/Monitor/clock/test 产生器的例化

时钟发生器
一般我们不希望在PLI中产生时钟发生器,最好是在verilog中实现。

1 #include "acc_user.h"
2 #include "veriuser.h"
3
4 // Define the ON and OFF time of clock
5 #define PERIOD 5
6
7 // Data structure
8 struct clkData {
9   int clk;
10   int clkCnt;
11 };
12
13 // Main routine which toggles the clock
14 void clkGen () {
15   // Get the stored workarea
16   struct clkData *data = ( struct clkData * )tf_igetworkarea(tf_getinstance());
17   if (data->clkCnt == PERIOD) {
18     data->clk = (data->clk == 0) ? 1 : 0;
19     data->clkCnt = 0;
20     //io_printf("%d Current clk = %dn",tf_gettime(), data->clk);
21   } else {
22     data->clkCnt ++;
23   }
24   // Drive the clock signal in HDL
25   tf_putp (1, data->clk);
26 }
27
28 // checktf() routine
29 // This function inits the objects and also stores the object in workarea
30 void clkInit() {
31   struct clkData *data = ( struct clkData * )malloc( sizeof( struct clkData ) );
32   data->clkCnt = 0;
33   data->clk = 0;
34   tf_setworkarea(data);
35 }
36
37 // misctf() routine
38 // This routine is called after 1 tick
39 void clkReactive (int data, int reason, int paramvc) {
40   // if callback reason is reactive, then call clkGen function
41   if (reason == reason_reactivate) {
42     clkGen();
43   }
44   // Set the callback delay to 1 tick
45   tf_setdelay(1);
46 }

Clock Generator HDL Wrapper

1 module clkGen(clk);
2 output clk;
3 reg clk;
4
5 initial $clkGen(clk);
6
7 endmodule

Counter Monitor

1 #include "acc_user.h"
2 #include "veriuser.h"
3 #include <malloc.h>
4 #include <string.h>
5
6 struct myCounter {
7   handle count;
8   handle enable;
9   handle reset;
10   handle clk;
11   char *count_value;
12   char *enable_value;
13   char *reset_value;
14   char *clk_value;
15   char *clk_last_value;
16   int checker_count;
17   int count_width;
18   int error;
19   int error_time;
20 };
21
22 // Multi-bit vector to integer conversion.
23 int pliConv (char *in_string, int no_bits, int sim_time) {
24   int conv = 0;
25   int i = 0;
26   int j = 0;
27   int bin = 0;
28   for ( i = no_bits-1; i >= 0; i = i - 1) {
29     if (*(in_string + i) == 49) {
30       bin = 1;
31     } else if (*(in_string + i) == 120) {
32       io_printf ( "%d counterMonitor : WARNING : X detectedn" , sim_time);
33       bin = 0;
34     } else if (*(in_string + i) == 122) {
35       io_printf ( "%d counterMonitor : WARNING : Z detectedn" , sim_time);
36       bin = 0;
37     } else {
38       bin = 0;
39     }
40     conv = conv + (1 << j)*bin;
41     j ++;
42   }
43   return conv;
44 }
45
46 void counterModel (struct myCounter *counter) {
47   int current_value ;
48   int time = tf_gettime();
49   // Our model checks only at posedge
50   if ((strcmp(counter->clk_value, "1" ) == 0) && (strcmp(counter->clk_last_value, "0" ) == 0)) {
51   // Conver the current count value
52   current_value = pliConv(counter->count_value,counter->count_width,time);
53   // Check input control signal to floating or UnKnown
54   if (strcmp(counter->reset_value, "x" ) == 0) {
55   io_printf( "%d counterMonitor : WARNING : reset is xn" , time);
56 }
57 if (strcmp(counter->reset_value, "z" ) == 0) {
58 io_printf( "%d counterMonitor : WARNING : reset is zn" , time);
59 }
60 if (strcmp(counter->enable_value, "x" ) == 0) {
61 io_printf( "%d counterMonitor : WARNING : enable is xn" , time);
62 }
63 if (strcmp(counter->enable_value, "z" ) == 0) {
64 io_printf( "%d counterMonitor : WARNING : enable is zn" , time);
65 }
66 // Increment monitor counter and compare only if enable is 1 and reset is not active
67 if (strcmp(counter->enable_value, "1" ) == 0 && strcmp(counter->reset_value, "0" ) == 0) {
68 if (counter->checker_count != current_value) {
69   io_printf( "%d counterMonitor : ERROR : Current value of monitor is %d dut is %dn" ,
70   time, counter->checker_count, current_value);
71   counter->error ++;
72   if (counter->error == 1) counter->error_time = time;
73 } else {
74   io_printf( "%d counterMonitor : INFO : Current value of monitor is %d dut is %dn" ,
75   time, counter->checker_count, current_value);
76 }
77 counter->checker_count = (counter->checker_count == 15) ? 0 : counter->checker_count + 1;
78 // Reset monitor counter if reset is active
79 } else if (strcmp(counter->reset_value, "1" ) == 0) {
80 io_printf( "%d counterMonitor : INFO : Reset is assertedn" , time);
81 counter->checker_count = 0;
82 }
83 }
84 // Update the clock state
85 strcpy(counter->clk_last_value,counter->clk_value);
86 }
87
88 // misctf
89 void counterMonitor(int data, int reason, int paramvc) {
90   struct myCounter *counter = (struct myCounter *) tf_igetworkarea(tf_getinstance());
91   if ((reason == reason_paramvc) || (reason == reason_paramdrc)) {
92     tf_synchronize( );
93   } else if (reason == reason_synch) {
94     counter->clk = acc_handle_tfarg(1);
95     counter->reset = acc_handle_tfarg(2);
96     counter->enable = acc_handle_tfarg(3);
97     counter->count = acc_handle_tfarg(4);
98     // Get the values
99     counter->clk_value = acc_fetch_value(counter->clk, "%b" , 0);
100     counter->reset_value = acc_fetch_value(counter->reset, "%b" , 0);
101     counter->enable_value = acc_fetch_value(counter->enable, "%b" , 0);
102     counter->count_value = acc_fetch_value(counter->count, "%b" , 0);
103     counter->count_width = acc_fetch_size (counter->count);
104     // Call the counter model
105     counterModel (counter);
106   }
107   // Print simulation stats when $finish is called
108   if (reason == reason_finish) {
109     io_printf( "=========================================n" );
110     if (counter->error != 0) {
111       io_printf ( " Simulation : FAILEDn" );
112       io_printf ( " Mismatched %dn" ,counter->error);
113       io_printf ( " First Mismatch at time %dn" , counter->error_time);
114     } else {
115       io_printf ( " Simulation : PASSEDn" );
116     }
117     io_printf( "=========================================n" );
118   }
119 }
120
121 // calltf()
122 void initCounter(int data, int reason) {
123   struct myCounter *counter;
124   // Allocate memory for all variables necessary to manage a
125   // single instance of the model.
126   counter = (struct myCounter *) malloc (sizeof(struct myCounter));
127   // Initialize this instance of the model.
128   counter->clk = acc_handle_tfarg(1);
129   counter->reset = acc_handle_tfarg(2);
130   counter->enable = acc_handle_tfarg(3);
131   counter->count = acc_handle_tfarg(4);
132   // Save a copy of the present clk value.
133   counter->clk_last_value = acc_fetch_value(counter->clk, "%b" , 0);
134   // Enable callback of `counter_monitor` whenever
135   // any argument to `$counter_monitor` changes.
136   tf_asynchon();
137   // Set initial counter value to 0.
138   counter->checker_count = 0;
139   counter->error = 0;
140   counter-> error_time = 0;
141   // Save the model data with this instance of `$counterMonitor`.
142   tf_setworkarea((char *)counter);
143 }

Counter Monitor HDL Wrapper

1 module counterMonitor (clk, reset, enable, count);
2 input clk, reset, enable;
3 input [3:0] count;
4
5 wire clk, reset, enable;
6 wire [3:0] count;
7
8 initial $counterMonitor(clk,reset,enable,count);
9
10 endmodule

Counter TestGen

1 #include "acc_user.h"
2 #include "veriuser.h"
3 #include "string.h"
4 #include "stdio.h"
5
6 #define IDLE 0
7 #define INCR 1
8 #define WAIT 2
9 #define DRIVE 3
10 #define DONE 4
11
12 struct testGenObject {
13   char* testFile;
14   int debug;
15   char cmdArray[100] [100];
16   int cmdSize;
17   int CmdPointer;
18   char* command;
19   int wait;
20   int value;
21   int clkCnt;
22   int state;
23   handle count;
24   handle enable;
25   handle reset;
26   handle clk;
27   char* clk_value;
28   char *clk_last_value;
29 };
30
31 static struct testGenObject *object;
32
33 // Increment counter
34 void waitTicks () {
35   object->clkCnt = object->clkCnt + 1;
36 }
37
38 // This function loads the content of test file into
39 // object command array
40 void loadTest() {
41   FILE *testFile;
42   char currentLine [100];
43   object->cmdSize = 0;
44   if((testFile = fopen(object->testFile, "r" )) == NULL) {
45   printf( "Error Opening File.n" );
46 }
47 while (fgets(currentLine, sizeof(currentLine), testFile) != NULL ) {
48   // Store the line cmdArray
49   strcpy(object->cmdArray[object->cmdSize], currentLine);
50   // print the line number and data
51   if (object->debug) printf( "Line %d: %sn" , object->cmdSize, object->cmdArray[object->cmdSize]);
52   // Get each line from the test file
53   object->cmdSize ++;
54 }
55 // Close the test file
56 fclose(testFile);
57 }
58
59 // This function process command line options
60 void processCmdOptions () {
61   // Get debug option
62   if (mc_scan_plusargs( "plidebug" ) != NULL) {
63   object->debug = 1;
64 } else {
65   object->debug = 0;
66 }
67 // Get test file name
68 if (mc_scan_plusargs( "test=" ) == NULL) {
69 printf( "ERROR : No test file option passed, use +test=testfilen" );
70 } else {
71 object->testFile = mc_scan_plusargs( "test=" );
72 if (object->debug) printf( "Test file name %sn" ,object->testFile);
73 }
74 }
75
76 void doTest() {
77   char* ptoks;
78   char* tcmd;
79   s_setval_delay delay_s;
80   s_setval_value value_s;
81   // Get current clock value
82   object->clk_value = acc_fetch_value(object->clk, "%b" , 0);
83   // BFM drives only at rising edge of clock
84   if (!strcmp(object->clk_last_value, "1" ) && !strcmp(object->clk_value, "0" )) {
85   switch (object->state) {
86     case IDLE : if (object->debug) printf( "%d Current state is IDLEn" , tf_gettime());
87     if (object->CmdPointer < object->cmdSize) {
88       tcmd = object->cmdArray[object->CmdPointer];
89       if (object->debug) printf ( "Test line %d current command-%s" ,object->CmdPointer, tcmd);
90       ptoks = strtok(tcmd, ":" );
91       int lcnt = 0;
92       while(ptoks != NULL) {
93         if (*ptoks != '=') {
94           if (lcnt == 0) {
95             object->wait = atoi(ptoks);
96             if (object->debug) printf( "Wait : %dn" , object->wait);
97           } else if (lcnt == 1) {
98             object->command = ptoks;
99             if (object->debug) printf( "Command : %sn" , ptoks);
100           } else {
101             object->value = atoi(ptoks);
102             if (object->debug) printf( "Value : %dn" , object->value);
103           }
104           lcnt ++;
105         }
106         ptoks = strtok(NULL, " " );
107       }
108       object->CmdPointer ++ ;
109       if (object->wait == 0) {
110         if (object->debug) printf( "%d Next State DRIVEn" , tf_gettime());
111         object->state = DRIVE;
112         doTest();
113       } else {
114         if (object->debug) printf( "%d Next State WAITn" , tf_gettime());
115         object->state = WAIT;
116       }
117     } else {
118       if (object->debug) printf( "%d Next State DONEn" , tf_gettime());
119       object->state = DONE;
120     }
121     break;
122     case WAIT : if (object->debug) printf( "%d Current state is WAIT : %dn" , tf_gettime(), object->clkCnt);
123     if ((object->clkCnt + 1) >= object->wait) {
124       object->wait = 0;
125       object->clkCnt = 0;
126       if (object->debug) printf( "%d Next State DRIVEn" , tf_gettime());
127       object->state = DRIVE;
128       doTest();
129     } else {
130       waitTicks();
131     }
132     break;
133     case DRIVE : if (object->debug) printf( "%d Current state is DRIVEn" , tf_gettime());
134     value_s.format = accIntVal;
135     delay_s.model = accNoDelay;
136     delay_s.time.type = accTime;
137     delay_s.time.low = 0;
138     delay_s.time.high = 0;
139     if (!strcmp(object->command, "reset" )) {
140     value_s.value.integer = object->value;
141     acc_set_value(object->reset,&value_s,&delay_s);
142   } else if (!strcmp(object->command, "enable" )) {
143   value_s.value.integer = object->value;
144   acc_set_value(object->enable,&value_s,&delay_s);
145 } else {
146   if (object->debug) printf( "ERROR : What command do you wantn" );
147 }
148 if (object->debug) printf( "%d Next State IDLEn" , tf_gettime());
149 object->state = IDLE;
150 break;
151 case DONE : if (object->debug) printf( "%d Current state is DONEn" , tf_gettime());
152 tf_dofinish();
153 break;
154 default : object->state = IDLE;
155 break;
156 }
157 }
158 object->clk_last_value = acc_fetch_value(object->clk, "%b" , 0);
159 }
160
161 void initCounterTestGen () {
162   //acc_initialize( );
163   //acc_configure( accDisplayErrors, "false" );
164   object = (struct testGenObject *) malloc (sizeof(struct testGenObject));