-
Notifications
You must be signed in to change notification settings - Fork 0
/
passive_interposer.py
240 lines (223 loc) · 15.7 KB
/
passive_interposer.py
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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
from system import System_25D
import os
import util.fill_space
import subprocess
class PassiveInterposer(System_25D):
"""docstring for Passive"""
def __init__(self):
self.chiplet_count = 0
self.width = [None] * self.chiplet_count
self.height = [None] * self.chiplet_count
self.hubump = [None] * self.chiplet_count
self.power = [None] * self.chiplet_count
self.rotation = [None] * self.chiplet_count
self.x = [None] * self.chiplet_count
self.y = [None] * self.chiplet_count
self.link_type = 'nppl'
self.length_threshold = 9
def gen_flp(self, filename):
# material properties
UnderFill = "\t2.32E+06\t0.625\n"
Copper = "\t3494400\t0.0025\n"
Silicon = "\t1.75E+06\t0.01\n"
resistivity_Cu = 0.0025
resistivity_UF = 0.625
resistivity_Si = 0.01
specHeat_Cu = 3494400
specHeat_UF = 2320000
specHeat_Si = 1750000
C4_diameter = 0.000250 #250um
C4_edge = 0.000600 #600um
TSV_diameter = 0.000010 #10um
TSV_edge = 0.000050 #50um
ubump_diameter = 0.000025 #25um
ubump_edge = 0.000045 #45um
Aratio_C4 = (C4_edge/C4_diameter)*(C4_edge/C4_diameter)-1 # ratio of white area and C4 area
Aratio_TSV= (TSV_edge/TSV_diameter)*(TSV_edge/TSV_diameter)-1
Aratio_ubump=(ubump_edge/ubump_diameter)*(ubump_edge/ubump_diameter)-1
resistivity_C4=(1+Aratio_C4)*resistivity_Cu*resistivity_UF/(resistivity_UF+Aratio_C4*resistivity_Cu)
resistivity_TSV=(1+Aratio_TSV)*resistivity_Cu*resistivity_Si/(resistivity_Si+Aratio_TSV*resistivity_Cu)
resistivity_ubump=(1+Aratio_ubump)*resistivity_Cu*resistivity_UF/(resistivity_UF+Aratio_ubump*resistivity_Cu)
specHeat_C4=(specHeat_Cu+Aratio_C4*specHeat_UF)/(1+Aratio_C4)
specHeat_TSV=(specHeat_Cu+Aratio_TSV*specHeat_Si)/(1+Aratio_TSV)
specHeat_ubump=(specHeat_Cu+Aratio_ubump*specHeat_UF)/(1+Aratio_ubump)
mat_C4 = "\t"+str(specHeat_C4)+"\t"+str(resistivity_C4)+"\n"
mat_TSV = "\t"+str(specHeat_TSV)+"\t"+str(resistivity_TSV)+"\n"
mat_ubump = "\t"+str(specHeat_ubump)+"\t"+str(resistivity_ubump)+"\n"
with open(self.path + filename+ 'L0_Substrate.flp','w') as L0_Substrate:
L0_Substrate.write("# Floorplan for Substrate Layer with size "+str(self.intp_size/1000)+"x"+str(self.intp_size/1000)+" m\n")
L0_Substrate.write("# Line Format: <unit-name>\\t<width>\\t<height>\\t<left-x>\\t<bottom-y>\\t[<specific-heat>]\\t[<resistivity>]\n")
L0_Substrate.write("# all dimensions are in meters\n")
L0_Substrate.write("# comment lines begin with a '#' \n")
L0_Substrate.write("# comments and empty lines are ignored\n\n")
L0_Substrate.write("Substrate\t"+str(self.intp_size/1000)+"\t"+str(self.intp_size/1000)+"\t0.0\t0.0\n")
# os.system("perl util/tofig.pl -f 20 "+self.path+filename+"L0_Substrate.flp | fig2dev -L ps | ps2pdf - "+self.path+filename+"L0_Substrate.pdf")
with open(self.path+filename +'L1_C4Layer.flp','w') as L1_C4Layer:
L1_C4Layer.write("# Floorplan for C4 Layer \n")
L1_C4Layer.write("# Line Format: <unit-name>\\t<width>\\t<height>\\t<left-x>\\t<bottom-y>\\t[<specific-heat>]\\t[<resistivity>]\n")
L1_C4Layer.write("# all dimensions are in meters\n")
L1_C4Layer.write("# comment lines begin with a '#' \n")
L1_C4Layer.write("# comments and empty lines are ignored\n\n")
L1_C4Layer.write("C4Layer\t"+str(self.intp_size / 1000)+"\t"+str(self.intp_size / 1000)+"\t0.0\t0.0"+mat_C4)
# os.system("perl util/tofig.pl -f 20 "+self.path+filename+"L1_C4Layer.flp | fig2dev -L ps | ps2pdf - "+self.path+filename+"L1_C4Layer.pdf")
with open(self.path+filename +'L2_Interposer.flp','w') as L2_Interposer:
L2_Interposer.write("# Floorplan for Silicon Interposer Layer\n")
L2_Interposer.write("# Line Format: <unit-name>\\t<width>\\t<height>\\t<left-x>\\t<bottom-y>\\t[<specific-heat>]\\t[<resistivity>]\n")
L2_Interposer.write("# all dimensions are in meters\n")
L2_Interposer.write("# comment lines begin with a '#' \n")
L2_Interposer.write("# comments and empty lines are ignored\n\n")
L2_Interposer.write("Interposer\t"+str(self.intp_size / 1000)+"\t"+str(self.intp_size / 1000)+"\t0.0\t0.0"+mat_TSV)
# os.system("perl util/tofig.pl -f 20 "+self.path+filename+"L2_Interposer.flp | fig2dev -L ps | ps2pdf - "+self.path+filename+"L2_Interposer.pdf")
with open(self.path+filename + 'sim.flp','w') as SIMP:
with open(self.path + filename + 'L3.flp', 'w') as L3_UbumpLayer:
with open(self.path + filename + 'L4.flp', 'w') as L4_ChipLayer:
L3_UbumpLayer.write("# Floorplan for Microbump Layer \n")
L3_UbumpLayer.write("# Line Format: <unit-name>\\t<width>\\t<height>\\t<left-x>\\t<bottom-y>\\t[<specific-heat>]\\t[<resistivity>]\n")
L3_UbumpLayer.write("# all dimensions are in meters\n")
L3_UbumpLayer.write("# comment lines begin with a '#' \n")
L3_UbumpLayer.write("# comments and empty lines are ignored\n\n")
L4_ChipLayer.write("# Floorplan for Chip Layer\n")
L4_ChipLayer.write("# Line Format: <unit-name>\\t<width>\\t<height>\\t<left-x>\\t<bottom-y>\\t[<specific-heat>]\\t[<resistivity>]\n")
L4_ChipLayer.write("# all dimensions are in meters\n")
L4_ChipLayer.write("# comment lines begin with a '#' \n")
L4_ChipLayer.write("# comments and empty lines are ignored\n\n")
L3_UbumpLayer.write('Edge_0\t' + str(self.intp_size / 1000 - self.granularity / 1000) + '\t' + str(self.granularity / 2 / 1000) + '\t'+str(self.granularity/2/1000)+'\t0\t' + mat_ubump)
L3_UbumpLayer.write('Edge_1\t' + str(self.intp_size / 1000 - self.granularity / 1000) + '\t' + str(self.granularity / 2 / 1000) + '\t'+str(self.granularity/2/1000)+'\t'+ str(self.intp_size / 1000 - self.granularity / 2 / 1000)+'\t' + mat_ubump)
L3_UbumpLayer.write('Edge_2\t' + str(self.granularity / 2 / 1000) + '\t' + str(self.intp_size / 1000) + '\t0\t0\t' + mat_ubump)
L3_UbumpLayer.write('Edge_3\t' + str(self.granularity / 2 / 1000) + '\t' + str(self.intp_size / 1000) + '\t'+str(self.intp_size/1000-self.granularity / 2/1000)+'\t0\t' + mat_ubump)
L4_ChipLayer.write('Edge_0\t' + str(self.intp_size / 1000 - self.granularity / 1000) + '\t' + str(self.granularity / 2 / 1000) + '\t'+str(self.granularity/2/1000)+'\t0\t' + mat_ubump)
L4_ChipLayer.write('Edge_1\t' + str(self.intp_size / 1000 - self.granularity / 1000) + '\t' + str(self.granularity / 2 / 1000) + '\t'+str(self.granularity/2/1000)+'\t'+ str(self.intp_size / 1000 - self.granularity / 2 / 1000)+'\t' + mat_ubump)
L4_ChipLayer.write('Edge_2\t' + str(self.granularity / 2 / 1000) + '\t' + str(self.intp_size / 1000) + '\t0\t0\t' + mat_ubump)
L4_ChipLayer.write('Edge_3\t' + str(self.granularity / 2 / 1000) + '\t' + str(self.intp_size / 1000) + '\t'+str(self.intp_size/1000-self.granularity / 2/1000)+'\t0\t' + mat_ubump)
x_offset0, y_offset0 = self.granularity / 2 / 1000, self.granularity / 2 / 1000
index_ubump = 0
for i in range(0, self.chiplet_count):
x_offset1 = self.x[i] / 1000 - self.width[i] / 1000 * 0.5 - self.hubump[i] / 1000
y_offset1 = self.y[i] / 1000 - self.height[i] / 1000 * 0.5 - self.hubump[i] / 1000
if self.hubump[i] > 0:
L3_UbumpLayer.write("Ubump_"+str(index_ubump)+"\t"+str(self.width[i] / 1000 + self.hubump[i] / 1000)+"\t"+str(self.hubump[i] / 1000)+"\t"+str(x_offset1)+"\t"+str(y_offset1)+mat_ubump)
L3_UbumpLayer.write("Ubump_"+str(index_ubump+1)+"\t"+str(self.hubump[i] / 1000)+"\t"+str(self.height[i] / 1000 + self.hubump[i] / 1000)+"\t"+str(x_offset1)+"\t"+str(y_offset1+self.hubump[i] / 1000)+mat_ubump)
L3_UbumpLayer.write("Ubump_"+str(index_ubump+2)+"\t"+str(self.hubump[i] / 1000)+"\t"+str(self.height[i] / 1000 + self.hubump[i] / 1000)+"\t"+str(x_offset1+self.width[i] / 1000 + self.hubump[i] / 1000)+"\t"+str(y_offset1)+mat_ubump)
L3_UbumpLayer.write("Ubump_"+str(index_ubump+3)+"\t"+str(self.width[i] / 1000 + self.hubump[i] / 1000)+"\t"+str(self.hubump[i] / 1000)+"\t"+str(x_offset1+self.hubump[i] / 1000)+"\t"+str(y_offset1+self.height[i] / 1000 + self.hubump[i] / 1000)+mat_ubump)
L4_ChipLayer.write("Ubump_"+str(index_ubump)+"\t"+str(self.width[i] / 1000 + self.hubump[i] / 1000)+"\t"+str(self.hubump[i] / 1000)+"\t"+str(x_offset1)+"\t"+str(y_offset1)+Silicon)
L4_ChipLayer.write("Ubump_"+str(index_ubump+1)+"\t"+str(self.hubump[i] / 1000)+"\t"+str(self.height[i] / 1000 + self.hubump[i] / 1000)+"\t"+str(x_offset1)+"\t"+str(y_offset1+self.hubump[i] / 1000)+Silicon)
L4_ChipLayer.write("Ubump_"+str(index_ubump+2)+"\t"+str(self.hubump[i] / 1000)+"\t"+str(self.height[i] / 1000 + self.hubump[i] / 1000)+"\t"+str(x_offset1+self.width[i] / 1000 + self.hubump[i] / 1000)+"\t"+str(y_offset1)+Silicon)
L4_ChipLayer.write("Ubump_"+str(index_ubump+3)+"\t"+str(self.width[i] / 1000 + self.hubump[i] / 1000)+"\t"+str(self.hubump[i] / 1000)+"\t"+str(x_offset1+self.hubump[i] / 1000)+"\t"+str(y_offset1+self.height[i] / 1000 + self.hubump[i] / 1000)+Silicon)
index_ubump += 4
# not sure about the microbump density for the center region. Assume the same as the edge area so far. Need to be updated if the microbump pitch for center power/gnd clk is found
L3_UbumpLayer.write("Chiplet_"+str(i)+"\t"+str(self.width[i] / 1000)+"\t"+str(self.height[i] / 1000)+"\t"+str(x_offset1 + self.hubump[i] / 1000)+"\t"+str(y_offset1+self.hubump[i] / 1000)+mat_ubump)
L4_ChipLayer.write("Chiplet_"+str(i)+"\t"+str(self.width[i] / 1000)+"\t"+str(self.height[i] / 1000)+"\t"+str(x_offset1 + self.hubump[i] / 1000)+"\t"+str(y_offset1+self.hubump[i] / 1000)+Silicon)
SIMP.write("Unit_"+str(i)+"\t"+str(self.width[i] / 1000 + 2 * self.hubump[i] / 1000)+"\t"+str(self.height[i] / 1000 + 2 * self.hubump[i] / 1000)+"\t"+str(x_offset1)+"\t"+str(y_offset1)+"\n")
# os.system("perl util/tofig.pl -f 20 "+self.path+filename+"L3.flp | fig2dev -L ps | ps2pdf - "+self.path+filename+"L3.pdf")
# os.system("perl util/tofig.pl -f 20 "+self.path+filename+"L4.flp | fig2dev -L ps | ps2pdf - "+self.path+filename+"L4.pdf")
util.fill_space.fill_space(x_offset0, self.intp_size / 1000 - x_offset0, y_offset0, self.intp_size / 1000 - y_offset0, self.path+filename+'sim', self.path+filename+'L3', self.path+filename+'L3_UbumpLayer')
util.fill_space.fill_space(x_offset0, self.intp_size / 1000 - x_offset0, y_offset0, self.intp_size / 1000 - y_offset0, self.path+filename+'sim', self.path+filename+'L4', self.path+filename+'L4_ChipLayer')
# os.system("perl util/tofig.pl -f 20 "+self.path+filename+"L3_UbumpLayer.flp | fig2dev -L ps | ps2pdf - "+self.path+filename+"L3_UbumpLayer.pdf")
# os.system("perl util/tofig.pl -f 20 "+self.path+filename+"L4_ChipLayer.flp | fig2dev -L ps | ps2pdf - "+self.path+filename+"L4_ChipLayer.pdf")
with open(self.path+filename +'L5_TIM.flp','w') as L5_TIM:
L5_TIM.write("# Floorplan for TIM Layer \n")
L5_TIM.write("# Line Format: <unit-name>\\t<width>\\t<height>\\t<left-x>\\t<bottom-y>\\t[<specific-heat>]\\t[<resistivity>]\n")
L5_TIM.write("# all dimensions are in meters\n")
L5_TIM.write("# comment lines begin with a '#' \n")
L5_TIM.write("# comments and empty lines are ignored\n\n")
L5_TIM.write("TIM\t"+str(self.intp_size / 1000)+"\t"+str(self.intp_size / 1000)+"\t0.0\t0.0\n")
# os.system("perl util/tofig.pl -f 20 "+self.path+filename+"L5_TIM.flp | fig2dev -L ps | ps2pdf - "+self.path+filename+"L5_TIM.pdf")
with open(self.path+filename + 'layers.lcf','w') as LCF:
LCF.write("# File Format:\n")
LCF.write("#<Layer Number>\n")
LCF.write("#<Lateral heat flow Y/N?>\n")
LCF.write("#<Power Dissipation Y/N?>\n")
LCF.write("#<Specific heat capacity in J/(m^3K)>\n")
LCF.write("#<Resistivity in (m-K)/W>\n")
LCF.write("#<Thickness in m>\n")
LCF.write("#<floorplan file>\n")
LCF.write("\n# Layer 0: substrate\n0\nY\nN\n1.06E+06\n3.33\n0.0002\n"+self.path+filename+"L0_Substrate.flp\n")
LCF.write("\n# Layer 1: Epoxy SiO2 underfill with C4 copper pillar\n1\nY\nN\n2.32E+06\n0.625\n0.00007\n"+self.path+filename+"L1_C4Layer.flp\n")
LCF.write("\n# Layer 2: silicon interposer\n2\nY\nN\n1.75E+06\n0.01\n0.00011\n"+self.path+filename+"L2_Interposer.flp\n")
LCF.write("\n# Layer 3: Underfill with ubump\n3\nY\nN\n2.32E+06\n0.625\n1.00E-05\n"+self.path+filename+"L3_UbumpLayer.flp\n")
LCF.write("\n# Layer 4: Chip layer\n4\nY\nY\n1.75E+06\n0.01\n0.00015\n"+self.path+filename+"L4_ChipLayer.flp\n")
LCF.write("\n# Layer 5: TIM\n5\nY\nN\n4.00E+06\n0.25\n2.00E-05\n"+self.path+filename+"L5_TIM.flp\n")
if os.path.isfile(self.path + 'new_hotspot.config') == False:
with open('util/hotspot.config','r') as Config_in:
with open(self.path + 'new_hotspot.config','w') as Config_out:
size_spreader = 2 * self.intp_size / 1000
size_heatsink = 2 * size_spreader
r_convec = 0.1 * 0.06 * 0.06 / size_heatsink / size_heatsink #0.1*0.06*0.06 are from default hotspot.config file
for line in Config_in:
if line == ' -s_sink 0.06\n':
Config_out.write(line.replace('0.06',str(size_heatsink)))
elif line == ' -s_spreader 0.03\n':
Config_out.write(line.replace('0.03',str(size_spreader)))
elif line == ' -r_convec 0.1\n':
Config_out.write(line.replace('0.1',str(r_convec)))
else:
Config_out.write(line)
def gen_ptrace(self, filename):
num_component = 0
component, component_name, component_index = [], [], []
# Read components from flp file
with open (self.path + filename + 'L4_ChipLayer.flp','r') as FLP:
for line in FLP:
line_sp = line.split()
if line_sp:
if line_sp[0] != '#':
component.append(line_sp[0])
comp = component[num_component].split('_')
component_name.append(comp[0])
component_index.append(int(comp[1]))
num_component+=1
with open (self.path + filename + '.ptrace','w') as Ptrace:
# Write ptrace header
for i in range(0,num_component):
# if component_name[i] == 'Core':
Ptrace.write(component[i]+'\t')
Ptrace.write('\n')
for i in range(0,num_component):
if component_name[i] == 'Chiplet':
Ptrace.write(str(self.power[component_index[i]])+'\t')
# elif component_name[i] == 'Ubump':
# Ptrace.write('0.3\t')
else:
Ptrace.write('0\t')
Ptrace.write('\n')
def run_hotspot(self, filename):
proc = subprocess.Popen(["./util/hotspot",
"-c",self.path+"new_hotspot.config",
"-f",self.path+filename+"L4_ChipLayer.flp",
"-p",self.path+filename+".ptrace",
"-steady_file",self.path+filename+".steady",
"-grid_steady_file",self.path+filename+".grid.steady",
"-model_type","grid",
"-detailed_3D","on",
"-grid_rows","128",
"-grid_cols","128",
"-grid_layer_file",self.path+filename+"layers.lcf"],
stdout=subprocess.PIPE, stderr = subprocess.PIPE)
stdout, stderr = proc.communicate()
outlist = stdout.split()
return (max(list(map(float,outlist[3::2])))-273.15)
def clean_hotspot(self, filename):
os.system('rm ' + self.path + filename + '{*.flp,*.lcf,*.ptrace,*.steady}')
def compute_ubump_overhead(self):
# print (self.link_type)
connection = self.connection_matrix
for i in range(self.chiplet_count):
assert connection[i][i] == 0, 'a link from and to the same chiplet is not allowed'
s = 0
for j in range(self.chiplet_count):
s += connection[i][j] + connection[j][i]
if self.link_type == 'ppl':
s *= 2
h = 1
w_stretch = 0.045 * h
while ((self.width[i] + self.height[i]) * 2 * w_stretch + 4 * w_stretch * w_stretch) / 0.045 / 0.045 < s:
h += 1
w_stretch = 0.045 * h
if h > 1000:
print ('microbump is too high to be a feasible case')
exit()
# print (i, s, self.width[i], self.height[i], h, w_stretch)
self.hubump[i] = w_stretch
# print (self.hubump)
def set_link_type(self, link_type):
self.link_type = link_type