1 /*
2 * Copyright (C) 2012-2018 Martin Whitaker. (icarus@martin-whitaker.me.uk)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include "sys_priv.h"
20 #include <assert.h>
21 #include <inttypes.h>
22 #include <stdlib.h>
23 #include "ivl_alloc.h"
24
25 /*
26 * Check to see if an argument is a single bit net.
27 */
check_net_arg(vpiHandle arg,vpiHandle callh,const char * name)28 static void check_net_arg(vpiHandle arg, vpiHandle callh, const char *name)
29 {
30 assert(arg);
31
32 switch (vpi_get(vpiType, arg)) {
33 case vpiPartSelect:
34 if (vpi_get(vpiType, vpi_handle(vpiParent, arg)) != vpiNet)
35 break;
36 // fallthrough
37 case vpiNet:
38 if (vpi_get(vpiSize, arg) != 1)
39 break;
40 return;
41 default:
42 break;
43 }
44 vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
45 (int)vpi_get(vpiLineNo, callh));
46 vpi_printf("%s's first argument must be a scalar net or "
47 "a bit-select of a vector net.\n", name);
48 vpi_control(vpiFinish, 1);
49 }
50
51 /*
52 * Check to see if an argument is a variable.
53 */
check_var_arg(vpiHandle arg,vpiHandle callh,const char * name,const char * arg_name)54 static void check_var_arg(vpiHandle arg, vpiHandle callh, const char *name,
55 const char *arg_name)
56 {
57 assert(arg);
58
59 switch (vpi_get(vpiType, arg)) {
60 case vpiPartSelect:
61 if (vpi_get(vpiType, vpi_handle(vpiParent, arg)) == vpiNet)
62 break;
63 case vpiMemoryWord:
64 case vpiBitVar:
65 case vpiReg:
66 case vpiIntegerVar:
67 case vpiIntVar:
68 case vpiLongIntVar:
69 case vpiTimeVar:
70 return;
71 default:
72 break;
73 }
74 vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
75 (int)vpi_get(vpiLineNo, callh));
76 vpi_printf("%s's %s argument must be a variable.\n",
77 name, arg_name);
78 vpi_control(vpiFinish, 1);
79 }
80
sys_countdrivers_sizetf(ICARUS_VPI_CONST PLI_BYTE8 * name)81 static PLI_INT32 sys_countdrivers_sizetf(ICARUS_VPI_CONST PLI_BYTE8*name)
82 {
83 (void)name; /* Parameter is not used. */
84 return 1;
85 }
86
87 /*
88 * Check that the given $countdrivers() call has valid arguments.
89 */
sys_countdrivers_compiletf(ICARUS_VPI_CONST PLI_BYTE8 * name)90 static PLI_INT32 sys_countdrivers_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
91 {
92 vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
93 vpiHandle argv = vpi_iterate(vpiArgument, callh);
94 vpiHandle arg;
95 unsigned arg_num;
96
97 /* Check that there are arguments. */
98 if (argv == 0) {
99 vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
100 (int)vpi_get(vpiLineNo, callh));
101 vpi_printf("%s requires at least one argument.\n", name);
102 vpi_control(vpiFinish, 1);
103 return 0;
104 }
105
106 /* The first argument must be a scalar net or a net bit select. */
107 arg = vpi_scan(argv);
108 check_net_arg(arg, callh, name);
109
110 /* The optional arguments must be variables. */
111 for (arg_num = 2; arg_num < 7; arg_num += 1) {
112 const char *arg_name = NULL;
113 switch (arg_num) {
114 case 2: arg_name = "second"; break;
115 case 3: arg_name = "third"; break;
116 case 4: arg_name = "fourth"; break;
117 case 5: arg_name = "fifth"; break;
118 case 6: arg_name = "sixth"; break;
119 default: assert(0);
120 }
121
122 arg = vpi_scan(argv);
123 if (arg == 0)
124 return 0;
125
126 check_var_arg(arg, callh, name, arg_name);
127 }
128
129 /* Make sure there are no extra arguments. */
130 check_for_extra_args(argv, callh, name, "six arguments", 0);
131 return 0;
132 }
133
134 /*
135 * The runtime code for $countdrivers().
136 */
sys_countdrivers_calltf(ICARUS_VPI_CONST PLI_BYTE8 * name)137 static PLI_INT32 sys_countdrivers_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
138 {
139 vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
140 vpiHandle argv = vpi_iterate(vpiArgument, callh);
141 vpiHandle arg;
142 unsigned idx;
143 unsigned counts[4];
144 unsigned num_drivers;
145 s_vpi_value val;
146
147 (void)name; /* Parameter is not used. */
148
149 /* All returned values are integers. */
150 val.format = vpiIntVal;
151
152 /* Get the base net reference and bit select */
153 idx = 0;
154 arg = vpi_scan(argv);
155 assert(arg);
156 if (vpi_get(vpiType, arg) == vpiPartSelect) {
157 idx = vpi_get(vpiLeftRange, arg);
158 arg = vpi_handle(vpiParent, arg);
159 assert(arg);
160 }
161
162 /* Get the net driver counts from the runtime. */
163 vpip_count_drivers(arg, idx, counts);
164 num_drivers = counts[0] + counts[1] + counts[2];
165
166 /* Handle optional net_is_forced argument. */
167 arg = vpi_scan(argv);
168 if (arg == 0) goto args_done;
169 val.value.integer = counts[3];
170 vpi_put_value(arg, &val, 0, vpiNoDelay);
171
172 /* Handle optional number_of_01x_drivers argument. */
173 arg = vpi_scan(argv);
174 if (arg == 0) goto args_done;
175 val.value.integer = num_drivers;
176 vpi_put_value(arg, &val, 0, vpiNoDelay);
177
178 /* Handle optional number_of_0_drivers argument. */
179 arg = vpi_scan(argv);
180 if (arg == 0) goto args_done;
181 val.value.integer = counts[0];
182 vpi_put_value(arg, &val, 0, vpiNoDelay);
183
184 /* Handle optional number_of_1_drivers argument. */
185 arg = vpi_scan(argv);
186 if (arg == 0) goto args_done;
187 val.value.integer = counts[1];
188 vpi_put_value(arg, &val, 0, vpiNoDelay);
189
190 /* Handle optional number_of_x_drivers argument. */
191 arg = vpi_scan(argv);
192 if (arg == 0) goto args_done;
193 val.value.integer = counts[2];
194 vpi_put_value(arg, &val, 0, vpiNoDelay);
195
196 /* Free the argument iterator. */
197 vpi_free_object(argv);
198
199 args_done:
200 val.value.integer = (num_drivers > 1) ? 1 : 0;
201 vpi_put_value(callh, &val, 0, vpiNoDelay);
202 return 0;
203 }
204
205 /*
206 * Routine to register the system tasks/functions provided in this file.
207 */
sys_countdrivers_register(void)208 void sys_countdrivers_register(void)
209 {
210 s_vpi_systf_data tf_data;
211 vpiHandle res;
212
213 tf_data.type = vpiSysFunc;
214 tf_data.sysfunctype = vpiSizedFunc;
215 tf_data.tfname = "$countdrivers";
216 tf_data.calltf = sys_countdrivers_calltf;
217 tf_data.compiletf = sys_countdrivers_compiletf;
218 tf_data.sizetf = sys_countdrivers_sizetf;
219 tf_data.user_data = "$countdrivers";
220 res = vpi_register_systf(&tf_data);
221 vpip_make_systf_system_defined(res);
222 }
223