1 /*
2 * Copyright (c) 2008-2011 Stephen Williams <steve@icarus.com>
3 * Copyright (c) 2002 Larry Doolittle (larry@doolittle.boa.org)
4 *
5 * This source code is free software; you can redistribute it
6 * and/or modify it in source code form under the terms of the GNU
7 * General Public License as published by the Free Software
8 * Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 # include "config.h"
22 # include "vpi_priv.h"
23 #ifdef CHECK_WITH_VALGRIND
24 # include "vvp_cleanup.h"
25 #endif
26 # include <cstdio>
27 # include <cstring>
28 # include <climits> /* for CHAR_BIT */
29 # include <cstdlib>
30 # include <cctype>
31 # include <cassert>
32 # include "ivl_alloc.h"
33
34 /* If you are allergic to malloc, you can set a stack memory allocation
35 * here. Otherwise, malloc() is used for the temporary array, so the
36 * conversion length is unlimited. */
37 /* #define MAX_DIGITS 20 */
38
39
40 #if SIZEOF_UNSIGNED_LONG * CHAR_BIT >= 64
41 #define BDIGITS 9
42 #define BASE 1000000000
43 #define BBITS 32
44 #define BMASK 0xffffffff
45 #else
46 #if SIZEOF_UNSIGNED_LONG * CHAR_BIT >= 32
47 #define BDIGITS 4
48 #define BASE 10000
49 #define BBITS 16
50 #define BMASK 0xffff
51 #else
52 #error apparent non-conforming word length
53 #endif
54 #endif
55
56 #define B_IS0(x) ((x) == 0)
57 #define B_IS1(x) ((x) == 1)
58 #define B_ISX(x) ((x) == 2)
59 #define B_ISZ(x) ((x) == 3)
60
61 /* The program works by building a base BASE representation of the number
62 * in the valv array. BBITS bits of the number can be put in at a time.
63 * Previous values of each valv element are always less than BASE, the
64 * input val is less than or equal to 2^BBITS, so (valv[i]<<BBITS)+val
65 * is guaranteed less than or equal to BASE<<BBITS, which is configured
66 * less than ULONG_MAX. When this number divided by BASE, to get the amount
67 * propagated as a "carry" to the next array element, the result is again
68 * less than or equal to 2^BBITS. BBITS and BASE are configured above
69 * to depend on the "unsigned long" length of the host, for efficiency.
70 */
shift_in(unsigned long * valv,unsigned int vlen,unsigned long val)71 static inline void shift_in(unsigned long *valv, unsigned int vlen, unsigned long val)
72 {
73 unsigned int i;
74 /* printf("shift in %u\n",val); */
75 for (i=0; i<vlen; i++) {
76 val=(valv[i]<<BBITS)+val;
77 valv[i]=val%BASE;
78 val=val/BASE;
79 }
80 if (val!=0)
81 fprintf(stderr,"internal error: carry out %lu in " __FILE__ "\n",val);
82 }
83
84 /* Since BASE is a power of ten, conversion of each element of the
85 * valv array to decimal is easy. sprintf(buf,"%d",v) could be made
86 * to work, I suppose, but for speed and control I prefer to write
87 * the steps out longhand.
88 */
write_digits(unsigned long v,char ** buf,unsigned int * nbuf,int zero_suppress)89 static inline int write_digits(unsigned long v, char **buf,
90 unsigned int *nbuf, int zero_suppress)
91 {
92 char segment[BDIGITS];
93 int i;
94 for (i=BDIGITS-1; i>=0; --i) {
95 segment[i] = '0' + v%10;
96 v=v/10;
97 }
98 for (i=0; i<BDIGITS; ++i) {
99 if (!(zero_suppress&=(segment[i]=='0'))) {
100 *(*buf)++=segment[i]; --(*nbuf);
101 }
102 }
103 return zero_suppress;
104 }
105
106 /* Jump through some hoops so we don't have to malloc/free valv
107 * on every call, and implement an optional malloc-less version. */
108 static unsigned long *valv=NULL;
109 static unsigned int vlen_alloc=0;
110
111 #ifdef CHECK_WITH_VALGRIND
dec_str_delete(void)112 void dec_str_delete(void)
113 {
114 free(valv);
115 valv = 0;
116 vlen_alloc = 0;
117 }
118 #endif
119
vpip_vec4_to_dec_str(const vvp_vector4_t & vec4,char * buf,unsigned int nbuf,int signed_flag)120 unsigned vpip_vec4_to_dec_str(const vvp_vector4_t&vec4,
121 char *buf, unsigned int nbuf,
122 int signed_flag)
123 {
124 unsigned int idx, vlen;
125 unsigned int mbits=vec4.size(); /* number of non-sign bits */
126 unsigned count_x = 0, count_z = 0;
127
128 unsigned long val=0;
129 int comp=0;
130 if (signed_flag) {
131 switch (vec4.value(vec4.size()-1)) {
132 case BIT4_X:
133 count_x += 1;
134 break;
135 case BIT4_Z:
136 count_z += 1;
137 break;
138 case BIT4_1:
139 comp=1;
140 break;
141 case BIT4_0:
142 break;
143 }
144 mbits -= 1;
145 }
146 assert(mbits<(UINT_MAX-92)/28);
147 vlen = ((mbits*28+92)/93+BDIGITS-1)/BDIGITS;
148 /* printf("vlen=%d\n",vlen); */
149
150 #define ALLOC_MARGIN 4
151 if (!valv || vlen > vlen_alloc) {
152 if (valv) free(valv);
153 valv = (unsigned long*) calloc(vlen+ALLOC_MARGIN, sizeof (*valv));
154 vlen_alloc=vlen+ALLOC_MARGIN;
155 } else {
156 memset(valv,0,vlen*sizeof(valv[0]));
157 }
158
159 for (idx = 0; idx < mbits; idx += 1) {
160 /* printf("%c ",bits[mbits-idx-1]); */
161 switch (vec4.value(mbits-idx-1)) {
162 case BIT4_Z:
163 count_z += 1;
164 break;
165 case BIT4_X:
166 count_x += 1;
167 break;
168 case BIT4_1:
169 if (! comp)
170 val += 1;
171 break;
172 case BIT4_0:
173 if (comp)
174 val += 1;
175 break;
176 }
177
178 if ((mbits-idx-1)%BBITS==0) {
179 /* make negative 2's complement, not 1's complement */
180 if (comp && idx==mbits-1) ++val;
181 shift_in(valv,vlen,val);
182 val=0;
183 } else {
184 val=val+val;
185 }
186 }
187
188 if (count_x == vec4.size()) {
189 buf[0] = 'x';
190 buf[1] = 0;
191 } else if (count_x > 0) {
192 buf[0] = 'X';
193 buf[1] = 0;
194 } else if (count_z == vec4.size()) {
195 buf[0] = 'z';
196 buf[1] = 0;
197 } else if (count_z > 0) {
198 buf[0] = 'Z';
199 buf[1] = 0;
200 } else {
201 int i;
202 int zero_suppress=1;
203 if (comp) {
204 *buf++='-';
205 nbuf--;
206 /* printf("-"); */
207 }
208 for (i=vlen-1; i>=0; i--) {
209 zero_suppress = write_digits(valv[i],
210 &buf,&nbuf,zero_suppress);
211 /* printf(",%.4u",valv[i]); */
212 }
213 /* Awkward special case, since we don't want to
214 * zero suppress down to nothing at all. The only
215 * way we can still have zero_suppress on in the
216 * comp=1 case is if mbits==0, and therefore vlen==0.
217 * We represent 1'sb1 as "-1". */
218 if (zero_suppress) *buf++='0'+comp;
219 /* printf("\n"); */
220 *buf='\0';
221 }
222 return 0;
223 }
224
vpip_dec_str_to_vec4(vvp_vector4_t & vec,const char * buf)225 void vpip_dec_str_to_vec4(vvp_vector4_t&vec, const char*buf)
226 {
227 /* Support for [xX]_*. */
228 if (buf[0] == 'x' || buf[0] == 'X') {
229 for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) {
230 vec.set_bit(idx, BIT4_X);
231 }
232 const char*tbuf = buf+1;
233 /* See if this is a valid constant. */
234 while (*tbuf) {
235 if (*tbuf != '_') {
236 fprintf(stderr, "Warning: Invalid decimal \"x\" "
237 "value \"%s\".\n", buf);
238 return;
239 }
240 tbuf += 1;
241 }
242 return;
243 }
244
245 /* Support for [zZ]_*. */
246 if (buf[0] == 'z' || buf[0] == 'Z') {
247 const char*tbuf = buf+1;
248 /* See if this is a valid constant, if not return "x". */
249 while (*tbuf) {
250 if (*tbuf != '_') {
251 fprintf(stderr, "Warning: Invalid decimal \"z\" "
252 "value \"%s\".\n", buf);
253 for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) {
254 vec.set_bit(idx, BIT4_X);
255 }
256 return;
257 }
258 tbuf += 1;
259 }
260 for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) {
261 vec.set_bit(idx, BIT4_Z);
262 }
263 return;
264 }
265
266 /* The str string is the decimal value with the least
267 significant digit first. This loop creates that string by
268 reversing the order of the buf string. For example, if the
269 input is "1234", str gets "4321". */
270 unsigned slen = strlen(buf);
271 char*str = new char[slen + 1];
272 bool is_negative = false;
273 for (unsigned idx = 0 ; idx < slen ; idx += 1) {
274 if (idx == slen-1 && buf[slen-idx-1] == '-') {
275 is_negative = true;
276 slen--;
277 continue;
278 }
279 while (buf[slen-idx-1] == '_') {
280 slen--;
281 }
282 if (isdigit(buf[slen-idx-1]))
283 str[idx] = buf[slen-idx-1];
284 else {
285 /* Return "x" if there are invalid digits in the string. */
286 fprintf(stderr, "Warning: Invalid decimal digit %c(%d) in "
287 "\"%s.\"\n", buf[slen-idx-1], buf[slen-idx-1], buf);
288 for (unsigned jdx = 0 ; jdx < vec.size() ; jdx += 1) {
289 vec.set_bit(jdx, BIT4_X);
290 }
291 return;
292 }
293 }
294
295 str[slen] = 0;
296
297 for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) {
298 vvp_bit4_t val4 = BIT4_0;
299
300 switch (str[0]) {
301 case '1':
302 case '3':
303 case '5':
304 case '7':
305 case '9':
306 val4 = BIT4_1;
307 break;
308 }
309
310 vec.set_bit(idx, val4);
311
312 /* Divide the str string by 2 in decimal. */
313 char*cp = str;
314 while (*cp) {
315 unsigned val = cp[0] - '0';
316 if ((val&1) && (cp > str))
317 cp[-1] += 5;
318
319 cp[0] = '0' + val/2;
320 cp += 1;
321 }
322
323 }
324
325 if (is_negative) {
326 vec.invert();
327 vec += (int64_t) 1;
328 }
329
330 delete[]str;
331 }
332