1 |
4 |
dargor |
#!/usr/bin/env python
|
2 |
|
|
# -*- coding: utf-8 -*-
|
3 |
|
|
|
4 |
|
|
#
|
5 |
|
|
# NoC Code generator - VHDL generator
|
6 |
|
|
#
|
7 |
|
|
# Author: Oscar Diaz
|
8 |
|
|
# Version: 0.1
|
9 |
|
|
# Date: 11-11-2011
|
10 |
|
|
|
11 |
|
|
#
|
12 |
|
|
# This code is free software; you can redistribute it and/or
|
13 |
|
|
# modify it under the terms of the GNU Lesser General Public
|
14 |
|
|
# License as published by the Free Software Foundation; either
|
15 |
|
|
# version 2.1 of the License, or (at your option) any later version.
|
16 |
|
|
#
|
17 |
|
|
# This code is distributed in the hope that it will be useful,
|
18 |
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19 |
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
20 |
|
|
# Lesser General Public License for more details.
|
21 |
|
|
#
|
22 |
|
|
# You should have received a copy of the GNU Lesser General Public
|
23 |
|
|
# License along with this library; if not, write to the
|
24 |
|
|
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
25 |
|
|
# Boston, MA 02111-1307 USA
|
26 |
|
|
#
|
27 |
|
|
|
28 |
|
|
#
|
29 |
|
|
# Changelog:
|
30 |
|
|
#
|
31 |
|
|
# 11-11-2011 : (OD) initial release
|
32 |
|
|
#
|
33 |
|
|
|
34 |
|
|
"""
|
35 |
|
|
Code generation support for VHDL
|
36 |
|
|
|
37 |
|
|
This module defines:
|
38 |
|
|
* Class 'noc_codegen_vhdl'
|
39 |
|
|
* Function 'add_codegen_vhdl_support'
|
40 |
|
|
"""
|
41 |
|
|
|
42 |
|
|
from nocmodel import *
|
43 |
|
|
from noc_codegen_base import *
|
44 |
|
|
from myhdl import intbv, bin
|
45 |
|
|
|
46 |
|
|
class noc_codegen_vhdl(noc_codegen_base):
|
47 |
|
|
"""
|
48 |
|
|
VHDL generator class
|
49 |
|
|
|
50 |
|
|
This class defines methods used to generate VHDL code from any noc object.
|
51 |
|
|
|
52 |
|
|
Like base class, this object has this base attributes:
|
53 |
|
|
* docheader
|
54 |
|
|
* libraries
|
55 |
|
|
* modulename
|
56 |
|
|
* generics
|
57 |
|
|
* ports
|
58 |
|
|
* implementation
|
59 |
|
|
"""
|
60 |
|
|
def __init__(self, nocobject_ref, **kwargs):
|
61 |
|
|
noc_codegen_base.__init__(self, nocobject_ref, **kwargs)
|
62 |
|
|
|
63 |
|
|
# note: the noc object must be complete, in order to
|
64 |
|
|
# add code generation support
|
65 |
|
|
#self.nocobject_ref = nocobject_ref
|
66 |
|
|
self.modulename = self.to_valid_str(self.nocobject_ref.name)
|
67 |
|
|
|
68 |
|
|
# default header and libraries
|
69 |
|
|
self.docheader = "-- Document header"
|
70 |
|
|
self.libraries = "library ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;"
|
71 |
|
|
|
72 |
|
|
# code generation attributes
|
73 |
|
|
self.usetab = " " # 4-space tabs
|
74 |
|
|
self.full_comments = True
|
75 |
|
|
|
76 |
|
|
# main methods
|
77 |
|
|
def generate_file(self):
|
78 |
|
|
"""
|
79 |
|
|
Generate the entire file that implements this object.
|
80 |
|
|
"""
|
81 |
|
|
# Unless code generation is externally generated.
|
82 |
|
|
if self.external_conversion:
|
83 |
|
|
# use "codemodel" object on nocobject_ref
|
84 |
|
|
if hasattr(self.nocobject_ref, "codemodel"):
|
85 |
|
|
return self.nocobject_ref.codemodel.generate_file()
|
86 |
|
|
else:
|
87 |
|
|
raise AttributeError("External conversion flag is enabled, but there's no 'codemodel' object available in nocobject %s" % self.nocobject_ref)
|
88 |
|
|
else:
|
89 |
|
|
# first try to call build_implementation() method
|
90 |
|
|
self.build_implementation()
|
91 |
|
|
sret = self.docheader + "\n\n" + self.libraries + "\n\n"
|
92 |
|
|
if self.full_comments:
|
93 |
|
|
sret += self.make_comment("Object '%s' name '%s' description '%s'\n" % (repr(self.nocobject_ref), self.nocobject_ref.name, self.nocobject_ref.description))
|
94 |
|
|
sret += self.generate_entity_section() + "\n\n"
|
95 |
|
|
sret += self.generate_architecture_section() + "\n"
|
96 |
|
|
return sret
|
97 |
|
|
|
98 |
|
|
def generate_component(self):
|
99 |
|
|
"""
|
100 |
|
|
Generate a component definition for this object.
|
101 |
|
|
"""
|
102 |
|
|
sret = "component %s\n" % self.modulename
|
103 |
|
|
stmp = self.generate_generics_section()
|
104 |
|
|
if stmp != "":
|
105 |
|
|
sret += self.add_tab(stmp) + ";\n"
|
106 |
|
|
stmp = self.generate_ports_section()
|
107 |
|
|
if stmp != "":
|
108 |
|
|
sret += self.add_tab(stmp) + ";\n"
|
109 |
|
|
sret += "end component;\n"
|
110 |
|
|
return sret
|
111 |
|
|
|
112 |
|
|
def generate_generic_declaration(self, generic=None, with_default=False):
|
113 |
|
|
"""
|
114 |
|
|
Generate a generic declaration for this object.
|
115 |
|
|
|
116 |
|
|
Arguments:
|
117 |
|
|
* generic : either a name or a list index for a particular generic
|
118 |
|
|
* with_default : True to add the default value
|
119 |
|
|
|
120 |
|
|
Returns:
|
121 |
|
|
* A string when generic argument is used
|
122 |
|
|
* A list of strings with all generics
|
123 |
|
|
"""
|
124 |
|
|
if generic is None:
|
125 |
|
|
# all generics
|
126 |
|
|
l = []
|
127 |
|
|
for i in range(len(self.generics)):
|
128 |
|
|
l.append(self.generate_generic_declaration(i, with_default))
|
129 |
|
|
return l
|
130 |
|
|
else:
|
131 |
|
|
# search for correct index
|
132 |
|
|
if isinstance(generic, int):
|
133 |
|
|
g = self.generics[generic]
|
134 |
|
|
elif isinstance(generic, string):
|
135 |
|
|
g = filter(lambda s: s["name"] == generic, self.generics)[0]
|
136 |
|
|
else:
|
137 |
|
|
raise TypeError("Don't know how to search with '%s'." % repr(generic))
|
138 |
|
|
sret = "%s : %s" % (self.to_valid_str(g["name"]), g["type"])
|
139 |
|
|
if with_default:
|
140 |
|
|
sret += ' := %s' % convert_value(g["default_value"], g["type"], g["type_array"])
|
141 |
|
|
# add string quotes
|
142 |
|
|
# if g["type"] == "string":
|
143 |
|
|
# sret += ' := "%s"' % g["default_value"]
|
144 |
|
|
# else:
|
145 |
|
|
# sret += ' := %s' % g["default_value"]
|
146 |
|
|
return sret
|
147 |
|
|
|
148 |
|
|
def generate_port_declaration(self, port=None, with_default=False):
|
149 |
|
|
"""
|
150 |
|
|
Generate a port declaration for this object.
|
151 |
|
|
|
152 |
|
|
Arguments:
|
153 |
|
|
* port : either a name or a list index for a particular port
|
154 |
|
|
* with_default : True to add the default value
|
155 |
|
|
|
156 |
|
|
Returns:
|
157 |
|
|
* A list of strings with all signals in port when port argument is used
|
158 |
|
|
* A list of strings with all signals in all ports
|
159 |
|
|
"""
|
160 |
|
|
if port is None:
|
161 |
|
|
# all ports
|
162 |
|
|
l = []
|
163 |
|
|
for i in range(len(self.ports)):
|
164 |
|
|
l.append(self.make_comment("Port '%s' : '%s'" % (self.to_valid_str(self.ports[i]["name"]), self.ports[i]["type"])))
|
165 |
|
|
pl = self.generate_port_declaration(i, with_default)
|
166 |
|
|
pl.sort()
|
167 |
|
|
l.extend(pl)
|
168 |
|
|
return l
|
169 |
|
|
else:
|
170 |
|
|
# search for correct index
|
171 |
|
|
if isinstance(port, int):
|
172 |
|
|
idx = port
|
173 |
|
|
elif isinstance(port, string):
|
174 |
|
|
p = filter(lambda s: s["name"] == port, self.ports)[0]
|
175 |
|
|
idx = self.ports.index(p)
|
176 |
|
|
else:
|
177 |
|
|
raise TypeError("Don't know how to search with '%s'." % repr(port))
|
178 |
|
|
return self.generate_signal_declaration(idx, None, with_default)
|
179 |
|
|
|
180 |
|
|
def generate_signal_declaration(self, inport=None, signal=None, with_default=False):
|
181 |
|
|
"""
|
182 |
|
|
Generate a signal declaration for this object.
|
183 |
|
|
|
184 |
|
|
Arguments:
|
185 |
|
|
* inport : either a name or a list index for a particular port. None
|
186 |
|
|
means use the external_signals list
|
187 |
|
|
* signal : either a name or a list index for a particular signal
|
188 |
|
|
* with_default : True to add the default value
|
189 |
|
|
|
190 |
|
|
Returns:
|
191 |
|
|
* A string when signal argument is used
|
192 |
|
|
* A list of strings with all signals
|
193 |
|
|
"""
|
194 |
|
|
if signal is None:
|
195 |
|
|
# all signals
|
196 |
|
|
l = []
|
197 |
|
|
if inport is None:
|
198 |
|
|
r = range(len(self.external_signals))
|
199 |
|
|
else:
|
200 |
|
|
# what port?
|
201 |
|
|
if isinstance(inport, int):
|
202 |
|
|
g = self.ports[inport]
|
203 |
|
|
elif isinstance(inport, string):
|
204 |
|
|
g = filter(lambda s: s["name"] == inport, self.ports)[0]
|
205 |
|
|
else:
|
206 |
|
|
raise TypeError("Don't know how to search with '%s'." % repr(inport))
|
207 |
|
|
r = range(len(g["signal_list"]))
|
208 |
|
|
for i in r:
|
209 |
|
|
l.append(self.generate_signal_declaration(inport, i, with_default))
|
210 |
|
|
return l
|
211 |
|
|
else:
|
212 |
|
|
# locate either port or external_signals
|
213 |
|
|
if inport is None:
|
214 |
|
|
if isinstance(signal, int):
|
215 |
|
|
sig = self.external_signals[signal]
|
216 |
|
|
elif isinstance(signal, string):
|
217 |
|
|
sig = filter(lambda s: s["name"] == signal, self.external_signals)[0]
|
218 |
|
|
else:
|
219 |
|
|
raise TypeError("Don't know how to search with '%s'." % repr(signal))
|
220 |
|
|
# put nothing as signal prefix
|
221 |
|
|
sprefix = ""
|
222 |
|
|
else:
|
223 |
|
|
# what port?
|
224 |
|
|
if isinstance(inport, int):
|
225 |
|
|
p = self.ports[inport]
|
226 |
|
|
elif isinstance(inport, string):
|
227 |
|
|
p = filter(lambda s: s["name"] == inport, self.ports)[0]
|
228 |
|
|
else:
|
229 |
|
|
raise TypeError("Don't know how to search with '%s'." % repr(inport))
|
230 |
|
|
# what signal?
|
231 |
|
|
if isinstance(signal, int):
|
232 |
|
|
sig = p["signal_list"][signal]
|
233 |
|
|
elif isinstance(signal, string):
|
234 |
|
|
sig = filter(lambda s: s["name"] == signal, p["signal_list"])[0]
|
235 |
|
|
else:
|
236 |
|
|
raise TypeError("Don't know how to search with '%s'." % repr(signal))
|
237 |
|
|
# put port name as signal prefix
|
238 |
|
|
#sprefix = self.to_valid_str(p["name"]) + "_"
|
239 |
|
|
sprefix = ""
|
240 |
|
|
sret = "%s%s : %s %s" % (sprefix, self.to_valid_str(sig["name"]), sig["direction"], sig["type"])
|
241 |
|
|
if with_default:
|
242 |
|
|
sret += ' := %s' % convert_value(sig["default_value"], sig["type"])
|
243 |
|
|
# if sig["type"] == "string":
|
244 |
|
|
# sret += ' := "%s"' % sig["default_value"]
|
245 |
|
|
# else:
|
246 |
|
|
# sret += ' := %s' % sig["default_value"]
|
247 |
|
|
return sret
|
248 |
|
|
|
249 |
|
|
def make_comment(self, data):
|
250 |
|
|
"""
|
251 |
|
|
Convert string data to language comment
|
252 |
|
|
|
253 |
|
|
Argument:
|
254 |
|
|
* data: string or list of strings to convert
|
255 |
|
|
|
256 |
|
|
Returns: a new string or list of strings with comments added.
|
257 |
|
|
"""
|
258 |
|
|
if isinstance(data, str):
|
259 |
|
|
return "-- %s%s" % (data[:-1].replace("\n", "\n-- "), data[-1])
|
260 |
|
|
else:
|
261 |
|
|
# don't put exception catch. It is an error if data is not
|
262 |
|
|
# iterable.
|
263 |
|
|
it = iter(data)
|
264 |
|
|
retval = []
|
265 |
|
|
for s in data:
|
266 |
|
|
retval.append("-- %s%s" % (s[:-1].replace("\n", "\n-- "), s[-1]))
|
267 |
|
|
return retval
|
268 |
|
|
|
269 |
|
|
def add_tab(self, data, level=1):
|
270 |
|
|
"""
|
271 |
|
|
Add an indentation level to the string
|
272 |
|
|
|
273 |
|
|
Argument:
|
274 |
|
|
* data: string or list of strings
|
275 |
|
|
* level: how many indentation levels to add. Default 1
|
276 |
|
|
|
277 |
|
|
Returns: string or list of strings with <level> indentation levels.
|
278 |
|
|
"""
|
279 |
|
|
leveltabs = self.usetab*level
|
280 |
|
|
if isinstance(data, str):
|
281 |
|
|
return "%s%s%s" % (leveltabs, data[:-1].replace("\n", "\n%s" % leveltabs), data[-1])
|
282 |
|
|
else:
|
283 |
|
|
# don't put exception catch. It is an error if data is not
|
284 |
|
|
# iterable.
|
285 |
|
|
it = iter(data)
|
286 |
|
|
retval = []
|
287 |
|
|
for s in data:
|
288 |
|
|
retval.append("%s%s%s" % (leveltabs, s[:-1].replace("\n", "\n%s" % leveltabs), s[-1]))
|
289 |
|
|
return retval
|
290 |
|
|
|
291 |
|
|
def to_valid_str(self, str_in):
|
292 |
|
|
"""
|
293 |
|
|
Convert an input string, changing special characters used on
|
294 |
|
|
the HDL language. Useful for set names .
|
295 |
|
|
|
296 |
|
|
Argument:
|
297 |
|
|
* str_in: string to convert
|
298 |
|
|
|
299 |
|
|
Returns: the converted string.
|
300 |
|
|
"""
|
301 |
|
|
# list of transformations:
|
302 |
|
|
# * strip spaces
|
303 |
|
|
# * space,":" with "_"
|
304 |
|
|
s = str_in.strip()
|
305 |
|
|
s = s.replace(" ", "_")
|
306 |
|
|
s = s.replace(":", "_")
|
307 |
|
|
return s
|
308 |
|
|
|
309 |
|
|
# codegen model management
|
310 |
|
|
def add_generic(self, name, value, description="", **kwargs):
|
311 |
|
|
"""
|
312 |
|
|
Add a generic to the model - with VHDL type formatting.
|
313 |
|
|
"""
|
314 |
|
|
g = noc_codegen_base.add_generic(self, name, value, description, **kwargs)
|
315 |
|
|
# Set correct type. String by default
|
316 |
|
|
gadd = {"type": "string"}
|
317 |
|
|
if "type" in kwargs:
|
318 |
|
|
# Optional type must be a string with a custom type name.
|
319 |
|
|
if isinstance(kwargs["type"], str):
|
320 |
|
|
# custom type name.
|
321 |
|
|
gadd.update({"type": kwargs["type"]})
|
322 |
|
|
#else:
|
323 |
|
|
# default to use string
|
324 |
|
|
else:
|
325 |
|
|
gadd["type"] = self.calculate_type(value)
|
326 |
|
|
## use type in value
|
327 |
|
|
#gadd["type"] = _pytovhdltype[type(value)]
|
328 |
|
|
## defined range
|
329 |
|
|
#if "type_array" in kwargs:
|
330 |
|
|
#if isinstance(value, int):
|
331 |
|
|
## for an integer it means range
|
332 |
|
|
#gadd["type"] += " range %d to %d" % (kwargs["type_array"][0], kwargs["type_array"][1])
|
333 |
|
|
#elif isinstance(value, intbv):
|
334 |
|
|
## for a intbv it means bit boundaries
|
335 |
|
|
#gadd["type"] += "_vector(%d to %d)" % (kwargs["type_array"][0], kwargs["type_array"][1])
|
336 |
|
|
##else:
|
337 |
|
|
## ignore array range
|
338 |
|
|
#else:
|
339 |
|
|
## special case
|
340 |
|
|
#if isinstance(value, intbv):
|
341 |
|
|
## put vector only if necessary
|
342 |
|
|
#if value._nrbits > 1:
|
343 |
|
|
## extract vector information
|
344 |
|
|
#gadd["type_array"] = [0, value._nrbits - 1]
|
345 |
|
|
#gadd["type"] += "_vector(%d to %d)" % (0, value._nrbits - 1)
|
346 |
|
|
|
347 |
|
|
g.update(gadd)
|
348 |
|
|
return g
|
349 |
|
|
|
350 |
|
|
def add_port(self, name, signal_desc=None, description="", **kwargs):
|
351 |
|
|
"""
|
352 |
|
|
Add a port to the model - with VHDL type formatting.
|
353 |
|
|
"""
|
354 |
|
|
p = noc_codegen_base.add_port(self, name, signal_desc, description, **kwargs)
|
355 |
|
|
if signal_desc is None:
|
356 |
|
|
# nothing else to do
|
357 |
|
|
return p
|
358 |
|
|
# set correct type for the particular signal_desc
|
359 |
|
|
sig = filter(lambda x: x["name"] == signal_desc["name"], p["signal_list"])
|
360 |
|
|
if len(sig) == 0:
|
361 |
|
|
# strange error
|
362 |
|
|
raise ValueError("Strange error: recently added signal '%s' to port '%s', but signal cannot be found." % (signal_desc["name"], p["name"]))
|
363 |
|
|
else:
|
364 |
|
|
sig = sig[0]
|
365 |
|
|
# type inferring: only apply if signal_desc has empty type
|
366 |
|
|
if sig["type"] != "":
|
367 |
|
|
return p
|
368 |
|
|
|
369 |
|
|
# integer by default
|
370 |
|
|
sadd = {"type": "integer"}
|
371 |
|
|
if "type" in kwargs:
|
372 |
|
|
# Optional type must be a string with a custom type name.
|
373 |
|
|
if isinstance(kwargs["type"], str):
|
374 |
|
|
# custom type name.
|
375 |
|
|
sadd["type"] = kwargs["type"]
|
376 |
|
|
# also add if it has default_value
|
377 |
|
|
if "default_value" in kwargs:
|
378 |
|
|
sadd["default_value"] = kwargs["default_value"]
|
379 |
|
|
#else:
|
380 |
|
|
# default to use integer
|
381 |
|
|
else:
|
382 |
|
|
sadd["type"] = self.calculate_type(sig["default_value"])
|
383 |
|
|
## use type in value
|
384 |
|
|
#sadd["type"] = _pytovhdltype[type(sig["default_value"])]
|
385 |
|
|
## defined range
|
386 |
|
|
#if "type_array" in kwargs:
|
387 |
|
|
#if isinstance(sig["default_value"], int):
|
388 |
|
|
#sadd["type"] += " range(%d to %d)" % (kwargs["type_array"][0], kwargs["type_array"][1])
|
389 |
|
|
#elif isinstance(sig["default_value"], intbv):
|
390 |
|
|
#sadd["type"] += "_vector(%d downto %d)" % (kwargs["type_array"][1], kwargs["type_array"][0])
|
391 |
|
|
##else:
|
392 |
|
|
## ignore array range
|
393 |
|
|
#else:
|
394 |
|
|
## special case
|
395 |
|
|
#if isinstance(sig["default_value"], intbv):
|
396 |
|
|
## put vector only if necessary
|
397 |
|
|
#if sig["default_value"]._nrbits > 1:
|
398 |
|
|
## extract vector information
|
399 |
|
|
#sadd["type_array"] = [0, sig["default_value"]._nrbits - 1]
|
400 |
|
|
#sadd["type"] += "_vector(%d downto 0)" % (sig["default_value"]._nrbits - 1)
|
401 |
|
|
sig.update(sadd)
|
402 |
|
|
return p
|
403 |
|
|
|
404 |
|
|
def add_external_signal(self, name, direction, value, description="", **kwargs):
|
405 |
|
|
"""
|
406 |
|
|
Add a external signal to the model - with VHDL type formatting.
|
407 |
|
|
"""
|
408 |
|
|
sig = noc_codegen_base.add_external_signal(self, name, direction, value, description, **kwargs)
|
409 |
|
|
# Set correct type. integer by default
|
410 |
|
|
sadd = {"type": "integer"}
|
411 |
|
|
if "type" in kwargs:
|
412 |
|
|
# Optional type must be a string with a custom type name.
|
413 |
|
|
if isinstance(kwargs["type"], str):
|
414 |
|
|
# custom type name.
|
415 |
|
|
sadd.update({"type": kwargs["type"]})
|
416 |
|
|
#else:
|
417 |
|
|
# default to use integer
|
418 |
|
|
else:
|
419 |
|
|
sadd["type"] = self.calculate_type(value)
|
420 |
|
|
## use type in value
|
421 |
|
|
#sadd["type"] = _pytovhdltype[type(value)]
|
422 |
|
|
## defined range
|
423 |
|
|
#if "type_array" in kwargs:
|
424 |
|
|
#if isinstance(value, int):
|
425 |
|
|
#sadd["type"] += " range(%d to %d)" % (kwargs["type_array"][0], kwargs["type_array"][1])
|
426 |
|
|
#elif isinstance(value, intbv):
|
427 |
|
|
#sadd["type"] += "_vector(%d to %d)" % (kwargs["type_array"][0], kwargs["type_array"][1])
|
428 |
|
|
##else:
|
429 |
|
|
## ignore array range
|
430 |
|
|
#else:
|
431 |
|
|
## special case
|
432 |
|
|
#if isinstance(value, intbv):
|
433 |
|
|
## extract vector information
|
434 |
|
|
#sadd["type_array"] = [0, sig["default_value"]._nrbits - 1]
|
435 |
|
|
#if None not in sadd["type_array"]:
|
436 |
|
|
#sadd["type"] += "_vector(%d to %d)" % (0, sig["default_value"]._nrbits - 1)
|
437 |
|
|
sig.update(sadd)
|
438 |
|
|
return sig
|
439 |
|
|
|
440 |
|
|
# particular VHDL methods
|
441 |
|
|
def generate_entity_section(self):
|
442 |
|
|
"""
|
443 |
|
|
Generate entity section
|
444 |
|
|
"""
|
445 |
|
|
sret = "entity %s is\n" % self.modulename
|
446 |
|
|
stmp = self.generate_generics_section()
|
447 |
|
|
if stmp != "":
|
448 |
|
|
sret += self.add_tab(stmp) + ";\n"
|
449 |
|
|
stmp = self.generate_ports_section()
|
450 |
|
|
if stmp != "":
|
451 |
|
|
sret += self.add_tab(stmp) + ";\n"
|
452 |
|
|
sret += "end %s;\n" % self.modulename
|
453 |
|
|
return sret
|
454 |
|
|
|
455 |
|
|
def generate_architecture_section(self, archname="rtl"):
|
456 |
|
|
"""
|
457 |
|
|
Generate architecture section
|
458 |
|
|
"""
|
459 |
|
|
sret = "architecture %s of %s is\n" % (archname, self.modulename)
|
460 |
|
|
if self.implementation != "":
|
461 |
|
|
sret += self.add_tab(self.implementation)
|
462 |
|
|
sret += "\nend %s;\n" % archname
|
463 |
|
|
return sret
|
464 |
|
|
|
465 |
|
|
def generate_generics_section(self):
|
466 |
|
|
"""
|
467 |
|
|
Generate generics section used on entity and component
|
468 |
|
|
"""
|
469 |
|
|
sret = "generic (\n"
|
470 |
|
|
l = self.generate_generic_declaration(None, True)
|
471 |
|
|
if len(l) > 0:
|
472 |
|
|
l = self.add_tab(l)
|
473 |
|
|
sret += ";\n".join(l)
|
474 |
|
|
sret += "\n)"
|
475 |
|
|
else:
|
476 |
|
|
# empty generics section
|
477 |
|
|
sret = ""
|
478 |
|
|
return sret
|
479 |
|
|
|
480 |
|
|
def generate_ports_section(self):
|
481 |
|
|
"""
|
482 |
|
|
Generate ports section used on entity and component
|
483 |
|
|
"""
|
484 |
|
|
# first ports and then external signals
|
485 |
|
|
sret = "port (\n"
|
486 |
|
|
l = self.generate_port_declaration(None, False)
|
487 |
|
|
l.extend(self.generate_signal_declaration(None, None, False))
|
488 |
|
|
if len(l) > 0:
|
489 |
|
|
l = self.add_tab(l)
|
490 |
|
|
sret += ";\n".join(l)
|
491 |
|
|
sret += "\n)"
|
492 |
|
|
else:
|
493 |
|
|
# empty ports section
|
494 |
|
|
sret = ""
|
495 |
|
|
return sret
|
496 |
|
|
|
497 |
|
|
def calculate_type(self, object, with_default=False):
|
498 |
|
|
"""
|
499 |
|
|
Calculate the correct VHDL type for a particular object
|
500 |
|
|
|
501 |
|
|
Arguments:
|
502 |
|
|
* object:
|
503 |
|
|
* with_default: True to add a default value at the end
|
504 |
|
|
Returns:
|
505 |
|
|
A string with the VHDL equivalent type
|
506 |
|
|
"""
|
507 |
|
|
if isinstance(object, bool):
|
508 |
|
|
return "std_logic"
|
509 |
|
|
elif isinstance(object, (int, long)):
|
510 |
|
|
# CHECK if this is a correct type translation
|
511 |
|
|
return "integer"
|
512 |
|
|
elif isinstance(object, str):
|
513 |
|
|
return "string"
|
514 |
|
|
elif isinstance(object, myhdl.intbv):
|
515 |
|
|
width = object._nrbits
|
516 |
|
|
initval = object._val
|
517 |
|
|
elif isinstance(object, myhdl.SignalType):
|
518 |
|
|
width = object._nrbits
|
519 |
|
|
initval = object._init
|
520 |
|
|
else:
|
521 |
|
|
raise ValueError("Type conversion for object %s not found (type: %s)" % (repr(object), type(object)))
|
522 |
|
|
if width <= 0:
|
523 |
|
|
raise ValueError("Object %s don't have a valid bit width." % repr(object))
|
524 |
|
|
if width == 1:
|
525 |
|
|
retval = "std_logic"
|
526 |
|
|
defval = "'%d'" % int(initval)
|
527 |
|
|
else:
|
528 |
|
|
retval = "unsigned(%s downto 0)" % (width - 1)
|
529 |
|
|
defval = '"%s"' % myhdl.bin(initval, width)
|
530 |
|
|
if with_default:
|
531 |
|
|
return "%s := %s" % (retval, defval)
|
532 |
|
|
else:
|
533 |
|
|
return retval
|
534 |
|
|
|
535 |
|
|
# helper functions
|
536 |
|
|
def add_codegen_vhdl_support(instance, **kwargs):
|
537 |
|
|
"""
|
538 |
|
|
This function will add for every object in instance a noc_codegen object
|
539 |
|
|
"""
|
540 |
|
|
if isinstance(instance, noc):
|
541 |
|
|
# add code generation object
|
542 |
|
|
instance.codegen = noc_codegen_vhdl(instance, **kwargs)
|
543 |
|
|
# and add cg objects recursively
|
544 |
|
|
for obj in instance.all_list(True):
|
545 |
|
|
add_codegen_vhdl_support(obj, **kwargs)
|
546 |
|
|
elif isinstance(instance, (ipcore, router, channel)):
|
547 |
|
|
instance.codegen = noc_codegen_vhdl(instance, **kwargs)
|
548 |
|
|
else:
|
549 |
|
|
raise TypeError("Unsupported object: type %s" % type(instance))
|
550 |
|
|
|
551 |
|
|
def convert_value(data, custom_type=None, type_array=[None, None]):
|
552 |
|
|
"""
|
553 |
|
|
This function converts data to a string valid in VHDL syntax.
|
554 |
|
|
"""
|
555 |
|
|
retval = ""
|
556 |
|
|
numbits = 0
|
557 |
|
|
usedata = data
|
558 |
|
|
if custom_type is not None:
|
559 |
|
|
# custom type
|
560 |
|
|
if custom_type == int:
|
561 |
|
|
usedata = int(data)
|
562 |
|
|
elif custom_type == bool:
|
563 |
|
|
usedata = data == True
|
564 |
|
|
elif custom_type == intbv:
|
565 |
|
|
# need fixed boundaries. Use type_array
|
566 |
|
|
if type_array == [None, None]:
|
567 |
|
|
# default: one bit width
|
568 |
|
|
usedata = intbv(data)[1:]
|
569 |
|
|
else:
|
570 |
|
|
# intbv boundaries refer to bit width
|
571 |
|
|
usedata = intbv(data)[type_array[1]+1:type_array[0]]
|
572 |
|
|
elif custom_type == str:
|
573 |
|
|
usedata = str(data)
|
574 |
|
|
elif isinstance(custom_type, str):
|
575 |
|
|
# type in a string format
|
576 |
|
|
if custom_type == "integer":
|
577 |
|
|
usedata = int(data)
|
578 |
|
|
elif custom_type == "std_logic":
|
579 |
|
|
usedata = intbv(data)[1:]
|
580 |
|
|
elif custom_type == "string":
|
581 |
|
|
usedata = str(data)
|
582 |
|
|
elif custom_type.find("std_logic_vector") == 0:
|
583 |
|
|
# strip values
|
584 |
|
|
vecinfo = custom_type.replace("std_logic_vector", "").strip("()").split()
|
585 |
|
|
if vecinfo[1] == "to":
|
586 |
|
|
vecmin = int(vecinfo[0])
|
587 |
|
|
vecmax = int(vecinfo[2])
|
588 |
|
|
elif vecinfo[1] == "downto":
|
589 |
|
|
vecmin = int(vecinfo[2])
|
590 |
|
|
vecmax = int(vecinfo[0])
|
591 |
|
|
usedata = intbv(data)[vecmax+1:vecmin]
|
592 |
|
|
else:
|
593 |
|
|
raise TypeError("Unsupported custom type string '%s' for VHDL conversion." % custom_type)
|
594 |
|
|
else:
|
595 |
|
|
raise TypeError("Unsupported custom type '%s' for VHDL conversion." % type(custom_type))
|
596 |
|
|
# convert
|
597 |
|
|
if isinstance(usedata, int):
|
598 |
|
|
retval = "%d" % data
|
599 |
|
|
elif isinstance(usedata, bool):
|
600 |
|
|
retval = "'%d'" % int(data)
|
601 |
|
|
elif isinstance(usedata, intbv):
|
602 |
|
|
# check boundaries
|
603 |
|
|
if usedata._nrbits > 1:
|
604 |
|
|
# print vector in bits
|
605 |
|
|
retval = '"%s"' % bin(usedata, usedata._nrbits)
|
606 |
|
|
else:
|
607 |
|
|
retval = "'%d'" % usedata
|
608 |
|
|
elif isinstance(usedata, str):
|
609 |
|
|
retval = '"%s"' % usedata
|
610 |
|
|
else:
|
611 |
|
|
raise TypeError("Unsupported type '%s' for VHDL conversion." % type(usedata))
|
612 |
|
|
return retval
|
613 |
|
|
|
614 |
|
|
# helper structures:
|
615 |
|
|
# type conversions
|
616 |
|
|
_pytovhdltype = {
|
617 |
|
|
"bool": "std_logic",
|
618 |
|
|
"int": "integer",
|
619 |
|
|
"intbv" : "unsigned",
|
620 |
|
|
"str" : "string",
|
621 |
|
|
bool: "std_logic",
|
622 |
|
|
int: "integer",
|
623 |
|
|
intbv : "unsigned",
|
624 |
|
|
str : "string"
|
625 |
|
|
}
|
626 |
|
|
_pytovhdlzeroval = {
|
627 |
|
|
"bool": "False",
|
628 |
|
|
"int": "0",
|
629 |
|
|
"intbv" : '"0"',
|
630 |
|
|
"str" : '""',
|
631 |
|
|
bool: "False",
|
632 |
|
|
int: "0",
|
633 |
|
|
intbv : '"0"',
|
634 |
|
|
str : '""'
|
635 |
|
|
}
|
636 |
|
|
|