import migen in litex/gen
[litex.git] / litex / gen / migen / fhdl / edif.py
1 from collections import OrderedDict, namedtuple
2
3 from migen.fhdl.structure import *
4 from migen.fhdl.namer import build_namespace
5 from migen.fhdl.tools import list_special_ios
6 from migen.fhdl.structure import _Fragment
7 from migen.fhdl.conv_output import ConvOutput
8
9
10 _Port = namedtuple("_Port", "name direction")
11 _Cell = namedtuple("_Cell", "name ports")
12 _Property = namedtuple("_Property", "name value")
13 _Instance = namedtuple("_Instance", "name cell properties")
14 _NetBranch = namedtuple("_NetBranch", "portname instancename")
15
16
17 def _write_cells(cells):
18 r = ""
19 for cell in cells:
20 r += """
21 (cell {0.name}
22 (cellType GENERIC)
23 (view view_1
24 (viewType NETLIST)
25 (interface""".format(cell)
26 for port in cell.ports:
27 r += """
28 (port {0.name} (direction {0.direction}))""".format(port)
29 r += """
30 )
31 )
32 )"""
33 return r
34
35
36 def _write_io(ios):
37 r = ""
38 for s in ios:
39 r += """
40 (port {0.name} (direction {0.direction}))""".format(s)
41 return r
42
43
44 def _write_instantiations(instances, cell_library):
45 instantiations = ""
46 for instance in instances:
47 instantiations += """
48 (instance {0.name}
49 (viewRef view_1 (cellRef {0.cell} (libraryRef {1})))""".format(instance, cell_library)
50 for prop in instance.properties:
51 instantiations += """
52 (property {0} (string "{1}"))""".format(prop.name, prop.value)
53 instantiations += """
54 )"""
55 return instantiations
56
57
58 def _write_connections(connections):
59 r = ""
60 for netname, branches in connections.items():
61 r += """
62 (net {0}
63 (joined""".format(netname)
64 for branch in branches:
65 r += """
66 (portRef {0}{1})""".format(branch.portname, "" if branch.instancename == "" else " (instanceRef {})".format(branch.instancename))
67 r += """
68 )
69 )"""
70 return r
71
72
73 def _write_edif(cells, ios, instances, connections, cell_library, design_name, part, vendor):
74 r = """(edif {0}
75 (edifVersion 2 0 0)
76 (edifLevel 0)
77 (keywordMap (keywordLevel 0))
78 (external {1}
79 (edifLevel 0)
80 (technology (numberDefinition))""".format(design_name, cell_library)
81 r += _write_cells(cells)
82 r += """
83 )
84 (library {0}_lib
85 (edifLevel 0)
86 (technology (numberDefinition))
87 (cell {0}
88 (cellType GENERIC)
89 (view view_1
90 (viewType NETLIST)
91 (interface""".format(design_name)
92 r += _write_io(ios)
93 r += """
94 (designator "{0}")
95 )
96 (contents""".format(part)
97 r += _write_instantiations(instances, cell_library)
98 r += _write_connections(connections)
99 r += """
100 )
101 )
102 )
103 )
104 (design {0}
105 (cellRef {0} (libraryRef {0}_lib))
106 (property PART (string "{1}") (owner "{2}"))
107 )
108 )""".format(design_name, part, vendor)
109
110 return r
111
112
113 def _generate_cells(f):
114 cell_dict = OrderedDict()
115 for special in f.specials:
116 if isinstance(special, Instance):
117 port_list = []
118 for port in special.items:
119 if isinstance(port, Instance.Input):
120 port_list.append(_Port(port.name, "INPUT"))
121 elif isinstance(port, Instance.Output):
122 port_list.append(_Port(port.name, "OUTPUT"))
123 elif isinstance(port, Instance.InOut):
124 port_list.append(_Port(port.name, "INOUT"))
125 elif isinstance(port, Instance.Parameter):
126 pass
127 else:
128 raise NotImplementedError("Unsupported instance item")
129 if special.of in cell_dict:
130 if set(port_list) != set(cell_dict[special.of]):
131 raise ValueError("All instances must have the same ports for EDIF conversion")
132 else:
133 cell_dict[special.of] = port_list
134 else:
135 raise ValueError("EDIF conversion can only handle synthesized fragments")
136 return [_Cell(k, v) for k, v in cell_dict.items()]
137
138
139 def _generate_instances(f, ns):
140 instances = []
141 for special in f.specials:
142 if isinstance(special, Instance):
143 props = []
144 for prop in special.items:
145 if isinstance(prop, Instance.Input):
146 pass
147 elif isinstance(prop, Instance.Output):
148 pass
149 elif isinstance(prop, Instance.InOut):
150 pass
151 elif isinstance(prop, Instance.Parameter):
152 props.append(_Property(name=prop.name, value=prop.value))
153 else:
154 raise NotImplementedError("Unsupported instance item")
155 instances.append(_Instance(name=ns.get_name(special), cell=special.of, properties=props))
156 else:
157 raise ValueError("EDIF conversion can only handle synthesized fragments")
158 return instances
159
160
161 def _generate_ios(f, ios, ns):
162 outs = list_special_ios(f, False, True, False)
163 inouts = list_special_ios(f, False, False, True)
164 r = []
165 for io in ios:
166 direction = "OUTPUT" if io in outs else "INOUT" if io in inouts else "INPUT"
167 r.append(_Port(name=ns.get_name(io), direction=direction))
168 return r
169
170
171 def _generate_connections(f, ios, ns):
172 r = OrderedDict()
173 for special in f.specials:
174 if isinstance(special, Instance):
175 instname = ns.get_name(special)
176 for port in special.items:
177 if isinstance(port, Instance._IO):
178 s = ns.get_name(port.expr)
179 if s not in r:
180 r[s] = []
181 r[s].append(_NetBranch(portname=port.name, instancename=instname))
182 elif isinstance(port, Instance.Parameter):
183 pass
184 else:
185 raise NotImplementedError("Unsupported instance item")
186 else:
187 raise ValueError("EDIF conversion can only handle synthesized fragments")
188 for s in ios:
189 io = ns.get_name(s)
190 if io not in r:
191 r[io] = []
192 r[io].append(_NetBranch(portname=io, instancename=""))
193 return r
194
195
196 def convert(f, ios, cell_library, vendor, device, name="top"):
197 if not isinstance(f, _Fragment):
198 f = f.get_fragment()
199 if f.comb != [] or f.sync != {}:
200 raise ValueError("EDIF conversion can only handle synthesized fragments")
201 if ios is None:
202 ios = set()
203 cells = _generate_cells(f)
204 ns = build_namespace(list_special_ios(f, True, True, True))
205 instances = _generate_instances(f, ns)
206 inouts = _generate_ios(f, ios, ns)
207 connections = _generate_connections(f, ios, ns)
208 src = _write_edif(cells, inouts, instances, connections, cell_library, name, device, vendor)
209
210 r = ConvOutput()
211 r.set_main_source(src)
212 r.ns = ns
213 return r