2016-11-08 18:57:35 +01:00
|
|
|
import hierarchy_layout
|
|
|
|
|
import hierarchy_spice
|
|
|
|
|
import globals
|
2017-11-14 23:59:14 +01:00
|
|
|
import verify
|
2017-06-02 20:11:57 +02:00
|
|
|
import debug
|
2016-11-08 18:57:35 +01:00
|
|
|
import os
|
2017-11-16 22:52:58 +01:00
|
|
|
from globals import OPTS
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2017-06-02 20:11:57 +02:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
class design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|
|
|
|
"""
|
|
|
|
|
Design Class for all modules to inherit the base features.
|
|
|
|
|
Class consisting of a set of modules and instances of these modules
|
|
|
|
|
"""
|
2017-06-02 20:11:57 +02:00
|
|
|
name_map = []
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
def __init__(self, name):
|
|
|
|
|
self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds"
|
|
|
|
|
self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp"
|
|
|
|
|
|
|
|
|
|
self.name = name
|
|
|
|
|
hierarchy_layout.layout.__init__(self, name)
|
|
|
|
|
hierarchy_spice.spice.__init__(self, name)
|
2017-12-12 23:53:19 +01:00
|
|
|
|
|
|
|
|
self.setup_drc_constants()
|
2017-06-02 20:11:57 +02:00
|
|
|
|
|
|
|
|
# Check if the name already exists, if so, give an error
|
|
|
|
|
# because each reference must be a unique name.
|
2018-01-26 21:39:00 +01:00
|
|
|
# These modules ensure unique names or have no changes if they
|
|
|
|
|
# aren't unique
|
2018-05-12 01:32:00 +02:00
|
|
|
ok_list = ['ms_flop',
|
|
|
|
|
'dff',
|
|
|
|
|
'dff_buf',
|
|
|
|
|
'bitcell',
|
|
|
|
|
'contact',
|
|
|
|
|
'ptx',
|
|
|
|
|
'sram',
|
|
|
|
|
'hierarchical_predecode2x4',
|
|
|
|
|
'hierarchical_predecode3x8']
|
2017-06-02 20:11:57 +02:00
|
|
|
if name not in design.name_map:
|
|
|
|
|
design.name_map.append(name)
|
2018-05-12 01:32:00 +02:00
|
|
|
elif self.__class__.__name__ in ok_list:
|
2017-06-02 20:11:57 +02:00
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
debug.error("Duplicate layout reference name {0} of class {1}. GDS2 requires names be unique.".format(name,self.__class__),-1)
|
|
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
def setup_drc_constants(self):
|
|
|
|
|
""" These are some DRC constants used in many places in the compiler."""
|
|
|
|
|
from tech import drc
|
2018-01-26 21:39:00 +01:00
|
|
|
self.well_width = drc["minwidth_well"]
|
2017-12-12 23:53:19 +01:00
|
|
|
self.poly_width = drc["minwidth_poly"]
|
|
|
|
|
self.poly_space = drc["poly_to_poly"]
|
|
|
|
|
self.m1_width = drc["minwidth_metal1"]
|
|
|
|
|
self.m1_space = drc["metal1_to_metal1"]
|
|
|
|
|
self.m2_width = drc["minwidth_metal2"]
|
|
|
|
|
self.m2_space = drc["metal2_to_metal2"]
|
|
|
|
|
self.m3_width = drc["minwidth_metal3"]
|
|
|
|
|
self.m3_space = drc["metal3_to_metal3"]
|
2018-01-26 21:39:00 +01:00
|
|
|
self.active_width = drc["minwidth_active"]
|
|
|
|
|
self.contact_width = drc["minwidth_contact"]
|
|
|
|
|
|
|
|
|
|
self.poly_to_active = drc["poly_to_active"]
|
|
|
|
|
self.poly_extend_active = drc["poly_extend_active"]
|
|
|
|
|
self.contact_to_gate = drc["contact_to_gate"]
|
|
|
|
|
self.well_enclose_active = drc["well_enclosure_active"]
|
|
|
|
|
self.implant_enclose_active = drc["implant_enclosure_active"]
|
|
|
|
|
self.implant_space = drc["implant_to_implant"]
|
|
|
|
|
|
2017-08-07 19:24:45 +02:00
|
|
|
def get_layout_pins(self,inst):
|
|
|
|
|
""" Return a map of pin locations of the instance offset """
|
|
|
|
|
# find the instance
|
|
|
|
|
for i in self.insts:
|
|
|
|
|
if i.name == inst.name:
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
debug.error("Couldn't find instance {0}".format(inst_name),-1)
|
|
|
|
|
inst_map = inst.mod.pin_map
|
|
|
|
|
return inst_map
|
2017-06-02 20:11:57 +02:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2018-02-05 23:52:51 +01:00
|
|
|
def DRC_LVS(self, final_verification=False):
|
2016-11-08 18:57:35 +01:00
|
|
|
"""Checks both DRC and LVS for a module"""
|
|
|
|
|
if OPTS.check_lvsdrc:
|
|
|
|
|
tempspice = OPTS.openram_temp + "/temp.sp"
|
|
|
|
|
tempgds = OPTS.openram_temp + "/temp.gds"
|
|
|
|
|
self.sp_write(tempspice)
|
|
|
|
|
self.gds_write(tempgds)
|
2017-11-14 23:59:14 +01:00
|
|
|
debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name))
|
2018-02-05 23:52:51 +01:00
|
|
|
debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name))
|
2016-11-08 18:57:35 +01:00
|
|
|
os.remove(tempspice)
|
|
|
|
|
os.remove(tempgds)
|
|
|
|
|
|
|
|
|
|
def DRC(self):
|
|
|
|
|
"""Checks DRC for a module"""
|
|
|
|
|
if OPTS.check_lvsdrc:
|
|
|
|
|
tempgds = OPTS.openram_temp + "/temp.gds"
|
|
|
|
|
self.gds_write(tempgds)
|
2017-11-14 23:59:14 +01:00
|
|
|
debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name))
|
2016-11-08 18:57:35 +01:00
|
|
|
os.remove(tempgds)
|
|
|
|
|
|
2018-02-05 23:52:51 +01:00
|
|
|
def LVS(self, final_verification=False):
|
2016-11-08 18:57:35 +01:00
|
|
|
"""Checks LVS for a module"""
|
|
|
|
|
if OPTS.check_lvsdrc:
|
|
|
|
|
tempspice = OPTS.openram_temp + "/temp.sp"
|
|
|
|
|
tempgds = OPTS.openram_temp + "/temp.gds"
|
|
|
|
|
self.sp_write(tempspice)
|
|
|
|
|
self.gds_write(tempgds)
|
2018-02-05 23:52:51 +01:00
|
|
|
debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name))
|
2016-11-08 18:57:35 +01:00
|
|
|
os.remove(tempspice)
|
|
|
|
|
os.remove(tempgds)
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
""" override print function output """
|
|
|
|
|
return "design: " + self.name
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
""" override print function output """
|
|
|
|
|
text="( design: " + self.name + " pins=" + str(self.pins) + " " + str(self.width) + "x" + str(self.height) + " )\n"
|
|
|
|
|
for i in self.objs:
|
|
|
|
|
text+=str(i)+",\n"
|
|
|
|
|
for i in self.insts:
|
|
|
|
|
text+=str(i)+",\n"
|
|
|
|
|
return text
|
2018-02-21 03:22:23 +01:00
|
|
|
|
2018-02-27 01:32:28 +01:00
|
|
|
def analytical_power(self, proc, vdd, temp, load):
|
2018-02-22 04:51:21 +01:00
|
|
|
""" Get total power of a module """
|
2018-02-22 09:15:55 +01:00
|
|
|
total_module_power = self.return_power()
|
2018-02-23 04:35:54 +01:00
|
|
|
for inst in self.insts:
|
2018-02-27 01:32:28 +01:00
|
|
|
total_module_power += inst.mod.analytical_power(proc, vdd, temp, load)
|
2018-02-22 04:51:21 +01:00
|
|
|
return total_module_power
|