1 /*
2  * Copyright (C) 2010-2020 Cary R. (cygcary@yahoo.com)
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  * This is the vlog95 target module. It generates a 1364-1995 compliant
20  * netlist from the input netlist. The generated netlist is expected to
21  * be simulation equivalent to the original.
22  */
23 
24 # include "version_base.h"
25 # include "version_tag.h"
26 # include "config.h"
27 # include "vlog95_priv.h"
28 # include <stdlib.h>
29 # include <string.h>
30 
31 static const char*version_string =
32 "Icarus Verilog VLOG95 Code Generator " VERSION " (" VERSION_TAG ")\n\n"
33 "Copyright (C) 2010-2020 Cary R. (cygcary@yahoo.com)\n\n"
34 "  This program is free software; you can redistribute it and/or modify\n"
35 "  it under the terms of the GNU General Public License as published by\n"
36 "  the Free Software Foundation; either version 2 of the License, or\n"
37 "  (at your option) any later version.\n\n"
38 "  This program is distributed in the hope that it will be useful,\n"
39 "  but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
40 "  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
41 "  GNU General Public License for more details.\n\n"
42 "  You should have received a copy of the GNU General Public License along\n"
43 "  with this program; if not, write to the Free Software Foundation, Inc.,\n"
44 "  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n"
45 ;
46 
47 FILE*vlog_out;
48 int vlog_errors = 0;
49 int sim_precision = 0;
50 unsigned indent = 0;
51 unsigned indent_incr = 2;
52 
53 unsigned emit_file_line = 0;
54 
55 unsigned allow_signed = 0;
56 
57 ivl_design_t design = 0;
58 
target_design(ivl_design_t des)59 int target_design(ivl_design_t des)
60 {
61       ivl_scope_t *roots;
62       unsigned nroots, idx;
63       const char*path = ivl_design_flag(des, "-o");
64 	/* Set the indent spacing with the -pspacing flag passed to iverilog
65 	 * (e.g. -pspacing=4). The default is 2 spaces. */
66       const char*spacing_str = ivl_design_flag(des, "spacing");
67 	/* Use -pfileline to determine if file and line information is
68 	 * printed for most lines. (e.g. -pfileline=1). The default is no
69 	 * file/line information will be printed for individual lines. */
70       const char*fileline_str = ivl_design_flag(des, "fileline");
71 	/* Use -pallowsigned to allow signed registers/nets and the
72 	 * $signed() and $unsigned() system tasks as an extension. */
73       const char*allowsigned_str = ivl_design_flag(des, "allowsigned");
74       assert(path);
75 
76 	/* Check for and use a provided indent spacing. */
77       if (strcmp(spacing_str, "") != 0) {
78 	    char *eptr;
79 	    long value = strtol(spacing_str, &eptr, 0);
80 	      /* Nothing usable in the spacing string. */
81 	    if (spacing_str == eptr) {
82 		  fprintf(stderr, "vlog95 error: Unable to extract spacing "
83 		                  "increment from string: %s\n", spacing_str);
84 		  return 1;
85 	    }
86 	      /* Extra stuff at the end. */
87 	    if (*eptr != 0) {
88 		  fprintf(stderr, "vlog95 error: Extra characters '%s' "
89 		                  "included at end of spacing string: %s\n",
90 		                  eptr, spacing_str);
91 		  return 1;
92 	    }
93 	      /* The increment must be greater than zero. */
94 	    if (value < 1) {
95 		  fprintf(stderr, "vlog95 error: Spacing increment (%ld) must "
96 		                  "be greater than zero.\n", value);
97 		  return 1;
98 	    }
99 	      /* An increment of more than sixteen is too much. */
100 	    if (value > 16) {
101 		  fprintf(stderr, "vlog95 error: Spacing increment (%ld) must "
102 		                  "be sixteen or less.\n", value);
103 		  return 1;
104 	    }
105 	    indent_incr = value;
106       }
107 
108 	/* Check to see if file/line information should be printed. */
109       if (strcmp(fileline_str, "") != 0) {
110 	    char *eptr;
111 	    long value = strtol(fileline_str, &eptr, 0);
112 	      /* Nothing usable in the file/line string. */
113 	    if (fileline_str == eptr) {
114 		  fprintf(stderr, "vlog95 error: Unable to extract file/line "
115 		                  "information from string: %s\n",
116 		                  fileline_str);
117 		  return 1;
118 	    }
119 	      /* Extra stuff at the end. */
120 	    if (*eptr != 0) {
121 		  fprintf(stderr, "vlog95 error: Extra characters '%s' "
122 		                  "included at end of file/line string: %s\n",
123 		                  eptr, fileline_str);
124 		  return 1;
125 	    }
126 	      /* The file/line flag must be positive. */
127 	    if (value < 0) {
128 		  fprintf(stderr, "vlog95 error: File/line flag (%ld) must "
129 		                  "be positive.\n", value);
130 		  return 1;
131 	    }
132 	    emit_file_line = value > 0;
133       }
134 
135 	/* Check to see if we should also print signed constructs. */
136       if (strcmp(allowsigned_str, "") != 0) {
137 	    char *eptr;
138 	    long value = strtol(allowsigned_str, &eptr, 0);
139 	      /* Nothing usable in the allow signed string. */
140 	    if (allowsigned_str == eptr) {
141 		  fprintf(stderr, "vlog95 error: Unable to extract allow "
142 		                  "signed information from string: %s\n",
143 		                  allowsigned_str);
144 		  return 1;
145 	    }
146 	      /* Extra stuff at the end. */
147 	    if (*eptr != 0) {
148 		  fprintf(stderr, "vlog95 error: Extra characters '%s' "
149 		                  "included at end of allow signed string: "
150 		                  "%s\n", eptr, allowsigned_str);
151 		  return 1;
152 	    }
153 	      /* The allow signed flag must be positive. */
154 	    if (value < 0) {
155 		  fprintf(stderr, "vlog95 error: Allow signed flag (%ld) must "
156 		                  "be positive.\n", value);
157 		  return 1;
158 	    }
159 	    allow_signed = value > 0;
160       }
161 
162       design = des;
163 
164 #ifdef HAVE_FOPEN64
165       vlog_out = fopen64(path, "w");
166 #else
167       vlog_out = fopen(path, "w");
168 #endif
169       if (vlog_out == 0) {
170 	    perror(path);
171 	    return -1;
172       }
173 
174       fprintf(vlog_out, "/*\n");
175       fprintf(vlog_out, " * 1364-1995 Verilog generated by Icarus Verilog "
176                         "VLOG95 Code Generator,\n");
177       fprintf(vlog_out, " * Version: " VERSION " (" VERSION_TAG ")\n");
178       fprintf(vlog_out, " * Converted using %s delays and %s signed support.\n",
179                         ivl_design_delay_sel(des),
180                         allow_signed ? "with" : "without");
181       fprintf(vlog_out, " */\n");
182 
183       sim_precision = ivl_design_time_precision(des);
184 
185 	/* Get all the root modules and then convert each one. */
186       ivl_design_roots(des, &roots, &nroots);
187 	/* Emit any root scope tasks or functions first. */
188       for (idx = 0; idx < nroots; idx += 1) {
189 	    switch(ivl_scope_type(roots[idx])) {
190 		  case IVL_SCT_FUNCTION:
191 		  case IVL_SCT_TASK:
192 			  /* Create a separate module for each task/function.
193 			     This allows us to handle different timescales. */
194 			fprintf(vlog_out, "\n`timescale %s/%s\n",
195 				get_time_const(ivl_scope_time_units(roots[idx])),
196 				get_time_const(ivl_scope_time_precision(roots[idx])));
197 			fprintf(vlog_out, "module ivl_root_scope_%s;\n",
198 				ivl_scope_basename(roots[idx]));
199 			indent += indent_incr;
200 
201 			  /* Say this task/function has a parent so the
202 			   * definition is emitted correctly. */
203 			emit_scope(roots[idx], roots[idx]);
204 
205 			indent -= indent_incr;
206 			assert(indent == 0);
207 			fprintf(vlog_out, "endmodule /* ivl_root_scope_%p */\n",
208 				roots[idx]);
209 			break;
210 		  default:
211 			break;
212 	    }
213       }
214 	/* Emit the rest of the scope objects. */
215       for (idx = 0; idx < nroots; idx += 1) emit_scope(roots[idx], 0);
216 
217       free_emitted_scope_list();
218 
219 	/* Emit any UDP definitions that the design used. */
220       emit_udp_list();
221 
222 	/* Emit any UDPs that are Icarus generated (D-FF or latch). */
223       emit_icarus_generated_udps();
224 
225 	/* Emit the Icarus top module used to trigger translated always_comb/latch processes at T0. */
226       emit_icarus_generated_top_module();
227 
228 	/* If there were errors then add this information to the output. */
229       if (vlog_errors) {
230 	    fprintf(vlog_out, "\n");
231 	    fprintf(vlog_out, "/*\n");
232 	    if (vlog_errors == 1) {
233 		  fprintf(vlog_out, " * There was 1 error during "
234 		                    "translation.\n");
235 	    } else {
236 		  fprintf(vlog_out, " * There were %d errors during "
237 		                    "translation.\n",
238 		                    vlog_errors);
239 	    }
240 	    fprintf(vlog_out, " */\n");
241 	      /* Add something that makes the file invalid to make sure
242 	       * the user knows there were errors. */
243 	    fprintf(vlog_out, "<Add some text to make sure this file is not "
244 	                      "valid Verilog>\n");
245       }
246 
247       fclose(vlog_out);
248 
249 	/* A do nothing call to prevent warnings about this routine not
250 	 * being used. */
251       dump_nexus_information(0, 0);
252 
253       return vlog_errors;
254 }
255 
256 
target_query(const char * key)257 const char* target_query(const char*key)
258 {
259       if (strcmp(key,"version") == 0) return version_string;
260 
261       return 0;
262 }
263