mirror of https://github.com/VLSIDA/OpenRAM.git
279 lines
8.3 KiB
Plaintext
279 lines
8.3 KiB
Plaintext
|
|
<?xml version="1.0" encoding="utf-8"?>
|
||
|
|
<klayout-macro>
|
||
|
|
<description/>
|
||
|
|
<version/>
|
||
|
|
<category>lvs</category>
|
||
|
|
<prolog/>
|
||
|
|
<epilog/>
|
||
|
|
<doc/>
|
||
|
|
<autorun>false</autorun>
|
||
|
|
<autorun-early>false</autorun-early>
|
||
|
|
<shortcut/>
|
||
|
|
<show-in-menu>true</show-in-menu>
|
||
|
|
<group-name>lvs_scripts</group-name>
|
||
|
|
<menu-path>tools_menu.lvs.end</menu-path>
|
||
|
|
<interpreter>dsl</interpreter>
|
||
|
|
<dsl-interpreter-name>lvs-dsl-xml</dsl-interpreter-name>
|
||
|
|
<text>#
|
||
|
|
tstart = Time.now
|
||
|
|
# Extraction for SKY130
|
||
|
|
#
|
||
|
|
############################
|
||
|
|
|
||
|
|
# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=my_report.lyrdb -rd schematic=reference_netlist.cir -rd target_netlist=extracted_netlist.cir -r lvs_sky130.lvs
|
||
|
|
if $input
|
||
|
|
source($input)
|
||
|
|
end
|
||
|
|
|
||
|
|
if $report
|
||
|
|
report_lvs($report)
|
||
|
|
else
|
||
|
|
report_lvs("lvs_report.lvsdb")
|
||
|
|
end
|
||
|
|
|
||
|
|
if $schematic
|
||
|
|
#reference netlist
|
||
|
|
schematic($schematic)
|
||
|
|
else
|
||
|
|
schematic(RBA::CellView::active.filename.sub(/\.(oas|gds|oas.gz|gds.gz)$/, ".sp"))
|
||
|
|
end
|
||
|
|
|
||
|
|
# true: use net names instead of numbers
|
||
|
|
# false: use numbers for nets
|
||
|
|
spice_with_net_names = true
|
||
|
|
|
||
|
|
# true: put in comments with details
|
||
|
|
# false: no comments
|
||
|
|
spice_with_comments = true
|
||
|
|
|
||
|
|
if $target_netlist
|
||
|
|
target_netlist($target_netlist)
|
||
|
|
else
|
||
|
|
target_netlist(File.join(File.dirname(RBA::CellView::active.filename), source.cell_name+"_extracted.cir"), write_spice(spice_with_net_names, spice_with_comments), "Extracted by KLayout on : #{Time.now.strftime("%d/%m/%Y %H:%M")}")
|
||
|
|
end
|
||
|
|
|
||
|
|
# klayout setup
|
||
|
|
########################
|
||
|
|
# Hierarchical mode
|
||
|
|
deep
|
||
|
|
# Use 4 CPU cores
|
||
|
|
threads(4)
|
||
|
|
# Print details
|
||
|
|
verbose(true)
|
||
|
|
|
||
|
|
# layers definitions
|
||
|
|
########################
|
||
|
|
|
||
|
|
|
||
|
|
# LVS section
|
||
|
|
########################
|
||
|
|
info("LVS section")
|
||
|
|
# layers definitions
|
||
|
|
########################
|
||
|
|
BOUND = polygons(235, 4)
|
||
|
|
DNWELL = polygons(64, 18)
|
||
|
|
PWRES = polygons(64, 13)
|
||
|
|
NWELL = polygons(64, 20)
|
||
|
|
NWELLTXT = input(64, 5)
|
||
|
|
NWELLPIN = polygons(64, 16)
|
||
|
|
SUBTXT = input(122, 5)
|
||
|
|
SUBPIN = input(64, 59)
|
||
|
|
DIFF = polygons(65, 20)
|
||
|
|
TAP = polygons(65, 44)
|
||
|
|
PSDM = polygons(94, 20)
|
||
|
|
NSDM = polygons(93, 44)
|
||
|
|
LVTN = polygons(125, 44)
|
||
|
|
HVTR = polygons(18, 20)
|
||
|
|
HVTP = polygons(78, 44)
|
||
|
|
SONOS = polygons(80, 20)
|
||
|
|
COREID = polygons(81, 2)
|
||
|
|
STDCELL = polygons(81, 4)
|
||
|
|
NPNID = polygons(82, 20)
|
||
|
|
PNPID = polygons(82, 44)
|
||
|
|
RPM = polygons(86, 20)
|
||
|
|
URPM = polygons(79, 20)
|
||
|
|
LDNTM = polygons(11, 44)
|
||
|
|
HVNTM = polygons(125, 20)
|
||
|
|
POLY = polygons(66, 20)
|
||
|
|
POLYTXT = input(66, 5)
|
||
|
|
POLYPIN = polygons(66, 16)
|
||
|
|
HVI = polygons(75, 20)
|
||
|
|
LICON = polygons(66, 44)
|
||
|
|
NPC = polygons(95, 20)
|
||
|
|
DIFFRES = polygons(65, 13)
|
||
|
|
POLYRES = polygons(66, 13)
|
||
|
|
POLYSHO = polygons(66, 15)
|
||
|
|
DIODE = polygons(81, 23)
|
||
|
|
LI = polygons(67, 20)
|
||
|
|
LITXT = input(67, 5)
|
||
|
|
LIPIN = polygons(67, 16)
|
||
|
|
LIRES = polygons(67, 13)
|
||
|
|
MCON = polygons(67, 44)
|
||
|
|
MET1 = polygons(68, 20)
|
||
|
|
MET1TXT = input(68, 5)
|
||
|
|
MET1PIN = polygons(68, 16)
|
||
|
|
MET1RES = polygons(68, 13)
|
||
|
|
VIA1 = polygons(68, 44)
|
||
|
|
MET2 = polygons(69, 20)
|
||
|
|
MET2TXT = input(69, 5)
|
||
|
|
MET2PIN = polygons(69, 16)
|
||
|
|
MET2RES = polygons(69, 13)
|
||
|
|
VIA2 = polygons(69, 44)
|
||
|
|
MET3 = polygons(70, 20)
|
||
|
|
MET3TXT = input(70, 5)
|
||
|
|
MET3PIN = polygons(70, 16)
|
||
|
|
MET3RES = polygons(70, 13)
|
||
|
|
VIA3 = polygons(70, 44)
|
||
|
|
MET4 = polygons(71, 20)
|
||
|
|
MET4TXT = input(71, 5)
|
||
|
|
MET4PIN = polygons(71, 16)
|
||
|
|
MET4RES = polygons(71, 13)
|
||
|
|
VIA4 = polygons(71, 44)
|
||
|
|
MET5 = polygons(72, 20)
|
||
|
|
MET5TXT = input(72, 5)
|
||
|
|
MET5PIN = polygons(72, 16)
|
||
|
|
MET5RES = polygons(72, 13)
|
||
|
|
RDL = polygons(74, 20)
|
||
|
|
RDLTXT = input(74, 5)
|
||
|
|
RDLPIN = polygons(74, 16)
|
||
|
|
GLASS = polygons(76, 20)
|
||
|
|
CAPM = polygons(89, 44)
|
||
|
|
CAPM2 = polygons(97, 44)
|
||
|
|
LOWTAPD = polygons(81, 14)
|
||
|
|
FILLOBSM1 = polygons(62, 24)
|
||
|
|
FILLOBSM2 = polygons(105, 52)
|
||
|
|
FILLOBSM3 = polygons(107, 24)
|
||
|
|
FILLOBSM4 = polygons(112, 4)
|
||
|
|
NCM = polygons(92, 44)
|
||
|
|
|
||
|
|
# Bulk layer for terminal provisioning
|
||
|
|
SUB = polygons(236, 0)
|
||
|
|
# SUB = polygon_layer
|
||
|
|
|
||
|
|
# Computed layers
|
||
|
|
PDIFF = DIFF & NWELL & PSDM
|
||
|
|
NTAP = TAP & NWELL & NSDM
|
||
|
|
PGATE = PDIFF & POLY
|
||
|
|
PSD = PDIFF - PGATE
|
||
|
|
CORE_PGATE = PGATE & COREID
|
||
|
|
STD_PGATE = PGATE - HVTP - NCM - HVI - COREID
|
||
|
|
HVT_PGATE = PGATE & HVTP - NCM - HVI
|
||
|
|
HV5_PGATE = PGATE - HVTP - NCM & HVI
|
||
|
|
|
||
|
|
NDIFF = DIFF - NWELL & NSDM
|
||
|
|
PTAP = TAP - NWELL & PSDM
|
||
|
|
NGATE = NDIFF & POLY
|
||
|
|
NSD = NDIFF - NGATE
|
||
|
|
CORE_NGATE = NGATE & COREID
|
||
|
|
STD_NGATE = NGATE - NCM - LVTN - HVI
|
||
|
|
LVT_NGATE = NGATE - NCM & LVTN - HVI
|
||
|
|
HV5_NGATE = NGATE - NCM - LVTN & HVI
|
||
|
|
HV5NA_NGATE = NGATE - NCM & LVTN & HVI
|
||
|
|
|
||
|
|
# drawing to physical
|
||
|
|
device_scaling(1000000)
|
||
|
|
|
||
|
|
# PMOS transistor device extraction
|
||
|
|
extract_devices(mos4("sky130_fd_pr__special_pfet_latch"), { "SD" => PSD, "G" => CORE_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL })
|
||
|
|
extract_devices(mos4("sky130_fd_pr__pfet_01v8"), { "SD" => PSD, "G" => STD_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL })
|
||
|
|
extract_devices(mos4("sky130_fd_pr__pfet_01v8_hvt"), { "SD" => PSD, "G" => HVT_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL })
|
||
|
|
extract_devices(mos4("sky130_fd_pr__pfet_g5v0d10v5"), { "SD" => PSD, "G" => HV5_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL })
|
||
|
|
|
||
|
|
# NMOS transistor device extraction
|
||
|
|
extract_devices(mos4("sky130_fd_pr__special_nfet_latch"), { "SD" => NSD, "G" => CORE_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB })
|
||
|
|
extract_devices(mos4("sky130_fd_pr__nfet_01v8"), { "SD" => NSD, "G" => STD_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB })
|
||
|
|
extract_devices(mos4("sky130_fd_pr__nfet_01v8_lvt"), { "SD" => NSD, "G" => LVT_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB })
|
||
|
|
extract_devices(mos4("sky130_fd_pr__nfet_g5v0d10v5"), { "SD" => NSD, "G" => HV5_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB })
|
||
|
|
extract_devices(mos4("sky130_fd_pr__nfet_01v8_nvt"), { "SD" => NSD, "G" => HV5NA_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB })
|
||
|
|
|
||
|
|
|
||
|
|
# Define connectivity for netlist extraction
|
||
|
|
|
||
|
|
# Inter-layer
|
||
|
|
connect(SUB, PTAP)
|
||
|
|
connect(NWELL, NTAP)
|
||
|
|
connect(LICON, PTAP)
|
||
|
|
connect(LICON, NTAP)
|
||
|
|
connect(PSD, LICON)
|
||
|
|
connect(NSD, LICON)
|
||
|
|
connect(POLY, LICON)
|
||
|
|
connect(LICON, LI)
|
||
|
|
connect(LI, MCON)
|
||
|
|
connect(MCON, MET1)
|
||
|
|
connect(MET1,VIA1)
|
||
|
|
connect(VIA1, MET2)
|
||
|
|
connect(MET2, VIA2)
|
||
|
|
connect(VIA2, MET3)
|
||
|
|
connect(MET3, VIA3)
|
||
|
|
connect(VIA3, MET4)
|
||
|
|
connect(MET4, VIA4)
|
||
|
|
connect(VIA4, MET5)
|
||
|
|
# Attaching labels
|
||
|
|
connect(SUB, SUBTXT)
|
||
|
|
connect(SUB, SUBPIN)
|
||
|
|
connect(NWELL, NWELLTXT)
|
||
|
|
connect(POLY, POLYTXT)
|
||
|
|
connect(LI, LITXT)
|
||
|
|
connect(MET1, MET1TXT)
|
||
|
|
connect(MET2, MET2TXT)
|
||
|
|
connect(MET3, MET3TXT)
|
||
|
|
connect(MET4, MET4TXT)
|
||
|
|
connect(MET5, MET5TXT)
|
||
|
|
|
||
|
|
# Global
|
||
|
|
connect_global(SUB, "gnd")
|
||
|
|
|
||
|
|
if $connect_supplies
|
||
|
|
connect_implicit("*", "vdd")
|
||
|
|
connect_implicit("*", "gnd")
|
||
|
|
end
|
||
|
|
|
||
|
|
#connect_global(pwell, "PWELL")
|
||
|
|
#connect_global(nwell, "NWELL")
|
||
|
|
#connect_global(bulk, "BULK")
|
||
|
|
|
||
|
|
# Actually performs the extraction
|
||
|
|
netlist # ... not really required
|
||
|
|
|
||
|
|
# Flatten cells which are present in one netlist only
|
||
|
|
align
|
||
|
|
# SIMPLIFICATION of the netlist
|
||
|
|
#netlist.make_top_level_pins
|
||
|
|
#netlist.combine_devices
|
||
|
|
#netlist.purge
|
||
|
|
#netlist.purge_nets
|
||
|
|
netlist.simplify
|
||
|
|
#schematic.simplify
|
||
|
|
|
||
|
|
# Tolerances for the devices extracted parameters
|
||
|
|
# tolerance(device_class_name, parameter_name [, :absolute => absolute_tolerance] [, :relative => relative_tolerance])
|
||
|
|
tolerance("pfet_01v8", "W", :absolute => 1.nm, :relative => 0.001)
|
||
|
|
tolerance("pfet_01v8", "L", :absolute => 1.nm, :relative => 0.001)
|
||
|
|
tolerance("pfet_01v8_hvt", "W", :absolute => 1.nm, :relative => 0.001)
|
||
|
|
tolerance("pfet_01v8_hvt", "L", :absolute => 1.nm, :relative => 0.001)
|
||
|
|
tolerance("nfet_01v8", "W", :absolute => 1.nm, :relative => 0.001)
|
||
|
|
tolerance("nfet_01v8", "L", :absolute => 1.nm, :relative => 0.001)
|
||
|
|
tolerance("nfet_01v8_lvt", "W", :absolute => 1.nm, :relative => 0.001)
|
||
|
|
tolerance("nfet_01v8_lvt", "L", :absolute => 1.nm, :relative => 0.001)
|
||
|
|
|
||
|
|
#max_res(1000000)
|
||
|
|
#min_caps(1e-15)
|
||
|
|
|
||
|
|
max_branch_complexity(65536)
|
||
|
|
max_depth(16)
|
||
|
|
|
||
|
|
if ! compare
|
||
|
|
#raise "ERROR : Netlists don't match"
|
||
|
|
puts "ERROR : Netlists don't match"
|
||
|
|
else
|
||
|
|
puts "CONGRATULATIONS! Netlists match."
|
||
|
|
end
|
||
|
|
|
||
|
|
# time spent for the LVS
|
||
|
|
time = Time.now
|
||
|
|
hours = ((time - tstart)/3600).to_i
|
||
|
|
minutes = ((time - tstart)/60 - hours * 60).to_i
|
||
|
|
seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i
|
||
|
|
$stdout.write "LVS finished at : #{time.hour}:#{time.min}:#{time.sec} - LVS duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n"</text>
|
||
|
|
</klayout-macro>
|