whitespace tidyup
[soclayout.git] / experiments7 / doAlu16.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 from __future__ import print_function
4 import sys
5 import re
6
7 import CRL
8 import Cfg
9 from Hurricane import Box
10 from Hurricane import Transformation
11 from Hurricane import Breakpoint
12 from Hurricane import Instance
13 from coriolis2.settings import af
14 from utils import Module, SessionManager, Config
15
16 import symbolic.cmos # do not remove
17
18 BIT_WIDTH = 16
19
20
21 def coriolis_setup():
22 with Config(Cfg.Parameter.Priority.UserFile) as cfg:
23 cfg.misc_catchCore = False
24 cfg.misc_info = False
25 cfg.misc_paranoid = False
26 cfg.misc_bug = False
27 cfg.misc_logMode = True
28 cfg.misc_verboseLevel1 = True
29 cfg.misc_verboseLevel2 = True
30 cfg.etesian_effort = 2
31 cfg.etesian_spaceMargin = "10.0%"
32 cfg.etesian_aspectRatio = "100.0%"
33 cfg.etesian_uniformDensity = True
34 cfg.anabatic_edgeLenght = 24
35 cfg.anabatic_edgeWidth = 8
36 cfg.anabatic_topRoutingLayer = 'METAL5'
37 cfg.katana_searchHalo = 30
38 cfg.katana_eventsLimit = 1000000
39 cfg.katana_hTracksReservedLocal = 7
40 cfg.katana_vTracksReservedLocal = 6
41
42 env = af.getEnvironment()
43 env.setCLOCK('^clk$|m_clock')
44 env.setPOWER('vdd')
45 env.setGROUND('vss')
46
47
48 class AddSub(Module):
49
50 def build(self):
51 """ Main routine. """
52
53 with SessionManager():
54 #self.compute_ab()
55 self.create_pins()
56
57 if self.editor:
58 self.editor.setCell(self.cell)
59
60 result = self.place_and_route()
61
62 with SessionManager():
63 self.create_pads()
64
65 self.save()
66 return result
67
68
69 class ALU16(Module):
70
71 @staticmethod
72 def match_instance(datapath_insts, op, plug_name, inst):
73 """
74 Guess the position of an instance from its nets connections,
75 and put it at the right place in the datapath vector.
76
77 :param datapath_insts: vector of bit slices,
78 :param op: operator name,
79 :param inst: instance to classify,
80 :param plug_name: name of the plug to use to guess the bit index,
81 :return: boolean, True if the instance has been matched.
82 """
83 if not inst.getMasterCell().getName().startswith(op):
84 return False
85 re_net_index = re.compile(r'[^(]+\((?P<index>[\d]+)\)$')
86 for plug in inst.getPlugs():
87 if plug.getMasterNet().getName() != plug_name:
88 continue
89 m = re_net_index.match(plug.getNet().getName())
90 if not m:
91 continue
92 bit_slice = datapath_insts[int(m.group('index'))]
93 for column in bit_slice:
94 if column[0] == op:
95 column[1] = inst
96 return True
97 break
98 return False
99
100 def place_datapath(self, datapath_insts, x_orig, y_orig, fold):
101 channel_sff1 = self.to_dbu(0)
102 with SessionManager():
103 slice_height = self.to_dbu(50.0)
104 for i in range(len(datapath_insts)):
105 if not i%fold:
106 x = self.to_dbu(x_orig)
107 slice = i/fold
108 if slice%2:
109 y = self.to_dbu(y_orig) + slice_height*(slice+1)
110 orient = Transformation.Orientation.MY
111 else:
112 y = self.to_dbu(y_orig) + slice_height*slice
113 orient = Transformation.Orientation.ID
114
115 for (opname, inst) in datapath_insts[i]:
116 if opname == 'sff1':
117 x += channel_sff1
118 inst.setTransformation(Transformation(x, y, orient))
119 inst.setPlacementStatus(Instance.PlacementStatus.PLACED)
120 x += inst.getAbutmentBox().getWidth()
121
122 def place(self):
123 """ALU16.place(), manual placement overload."""
124 datapath_insts = []
125 for i in range(BIT_WIDTH):
126 datapath_insts.append([['nmx2', None],
127 ['no2', None],
128 ['sff1', None]])
129
130 for inst in self.cell.getInstances():
131 if (ALU16.match_instance(datapath_insts, 'nmx2', 'i0', inst) or
132 ALU16.match_instance(datapath_insts, 'no2', 'nq', inst) or
133 ALU16.match_instance(datapath_insts, 'sff1', 'i', inst)):
134 continue
135
136 # place to right of add
137 add, sub = self.submodules
138 add_wid = self.from_dbu(add.ab.getWidth())
139 self.place_datapath(datapath_insts, add_wid, 40.0, 1)
140
141 def save(self):
142 self.name = self.name + '_r'
143 self.af.saveCell(self.cell, CRL.Catalog.State.Views)
144 super(ALU16, self).save()
145
146 def build(self):
147
148 h_margin = 0.0
149 v_margin = 40.0
150
151 if not self.build_submodules():
152 return False
153
154 # at this point we have the (auto-calculated) submodules' dimensions
155 # in their `ab` properties.
156
157 add, sub = self.submodules
158
159 with SessionManager():
160 self.compute_ab()
161
162 width = self.from_dbu(
163 self.ab.getWidth() + add.ab.getWidth() + sub.ab.getWidth()
164 ) + 4*h_margin
165 height = self.from_dbu(max([
166 self.ab.getHeight(), add.ab.getHeight(), sub.ab.getHeight()
167 ])) + v_margin
168
169 # experiment, over-ride
170 width = 490
171 #width = 1310
172 #height = 370
173
174 self.ab = Box(0, 0, self.to_dbu(width), self.to_dbu(height))
175
176 add_wid = self.from_dbu(add.ab.getWidth())
177 sub_ht = self.from_dbu(sub.ab.getHeight())
178 sub_wid = self.from_dbu(sub.ab.getWidth())
179
180 self.place_submodule(add, 0, v_margin)
181 self.place_submodule(sub, width-sub_wid, v_margin)
182
183 # TODO: replace with some form of lazy evaluation?
184 y_north = self.from_dbu(self.ab.getYMax())
185 for pin_conf in self.north_pins:
186 pin_conf['y'] = y_north
187
188 self.create_pins()
189
190 if self.editor:
191 self.editor.setCell(self.cell)
192
193 # place first (in middle, between two)
194 # this puts all the remaining cells (little ones)
195 # into this (small) space so that they do not go
196 # "all over the place" around the add and sub
197
198 # XXX this doesn't work: box is far too big, covers the entire
199 # area (including "under" the add and sub)
200 #self.ab = Box(
201 # self.to_dbu((width-self.ab_width)/2 - h_margin),
202 # self.to_dbu(v_margin),
203 # self.to_dbu((width+self.ab_width)/2 + h_margin),
204 # self.to_dbu(height - v_margin)
205 #)
206 #self.ab = Box(self.to_dbu(475), self.to_dbu(10),
207 # self.to_dbu(840), self.to_dbu(360))
208 self.ab = Box(0, 0, self.to_dbu(width), self.to_dbu(height))
209 self.place() # place only
210
211 # then route (globally)
212 # this connects up not just in the remaining (little) cells,
213 # it connects *to add and sub and the outside world as well*
214 result = self.route()
215
216 self.save()
217 return result
218
219
220 def scriptMain(editor=None, **kwargs):
221 coriolis_setup()
222
223 add = AddSub(
224 'add', editor,
225 east_pins=[
226 {'net': 'a({})', 'y': 15.0, 'delta': 50.0,
227 'repeat': BIT_WIDTH, 'layer': 'METAL2'},
228 {'net': 'b({})', 'y': 20.0, 'delta': 50.0,
229 'repeat': BIT_WIDTH, 'layer': 'METAL2'},
230 {'net': 'o({})', 'y': 25.0, 'delta': 50.0,
231 'repeat': BIT_WIDTH, 'layer': 'METAL2'},
232 ],
233 pads={
234 'b({})'.format(BIT_WIDTH-1): (
235 'BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4',
236 ),
237 },
238 orientation=Transformation.Orientation.ID,
239 )
240 add.set_ab(160.0, 800.0)
241 sub = AddSub(
242 'sub', editor,
243 west_pins=[
244 {'net': 'a({})', 'y': 15.0, 'delta': 50.0,
245 'repeat': BIT_WIDTH, 'layer': 'METAL2'},
246 {'net': 'b({})', 'y': 20.0, 'delta': 50.0,
247 'repeat': BIT_WIDTH, 'layer': 'METAL2'},
248 {'net': 'o({})', 'y': 25.0, 'delta': 50.0,
249 'repeat': BIT_WIDTH, 'layer': 'METAL2'},
250 ],
251 pads={
252 'b({})'.format(BIT_WIDTH-1): (
253 'BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4',
254 ),
255 },
256 orientation=Transformation.Orientation.ID,
257 )
258 sub.set_ab(165.0, 800.0)
259
260 o = 00.0
261 alu16 = ALU16(
262 'alu16', editor, submodules=[add, sub],
263 north_pins=[
264 {'net': 'o({})', 'x': 245.0+o, 'delta': 5.0, 'repeat': BIT_WIDTH},
265 {'net': 'op'},
266 ],
267 south_pins=[
268 {'net': 'a({})', 'x': 195.0+o, 'delta': 10.0, 'repeat': BIT_WIDTH},
269 {'net': 'b({})', 'x': 200.0+o, 'delta': 10.0, 'repeat': BIT_WIDTH},
270 ],
271 east_pins=[
272 {'net': 'rst', 'y': 10.0, 'layer': 'METAL2'},
273 ],
274 )
275 return alu16.build()
276
277
278 if __name__ == '__main__':
279 kwargs = {}
280 success = scriptMain(**kwargs)
281 shellSuccess = 0
282 if not success:
283 shellSuccess = 1
284
285 sys.exit(shellSuccess)