2019-04-26 21:21:50 +02:00
|
|
|
# See LICENSE for licensing information.
|
|
|
|
|
#
|
2019-06-14 17:43:41 +02:00
|
|
|
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
|
|
|
|
# of Regents for the Oklahoma Agricultural and Mechanical College
|
|
|
|
|
# (acting for and on behalf of Oklahoma State University)
|
|
|
|
|
# All rights reserved.
|
2019-04-26 21:21:50 +02:00
|
|
|
#
|
2018-07-10 23:17:09 +02:00
|
|
|
from hierarchy_design import hierarchy_design
|
2018-07-10 00:43:26 +02:00
|
|
|
import contact
|
|
|
|
|
from globals import OPTS
|
2019-12-17 20:03:36 +01:00
|
|
|
import re
|
2019-10-03 01:26:02 +02:00
|
|
|
|
2018-07-10 23:17:09 +02:00
|
|
|
class design(hierarchy_design):
|
2018-07-10 00:43:26 +02:00
|
|
|
"""
|
|
|
|
|
This is the same as the hierarchy_design class except it contains
|
2019-12-13 23:13:41 +01:00
|
|
|
some DRC/layer constants and analytical models for other modules to reuse.
|
2018-07-10 00:43:26 +02:00
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, name):
|
2019-10-03 01:26:02 +02:00
|
|
|
hierarchy_design.__init__(self, name)
|
2018-07-10 00:43:26 +02:00
|
|
|
|
|
|
|
|
self.setup_drc_constants()
|
2019-12-13 23:13:41 +01:00
|
|
|
self.setup_layer_constants()
|
2018-09-28 09:11:39 +02:00
|
|
|
self.setup_multiport_constants()
|
2018-07-10 00:43:26 +02:00
|
|
|
|
2019-12-13 23:13:41 +01:00
|
|
|
|
|
|
|
|
def setup_layer_constants(self):
|
|
|
|
|
""" These are some layer constants used in many places in the compiler."""
|
|
|
|
|
|
|
|
|
|
import tech
|
|
|
|
|
|
2019-10-03 01:26:02 +02:00
|
|
|
self.m1_pitch = max(contact.m1m2.width, contact.m1m2.height) + max(self.m1_space, self.m2_space)
|
|
|
|
|
self.m2_pitch = max(contact.m2m3.width, contact.m2m3.height) + max(self.m2_space, self.m3_space)
|
2019-12-17 20:03:36 +01:00
|
|
|
if "m4" in tech.layer:
|
2019-10-03 01:26:02 +02:00
|
|
|
self.m3_pitch = max(contact.m3m4.width, contact.m3m4.height) + max(self.m3_space, self.m4_space)
|
2019-05-28 01:19:29 +02:00
|
|
|
else:
|
|
|
|
|
self.m3_pitch = self.m2_pitch
|
2018-07-10 00:43:26 +02:00
|
|
|
|
2019-12-13 23:13:41 +01:00
|
|
|
self.poly_stack = tech.poly_stack
|
|
|
|
|
self.active_stack = tech.active_stack
|
|
|
|
|
self.m1_stack = tech.m1_stack
|
|
|
|
|
self.m2_stack = tech.m2_stack
|
|
|
|
|
self.m3_stack = tech.m3_stack
|
|
|
|
|
|
2018-07-10 00:43:26 +02:00
|
|
|
def setup_drc_constants(self):
|
|
|
|
|
""" These are some DRC constants used in many places in the compiler."""
|
2019-10-03 01:26:02 +02:00
|
|
|
from tech import drc, layer
|
2018-07-10 00:43:26 +02:00
|
|
|
|
2019-12-17 20:03:36 +01:00
|
|
|
# Make some local rules for convenience
|
|
|
|
|
for rule in drc.keys():
|
|
|
|
|
# Single layer width rules
|
|
|
|
|
match = re.search(r"minwidth_(.*)", rule)
|
|
|
|
|
if match:
|
|
|
|
|
if match.group(1)=="active_contact":
|
|
|
|
|
setattr(self, "contact_width", drc(match.group(0)))
|
|
|
|
|
else:
|
|
|
|
|
setattr(self, match.group(1)+"_width", drc(match.group(0)))
|
|
|
|
|
|
|
|
|
|
# Single layer area rules
|
|
|
|
|
match = re.search(r"minarea_(.*)", rule)
|
|
|
|
|
if match:
|
|
|
|
|
setattr(self, match.group(0), drc(match.group(0)))
|
|
|
|
|
|
|
|
|
|
# Single layer spacing rules
|
|
|
|
|
match = re.search(r"(.*)_to_(.*)", rule)
|
|
|
|
|
if match and match.group(1)==match.group(2):
|
|
|
|
|
setattr(self, match.group(1)+"_space", drc(match.group(0)))
|
|
|
|
|
elif match and match.group(1)!=match.group(2):
|
|
|
|
|
if match.group(2)=="poly_active":
|
|
|
|
|
setattr(self, match.group(1)+"_to_contact", drc(match.group(0)))
|
|
|
|
|
else:
|
|
|
|
|
setattr(self, match.group(0), drc(match.group(0)))
|
|
|
|
|
|
|
|
|
|
match = re.search(r"(.*)_enclose_(.*)", rule)
|
|
|
|
|
if match:
|
|
|
|
|
setattr(self, match.group(0), drc(match.group(0)))
|
|
|
|
|
|
|
|
|
|
match = re.search(r"(.*)_extend_(.*)", rule)
|
|
|
|
|
if match:
|
|
|
|
|
setattr(self, match.group(0), drc(match.group(0)))
|
|
|
|
|
|
|
|
|
|
# These are for debugging previous manual rules
|
2019-12-17 20:23:59 +01:00
|
|
|
if False:
|
|
|
|
|
print("poly_width", self.poly_width)
|
|
|
|
|
print("poly_space", self.poly_space)
|
|
|
|
|
print("m1_width", self.m1_width)
|
|
|
|
|
print("m1_space", self.m1_space)
|
|
|
|
|
print("m2_width", self.m2_width)
|
|
|
|
|
print("m2_space", self.m2_space)
|
|
|
|
|
print("m3_width", self.m3_width)
|
|
|
|
|
print("m3_space", self.m3_space)
|
|
|
|
|
print("m4_width", self.m4_width)
|
|
|
|
|
print("m4_space", self.m4_space)
|
|
|
|
|
print("active_width", self.active_width)
|
|
|
|
|
print("active_space", self.active_space)
|
|
|
|
|
print("contact_width", self.contact_width)
|
|
|
|
|
print("poly_to_active", self.poly_to_active)
|
|
|
|
|
print("poly_extend_active", self.poly_extend_active)
|
|
|
|
|
print("poly_to_contact", self.poly_to_contact)
|
|
|
|
|
print("contact_to_gate", self.contact_to_gate)
|
|
|
|
|
print("well_enclose_active", self.well_enclose_active)
|
|
|
|
|
print("implant_enclose_active", self.implant_enclose_active)
|
|
|
|
|
print("implant_space", self.implant_space)
|
|
|
|
|
import sys; sys.exit(1)
|
|
|
|
|
|
2018-09-28 09:11:39 +02:00
|
|
|
def setup_multiport_constants(self):
|
2018-11-08 21:19:40 +01:00
|
|
|
"""
|
|
|
|
|
These are contants and lists that aid multiport design.
|
|
|
|
|
Ports are always in the order RW, W, R.
|
|
|
|
|
Port indices start from 0 and increment.
|
|
|
|
|
A first RW port will have clk0, csb0, web0, addr0, data0
|
|
|
|
|
A first W port (with no RW ports) will be: clk0, csb0, addr0, data0
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
|
|
|
|
|
|
|
|
|
|
# These are the read/write port indices.
|
|
|
|
|
self.readwrite_ports = []
|
|
|
|
|
# These are the read/write and write-only port indices
|
|
|
|
|
self.write_ports = []
|
2018-11-17 00:03:12 +01:00
|
|
|
# These are the write-only port indices.
|
|
|
|
|
self.writeonly_ports = []
|
2018-11-08 21:19:40 +01:00
|
|
|
# These are teh read/write and read-only port indice
|
|
|
|
|
self.read_ports = []
|
2018-11-17 00:03:12 +01:00
|
|
|
# These are the read-only port indices.
|
|
|
|
|
self.readonly_ports = []
|
2018-11-08 21:19:40 +01:00
|
|
|
# These are all the ports
|
|
|
|
|
self.all_ports = list(range(total_ports))
|
2018-09-28 09:11:39 +02:00
|
|
|
|
|
|
|
|
port_number = 0
|
|
|
|
|
for port in range(OPTS.num_rw_ports):
|
2018-11-08 21:19:40 +01:00
|
|
|
self.readwrite_ports.append(port_number)
|
|
|
|
|
self.write_ports.append(port_number)
|
|
|
|
|
self.read_ports.append(port_number)
|
2018-09-28 09:11:39 +02:00
|
|
|
port_number += 1
|
|
|
|
|
for port in range(OPTS.num_w_ports):
|
2018-11-08 21:19:40 +01:00
|
|
|
self.write_ports.append(port_number)
|
2019-10-03 01:26:02 +02:00
|
|
|
self.writeonly_ports.append(port_number)
|
2018-09-28 09:11:39 +02:00
|
|
|
port_number += 1
|
|
|
|
|
for port in range(OPTS.num_r_ports):
|
2018-11-08 21:19:40 +01:00
|
|
|
self.read_ports.append(port_number)
|
2018-11-17 00:03:12 +01:00
|
|
|
self.readonly_ports.append(port_number)
|
2019-10-03 01:26:02 +02:00
|
|
|
port_number += 1
|
2019-04-19 10:27:06 +02:00
|
|
|
|
2019-03-05 04:27:53 +01:00
|
|
|
def analytical_power(self, corner, load):
|
2018-07-10 00:43:26 +02:00
|
|
|
""" Get total power of a module """
|
|
|
|
|
total_module_power = self.return_power()
|
|
|
|
|
for inst in self.insts:
|
2019-03-05 04:27:53 +01:00
|
|
|
total_module_power += inst.mod.analytical_power(corner, load)
|
2018-07-10 00:43:26 +02:00
|
|
|
return total_module_power
|
2018-10-04 23:04:29 +02:00
|
|
|
|