forked from patrickschulz/openPCells
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtechnology.lua
221 lines (206 loc) · 6.85 KB
/
technology.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
local M = {}
local layermap
local config
-- make relative metal (negative indices) absolute
function M.translate_metals(cell)
for _, S in cell:iter(function(S) return S.lpp:is_type("metal") end) do
if S.lpp.value < 0 then
S.lpp.value = config.metals + S.lpp.value + 1
end
end
for _, S in cell:iter(function(S) return S.lpp:is_type("via") end) do
local value = S.lpp.value
if value.from < 0 then
value.from = config.metals + value.from + 1
end
if value.to < 0 then
value.to = config.metals + value.to + 1
end
-- reorder
if value.from > value.to then
value.from, value.to = value.to, value.from
end
end
end
function M.place_via_conductors(cell)
for _, S in cell:iter() do
if S.lpp:is_type("via") then
local m1, m2 = S.lpp:get()
local s1 = S:copy()
s1.lpp = generics.metal(m1)
local s2 = S:copy()
s2.lpp = generics.metal(m2)
cell:add_shape(s1)
cell:add_shape(s2)
elseif S.lpp:is_type("contact") then
-- FIXME: can't place active contact surrounding as this needs more data than available here
local smetal = S:copy()
smetal.lpp = generics.metal(1)
cell:add_shape(smetal)
end
end
end
function M.split_vias(cell)
for i, S in cell:iter(function(S) return S:is_lpp_type("via") end) do
local from, to = S.lpp:get()
for j = from, to - 1 do
local sc = S:copy()
sc.lpp = generics.via(j, j + 1)
cell:add_shape(sc)
end
cell:remove_shape(i)
end
end
local function _get_lpp(lpp, interface)
if type(lpp) == "function" then
lpp = lpp()
end
if not lpp[interface] then
error(string.format("no layer information for interface '%s'", interface))
end
return lpp[interface]
end
local function _do_map(cell, S, entry, interface)
entry = entry.func(S.lpp:get())
if entry.lpp then
local new = S:copy()
new.lpp = generics.mapped(_get_lpp(entry.lpp, interface))
if entry.left > 0 or
entry.right > 0 or
entry.top > 0 or
entry.bottom > 0
then -- this check ensures that not-resized polygons work
new:resize_lrtb(entry.left, entry.right, entry.top, entry.bottom)
end
cell:add_shape(new)
end
end
local function _do_array(cell, S, entry, interface)
entry = entry.func(S.lpp:get())
local lpp = entry.lpp
local width = S:width()
local height = S:height()
local c = S:center()
local xrep = math.max(1, math.floor((width + entry.xspace - 2 * entry.xencl) / (entry.width + entry.xspace)))
local yrep = math.max(1, math.floor((height + entry.yspace - 2 * entry.yencl) / (entry.height + entry.yspace)))
local xpitch = entry.width + entry.xspace
local ypitch = entry.height + entry.yspace
local enlarge = 0
local cut = geometry.multiple(
geometry.rectangle(generics.mapped(_get_lpp(lpp, interface)), entry.width + enlarge, entry.height + enlarge),
xrep, yrep, xpitch, ypitch
)
cell:merge_into(cut:translate(c:unwrap()))
end
function M.translate(cell, interface)
for i, S in cell:iter() do
local layer = S.lpp:str()
local mappings = layermap[layer]
if not mappings then
error(string.format("no layer information for '%s'\nif the layer is not provided, set it to {}", layer))
end
for _, entry in ipairs(mappings) do
if entry.action == "map" then
_do_map(cell, S, entry, interface)
elseif entry.action == "array" then
_do_array(cell, S, entry, interface)
end
end
cell:remove_shape(i)
end
--[[
for _, port in pairs(cell.ports) do
local layer = port.layer:str()
end
--]]
end
function M.fix_to_grid(cell)
for _, s in cell:iter() do
for _, pt in pairs(s.points) do
pt:fix(config.grid)
end
end
end
local function _load_layermap(name)
local env = {
map = function(entry)
if type(entry) == "function" then
return {
action = "map",
func = entry,
}
else -- table
return {
action = "map",
func = function()
return {
lpp = entry.lpp,
left = entry.left or 0,
right = entry.right or 0,
top = entry.top or 0,
bottom = entry.bottom or 0,
}
end,
}
end
end,
array = function(entry)
if type(entry) == "function" then
return {
action = "array",
func = entry
}
else
return {
action = "array",
func = function()
return {
lpp = entry.lpp,
width = entry.width,
height = entry.height,
xspace = entry.xspace,
yspace = entry.yspace,
xencl = entry.xencl,
yencl = entry.yencl,
}
end,
}
end
end,
refer = function(reference)
return function()
return layermap[reference]
end
end,
}
local filename = string.format("%s/tech/%s/layermap.lua", _get_opc_home(), name)
local chunkname = "@techfile"
local reader = _get_reader(filename)
if not reader then
error(string.format("no techfile for technology '%s' found", name))
end
return _generic_load(
reader, chunkname,
string.format("syntax error while loading layermap for technology '%s'", name),
string.format("semantic error while loading layermap for technology '%s'", name),
env
)
end
local function _load_config(name)
local filename = string.format("%s/tech/%s/config.lua", _get_opc_home(), name)
local chunkname = "@techconfig"
local reader = _get_reader(filename)
if not reader then
error(string.format("no config for technology '%s' found", name))
end
return _generic_load(
reader, chunkname,
string.format("syntax error while loading config for technology '%s'", name),
string.format("semantic error while loading config for technology '%s'", name)
)
end
function M.load(name)
layermap = _load_layermap(name)
config = _load_config(name)
end
return M