1 /*
2  * Copyright (c) 2008-2010 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 # include  "compiler.h"
22 # include  "pform.h"
23 # include  "parse_misc.h"
24 # include  "discipline.h"
25 
26 map<perm_string,ivl_nature_t> natures;
27 map<perm_string,ivl_discipline_t> disciplines;
28 map<perm_string,ivl_nature_t> access_function_nature;
29 
30 static perm_string nature_name = perm_string();
31 static perm_string nature_access = perm_string();
32 
pform_start_nature(const char * name)33 void pform_start_nature(const char*name)
34 {
35       nature_name = lex_strings.make(name);
36 }
37 
pform_nature_access(const struct vlltype & loc,const char * name)38 void pform_nature_access(const struct vlltype&loc, const char*name)
39 {
40       if (nature_access) {
41 	    cerr << loc.text << ":" << loc.first_line << ": error: "
42 		 << "Too many access names for nature "
43 		 << nature_name << "." << endl;
44 	    error_count += 1;
45 	    return;
46       }
47 
48       nature_access = lex_strings.make(name);
49 }
50 
pform_end_nature(const struct vlltype & loc)51 void pform_end_nature(const struct vlltype&loc)
52 {
53 	// The nature access function is required. If it is missing,
54 	// then signal an error. For a temporary expedient, we can set
55 	// the nature name as the access function, but don't expect it
56 	// to work.
57       if (! nature_access) {
58 	    cerr << loc.text << ":" << loc.first_line << ": error: "
59 		 << "Missing access name for nature "
60 		 << nature_name << "." << endl;
61 	    error_count += 1;
62 	    nature_access = nature_name;
63       }
64 
65       ivl_nature_s*tmp = new ivl_nature_s(nature_name, nature_access);
66       FILE_NAME(tmp, loc);
67 
68       natures[nature_name] = tmp;
69 
70 	// Make sure the access function is not used by multiple
71 	// different natures.
72       if (ivl_nature_t dup_access_nat = access_function_nature[nature_access]) {
73 	    cerr << tmp->get_fileline() << ": error: "
74 		 << "Access function name " << nature_access
75 		 << " is already used by nature " << dup_access_nat->name()
76 		 << " declared at " << dup_access_nat->get_fileline()
77 		 << "." << endl;
78 	    error_count += 1;
79       }
80 
81 	// Map the access function back to the nature so that
82 	// expressions that use the access function can find it.
83       access_function_nature[nature_access] = tmp;
84 
85       nature_name = perm_string();
86       nature_access = perm_string();
87 }
88 
89 
90 static perm_string discipline_name;
91 static ivl_dis_domain_t discipline_domain = IVL_DIS_NONE;
92 static ivl_nature_t discipline_potential = 0;
93 static ivl_nature_t discipline_flow = 0;
94 
pform_start_discipline(const char * name)95 void pform_start_discipline(const char*name)
96 {
97       discipline_name = lex_strings.make(name);
98       discipline_domain = IVL_DIS_NONE;
99 }
100 
pform_discipline_domain(const struct vlltype & loc,ivl_dis_domain_t use_domain)101 void pform_discipline_domain(const struct vlltype&loc, ivl_dis_domain_t use_domain)
102 {
103       assert(use_domain != IVL_DIS_NONE);
104 
105       if (discipline_domain != IVL_DIS_NONE) {
106 	    cerr << loc.text << ":" << loc.first_line << ": error: "
107 		 << "Too many domain attributes for discipline "
108 		 << discipline_name << "." << endl;
109 	    error_count += 1;
110 	    return;
111       }
112 
113       discipline_domain = use_domain;
114 }
115 
pform_discipline_potential(const struct vlltype & loc,const char * name)116 void pform_discipline_potential(const struct vlltype&loc, const char*name)
117 {
118       if (discipline_potential) {
119 	    cerr << loc.text << ":" << loc.first_line << ": error: "
120 		 << "Too many potential natures for discipline "
121 		 << discipline_name << "." << endl;
122 	    error_count += 1;
123 	    return;
124       }
125 
126       perm_string key = lex_strings.make(name);
127       discipline_potential = natures[key];
128 
129       if (discipline_potential == 0) {
130 	    cerr << loc.text << ":" << loc.first_line << ": error: "
131 		 << "nature " << key << " is not declared." << endl;
132 	    error_count += 1;
133 	    return;
134       }
135 }
136 
pform_discipline_flow(const struct vlltype & loc,const char * name)137 void pform_discipline_flow(const struct vlltype&loc, const char*name)
138 {
139       if (discipline_flow) {
140 	    cerr << loc.text << ":" << loc.first_line << ": error: "
141 		 << "Too many flow natures for discipline "
142 		 << discipline_name << "." << endl;
143 	    error_count += 1;
144 	    return;
145       }
146 
147       perm_string key = lex_strings.make(name);
148       discipline_flow = natures[key];
149 
150       if (discipline_flow == 0) {
151 	    cerr << loc.text << ":" << loc.first_line << ": error: "
152 		 << "nature " << key << " is not declared." << endl;
153 	    error_count += 1;
154 	    return;
155       }
156 }
157 
pform_end_discipline(const struct vlltype & loc)158 void pform_end_discipline(const struct vlltype&loc)
159 {
160 	// If the domain is not otherwise specified, then take it to
161 	// be continuous if potential or flow natures are given.
162       if (discipline_domain == IVL_DIS_NONE && (discipline_potential||discipline_flow))
163 	    discipline_domain = IVL_DIS_CONTINUOUS;
164 
165       ivl_discipline_t tmp = new ivl_discipline_s(discipline_name,
166 						  discipline_domain,
167 						  discipline_potential,
168 						  discipline_flow);
169       disciplines[discipline_name] = tmp;
170 
171       FILE_NAME(tmp, loc);
172 
173 	/* Clear the static variables for the next item. */
174       discipline_name = perm_string();
175       discipline_domain = IVL_DIS_NONE;
176       discipline_potential = 0;
177       discipline_flow = 0;
178 }
179 
180 /*
181  * The parser uses this function to attach a discipline to a wire. The
182  * wire may be declared by now, or will be declared further later. If
183  * it is already declared, we just attach the discipline. If it is not
184  * declared yet, then this is the declaration and we create the signal
185  * in the current lexical scope.
186  */
pform_attach_discipline(const struct vlltype & loc,ivl_discipline_t discipline,list<perm_string> * names)187 void pform_attach_discipline(const struct vlltype&loc,
188 			     ivl_discipline_t discipline, list<perm_string>*names)
189 {
190       for (list<perm_string>::iterator cur = names->begin()
191 		 ; cur != names->end() ; ++ cur ) {
192 
193 	    PWire* cur_net = pform_get_wire_in_scope(*cur);
194 	    if (cur_net == 0) {
195 		    /* Not declared yet, declare it now. */
196 		  pform_makewire(loc, *cur, NetNet::WIRE,
197 				 NetNet::NOT_A_PORT, IVL_VT_REAL, 0);
198 		  cur_net = pform_get_wire_in_scope(*cur);
199 		  assert(cur_net);
200 	    }
201 
202 	    if (ivl_discipline_t tmp = cur_net->get_discipline()) {
203 		  cerr << loc.text << ":" << loc.first_line << ": error: "
204 		       << "discipline " << discipline->name()
205 		       << " cannot override existing discipline " << tmp->name()
206 		       << " on net " << cur_net->basename() << endl;
207 		  error_count += 1;
208 
209 	    } else {
210 		  cur_net->set_data_type(IVL_VT_REAL);
211 		  cur_net->set_discipline(discipline);
212 	    }
213       }
214 }
215