1 /*
2  * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
3  *
4  *    This source code is free software; you can redistribute it
5  *    and/or modify it in source code form under the terms of the GNU
6  *    General Public License as published by the Free Software
7  *    Foundation; either version 2 of the License, or (at your option)
8  *    any later version.
9  *
10  *    This program is distributed in the hope that it will be useful,
11  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *    GNU General Public License for more details.
14  *
15  *    You should have received a copy of the GNU General Public License
16  *    along with this program; if not, write to the Free Software
17  *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 # include "config.h"
21 
22 /*
23  * This is the FPGA target module.
24  */
25 
26 # include  <ivl_target.h>
27 # include  <string.h>
28 # include  "fpga_priv.h"
29 # include  <assert.h>
30 
31 /* This is the opened xnf file descriptor. It is the output that this
32    code generator writes to. */
33 FILE*xnf = 0;
34 
35 const char*part = 0;
36 const char*arch = 0;
37 device_t device = 0;
38 
scope_has_attribute(ivl_scope_t s,const char * name)39 int scope_has_attribute(ivl_scope_t s, const char *name)
40 {
41       int i;
42       for (i=0; i<ivl_scope_attr_cnt(s); i++) {
43 	    const struct ivl_attribute_s *a;
44 	    a = ivl_scope_attr_val(s, i);
45 	    if (strcmp(a->key,name) == 0) return 1;
46       }
47       return 0;
48 }
49 
show_process(ivl_process_t net,void * x)50 static int show_process(ivl_process_t net, void*x)
51 {
52       ivl_scope_t scope = ivl_process_scope(net);
53 
54 	/* Ignore processes that are within scopes that are cells. The
55 	   cell_scope will generate a cell to represent the entire
56 	   scope. */
57       if (scope_has_attribute(scope, "ivl_synthesis_cell"))
58 	    return 0;
59 
60       fprintf(stderr, "fpga target: unsynthesized behavioral code\n");
61       return 0;
62 }
63 
show_pads(ivl_scope_t scope)64 static void show_pads(ivl_scope_t scope)
65 {
66       unsigned idx;
67 
68       if (device->show_pad == 0)
69 	    return;
70 
71       for (idx = 0 ;  idx < ivl_scope_sigs(scope) ;  idx += 1) {
72 	    ivl_signal_t sig = ivl_scope_sig(scope, idx);
73 	    const char*pad;
74 
75 	    if (ivl_signal_port(sig) == IVL_SIP_NONE)
76 		  continue;
77 
78 	    pad = ivl_signal_attr(sig, "PAD");
79 	    if (pad == 0)
80 		  continue;
81 
82 	    assert(device->show_pad);
83 	    device->show_pad(sig, pad);
84       }
85 }
86 
show_constants(ivl_design_t des)87 static void show_constants(ivl_design_t des)
88 {
89       unsigned idx;
90 
91       if (device->show_constant == 0)
92 	    return;
93 
94       for (idx = 0 ;  idx < ivl_design_consts(des) ;  idx += 1) {
95 	    ivl_net_const_t con = ivl_design_const(des, idx);
96 	    device->show_constant(con);
97       }
98 }
99 
100 /*
101  * This is the main entry point that ivl uses to invoke me, the code
102  * generator.
103  */
target_design(ivl_design_t des)104 int target_design(ivl_design_t des)
105 {
106       ivl_scope_t root = ivl_design_root(des);
107       const char*path = ivl_design_flag(des, "-o");
108 
109       xnf = fopen(path, "w");
110       if (xnf == 0) {
111 	    perror(path);
112 	    return -1;
113       }
114 
115       part = ivl_design_flag(des, "part");
116       if (part && (part[0] == 0))
117 	    part = 0;
118 
119       arch = ivl_design_flag(des, "arch");
120       if (arch && (arch[0] == 0))
121 	    arch = 0;
122 
123       if (arch == 0)
124 	    arch = "lpm";
125 
126       device = device_from_arch(arch);
127       if (device == 0) {
128 	    fprintf(stderr, "Unknown architecture arch=%s\n", arch);
129 	    return -1;
130       }
131 
132 	/* Call the device driver to generate the netlist header. */
133       device->show_header(des);
134 
135 	/* Catch any behavioral code that is left, and write warnings
136 	   that it is not supported. */
137       ivl_design_process(des, show_process, 0);
138 
139 	/* Get the pads from the design, and draw them to connect to
140 	   the associated signals. */
141       show_pads(root);
142 
143 	/* Scan the scopes, looking for gates to draw into the output
144 	   netlist. */
145       show_scope_gates(root, 0);
146 
147       show_constants(des);
148 
149 	/* Call the device driver to close out the file. */
150       device->show_footer(des);
151 
152       fclose(xnf);
153       xnf = 0;
154       return 0;
155 }
156