mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'driver_sizing' into dev
This commit is contained in:
commit
47a3dfafee
|
|
@ -133,7 +133,7 @@ To increase the verbosity of the test, add one (or more) -v options:
|
|||
python3 tests/00_code_format_check_test.py -v -t freepdk45
|
||||
```
|
||||
To specify a particular technology use "-t <techname>" such as
|
||||
"-t freepdk45" or "-t scn4m\_subm". The default for a unit test is scn4m_subm.
|
||||
"-t freepdk45". The default for a unit test is scn4m_subm.
|
||||
The default for openram.py is specified in the configuration file.
|
||||
|
||||
|
||||
|
|
@ -164,7 +164,7 @@ Each specific technology (e.g., [FreePDK45]) should be a subdirectory
|
|||
* replica\_cell\_6t.gds
|
||||
* sp_lib folder with all the .sp (premade) library netlists for the above cells.
|
||||
* layers.map
|
||||
* A valid tech Python module (tech directory with __init__.py and tech.py) with:
|
||||
* A valid tech Python module (tech directory with \_\_init\_\_.py and tech.py) with:
|
||||
* References in tech.py to spice models
|
||||
* DRC/LVS rules needed for dynamic cells and routing
|
||||
* Layer information
|
||||
|
|
|
|||
|
|
@ -320,17 +320,17 @@ class layout():
|
|||
def add_path(self, layer, coordinates, width=None):
|
||||
"""Connects a routing path on given layer,coordinates,width."""
|
||||
debug.info(4,"add path " + str(layer) + " " + str(coordinates))
|
||||
import path
|
||||
import wire_path
|
||||
# NOTE: (UNTESTED) add_path(...) is currently not used
|
||||
# negative layers indicate "unused" layers in a given technology
|
||||
#layer_num = techlayer[layer]
|
||||
#if layer_num >= 0:
|
||||
# self.objs.append(geometry.path(layer_num, coordinates, width))
|
||||
|
||||
path.path(obj=self,
|
||||
layer=layer,
|
||||
position_list=coordinates,
|
||||
width=width)
|
||||
wire_path.wire_path(obj=self,
|
||||
layer=layer,
|
||||
position_list=coordinates,
|
||||
width=width)
|
||||
|
||||
def add_route(self, layers, coordinates, layer_widths):
|
||||
"""Connects a routing path on given layer,coordinates,width. The
|
||||
|
|
|
|||
|
|
@ -19,13 +19,15 @@ class spice():
|
|||
# Holds subckts/mods for this module
|
||||
self.mods = []
|
||||
# Holds the pins for this module
|
||||
self.pins = []
|
||||
self.pins = []
|
||||
# The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND
|
||||
# for each instance, this is the set of nets/nodes that map to the pins for this instance
|
||||
self.pin_type = {}
|
||||
# THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the
|
||||
# Spice format)
|
||||
self.conns = []
|
||||
# Keep track of any comments to add the the spice
|
||||
self.comments = []
|
||||
|
||||
self.sp_read()
|
||||
|
||||
|
|
@ -33,6 +35,10 @@ class spice():
|
|||
# Spice circuit
|
||||
############################################################
|
||||
|
||||
def add_comment(self, comment):
|
||||
""" Add a comment to the spice file """
|
||||
self.comments.append(comment)
|
||||
|
||||
def add_pin(self, name, pin_type="INOUT"):
|
||||
""" Adds a pin to the pins list. Default type is INOUT signal. """
|
||||
self.pins.append(name)
|
||||
|
|
@ -162,6 +168,9 @@ class spice():
|
|||
sp.write("\n.SUBCKT {0} {1}\n".format(self.name,
|
||||
" ".join(self.pins)))
|
||||
|
||||
for line in self.comments:
|
||||
sp.write("* {}\n".format(line))
|
||||
|
||||
# every instance must have a set of connections, even if it is empty.
|
||||
if len(self.insts)!=len(self.conns):
|
||||
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
from tech import drc
|
||||
import debug
|
||||
from path import path
|
||||
from wire_path import wire_path
|
||||
from sram_factory import factory
|
||||
|
||||
class wire(path):
|
||||
class wire(wire_path):
|
||||
"""
|
||||
Object metal wire; given the layer type
|
||||
Add a wire of minimium metal width between a set of points.
|
||||
|
|
@ -26,7 +26,7 @@ class wire(path):
|
|||
self.create_rectilinear()
|
||||
self.create_vias()
|
||||
self.create_rectangles()
|
||||
# wires and paths should not be offset to (0,0)
|
||||
# wires and wire_paths should not be offset to (0,0)
|
||||
|
||||
def setup_layers(self):
|
||||
(horiz_layer, via_layer, vert_layer) = self.layer_stack
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ def create_rectilinear_route(my_list):
|
|||
my_list.append(vector(pl[-1]))
|
||||
return my_list
|
||||
|
||||
class path():
|
||||
class wire_path():
|
||||
"""
|
||||
Object metal path; given the layer type
|
||||
Add a path of minimium metal width between a set of points.
|
||||
Object metal wire_path; given the layer type
|
||||
Add a wire_path of minimium metal width between a set of points.
|
||||
The points should be rectilinear to control the bend points. If
|
||||
not, it will always go down first. The points are the center of the path.
|
||||
not, it will always go down first. The points are the center of the wire_path.
|
||||
If width is not given, it uses minimum layer width.
|
||||
"""
|
||||
def __init__(self, obj, layer, position_list, width=None):
|
||||
|
|
@ -44,7 +44,7 @@ class path():
|
|||
self.create_rectilinear()
|
||||
self.connect_corner()
|
||||
self.create_rectangles()
|
||||
# wires and paths should not be offset to (0,0)
|
||||
# wires and wire_paths should not be offset to (0,0)
|
||||
|
||||
def create_rectilinear(self):
|
||||
""" Add intermediate nodes if it isn't rectilinear. Also skip
|
||||
|
|
@ -52,7 +52,7 @@ class path():
|
|||
self.position_list = create_rectilinear_route(self.position_list)
|
||||
|
||||
def connect_corner(self):
|
||||
""" Add a corner square at every corner of the path."""
|
||||
""" Add a corner square at every corner of the wire_path."""
|
||||
from itertools import tee,islice
|
||||
nwise = lambda g,n=2: zip(*(islice(g,i,None) for i,g in enumerate(tee(g,n))))
|
||||
threewise=nwise(self.position_list,3)
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
Delivered-To: mrg@ucsc.edu
|
||||
Received: by 10.216.164.197 with SMTP id c47cs36474wel;
|
||||
Sat, 19 Nov 2011 21:23:28 -0800 (PST)
|
||||
Received: by 10.216.133.5 with SMTP id p5mr1106280wei.105.1321766513080;
|
||||
Sat, 19 Nov 2011 21:21:53 -0800 (PST)
|
||||
Received-SPF: softfail (google.com: best guess record for domain of transitioning wieckows@umich.edu does not designate 128.114.48.32 as permitted sender) client-ip=128.114.48.32;
|
||||
Received: by 10.241.242.69 with POP3 id 5mf3470160wwf.5;
|
||||
Sat, 19 Nov 2011 21:21:53 -0800 (PST)
|
||||
X-Gmail-Fetch-Info: mguthaus@gmail.com 1 smtp.gmail.com 995 mguthaus
|
||||
Delivered-To: mguthaus@gmail.com
|
||||
Received: by 10.231.207.15 with SMTP id fw15cs52829ibb;
|
||||
Thu, 14 Oct 2010 12:49:35 -0700 (PDT)
|
||||
Received: by 10.142.224.8 with SMTP id w8mr3585480wfg.123.1287085774723;
|
||||
Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
|
||||
Return-Path: <wieckows@umich.edu>
|
||||
Received: from mail-01.cse.ucsc.edu (mail-01.cse.ucsc.edu [128.114.48.32])
|
||||
by mx.google.com with ESMTP id x31si25240170wfd.118.2010.10.14.12.49.34;
|
||||
Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
|
||||
Received-SPF: neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) client-ip=128.114.48.32;
|
||||
Authentication-Results: mx.google.com; spf=neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) smtp.mail=wieckows@umich.edu
|
||||
Received: from services.cse.ucsc.edu (services.cse.ucsc.edu [128.114.48.10])
|
||||
by mail-01.cse.ucsc.edu (Postfix) with ESMTP id 60660100985C
|
||||
for <mrg@mail-01.cse.ucsc.edu>; Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
|
||||
Received: from mailgw.soe.ucsc.edu (mailgw.cse.ucsc.edu [128.114.48.9])
|
||||
by services.cse.ucsc.edu (8.13.6/8.13.6) with ESMTP id o9EJnXcg026705
|
||||
(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL)
|
||||
for <mrg@soe.ucsc.edu>; Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
|
||||
X-ASG-Debug-ID: 1287085773-35c0a0820001-k66d7V
|
||||
Received: from hellskitchen.mr.itd.umich.edu (smtp.mail.umich.edu [141.211.14.82]) by mailgw.soe.ucsc.edu with ESMTP id iCFqYJFhVj1wHPNy for <mrg@soe.ucsc.edu>; Thu, 14 Oct 2010 12:49:33 -0700 (PDT)
|
||||
X-Barracuda-Envelope-From: wieckows@umich.edu
|
||||
X-Barracuda-Apparent-Source-IP: 141.211.14.82
|
||||
Received: FROM [10.0.1.4] (adsl-99-67-97-169.dsl.sfldmi.sbcglobal.net [99.67.97.169])
|
||||
By hellskitchen.mr.itd.umich.edu ID 4CB75ECA.5F7DC.12653 ;
|
||||
Authuser wieckows;
|
||||
14 Oct 2010 15:49:30 EDT
|
||||
Content-Type: text/plain; charset=us-ascii
|
||||
Mime-Version: 1.0 (Apple Message framework v1081)
|
||||
Subject: Re: GDS Mill
|
||||
From: Michael Wieckowski <wieckows@umich.edu>
|
||||
X-ASG-Orig-Subj: Re: GDS Mill
|
||||
In-Reply-To: <BEC6726E-7B98-43D8-8AAA-2AA259DFFDA8@soe.ucsc.edu>
|
||||
Date: Thu, 14 Oct 2010 15:49:29 -0400
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Message-Id: <7C1B8C49-7D87-4BF2-8ABF-6555CF7B37AD@umich.edu>
|
||||
References: <BEC6726E-7B98-43D8-8AAA-2AA259DFFDA8@soe.ucsc.edu>
|
||||
To: Matthew Guthaus <mrg@soe.ucsc.edu>
|
||||
X-Mailer: Apple Mail (2.1081)
|
||||
X-Barracuda-Connect: smtp.mail.umich.edu[141.211.14.82]
|
||||
X-Barracuda-Start-Time: 1287085773
|
||||
X-Barracuda-URL: http://mailgw.cse.ucsc.edu:8000/cgi-mod/mark.cgi
|
||||
X-Virus-Scanned: by bsmtpd at soe.ucsc.edu
|
||||
|
||||
Hi Matt,
|
||||
|
||||
Feel free to use / modify / distribute the code as you like.
|
||||
|
||||
-Mike
|
||||
|
||||
|
||||
On Oct 14, 2010, at 3:07 PM, Matthew Guthaus wrote:
|
||||
|
||||
> Hi Michael (& Dennis),
|
||||
>=20
|
||||
> A student and I were looking at your GDS tools, but we noticed that =
|
||||
there is no license. What is the license?
|
||||
>=20
|
||||
> Thanks,
|
||||
>=20
|
||||
> Matt
|
||||
>=20
|
||||
> ---
|
||||
> Matthew Guthaus
|
||||
> Assistant Professor, Computer Engineering
|
||||
> University of California Santa Cruz
|
||||
> http://vlsida.soe.ucsc.edu/
|
||||
>=20
|
||||
>=20
|
||||
>=20
|
||||
|
|
@ -1,30 +1,81 @@
|
|||
README BY TOM GOLUBEV
|
||||
|
||||
gdsMill was adapted from gdsMill by Michael Wieckowski.
|
||||
|
||||
gdsMill allows one to work with GDS files, opening, reading, writing and altering.
|
||||
It is a library and does not work by itself. To get started, refer to ExampleUserDir.
|
||||
To look at sram compiler related example, refer to the sram_examples subdir.
|
||||
|
||||
gdsMill takes a layermap, in a standard format (virtuoso .map files). This is necessary
|
||||
for drawing text and rectangles, since those functions take layernames, and gdsMill needs layer numbers.
|
||||
Delivered-To: mrg@ucsc.edu
|
||||
Received: by 10.216.164.197 with SMTP id c47cs36474wel;
|
||||
Sat, 19 Nov 2011 21:23:28 -0800 (PST)
|
||||
Received: by 10.216.133.5 with SMTP id p5mr1106280wei.105.1321766513080;
|
||||
Sat, 19 Nov 2011 21:21:53 -0800 (PST)
|
||||
Received-SPF: softfail (google.com: best guess record for domain of transitioning wieckows@umich.edu does not designate 128.114.48.32 as permitted sender) client-ip=128.114.48.32;
|
||||
Received: by 10.241.242.69 with POP3 id 5mf3470160wwf.5;
|
||||
Sat, 19 Nov 2011 21:21:53 -0800 (PST)
|
||||
X-Gmail-Fetch-Info: mguthaus@gmail.com 1 smtp.gmail.com 995 mguthaus
|
||||
Delivered-To: mguthaus@gmail.com
|
||||
Received: by 10.231.207.15 with SMTP id fw15cs52829ibb;
|
||||
Thu, 14 Oct 2010 12:49:35 -0700 (PDT)
|
||||
Received: by 10.142.224.8 with SMTP id w8mr3585480wfg.123.1287085774723;
|
||||
Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
|
||||
Return-Path: <wieckows@umich.edu>
|
||||
Received: from mail-01.cse.ucsc.edu (mail-01.cse.ucsc.edu [128.114.48.32])
|
||||
by mx.google.com with ESMTP id x31si25240170wfd.118.2010.10.14.12.49.34;
|
||||
Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
|
||||
Received-SPF: neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) client-ip=128.114.48.32;
|
||||
Authentication-Results: mx.google.com; spf=neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) smtp.mail=wieckows@umich.edu
|
||||
Received: from services.cse.ucsc.edu (services.cse.ucsc.edu [128.114.48.10])
|
||||
by mail-01.cse.ucsc.edu (Postfix) with ESMTP id 60660100985C
|
||||
for <mrg@mail-01.cse.ucsc.edu>; Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
|
||||
Received: from mailgw.soe.ucsc.edu (mailgw.cse.ucsc.edu [128.114.48.9])
|
||||
by services.cse.ucsc.edu (8.13.6/8.13.6) with ESMTP id o9EJnXcg026705
|
||||
(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL)
|
||||
for <mrg@soe.ucsc.edu>; Thu, 14 Oct 2010 12:49:34 -0700 (PDT)
|
||||
X-ASG-Debug-ID: 1287085773-35c0a0820001-k66d7V
|
||||
Received: from hellskitchen.mr.itd.umich.edu (smtp.mail.umich.edu [141.211.14.82]) by mailgw.soe.ucsc.edu with ESMTP id iCFqYJFhVj1wHPNy for <mrg@soe.ucsc.edu>; Thu, 14 Oct 2010 12:49:33 -0700 (PDT)
|
||||
X-Barracuda-Envelope-From: wieckows@umich.edu
|
||||
X-Barracuda-Apparent-Source-IP: 141.211.14.82
|
||||
Received: FROM [10.0.1.4] (adsl-99-67-97-169.dsl.sfldmi.sbcglobal.net [99.67.97.169])
|
||||
By hellskitchen.mr.itd.umich.edu ID 4CB75ECA.5F7DC.12653 ;
|
||||
Authuser wieckows;
|
||||
14 Oct 2010 15:49:30 EDT
|
||||
Content-Type: text/plain; charset=us-ascii
|
||||
Mime-Version: 1.0 (Apple Message framework v1081)
|
||||
Subject: Re: GDS Mill
|
||||
From: Michael Wieckowski <wieckows@umich.edu>
|
||||
X-ASG-Orig-Subj: Re: GDS Mill
|
||||
In-Reply-To: <BEC6726E-7B98-43D8-8AAA-2AA259DFFDA8@soe.ucsc.edu>
|
||||
Date: Thu, 14 Oct 2010 15:49:29 -0400
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Message-Id: <7C1B8C49-7D87-4BF2-8ABF-6555CF7B37AD@umich.edu>
|
||||
References: <BEC6726E-7B98-43D8-8AAA-2AA259DFFDA8@soe.ucsc.edu>
|
||||
To: Matthew Guthaus <mrg@soe.ucsc.edu>
|
||||
X-Mailer: Apple Mail (2.1081)
|
||||
X-Barracuda-Connect: smtp.mail.umich.edu[141.211.14.82]
|
||||
X-Barracuda-Start-Time: 1287085773
|
||||
X-Barracuda-URL: http://mailgw.cse.ucsc.edu:8000/cgi-mod/mark.cgi
|
||||
X-Virus-Scanned: by bsmtpd at soe.ucsc.edu
|
||||
|
||||
Hi Matt,
|
||||
|
||||
Feel free to use / modify / distribute the code as you like.
|
||||
|
||||
-Mike
|
||||
|
||||
|
||||
gdsMill funcionality:
|
||||
On Oct 14, 2010, at 3:07 PM, Matthew Guthaus wrote:
|
||||
|
||||
The main functions are from vlsilayout. They allow creating a new layout, fill in a box, text, and instancing other structures.
|
||||
|
||||
Files:
|
||||
|
||||
sram_examples:
|
||||
|
||||
gdsMill.sh: Adds gdsMill to python path.
|
||||
Source this before working
|
||||
|
||||
printGDS.py: will dump a text version structures within the gds file.
|
||||
usage: python printGDS.py file
|
||||
|
||||
cell6tDemo.py: Will tile cell6t from sram_lib2.gds and output into layoutB.gds. All cells from source are copied into layoutB.gds.
|
||||
usage: python ./cell6tDemo.py
|
||||
|
||||
|
||||
> Hi Michael (& Dennis),
|
||||
>=20
|
||||
> A student and I were looking at your GDS tools, but we noticed that =
|
||||
there is no license. What is the license?
|
||||
>=20
|
||||
> Thanks,
|
||||
>=20
|
||||
> Matt
|
||||
>=20
|
||||
> ---
|
||||
> Matthew Guthaus
|
||||
> Assistant Professor, Computer Engineering
|
||||
> University of California Santa Cruz
|
||||
> http://vlsida.soe.ucsc.edu/
|
||||
>=20
|
||||
>=20
|
||||
>=20
|
||||
|
|
|
|||
|
|
@ -446,7 +446,8 @@ class bank(design.design):
|
|||
self.add_mod(self.row_decoder)
|
||||
|
||||
self.wordline_driver = factory.create(module_type="wordline_driver",
|
||||
rows=self.num_rows)
|
||||
rows=self.num_rows,
|
||||
cols=self.num_cols)
|
||||
self.add_mod(self.wordline_driver)
|
||||
|
||||
self.inv = factory.create(module_type="pinv")
|
||||
|
|
@ -1067,8 +1068,8 @@ class bank(design.design):
|
|||
# The mid guarantees we exit the input cell to the right.
|
||||
driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).rc()
|
||||
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).lc()
|
||||
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
|
||||
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
|
||||
mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].rx() + 0.5*self.bitcell_array_inst.lx(),0)
|
||||
mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0.5,1)
|
||||
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
|
||||
|
||||
|
||||
|
|
@ -1086,8 +1087,8 @@ class bank(design.design):
|
|||
# The mid guarantees we exit the input cell to the right.
|
||||
driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).lc()
|
||||
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).rc()
|
||||
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
|
||||
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
|
||||
mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0)
|
||||
mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0,1)
|
||||
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
|
||||
|
||||
def route_column_address_lines(self, port):
|
||||
|
|
@ -1253,20 +1254,22 @@ class bank(design.design):
|
|||
def get_wl_en_cin(self):
|
||||
"""Get the relative capacitance of all the clk connections in the bank"""
|
||||
#wl_en only used in the wordline driver.
|
||||
total_clk_cin = self.wordline_driver.get_wl_en_cin()
|
||||
return total_clk_cin
|
||||
|
||||
return self.wordline_driver.get_wl_en_cin()
|
||||
|
||||
def get_w_en_cin(self):
|
||||
"""Get the relative capacitance of all the clk connections in the bank"""
|
||||
#wl_en only used in the wordline driver.
|
||||
return self.write_driver.get_w_en_cin()
|
||||
|
||||
def get_clk_bar_cin(self):
|
||||
"""Get the relative capacitance of all the clk_bar connections in the bank"""
|
||||
#Current bank only uses clock bar (clk_buf_bar) as an enable for the precharge array.
|
||||
|
||||
#Precharges are the all the same in Mulitport, one is picked
|
||||
port = self.read_ports[0]
|
||||
total_clk_bar_cin = self.precharge_array[port].get_en_cin()
|
||||
return total_clk_bar_cin
|
||||
return self.precharge_array[port].get_en_cin()
|
||||
|
||||
def get_sen_cin(self):
|
||||
"""Get the relative capacitance of all the sense amp enable connections in the bank"""
|
||||
#Current bank only uses sen as an enable for the sense amps.
|
||||
total_sen_cin = self.sense_amp_array.get_en_cin()
|
||||
return total_sen_cin
|
||||
return self.sense_amp_array.get_en_cin()
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class bitcell_array(design.design):
|
|||
def __init__(self, cols, rows, name):
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
|
||||
|
||||
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
|
||||
|
||||
self.column_size = cols
|
||||
self.row_size = rows
|
||||
|
|
|
|||
|
|
@ -14,20 +14,26 @@ class control_logic(design.design):
|
|||
Dynamically generated Control logic for the total SRAM circuit.
|
||||
"""
|
||||
|
||||
def __init__(self, num_rows, words_per_row, sram=None, port_type="rw"):
|
||||
def __init__(self, num_rows, words_per_row, word_size, sram=None, port_type="rw"):
|
||||
""" Constructor """
|
||||
name = "control_logic_" + port_type
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(name))
|
||||
self.add_comment("num_rows: {0}".format(num_rows))
|
||||
self.add_comment("words_per_row: {0}".format(words_per_row))
|
||||
self.add_comment("word_size {0}".format(word_size))
|
||||
|
||||
self.sram=sram
|
||||
self.num_rows = num_rows
|
||||
self.words_per_row = words_per_row
|
||||
self.word_size = word_size
|
||||
self.port_type = port_type
|
||||
|
||||
self.num_cols = word_size*words_per_row
|
||||
self.num_words = num_rows * words_per_row
|
||||
|
||||
self.enable_delay_chain_resizing = False
|
||||
|
||||
#This is needed to resize the delay chain. Likely to be changed at some point.
|
||||
self.sram=sram
|
||||
#self.sram=None #disable re-sizing for debugging, FIXME: resizing is not working, needs to be adjusted for new control logic.
|
||||
self.wl_timing_tolerance = 1 #Determines how much larger the sen delay should be. Accounts for possible error in model.
|
||||
self.parasitic_inv_delay = parameter["min_inv_para_delay"] #Keeping 0 for now until further testing.
|
||||
|
|
@ -81,34 +87,47 @@ class control_logic(design.design):
|
|||
height=dff_height)
|
||||
self.add_mod(self.and2)
|
||||
|
||||
# Special gates: inverters for buffering
|
||||
# Size the clock for the number of rows (fanout)
|
||||
clock_driver_size = max(1,int(self.num_rows/4))
|
||||
self.clkbuf = factory.create(module_type="pbuf",
|
||||
size=clock_driver_size,
|
||||
height=dff_height)
|
||||
# clk_buf drives a flop for every address and control bit
|
||||
# plus about 5 fanouts for the control logic
|
||||
# each flop internally has a FO 4 approximately
|
||||
clock_fanout = 4*(math.log(self.num_words,2) + math.log(self.words_per_row,2) \
|
||||
+ self.num_control_signals) + 5
|
||||
self.clk_buf_driver = factory.create(module_type="pdriver",
|
||||
fanout=clock_fanout,
|
||||
height=dff_height)
|
||||
|
||||
self.add_mod(self.clkbuf)
|
||||
self.add_mod(self.clk_buf_driver)
|
||||
|
||||
self.buf16 = factory.create(module_type="pbuf",
|
||||
size=16,
|
||||
height=dff_height)
|
||||
self.add_mod(self.buf16)
|
||||
# wl_en drives every row in the bank
|
||||
self.wl_en_driver = factory.create(module_type="pdriver",
|
||||
fanout=self.num_rows,
|
||||
height=dff_height)
|
||||
self.add_mod(self.wl_en_driver)
|
||||
|
||||
self.buf8 = factory.create(module_type="pbuf",
|
||||
size=8,
|
||||
height=dff_height)
|
||||
self.add_mod(self.buf8)
|
||||
|
||||
self.inv = self.inv1 = factory.create(module_type="pinv",
|
||||
# w_en drives every write driver
|
||||
self.w_en_driver = factory.create(module_type="pdriver",
|
||||
fanout=self.word_size+8,
|
||||
height=dff_height)
|
||||
self.add_mod(self.w_en_driver)
|
||||
|
||||
# s_en drives every sense amp
|
||||
self.s_en_driver = factory.create(module_type="pdriver",
|
||||
fanout=self.word_size,
|
||||
height=dff_height)
|
||||
self.add_mod(self.s_en_driver)
|
||||
|
||||
# used to generate inverted signals with low fanout
|
||||
self.inv = factory.create(module_type="pinv",
|
||||
size=1,
|
||||
height=dff_height)
|
||||
self.add_mod(self.inv1)
|
||||
|
||||
self.inv8 = factory.create(module_type="pinv",
|
||||
size=8,
|
||||
height=dff_height)
|
||||
self.add_mod(self.inv8)
|
||||
self.add_mod(self.inv)
|
||||
|
||||
# p_en_bar drives every column in the bicell array
|
||||
self.p_en_bar_driver = factory.create(module_type="pdriver",
|
||||
neg_polarity=True,
|
||||
fanout=self.num_cols,
|
||||
height=dff_height)
|
||||
self.add_mod(self.p_en_bar_driver)
|
||||
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
|
||||
|
|
@ -399,8 +418,8 @@ class control_logic(design.design):
|
|||
|
||||
def create_clk_buf_row(self):
|
||||
""" Create the multistage and gated clock buffer """
|
||||
self.clkbuf_inst = self.add_inst(name="clkbuf",
|
||||
mod=self.clkbuf)
|
||||
self.clk_buf_inst = self.add_inst(name="clkbuf",
|
||||
mod=self.clk_buf_driver)
|
||||
self.connect_inst(["clk","clk_buf","vdd","gnd"])
|
||||
|
||||
def place_clk_buf_row(self,row):
|
||||
|
|
@ -409,12 +428,12 @@ class control_logic(design.design):
|
|||
(y_off,mirror)=self.get_offset(row)
|
||||
|
||||
offset = vector(x_off,y_off)
|
||||
self.clkbuf_inst.place(offset, mirror)
|
||||
self.clk_buf_inst.place(offset, mirror)
|
||||
|
||||
self.row_end_inst.append(self.clkbuf_inst)
|
||||
self.row_end_inst.append(self.clk_buf_inst)
|
||||
|
||||
def route_clk_buf(self):
|
||||
clk_pin = self.clkbuf_inst.get_pin("A")
|
||||
clk_pin = self.clk_buf_inst.get_pin("A")
|
||||
clk_pos = clk_pin.center()
|
||||
self.add_layout_pin_segment_center(text="clk",
|
||||
layer="metal2",
|
||||
|
|
@ -424,14 +443,17 @@ class control_logic(design.design):
|
|||
offset=clk_pos)
|
||||
|
||||
|
||||
clkbuf_map = zip(["Z"], ["clk_buf"])
|
||||
self.connect_vertical_bus(clkbuf_map, self.clkbuf_inst, self.rail_offsets, ("metal3", "via2", "metal2"))
|
||||
# Connect this at the bottom of the buffer
|
||||
out_pos = self.clk_buf_inst.get_pin("Z").center()
|
||||
mid1 = vector(out_pos.x,2*self.m2_pitch)
|
||||
mid2 = vector(self.rail_offsets["clk_buf"].x, mid1.y)
|
||||
bus_pos = self.rail_offsets["clk_buf"]
|
||||
self.add_wire(("metal3","via2","metal2"),[out_pos, mid1, mid2, bus_pos])
|
||||
# The pin is on M1, so we need another via as well
|
||||
self.add_via_center(layers=("metal1","via1","metal2"),
|
||||
offset=self.clkbuf_inst.get_pin("Z").center())
|
||||
|
||||
offset=self.clk_buf_inst.get_pin("Z").center())
|
||||
|
||||
self.connect_output(self.clkbuf_inst, "Z", "clk_buf")
|
||||
self.connect_output(self.clk_buf_inst, "Z", "clk_buf")
|
||||
|
||||
def create_gated_clk_bar_row(self):
|
||||
self.clk_bar_inst = self.add_inst(name="inv_clk_bar",
|
||||
|
|
@ -510,7 +532,7 @@ class control_logic(design.design):
|
|||
def create_wlen_row(self):
|
||||
# input pre_p_en, output: wl_en
|
||||
self.wl_en_inst=self.add_inst(name="buf_wl_en",
|
||||
mod=self.buf16)
|
||||
mod=self.wl_en_driver)
|
||||
self.connect_inst(["gated_clk_bar", "wl_en", "vdd", "gnd"])
|
||||
|
||||
def place_wlen_row(self, row):
|
||||
|
|
@ -580,7 +602,7 @@ class control_logic(design.design):
|
|||
|
||||
# input: pre_p_en, output: p_en_bar
|
||||
self.p_en_bar_inst=self.add_inst(name="inv_p_en_bar",
|
||||
mod=self.inv8)
|
||||
mod=self.p_en_bar_driver)
|
||||
self.connect_inst([input_name, "p_en_bar", "vdd", "gnd"])
|
||||
|
||||
|
||||
|
|
@ -620,7 +642,7 @@ class control_logic(design.design):
|
|||
# BUFFER FOR S_EN
|
||||
# input: pre_s_en, output: s_en
|
||||
self.s_en_inst=self.add_inst(name="buf_s_en",
|
||||
mod=self.buf8)
|
||||
mod=self.s_en_driver)
|
||||
self.connect_inst(["pre_s_en", "s_en", "vdd", "gnd"])
|
||||
|
||||
def place_sen_row(self,row):
|
||||
|
|
@ -657,7 +679,7 @@ class control_logic(design.design):
|
|||
|
||||
# BUFFER FOR W_EN
|
||||
self.w_en_inst = self.add_inst(name="buf_w_en_buf",
|
||||
mod=self.buf8)
|
||||
mod=self.w_en_driver)
|
||||
self.connect_inst([input_name, "w_en", "vdd", "gnd"])
|
||||
|
||||
|
||||
|
|
@ -814,7 +836,7 @@ class control_logic(design.design):
|
|||
#Calculate the load on wl_en within the module and add it to external load
|
||||
external_cout = self.sram.get_wl_en_cin()
|
||||
#First stage is the clock buffer
|
||||
stage_effort_list += self.clkbuf.get_output_stage_efforts(external_cout, is_clk_bar_rise)
|
||||
stage_effort_list += self.clk_buf_driver.get_stage_efforts(external_cout, is_clk_bar_rise)
|
||||
last_stage_is_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
#Then ask the sram for the other path delays (from the bank)
|
||||
|
|
@ -845,17 +867,17 @@ class control_logic(design.design):
|
|||
#First stage, gated_clk_bar -(and2)-> rbl_in. Only for RW ports.
|
||||
if self.port_type == "rw":
|
||||
stage1_cout = self.replica_bitline.get_en_cin()
|
||||
stage_effort_list += self.and2.get_output_stage_efforts(stage1_cout, last_stage_rise)
|
||||
stage_effort_list += self.and2.get_stage_efforts(stage1_cout, last_stage_rise)
|
||||
last_stage_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
#Replica bitline stage, rbl_in -(rbl)-> pre_s_en
|
||||
stage2_cout = self.buf8.get_cin()
|
||||
stage2_cout = self.s_en_driver.get_cin()
|
||||
stage_effort_list += self.replica_bitline.determine_sen_stage_efforts(stage2_cout, last_stage_rise)
|
||||
last_stage_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
#buffer stage, pre_s_en -(buffer)-> s_en
|
||||
stage3_cout = self.sram.get_sen_cin()
|
||||
stage_effort_list += self.buf8.get_output_stage_efforts(stage3_cout, last_stage_rise)
|
||||
stage_effort_list += self.s_en_driver.get_stage_efforts(stage3_cout, last_stage_rise)
|
||||
last_stage_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
return stage_effort_list
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@ class delay_chain(design.design):
|
|||
def __init__(self, name, fanout_list):
|
||||
"""init function"""
|
||||
design.design.__init__(self, name)
|
||||
|
||||
debug.info(1, "creating delay chain {0}".format(str(fanout_list)))
|
||||
self.add_comment("fanouts: {0}".format(str(fanout_list)))
|
||||
|
||||
# Two fanouts are needed so that we can route the vdd/gnd connections
|
||||
for f in fanout_list:
|
||||
debug.check(f>=2,"Must have >=2 fanouts for each stage.")
|
||||
|
|
@ -230,7 +232,7 @@ class delay_chain(design.design):
|
|||
stage_cout = self.inv.get_cin()*(stage_fanout+1)
|
||||
if len(stage_effort_list) == len(self.fanout_list)-1: #last stage
|
||||
stage_cout+=ext_delayed_en_cout
|
||||
stage = self.inv.get_effort_stage(stage_cout, last_stage_is_rise)
|
||||
stage = self.inv.get_stage_effort(stage_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage)
|
||||
last_stage_is_rise = stage.is_rise
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class dff_array(design.design):
|
|||
Unlike the data flops, these are never spaced out.
|
||||
"""
|
||||
|
||||
def __init__(self, rows, columns, inv1_size=2, inv2_size=4, name=""):
|
||||
def __init__(self, rows, columns, name=""):
|
||||
self.rows = rows
|
||||
self.columns = columns
|
||||
|
||||
|
|
@ -20,7 +20,8 @@ class dff_array(design.design):
|
|||
name = "dff_array_{0}x{1}".format(rows, columns)
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {0} rows={1} cols={2}".format(self.name, self.rows, self.columns))
|
||||
|
||||
self.add_comment("rows: {0} cols: {1}".format(rows, columns))
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ class dff_buf(design.design):
|
|||
dff_buf.unique_id += 1
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
self.add_comment("inv1: {0} inv2: {1}".format(inv1_size, inv2_size))
|
||||
|
||||
# This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width.
|
||||
# This causes a DRC in the pinv which assumes min width rails. This ensures the output
|
||||
# contact does not violate spacing to the rail in the NMOS.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ class dff_buf_array(design.design):
|
|||
dff_buf_array.unique_id += 1
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
self.add_comment("rows: {0} cols: {1}".format(rows, columns))
|
||||
self.add_comment("inv1: {0} inv2: {1}".format(inv1_size, inv2_size))
|
||||
|
||||
self.inv1_size = inv1_size
|
||||
self.inv2_size = inv2_size
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ class dff_inv(design.design):
|
|||
dff_inv.unique_id += 1
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
self.add_comment("inv: {0}".format(inv_size))
|
||||
|
||||
self.inv_size = inv_size
|
||||
|
||||
# This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ class dff_inv_array(design.design):
|
|||
dff_inv_array.unique_id += 1
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
self.add_comment("rows: {0} cols: {1}".format(rows, columns))
|
||||
self.add_comment("inv1: {0}".format(inv1_size))
|
||||
|
||||
self.inv_size = inv_size
|
||||
|
||||
self.create_netlist()
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ class precharge_array(design.design):
|
|||
def __init__(self, name, columns, size=1, bitcell_bl="bl", bitcell_br="br"):
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {0}".format(self.name))
|
||||
|
||||
self.add_comment("cols: {0} size: {1} bl: {2} br: {3}".format(columns, size, bitcell_bl, bitcell_br))
|
||||
|
||||
self.columns = columns
|
||||
self.size = size
|
||||
self.bitcell_bl = bitcell_bl
|
||||
|
|
|
|||
|
|
@ -614,7 +614,7 @@ class replica_bitline(design.design):
|
|||
|
||||
#The delay chain triggers the enable on the replica bitline (rbl). This is used to track the bitline delay whereas this
|
||||
#model is intended to track every but that. Therefore, the next stage is the inverter after the rbl.
|
||||
stage2 = self.inv.get_effort_stage(ext_cout, last_stage_is_rise)
|
||||
stage2 = self.inv.get_stage_effort(ext_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage2)
|
||||
|
||||
return stage_effort_list
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ class sense_amp_array(design.design):
|
|||
def __init__(self, name, word_size, words_per_row):
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {0}".format(self.name))
|
||||
self.add_comment("word_size {0}".format(word_size))
|
||||
self.add_comment("words_per_row: {0}".format(words_per_row))
|
||||
|
||||
self.word_size = word_size
|
||||
self.words_per_row = words_per_row
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ class single_level_column_mux_array(design.design):
|
|||
def __init__(self, name, columns, word_size, bitcell_bl="bl", bitcell_br="br"):
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {0}".format(self.name))
|
||||
self.add_comment("cols: {0} word_size: {1} bl: {2} br: {3}".format(columns, word_size, bitcell_bl, bitcell_br))
|
||||
|
||||
self.columns = columns
|
||||
self.word_size = word_size
|
||||
self.words_per_row = int(self.columns / self.word_size)
|
||||
|
|
|
|||
|
|
@ -15,10 +15,13 @@ class wordline_driver(design.design):
|
|||
Generates the wordline-driver to drive the bitcell
|
||||
"""
|
||||
|
||||
def __init__(self, name, rows):
|
||||
def __init__(self, name, rows, cols):
|
||||
design.design.__init__(self, name)
|
||||
|
||||
debug.info(1, "Creating {0}".format(self.name))
|
||||
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
|
||||
|
||||
self.rows = rows
|
||||
self.cols = cols
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
@ -52,7 +55,9 @@ class wordline_driver(design.design):
|
|||
# This is just used for measurements,
|
||||
# so don't add the module
|
||||
|
||||
self.inv = factory.create(module_type="pinv")
|
||||
self.inv = factory.create(module_type="pdriver",
|
||||
fanout=self.cols,
|
||||
neg_polarity=True)
|
||||
self.add_mod(self.inv)
|
||||
|
||||
self.inv_no_output = factory.create(module_type="pinv",
|
||||
|
|
@ -224,12 +229,12 @@ class wordline_driver(design.design):
|
|||
stage_effort_list = []
|
||||
|
||||
stage1_cout = self.inv.get_cin()
|
||||
stage1 = self.nand2.get_effort_stage(stage1_cout, inp_is_rise)
|
||||
stage1 = self.nand2.get_stage_effort(stage1_cout, inp_is_rise)
|
||||
stage_effort_list.append(stage1)
|
||||
last_stage_is_rise = stage1.is_rise
|
||||
|
||||
stage2 = self.inv.get_effort_stage(external_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage2)
|
||||
stage2 = self.inv.get_stage_efforts(external_cout, last_stage_is_rise)
|
||||
stage_effort_list.extend(stage2)
|
||||
|
||||
return stage_effort_list
|
||||
|
||||
|
|
|
|||
|
|
@ -23,3 +23,8 @@ class write_driver(design.design):
|
|||
self.height = write_driver.height
|
||||
self.pin_map = write_driver.pin_map
|
||||
|
||||
|
||||
def get_w_en_cin(self):
|
||||
"""Get the relative capacitance of a single input"""
|
||||
# This is approximated from SCMOS. It has roughly 5 3x transistor gates.
|
||||
return 5*3
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ class write_driver_array(design.design):
|
|||
def __init__(self, name, columns, word_size):
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {0}".format(self.name))
|
||||
self.add_comment("columns: {0}".format(columns))
|
||||
self.add_comment("word_size {0}".format(word_size))
|
||||
|
||||
self.columns = columns
|
||||
self.word_size = word_size
|
||||
|
|
@ -130,3 +132,7 @@ class write_driver_array(design.design):
|
|||
|
||||
|
||||
|
||||
def get_w_en_cin(self):
|
||||
"""Get the relative capacitance of all the enable connections in the bank"""
|
||||
#The enable is connected to a nand2 for every row.
|
||||
return self.driver.get_w_en_cin() * len(self.driver_insts)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class pand2(pgate.pgate):
|
|||
|
||||
pgate.pgate.__init__(self, name, height)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
self.add_comment("size: {}".format(size))
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
@ -113,15 +113,15 @@ class pand2(pgate.pgate):
|
|||
inv_delay = self.inv.analytical_delay(slew=nand_delay.slew, load=load)
|
||||
return nand_delay + inv_delay
|
||||
|
||||
def get_output_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||
def get_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||
"""Get the stage efforts of the A or B -> Z path"""
|
||||
stage_effort_list = []
|
||||
stage1_cout = self.inv.get_cin()
|
||||
stage1 = self.nand.get_effort_stage(stage1_cout, inp_is_rise)
|
||||
stage1 = self.nand.get_stage_effort(stage1_cout, inp_is_rise)
|
||||
stage_effort_list.append(stage1)
|
||||
last_stage_is_rise = stage1.is_rise
|
||||
|
||||
stage2 = self.inv.get_effort_stage(external_cout, last_stage_is_rise)
|
||||
stage2 = self.inv.get_stage_effort(external_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage2)
|
||||
|
||||
return stage_effort_list
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ class pbuf(pgate.pgate):
|
|||
|
||||
pgate.pgate.__init__(self, name, height)
|
||||
debug.info(1, "creating {0} with size of {1}".format(self.name,self.size))
|
||||
|
||||
self.add_comment("size: {}".format(size))
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
|
@ -115,15 +116,15 @@ class pbuf(pgate.pgate):
|
|||
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
|
||||
return inv1_delay + inv2_delay
|
||||
|
||||
def get_output_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||
def get_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||
"""Get the stage efforts of the A -> Z path"""
|
||||
stage_effort_list = []
|
||||
stage1_cout = self.inv2.get_cin()
|
||||
stage1 = self.inv1.get_effort_stage(stage1_cout, inp_is_rise)
|
||||
stage1 = self.inv1.get_stage_effort(stage1_cout, inp_is_rise)
|
||||
stage_effort_list.append(stage1)
|
||||
last_stage_is_rise = stage1.is_rise
|
||||
|
||||
stage2 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise)
|
||||
stage2 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage2)
|
||||
|
||||
return stage_effort_list
|
||||
|
|
|
|||
|
|
@ -11,100 +11,68 @@ class pdriver(pgate.pgate):
|
|||
"""
|
||||
This instantiates an even or odd number of inverters sized for driving a load.
|
||||
"""
|
||||
def __init__(self, name, neg_polarity=False, fanout_size=8, size_list = [], height=None):
|
||||
def __init__(self, name, neg_polarity=False, fanout=0, size_list=None, height=None):
|
||||
|
||||
self.stage_effort = 4
|
||||
self.stage_effort = 3
|
||||
self.height = height
|
||||
self.neg_polarity = neg_polarity
|
||||
self.size_list = size_list
|
||||
self.fanout_size = fanout_size
|
||||
self.fanout = fanout
|
||||
|
||||
if len(self.size_list) > 0 and (self.fanout_size != 8 or self.neg_polarity):
|
||||
debug.error("Cannot specify both size_list and neg_polarity or fanout_size.", -1)
|
||||
if self.size_list and self.fanout != 0:
|
||||
debug.error("Cannot specify both size_list and fanout.", -1)
|
||||
if self.size_list and self.neg_polarity:
|
||||
debug.error("Cannot specify both size_list and neg_polarity.", -1)
|
||||
|
||||
pgate.pgate.__init__(self, name, height)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
self.compute_sizes()
|
||||
|
||||
self.add_comment("sizes: {}".format(str(self.size_list)))
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def compute_sizes(self):
|
||||
# size_list specified
|
||||
if len(self.size_list) > 0:
|
||||
if not len(self.size_list) % 2:
|
||||
neg_polarity = True
|
||||
self.num_inv = len(self.size_list)
|
||||
if self.size_list:
|
||||
self.num_stages = len(self.size_list)
|
||||
else:
|
||||
# find the number of stages
|
||||
#fanout_size is a unit inverter fanout, not a capacitance so c_in=1
|
||||
num_stages = max(1,int(round(log(self.fanout_size)/log(4))))
|
||||
# Find the optimal number of stages for the given effort
|
||||
self.num_stages = max(1,int(round(log(self.fanout)/log(self.stage_effort))))
|
||||
|
||||
# find inv_num and compute sizes
|
||||
if self.neg_polarity:
|
||||
if (num_stages % 2 == 0): # if num_stages is even
|
||||
self.diff_polarity(num_stages=num_stages)
|
||||
else: # if num_stages is odd
|
||||
self.same_polarity(num_stages=num_stages)
|
||||
else: # positive polarity
|
||||
if (num_stages % 2 == 0):
|
||||
self.same_polarity(num_stages=num_stages)
|
||||
else:
|
||||
self.diff_polarity(num_stages=num_stages)
|
||||
|
||||
# Increase the number of stages if we need to fix polarity
|
||||
if self.neg_polarity and (self.num_stages%2==0):
|
||||
self.num_stages += 1
|
||||
elif not self.neg_polarity and (self.num_stages%2):
|
||||
self.num_stages += 1
|
||||
|
||||
def same_polarity(self, num_stages):
|
||||
self.calc_size_list = []
|
||||
self.num_inv = num_stages
|
||||
# compute sizes
|
||||
fanout_size_prev = self.fanout_size
|
||||
for x in range(self.num_inv-1,-1,-1):
|
||||
fanout_size_prev = int(round(fanout_size_prev/self.stage_effort))
|
||||
self.calc_size_list.append(fanout_size_prev)
|
||||
self.size_list = []
|
||||
# compute sizes backwards from the fanout
|
||||
fanout_prev = self.fanout
|
||||
for x in range(self.num_stages):
|
||||
fanout_prev = max(round(fanout_prev/self.stage_effort),1)
|
||||
self.size_list.append(fanout_prev)
|
||||
|
||||
|
||||
def diff_polarity(self, num_stages):
|
||||
self.calc_size_list = []
|
||||
# find which delay is smaller
|
||||
if (num_stages > 1):
|
||||
delay_below = ((num_stages-1)*(self.fanout_size**(1/num_stages-1))) + num_stages-1
|
||||
delay_above = ((num_stages+1)*(self.fanout_size**(1/num_stages+1))) + num_stages+1
|
||||
if (delay_above < delay_below):
|
||||
# recompute stage_effort for this delay
|
||||
self.num_inv = num_stages+1
|
||||
polarity_stage_effort = self.fanout_size**(1/self.num_inv)
|
||||
else:
|
||||
self.num_inv = num_stages-1
|
||||
polarity_stage_effort = self.fanout_size**(1/self.num_inv)
|
||||
else: # num_stages is 1, can't go to 0
|
||||
self.num_inv = num_stages+1
|
||||
polarity_stage_effort = self.fanout_size**(1/self.num_inv)
|
||||
|
||||
|
||||
# compute sizes
|
||||
fanout_size_prev = self.fanout_size
|
||||
for x in range(self.num_inv-1,-1,-1):
|
||||
fanout_size_prev = int(round(fanout_size_prev/polarity_stage_effort))
|
||||
self.calc_size_list.append(fanout_size_prev)
|
||||
# reverse the sizes to be from input to output
|
||||
self.size_list.reverse()
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
inv_list = []
|
||||
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.create_insts()
|
||||
|
||||
def create_layout(self):
|
||||
self.width = self.num_inv * self.inv_list[0].width
|
||||
self.height = self.inv_list[0].height
|
||||
|
||||
self.place_modules()
|
||||
self.route_wires()
|
||||
self.add_layout_pins()
|
||||
|
||||
|
||||
self.width = self.inv_inst_list[-1].rx()
|
||||
self.height = self.inv_inst_list[0].height
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
|
|
@ -115,33 +83,27 @@ class pdriver(pgate.pgate):
|
|||
|
||||
def add_modules(self):
|
||||
self.inv_list = []
|
||||
if len(self.size_list) > 0: # size list specified
|
||||
for x in range(len(self.size_list)):
|
||||
temp_inv = factory.create(module_type="pinv", size=self.size_list[x], height=self.height)
|
||||
self.inv_list.append(temp_inv)
|
||||
self.add_mod(self.inv_list[x])
|
||||
else: # find inv sizes
|
||||
for x in range(len(self.calc_size_list)):
|
||||
temp_inv = factory.create(module_type="pinv", size=self.calc_size_list[x], height=self.height)
|
||||
self.inv_list.append(temp_inv)
|
||||
self.add_mod(self.inv_list[x])
|
||||
for size in self.size_list:
|
||||
temp_inv = factory.create(module_type="pinv", size=size, height=self.height)
|
||||
self.inv_list.append(temp_inv)
|
||||
self.add_mod(temp_inv)
|
||||
|
||||
|
||||
def create_insts(self):
|
||||
self.inv_inst_list = []
|
||||
for x in range(1,self.num_inv+1):
|
||||
for x in range(1,self.num_stages+1):
|
||||
# Create first inverter
|
||||
if x == 1:
|
||||
zbx_int = "Zb{}_int".format(x);
|
||||
self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x),
|
||||
mod=self.inv_list[x-1]))
|
||||
if self.num_inv == 1:
|
||||
if self.num_stages == 1:
|
||||
self.connect_inst(["A", "Z", "vdd", "gnd"])
|
||||
else:
|
||||
self.connect_inst(["A", zbx_int, "vdd", "gnd"])
|
||||
|
||||
# Create last inverter
|
||||
elif x == self.num_inv:
|
||||
elif x == self.num_stages:
|
||||
zbn_int = "Zb{}_int".format(x-1);
|
||||
self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x),
|
||||
mod=self.inv_list[x-1]))
|
||||
|
|
@ -157,10 +119,10 @@ class pdriver(pgate.pgate):
|
|||
|
||||
|
||||
def place_modules(self):
|
||||
# Add INV1 to the left
|
||||
# Add the first inverter at the origin
|
||||
self.inv_inst_list[0].place(vector(0,0))
|
||||
|
||||
# Add inverters to the right of INV1
|
||||
# Add inverters to the right of the previous inverter
|
||||
for x in range(1,len(self.inv_inst_list)):
|
||||
self.inv_inst_list[x].place(vector(self.inv_inst_list[x-1].rx(),0))
|
||||
|
||||
|
|
@ -207,22 +169,49 @@ class pdriver(pgate.pgate):
|
|||
width = a_pin.width(),
|
||||
height = a_pin.height())
|
||||
|
||||
def input_load(self):
|
||||
return self.inv_list[0].input_load()
|
||||
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
"""Calculate the analytical delay of INV1 -> ... -> INVn"""
|
||||
delay = 0;
|
||||
if len(self.inv_inst_list) == 1:
|
||||
delay = self.inv_inst_list[x].analytical_delay(slew=slew);
|
||||
else:
|
||||
for x in range(len(self.inv_inst_list-1)):
|
||||
load_next = 0.0
|
||||
for n in range(x,len(self.inv_inst_list+1)):
|
||||
load_next += self.inv_inst_list[x+1]
|
||||
if x == 1:
|
||||
delay += self.inv_inst_list[x].analytical_delay(slew=slew,
|
||||
load=load_next)
|
||||
else:
|
||||
delay += self.inv_inst_list[x+1].analytical_delay(slew=delay.slew,
|
||||
load=load_next)
|
||||
|
||||
cout_list = []
|
||||
for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]):
|
||||
cout_list.append(inv.input_load())
|
||||
cout_list.append(load)
|
||||
|
||||
input_slew = slew
|
||||
|
||||
delays = []
|
||||
for inv,cout in zip(self.inv_list,cout_list):
|
||||
delays.append(inv.analytical_delay(slew=input_slew, load=cout))
|
||||
input_slew = delays[-1].slew
|
||||
|
||||
delay = delays[0]
|
||||
for i in range(len(delays)-1):
|
||||
delay += delays[i]
|
||||
|
||||
return delay
|
||||
|
||||
|
||||
def get_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||
"""Get the stage efforts of the A -> Z path"""
|
||||
|
||||
cout_list = {}
|
||||
for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]):
|
||||
cout_list[prev_inv]=inv.get_cin()
|
||||
|
||||
cout_list[self.inv_list[-1]]=external_cout
|
||||
|
||||
stage_effort_list = []
|
||||
last_inp_is_rise = inp_is_rise
|
||||
for inv in self.inv_list:
|
||||
stage = inv.get_stage_effort(cout_list[inv], last_inp_is_rise)
|
||||
stage_effort_list.append(stage)
|
||||
last_inp_is_rise = stage.is_rise
|
||||
|
||||
return stage_effort_list
|
||||
|
||||
def get_cin(self):
|
||||
"""Returns the relative capacitance of the input"""
|
||||
return self.inv_list[0].get_cin()
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ class pinv(pgate.pgate):
|
|||
# have poly connected, for example.
|
||||
pgate.pgate.__init__(self, name, height)
|
||||
debug.info(2, "create pinv structure {0} with size of {1}".format(name, size))
|
||||
self.add_comment("size: {}".format(size))
|
||||
|
||||
self.size = size
|
||||
self.nmos_size = size
|
||||
|
|
@ -286,7 +287,7 @@ class pinv(pgate.pgate):
|
|||
"""Return the capacitance of the gate connection in generic capacitive units relative to the minimum width of a transistor"""
|
||||
return self.nmos_size + self.pmos_size
|
||||
|
||||
def get_effort_stage(self, cout, inp_is_rise=True):
|
||||
def get_stage_effort(self, cout, inp_is_rise=True):
|
||||
"""Returns an object representing the parameters for delay in tau units.
|
||||
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ class pinvbuf(design.design):
|
|||
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
self.add_comment("size: {}".format(size))
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
@ -186,11 +187,11 @@ class pinvbuf(design.design):
|
|||
"""Get the stage efforts of the clk -> clk_buf path"""
|
||||
stage_effort_list = []
|
||||
stage1_cout = self.inv1.get_cin() + self.inv2.get_cin()
|
||||
stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise)
|
||||
stage1 = self.inv.get_stage_effort(stage1_cout, inp_is_rise)
|
||||
stage_effort_list.append(stage1)
|
||||
last_stage_is_rise = stage1.is_rise
|
||||
|
||||
stage2 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise)
|
||||
stage2 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage2)
|
||||
|
||||
return stage_effort_list
|
||||
|
|
@ -200,16 +201,16 @@ class pinvbuf(design.design):
|
|||
#After (almost) every stage, the direction of the signal inverts.
|
||||
stage_effort_list = []
|
||||
stage1_cout = self.inv1.get_cin() + self.inv2.get_cin()
|
||||
stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise)
|
||||
stage1 = self.inv.get_stage_effort(stage1_cout, inp_is_rise)
|
||||
stage_effort_list.append(stage1)
|
||||
last_stage_is_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
stage2_cout = self.inv2.get_cin()
|
||||
stage2 = self.inv1.get_effort_stage(stage2_cout, last_stage_is_rise)
|
||||
stage2 = self.inv1.get_stage_effort(stage2_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage2)
|
||||
last_stage_is_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
stage3 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise)
|
||||
stage3 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage3)
|
||||
|
||||
return stage_effort_list
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ class pnand2(pgate.pgate):
|
|||
""" Creates a cell for a simple 2 input nand """
|
||||
pgate.pgate.__init__(self, name, height)
|
||||
debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size))
|
||||
self.add_comment("size: {}".format(size))
|
||||
|
||||
self.size = size
|
||||
self.nmos_size = 2*size
|
||||
|
|
@ -252,7 +253,7 @@ class pnand2(pgate.pgate):
|
|||
"""Return the relative input capacitance of a single input"""
|
||||
return self.nmos_size+self.pmos_size
|
||||
|
||||
def get_effort_stage(self, cout, inp_is_rise=True):
|
||||
def get_stage_effort(self, cout, inp_is_rise=True):
|
||||
"""Returns an object representing the parameters for delay in tau units.
|
||||
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ class pnand3(pgate.pgate):
|
|||
""" Creates a cell for a simple 3 input nand """
|
||||
pgate.pgate.__init__(self, name, height)
|
||||
debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size))
|
||||
self.add_comment("size: {}".format(size))
|
||||
|
||||
# We have trouble pitch matching a 3x sizes to the bitcell...
|
||||
# If we relax this, we could size this better.
|
||||
|
|
@ -264,7 +265,7 @@ class pnand3(pgate.pgate):
|
|||
"""Return the relative input capacitance of a single input"""
|
||||
return self.nmos_size+self.pmos_size
|
||||
|
||||
def get_effort_stage(self, cout, inp_is_rise=True):
|
||||
def get_stage_effort(self, cout, inp_is_rise=True):
|
||||
"""Returns an object representing the parameters for delay in tau units.
|
||||
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ class pnor2(pgate.pgate):
|
|||
""" Creates a cell for a simple 2 input nor """
|
||||
pgate.pgate.__init__(self, name, height)
|
||||
debug.info(2, "create pnor2 structure {0} with size of {1}".format(name, size))
|
||||
self.add_comment("size: {}".format(size))
|
||||
|
||||
self.nmos_size = size
|
||||
# We will just make this 1.5 times for now. NORs are not ideal anyhow.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import debug
|
|||
from tech import drc, spice
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
import path
|
||||
from sram_factory import factory
|
||||
|
||||
class ptx(design.design):
|
||||
|
|
|
|||
|
|
@ -279,20 +279,23 @@ class sram_base(design, verilog, lef):
|
|||
|
||||
# Create the control logic module for each port type
|
||||
if len(self.readwrite_ports)>0:
|
||||
self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
|
||||
self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
|
||||
words_per_row=self.words_per_row,
|
||||
word_size=self.word_size,
|
||||
sram=self,
|
||||
port_type="rw")
|
||||
self.add_mod(self.control_logic_rw)
|
||||
if len(self.writeonly_ports)>0:
|
||||
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
|
||||
words_per_row=self.words_per_row,
|
||||
word_size=self.word_size,
|
||||
sram=self,
|
||||
port_type="w")
|
||||
self.add_mod(self.control_logic_w)
|
||||
if len(self.readonly_ports)>0:
|
||||
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
|
||||
words_per_row=self.words_per_row,
|
||||
word_size=self.word_size,
|
||||
sram=self,
|
||||
port_type="r")
|
||||
self.add_mod(self.control_logic_r)
|
||||
|
|
@ -512,25 +515,30 @@ class sram_base(design, verilog, lef):
|
|||
|
||||
def get_wl_en_cin(self):
|
||||
"""Gets the capacitive load the of clock (clk_buf) for the sram"""
|
||||
#As clk_buf is an output of the control logic. The cap for that module is not determined here.
|
||||
#Only the wordline drivers within the bank use this signal
|
||||
bank_clk_cin = self.bank.get_wl_en_cin()
|
||||
|
||||
return bank_clk_cin
|
||||
|
||||
return self.bank.get_wl_en_cin()
|
||||
|
||||
def get_w_en_cin(self):
|
||||
"""Gets the capacitive load the of write enable (w_en) for the sram"""
|
||||
#Only the write drivers within the bank use this signal
|
||||
return self.bank.get_w_en_cin()
|
||||
|
||||
|
||||
def get_p_en_bar_cin(self):
|
||||
"""Gets the capacitive load the of precharge enable (p_en_bar) for the sram"""
|
||||
#Only the precharges within the bank use this signal
|
||||
return self.bank.get_p_en_bar_cin()
|
||||
|
||||
def get_clk_bar_cin(self):
|
||||
"""Gets the capacitive load the of clock (clk_buf_bar) for the sram"""
|
||||
#As clk_buf_bar is an output of the control logic. The cap for that module is not determined here.
|
||||
#Only the precharge cells use this signal (other than the control logic)
|
||||
bank_clk_cin = self.bank.get_clk_bar_cin()
|
||||
return bank_clk_cin
|
||||
return self.bank.get_clk_bar_cin()
|
||||
|
||||
def get_sen_cin(self):
|
||||
"""Gets the capacitive load the of sense amp enable for the sram"""
|
||||
#As clk_buf_bar is an output of the control logic. The cap for that module is not determined here.
|
||||
#Only the sense_amps use this signal (other than the control logic)
|
||||
bank_sen_cin = self.bank.get_sen_cin()
|
||||
return bank_sen_cin
|
||||
return self.bank.get_sen_cin()
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ class sram_factory:
|
|||
(obj_kwargs, obj_item) = obj
|
||||
# Must have the same dictionary exactly (conservative)
|
||||
if obj_kwargs == kwargs:
|
||||
debug.info(1, "Existing module: type={0} name={1} kwargs={2}".format(module_type, obj_item.name, str(kwargs)))
|
||||
#debug.info(1, "Existing module: type={0} name={1} kwargs={2}".format(module_type, obj_item.name, str(kwargs)))
|
||||
return obj_item
|
||||
|
||||
# Use the default name if there are default arguments
|
||||
|
|
@ -67,7 +67,7 @@ class sram_factory:
|
|||
# Create a unique name and increment the index
|
||||
module_name = "{0}_{1}".format(module_name, self.module_indices[module_type])
|
||||
self.module_indices[module_type] += 1
|
||||
debug.info(1, "New module: type={0} name={1} kwargs={2}".format(module_type,module_name,str(kwargs)))
|
||||
#debug.info(1, "New module: type={0} name={1} kwargs={2}".format(module_type,module_name,str(kwargs)))
|
||||
obj = mod(name=module_name,**kwargs)
|
||||
self.objects[module_type].append((kwargs,obj))
|
||||
return obj
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class path_test(openram_test):
|
|||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
import path
|
||||
import wire_path
|
||||
import tech
|
||||
import design
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ class path_test(openram_test):
|
|||
[0, 3 * min_space ],
|
||||
[0, 6 * min_space ]]
|
||||
w = design.design("path_test0")
|
||||
path.path(w,layer_stack, position_list)
|
||||
wire_path.wire_path(w,layer_stack, position_list)
|
||||
self.local_drc_check(w)
|
||||
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ class path_test(openram_test):
|
|||
[-1 * min_space, 0]]
|
||||
position_list = [[x+min_space, y+min_space] for x,y in old_position_list]
|
||||
w = design.design("path_test1")
|
||||
path.path(w,layer_stack, position_list)
|
||||
wire_path.wire_path(w,layer_stack, position_list)
|
||||
self.local_drc_check(w)
|
||||
|
||||
min_space = 2 * tech.drc["minwidth_metal2"]
|
||||
|
|
@ -60,7 +60,7 @@ class path_test(openram_test):
|
|||
[-1 * min_space, 0]]
|
||||
position_list = [[x-min_space, y-min_space] for x,y in old_position_list]
|
||||
w = design.design("path_test2")
|
||||
path.path(w, layer_stack, position_list)
|
||||
wire_path.wire_path(w, layer_stack, position_list)
|
||||
self.local_drc_check(w)
|
||||
|
||||
min_space = 2 * tech.drc["minwidth_metal3"]
|
||||
|
|
@ -77,7 +77,7 @@ class path_test(openram_test):
|
|||
# run on the reverse list
|
||||
position_list.reverse()
|
||||
w = design.design("path_test3")
|
||||
path.path(w, layer_stack, position_list)
|
||||
wire_path.wire_path(w, layer_stack, position_list)
|
||||
self.local_drc_check(w)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -22,22 +22,22 @@ class pdriver_test(openram_test):
|
|||
|
||||
debug.info(2, "Testing inverter/buffer 4x 8x")
|
||||
# a tests the error message for specifying conflicting conditions
|
||||
#a = pdriver.pdriver(fanout_size = 4,size_list = [1,2,4,8])
|
||||
#a = pdriver.pdriver(fanout = 4,size_list = [1,2,4,8])
|
||||
#self.local_check(a)
|
||||
|
||||
b = pdriver.pdriver(name="pdriver1", size_list = [1,2,4,8])
|
||||
self.local_check(b)
|
||||
|
||||
c = pdriver.pdriver(name="pdriver2", fanout_size = 50)
|
||||
c = pdriver.pdriver(name="pdriver2", fanout = 50)
|
||||
self.local_check(c)
|
||||
|
||||
d = pdriver.pdriver(name="pdriver3", fanout_size = 50, neg_polarity = True)
|
||||
d = pdriver.pdriver(name="pdriver3", fanout = 50, neg_polarity = True)
|
||||
self.local_check(d)
|
||||
|
||||
e = pdriver.pdriver(name="pdriver4", fanout_size = 64)
|
||||
e = pdriver.pdriver(name="pdriver4", fanout = 64)
|
||||
self.local_check(e)
|
||||
|
||||
f = pdriver.pdriver(name="pdriver5", fanout_size = 64, neg_polarity = True)
|
||||
f = pdriver.pdriver(name="pdriver5", fanout = 64, neg_polarity = True)
|
||||
self.local_check(f)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class wordline_driver_test(openram_test):
|
|||
|
||||
# check wordline driver for single port
|
||||
debug.info(2, "Checking driver")
|
||||
tx = wordline_driver.wordline_driver(name="wld1", rows=8)
|
||||
tx = wordline_driver.wordline_driver(name="wld1", rows=8, cols=32)
|
||||
self.local_check(tx)
|
||||
|
||||
# check wordline driver for multi-port
|
||||
|
|
@ -33,7 +33,7 @@ class wordline_driver_test(openram_test):
|
|||
|
||||
factory.reset()
|
||||
debug.info(2, "Checking driver (multi-port case)")
|
||||
tx = wordline_driver.wordline_driver(name="wld2", rows=8)
|
||||
tx = wordline_driver.wordline_driver(name="wld2", rows=8, cols=64)
|
||||
self.local_check(tx)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class control_logic_test(openram_test):
|
|||
|
||||
# check control logic for single port
|
||||
debug.info(1, "Testing sample for control_logic")
|
||||
a = control_logic.control_logic(num_rows=128, words_per_row=1)
|
||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=32)
|
||||
self.local_check(a)
|
||||
|
||||
# check control logic for multi-port
|
||||
|
|
@ -31,7 +31,7 @@ class control_logic_test(openram_test):
|
|||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(1, "Testing sample for control_logic for multiport")
|
||||
a = control_logic.control_logic(num_rows=128, words_per_row=1)
|
||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8)
|
||||
self.local_check(a)
|
||||
|
||||
# Check port specific control logic
|
||||
|
|
@ -40,15 +40,15 @@ class control_logic_test(openram_test):
|
|||
OPTS.num_r_ports = 1
|
||||
|
||||
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="rw")
|
||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="rw")
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="w")
|
||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="w")
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
|
||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="r")
|
||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="r")
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -53,27 +53,27 @@ class timing_sram_test(openram_test):
|
|||
data.update(port_data[0])
|
||||
|
||||
if OPTS.tech_name == "freepdk45":
|
||||
golden_data = {'delay_hl': [0.2011],
|
||||
'delay_lh': [0.2011],
|
||||
'leakage_power': 0.002,
|
||||
'min_period': 0.41,
|
||||
'read0_power': [0.63604],
|
||||
'read1_power': [0.6120599999999999],
|
||||
'slew_hl': [0.10853],
|
||||
'slew_lh': [0.10853],
|
||||
'write0_power': [0.51742],
|
||||
'write1_power': [0.51095]}
|
||||
golden_data = {'delay_hl': [0.2152017],
|
||||
'delay_lh': [0.2152017],
|
||||
'leakage_power': 0.0022907,
|
||||
'min_period': 0.488,
|
||||
'read0_power': [0.47437749999999995],
|
||||
'read1_power': [0.45026109999999997],
|
||||
'slew_hl': [0.0846786],
|
||||
'slew_lh': [0.0846786],
|
||||
'write0_power': [0.40809259999999997],
|
||||
'write1_power': [0.4078904]}
|
||||
elif OPTS.tech_name == "scn4m_subm":
|
||||
golden_data = {'delay_hl': [1.3911],
|
||||
'delay_lh': [1.3911],
|
||||
'leakage_power': 0.0278488,
|
||||
'min_period': 2.812,
|
||||
'read0_power': [22.1183],
|
||||
'read1_power': [21.4388],
|
||||
'slew_hl': [0.7397553],
|
||||
'slew_lh': [0.7397553],
|
||||
'write0_power': [19.4103],
|
||||
'write1_power': [20.1167]}
|
||||
golden_data = {'delay_hl': [1.4333000000000002],
|
||||
'delay_lh': [1.4333000000000002],
|
||||
'leakage_power': 0.0271847,
|
||||
'min_period': 2.891,
|
||||
'read0_power': [15.714200000000002],
|
||||
'read1_power': [14.9848],
|
||||
'slew_hl': [0.6819276999999999],
|
||||
'slew_lh': [0.6819276999999999],
|
||||
'write0_power': [13.9658],
|
||||
'write1_power': [14.8422]}
|
||||
else:
|
||||
self.assertTrue(False) # other techs fail
|
||||
# Check if no too many or too few results
|
||||
|
|
|
|||
|
|
@ -51,27 +51,27 @@ class timing_sram_test(openram_test):
|
|||
data.update(port_data[0])
|
||||
|
||||
if OPTS.tech_name == "freepdk45":
|
||||
golden_data = {'delay_hl': [0.20443139999999999],
|
||||
'delay_lh': [0.20443139999999999],
|
||||
'leakage_power': 0.0017840640000000001,
|
||||
'min_period': 0.41,
|
||||
'read0_power': [0.6435831],
|
||||
'read1_power': [0.6233463],
|
||||
'slew_hl': [0.1138734],
|
||||
'slew_lh': [0.1138734],
|
||||
'write0_power': [0.5205761],
|
||||
'write1_power': [0.5213689]}
|
||||
golden_data = {'delay_hl': [0.221699],
|
||||
'delay_lh': [0.221699],
|
||||
'leakage_power': 0.001467648,
|
||||
'min_period': 0.605,
|
||||
'read0_power': [0.3879335],
|
||||
'read1_power': [0.3662724],
|
||||
'slew_hl': [0.08562444999999999],
|
||||
'slew_lh': [0.08562444999999999],
|
||||
'write0_power': [0.3362456],
|
||||
'write1_power': [0.3372035]}
|
||||
elif OPTS.tech_name == "scn4m_subm":
|
||||
golden_data = {'delay_hl': [1.610911],
|
||||
'delay_lh': [1.610911],
|
||||
'leakage_power': 0.0023593859999999998,
|
||||
'min_period': 3.281,
|
||||
'read0_power': [20.763569999999998],
|
||||
'read1_power': [20.32745],
|
||||
'slew_hl': [0.7986348999999999],
|
||||
'slew_lh': [0.7986348999999999],
|
||||
'write0_power': [17.58272],
|
||||
'write1_power': [18.523419999999998]}
|
||||
golden_data = {'delay_hl': [1.7951730000000001],
|
||||
'delay_lh': [1.7951730000000001],
|
||||
'leakage_power': 0.001669513,
|
||||
'min_period': 3.594,
|
||||
'read0_power': [17.03022],
|
||||
'read1_power': [16.55897],
|
||||
'slew_hl': [0.7079951],
|
||||
'slew_lh': [0.7079951],
|
||||
'write0_power': [15.16726],
|
||||
'write1_power': [16.13527]}
|
||||
else:
|
||||
self.assertTrue(False) # other techs fail
|
||||
|
||||
|
|
|
|||
|
|
@ -183,7 +183,9 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
|
|||
#'lvsAbortOnSupplyError' : 0
|
||||
|
||||
# This should be removed for final verification
|
||||
if not final_verification:
|
||||
# FIXMEFIXMEFIXME
|
||||
# MRG: Just doing this to merge pdriver
|
||||
if True or not final_verification:
|
||||
lvs_runset['cmnVConnectReport']=1
|
||||
lvs_runset['cmnVConnectNamesState']='SOME'
|
||||
lvs_runset['cmnVConnectNames']='vdd gnd'
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
The NCSU CDK is Copyright (C) NC State University, 1998, 1999, 2004,
|
||||
2006. Users are free to use or modify the NCSU CDK as appropriate as long
|
||||
as this notice appears in the modified package. The NCSU CDK is
|
||||
provided with NO WARRANTY.
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
The NCSU CDK is Copyright (C) NC State University, 1998, 1999, 2004,
|
||||
2006. Users are free to use or modify the NCSU CDK as appropriate as long
|
||||
as this notice appears in the modified package. The NCSU CDK is
|
||||
provided with NO WARRANTY.
|
||||
Loading…
Reference in New Issue