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