quick.gif

space2.gif

space2.gif

space2.gif

space2.gif

space2.gif

space2.gif

space2.gif

   

space.gif

   

space.gif

  ../images/main/bulllet_4dots_orange.gif PLI Example

As in the rest of the tutorial, let's verify the counter example with test vector generation, monitor, checker: everything built with C code. Most of the common pli functions have been used to show their usage.

   

space.gif

The testbench will have these components:

   

space.gif

  • Clock generation in C
  • Clock generator HDL wrapper
  • Test generation in C
  • Test generator HDL Wrapper
  • Monitor and Checker in C
  • Monitor Checker HDL Wrapper
  • DUT/Monitor/Clock/Test Generation instance in Verilog
   

space.gif

It is a good idea to write HDL wrappers for the C functions that will be calling them.

   

space.gif

  ../images/main/bullet_star_pink.gif Clock Generator

Normally we don't want to have clock generators in PLI, it is always better to put them in Verilog.

   

space.gif


  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 = %d\n",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 }
You could download file clkGen.c here
   

space.gif

  ../images/main/bullet_star_pink.gif Clock Generator HDL Wrapper
   

space.gif


 1 module clkGen(clk);
 2 output clk;
 3 reg clk;
 4 
 5 initial $clkGen(clk);
 6 
 7 endmodule
You could download file clkGen.v here
   

space.gif

  ../images/main/bullet_star_pink.gif Counter Monitor
   

space.gif


   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 detected\n", sim_time);
  33       bin = 0;
  34     } else if (*(in_string + i) == 122) {
  35       io_printf ("%d counterMonitor : WARNING : Z detected\n", 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) 
  51       && (strcmp(counter->clk_last_value,"0") == 0))  {
  52     // Conver the current count value
  53     current_value  = 
  54       pliConv(counter->count_value,counter->count_width,time);
  55     // Check input control signal to floating or UnKnown
  56     if (strcmp(counter->reset_value,"x") == 0) {
  57       io_printf("%d counterMonitor : WARNING : reset is x\n", time);
  58     } 
  59     if (strcmp(counter->reset_value,"z") == 0) {
  60       io_printf("%d counterMonitor : WARNING : reset is z\n", time);
  61     } 
  62     if (strcmp(counter->enable_value,"x") == 0) {
  63       io_printf("%d counterMonitor : WARNING : enable is x\n", time);
  64     } 
  65     if (strcmp(counter->enable_value,"z") == 0) {
  66       io_printf("%d counterMonitor : WARNING : enable is z\n", time);
  67     } 
  68     // Increment monitor counter and compare only if 
  69     // enable is 1 and reset is not active
  70     if (strcmp(counter->enable_value,"1") == 0 
  71         && strcmp(counter->reset_value,"0") == 0) {
  72       if (counter->checker_count  ! = current_value) {
  73         io_printf
  74           ("%d counterMonitor : ERROR : Current value of monitor is %d dut is %d\n", 
  75           time, counter->checker_count, current_value);
  76         counter->error ++;
  77         if (counter->error == 1) counter->error_time = time;
  78       } else {
  79         io_printf
  80           ("%d counterMonitor : INFO  : Current value of monitor is %d dut is %d\n", 
  81           time, counter->checker_count, current_value);
  82       }
  83       counter->checker_count = 
  84         (counter->checker_count == 15) ? 0 : counter->checker_count + 1;
  85     // Reset monitor counter if reset is active
  86     } else if (strcmp(counter->reset_value,"1") == 0) {
  87       io_printf("%d counterMonitor : INFO  : Reset is asserted\n", time);
  88       counter->checker_count = 0; 
  89     }
  90   }
  91   // Update the clock state
  92   strcpy(counter->clk_last_value,counter->clk_value);
  93 }
  94 
  95 // misctf
  96 void counterMonitor(int data, int reason, int paramvc) {
  97   struct myCounter *counter = 
  98     (struct myCounter *) tf_igetworkarea(tf_getinstance());
  99   if ((reason == reason_paramvc) || (reason == reason_paramdrc)) {
 100     tf_synchronize( );
 101   } else if (reason == reason_synch) {
 102     counter->clk    = acc_handle_tfarg(1);
 103     counter->reset  = acc_handle_tfarg(2);
 104     counter->enable = acc_handle_tfarg(3);
 105     counter->count  = acc_handle_tfarg(4);
 106     // Get the values
 107     counter->clk_value    = acc_fetch_value(counter->clk, "%b", 0);
 108     counter->reset_value  = acc_fetch_value(counter->reset, "%b", 0);
 109     counter->enable_value = acc_fetch_value(counter->enable, "%b", 0);
 110     counter->count_value  = acc_fetch_value(counter->count, "%b", 0);
 111     counter->count_width  = acc_fetch_size (counter->count);
 112     // Call the counter model
 113     counterModel (counter);
 114   } 
 115   // Print simulation stats when $finish is called
 116   if (reason == reason_finish) {
 117     io_printf("=========================================\n");
 118     if (counter->error  ! = 0) {
 119       io_printf (" Simulation : FAILED\n");
 120       io_printf ("   Mismatched %d\n",counter->error);
 121       io_printf ("   First Mismatch at time %d\n", counter->error_time);
 122     } else {
 123       io_printf (" Simulation : PASSED\n");
 124     }
 125     io_printf("=========================================\n");
 126   }
 127 }
 128 
 129 // calltf()
 130 void initCounter(int data, int reason) {
 131   struct myCounter	*counter;
 132   // Allocate memory for all variables necessary to manage a 
 133   // single instance of the model.
 134   counter = (struct myCounter *) malloc (sizeof(struct myCounter));
 135   // Initialize this instance of the model.
 136   counter->clk    = acc_handle_tfarg(1);
 137   counter->reset  = acc_handle_tfarg(2);
 138   counter->enable = acc_handle_tfarg(3);
 139   counter->count  = acc_handle_tfarg(4);
 140   // Save a copy of the present clk value.
 141   counter->clk_last_value  =  acc_fetch_value(counter->clk, "%b", 0);
 142   // Enable callback of `counter_monitor` whenever 
 143   // any argument to `$counter_monitor` changes.
 144   tf_asynchon();
 145   // Set initial counter value to 0.
 146   counter->checker_count = 0;
 147   counter->error = 0;
 148   counter-> error_time = 0;
 149   // Save the model data with this instance of `$counterMonitor`.
 150   tf_setworkarea((char *)counter);
 151 }
You could download file counterMonitor.c here
   

space.gif

   

space.gif

  ../images/main/bullet_star_pink.gif Counter Monitor HDL Wrapper
   

space.gif


  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
You could download file counterMonitor.v here
   

space.gif

  ../images/main/bullet_star_pink.gif Counter TestGen
   

space.gif

Syntax for test file

   

space.gif

delay : Command = Value

   

space.gif

Where

Delay : Delay in clock ticks

Command : reset or enable

Value : 0 or 1

   

space.gif


   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) 
  52       printf("Line %d: %s\n", object->cmdSize, 
  53           object->cmdArray[object->cmdSize]);
  54     // Get each line from the test file 
  55     object->cmdSize ++;
  56   }
  57   // Close the test file 
  58   fclose(testFile);  
  59 }
  60 
  61 // This function process command line options
  62 void processCmdOptions () {
  63   // Get debug option
  64   if (mc_scan_plusargs("plidebug")  ! = NULL) {
  65      object->debug = 1;
  66   } else {
  67      object->debug = 0;
  68   }
  69   // Get test file name
  70   if (mc_scan_plusargs("test=") == NULL) {
  71     printf("ERROR : No test file option passed, use +test=testfile\n");
  72   } else {
  73     object->testFile =  mc_scan_plusargs("test=");
  74     if (object->debug) printf("Test file name %s\n",object->testFile);
  75   }
  76 }
  77 
  78 void doTest() {
  79   char* ptoks;
  80   char* tcmd;
  81   s_setval_delay delay_s;
  82   s_setval_value value_s;
  83   // Get current clock value
  84   object->clk_value =   acc_fetch_value(object->clk, "%b", 0);
  85   // BFM drives only at rising edge of clock
  86   if ( ! strcmp(object->clk_last_value,"1") &&  ! strcmp(object->clk_value,"0")) {
  87     switch (object->state) {
  88       case IDLE  : 
  89         if (object->debug) printf("%d Current state is IDLE\n", tf_gettime());
  90         if (object->CmdPointer < object->cmdSize) {
  91           tcmd = object->cmdArray[object->CmdPointer];
  92           if (object->debug) printf ("Test line %d current command-%s",
  93               object->CmdPointer, tcmd);
  94           ptoks = strtok(tcmd, ":");
  95           int lcnt = 0;
  96           while(ptoks  ! = NULL) {
  97             if (*ptoks  ! = '=') {
  98               if (lcnt == 0) {
  99                 object->wait = atoi(ptoks);
 100                 if (object->debug) printf("Wait    : %d\n", object->wait);
 101               } else if (lcnt == 1) {
 102                 object->command = ptoks;
 103                 if (object->debug) printf("Command : %s\n", ptoks);
 104               } else {
 105                 object->value = atoi(ptoks);
 106                 if (object->debug) printf("Value   : %d\n", object->value);
 107               }
 108               lcnt ++;
 109             }
 110             ptoks = strtok(NULL, " ");
 111           }
 112           object->CmdPointer ++ ;
 113           if (object->wait == 0) {
 114             if (object->debug) printf("%d Next State DRIVE\n", tf_gettime());
 115             object->state = DRIVE;
 116             doTest();
 117           } else {
 118             if (object->debug) printf("%d Next State WAIT\n", tf_gettime());
 119             object->state = WAIT;
 120           }
 121         } else {
 122           if (object->debug) printf("%d Next State DONE\n", tf_gettime());
 123           object->state = DONE;
 124         }
 125         break;
 126       case WAIT  : 
 127           if (object->debug) printf("%d Current state is WAIT : %d\n", 
 128               tf_gettime(), object->clkCnt);
 129           if ((object->clkCnt + 1) >= object->wait) {
 130             object->wait = 0;
 131             object->clkCnt = 0;
 132             if (object->debug) printf("%d Next State DRIVE\n", tf_gettime());
 133             object->state = DRIVE;
 134             doTest();
 135           } else {
 136             waitTicks();
 137           }
 138           break;
 139       case DRIVE : 
 140          if (object->debug) printf("%d Current state is DRIVE\n", tf_gettime());
 141          value_s.format    = accIntVal;
 142          delay_s.model     = accNoDelay; 
 143          delay_s.time.type = accTime;
 144          delay_s.time.low  = 0;
 145          delay_s.time.high = 0;
 146          if ( ! strcmp(object->command,"reset")) {
 147            value_s.value.integer =  object->value;
 148            acc_set_value(object->reset,&value_s,&delay_s);
 149          } else if ( ! strcmp(object->command,"enable")) {
 150            value_s.value.integer =  object->value;
 151            acc_set_value(object->enable,&value_s,&delay_s);
 152          } else {
 153            if (object->debug) printf("ERROR : What command do you want\n");
 154          }
 155          if (object->debug) printf("%d Next State IDLE\n", tf_gettime());
 156          object->state = IDLE;
 157          break;
 158       case DONE  : 
 159          if (object->debug) printf("%d Current state is DONE\n", tf_gettime());
 160          tf_dofinish(); 
 161          break;
 162       default    : object->state = IDLE;
 163                    break;
 164     }
 165   }
 166   object->clk_last_value =   acc_fetch_value(object->clk, "%b", 0);
 167 }
 168 
 169 void initCounterTestGen () {
 170   //acc_initialize( ); 
 171   //acc_configure( accDisplayErrors, "false" );
 172   object = (struct testGenObject *) malloc (sizeof(struct testGenObject));
 173   // Load the initial and defaule values
 174   object->testFile = "simple.tst";
 175   object->cmdSize = 0;
 176   object->CmdPointer = 0;
 177   object->clkCnt = 0;
 178   object->state = IDLE;
 179   // Initialize this instance of the model.
 180   object->clk    = acc_handle_tfarg(1);
 181   object->reset  = acc_handle_tfarg(2);
 182   object->enable = acc_handle_tfarg(3);
 183   object->count  = acc_handle_tfarg(4);
 184   // Drive inactive signals on all inputs
 185   tf_putp (2, 0);
 186   tf_putp (3, 0);
 187   // Save a copy of the present clk value.
 188   object->clk_last_value =   acc_fetch_value(object->clk, "%b", 0);
 189   // Get the command line testfile name and debug option
 190   processCmdOptions();
 191   // Open the testfile and make array of command
 192   loadTest(object);
 193   // Add callback when ever clock changes
 194   acc_vcl_add( object->clk, doTest, object->clk_value, vcl_verilog_logic );
 195   // All acc routines should have this
 196   acc_close();
 197 }
You could download file counterTestGen.c here
   

space.gif

  ../images/main/bullet_star_pink.gif Counter TestGen HDL Wrapper
   

space.gif


  1 module counterTestGen (clk, reset, enable, count);
  2 input clk;
  3 output reset, enable;
  4 input [3:0] count;
  5 
  6 wire clk;
  7 reg reset, enable;
  8 wire [3:0] count;
  9 
 10 initial $counterTestGen(clk,reset,enable,count);
 11 
 12 endmodule
You could download file counterTestGen.v here
   

space.gif

  ../images/main/bullet_star_pink.gif HDL TestBench Top
   

space.gif


  1 module top();
  2 wire clk;
  3 wire [3:0] count;
  4 wire enable;
  5 wire reset;
  6   	 
  7 // Connect the clk generator
  8 clkGen clkGen(.clk (clk));
  9   	
 10 // Connect the DUT
 11 counter dut(
 12 .clk    (clk),
 13 .reset  (reset),
 14 .enable (enable),
 15 .count  (count)
 16 );
 17 
 18 // Connect the Monitor/Checker
 19 counterMonitor monitor(
 20 .clk    (clk),
 21 .reset  (reset),
 22 .enable (enable),
 23 .count  (count)
 24 );
 25 
 26 // Connect the Test Generator
 27 counterTestGen test(
 28 .clk    (clk),
 29 .reset  (reset),
 30 .enable (enable),
 31 .count  (count)
 32 );
 33 	
 34 endmodule
You could download file top.v here
   

space.gif

  ../images/main/bullet_star_pink.gif Sample : Test File
   

space.gif

 1 : reset = 1
 10 : reset = 0
 5 : enable = 1
 20 : enable = 0
   

space.gif

  ../images/main/bullet_star_pink.gif Sample Ouput
   

space.gif

 5 counterMonitor : WARNING : X detected
 5 counterMonitor : WARNING : X detected
 5 counterMonitor : WARNING : X detected
 5 counterMonitor : WARNING : X detected
 17 counterMonitor : WARNING : X detected
 17 counterMonitor : WARNING : X detected
 17 counterMonitor : WARNING : X detected
 17 counterMonitor : WARNING : X detected
 29 counterMonitor : WARNING : X detected
 29 counterMonitor : WARNING : X detected
 29 counterMonitor : WARNING : X detected
 29 counterMonitor : WARNING : X detected
 29 counterMonitor : INFO  : Reset is asserted
 41 counterMonitor : INFO  : Reset is asserted
 53 counterMonitor : INFO  : Reset is asserted
 65 counterMonitor : INFO  : Reset is asserted
 77 counterMonitor : INFO  : Reset is asserted
 89 counterMonitor : INFO  : Reset is asserted
 101 counterMonitor : INFO  : Reset is asserted
 113 counterMonitor : INFO  : Reset is asserted
 125 counterMonitor : INFO  : Reset is asserted
 137 counterMonitor : INFO  : Reset is asserted
 149 counterMonitor : INFO  : Reset is asserted
 233 counterMonitor : INFO  : Current value of monitor is 0 dut is 0
 245 counterMonitor : INFO  : Current value of monitor is 1 dut is 1
 257 counterMonitor : INFO  : Current value of monitor is 2 dut is 2
 269 counterMonitor : INFO  : Current value of monitor is 3 dut is 3
 281 counterMonitor : INFO  : Current value of monitor is 4 dut is 4
 293 counterMonitor : INFO  : Current value of monitor is 5 dut is 5
 305 counterMonitor : INFO  : Current value of monitor is 6 dut is 6
 317 counterMonitor : INFO  : Current value of monitor is 7 dut is 7
 329 counterMonitor : INFO  : Current value of monitor is 8 dut is 8
 341 counterMonitor : INFO  : Current value of monitor is 9 dut is 9
 353 counterMonitor : INFO  : Current value of monitor is 10 dut is 10
 365 counterMonitor : INFO  : Current value of monitor is 11 dut is 11
 377 counterMonitor : INFO  : Current value of monitor is 12 dut is 12
 389 counterMonitor : INFO  : Current value of monitor is 13 dut is 13
 401 counterMonitor : INFO  : Current value of monitor is 14 dut is 14
 413 counterMonitor : INFO  : Current value of monitor is 15 dut is 15
 425 counterMonitor : INFO  : Current value of monitor is 0 dut is 0
 437 counterMonitor : INFO  : Current value of monitor is 1 dut is 1
 449 counterMonitor : INFO  : Current value of monitor is 2 dut is 2
 461 counterMonitor : INFO  : Current value of monitor is 3 dut is 3
 473 counterMonitor : INFO  : Current value of monitor is 4 dut is 4
 =========================================
  Simulation : PASSED
 =========================================
   

space.gif

   

space.gif

   

space.gif

   

space.gif

space2.gif

space2.gif

space2.gif

space2.gif

space2.gif

  

Copyright 1998-2014

Deepak Kumar Tala - All rights reserved

Do you have any Comment? mail me at:deepak@asic-world.com