mirror of https://github.com/VLSIDA/OpenRAM.git
390 lines
17 KiB
TeX
390 lines
17 KiB
TeX
\section{Software Implementation}
|
|
\label{sec:implementation}
|
|
|
|
OpenRAM is implemented using object-oriented data structures in the
|
|
Python programming language. The top-level executable is
|
|
\verb|openram.py| which parses input arguments, creates the memory and
|
|
saves the output.
|
|
|
|
|
|
\subsection{Design Hierarchy}
|
|
\label{sec:design}
|
|
|
|
All modules in OpenRAM are derived from the \verb|design| class in
|
|
\verb|design.py|. The design class is a data structure that consists
|
|
of a spice netlist, a layout, and a name. The spice netlist
|
|
capabilities are inherited from the \verb|hierarchy_spice| class while
|
|
the layout capabilities are inherited from the \verb|hierarchy_layout|
|
|
class. The only additional function in design.py is \verb|DRC_LVS()|,
|
|
which performs a DRC/LVS check on the module.
|
|
|
|
|
|
\begin{figure}[htb]
|
|
\centering
|
|
\includegraphics[width=10cm]{./figs/class_hierarchy.pdf}
|
|
\caption{Class hierarchy}
|
|
\label{fig:class_hierarchy}
|
|
\end{figure}
|
|
|
|
\subsubsection{Spice Hierarchy}
|
|
|
|
The spice hierarchy is stored in the \verb|spice| class in
|
|
\verb|hierarchy_spice.py|. When the design class is initialized for a
|
|
module, a data structure for the spice hierarchy is created. The
|
|
spice data stucture name becomes the name of the top-level subcircuit
|
|
definition for the module. The list of pins for the module are added
|
|
to the subcircuit definition by using the \verb|add_pin()| function.
|
|
The \verb|add_mod()| function adds an instance of a
|
|
module/library\_cell/parameterized\_cell as a subcircuit to the
|
|
top-level structure. Each time a sub-module has been added to the
|
|
hierarchy, the pins of the sub-module must be connected using the
|
|
\verb|connect_pins()| function. It is important to note that the pins
|
|
must be listed in the same order as they were added to the submodule.
|
|
Also, an assertion error will occur if there is a mismatch in the
|
|
number of net connections. The \verb|spice| class also contains
|
|
functions for reading or writing spice files:
|
|
\begin{itemize}
|
|
\item \verb|sp_read():| this function is used to read in spice
|
|
netlists and parse the inputs defined by the ``subckt'' definition.
|
|
\item \verb|sp_write():| this function creates an empty spice file in
|
|
write mode and calls \verb|sp_write_file()|.
|
|
\item \verb|sp_write_file():| this function recursively writes the
|
|
modules and sub-modules from the data structure into the spice file
|
|
created by \verb|sp_write()|.
|
|
\end{itemize}
|
|
|
|
\subsubsection{Layout Hierarchy}
|
|
|
|
The layout hierarchy is stroed in the \verb|layout| class in
|
|
\verb|hierarchy_layout.py|. When the design class is initialized for
|
|
a module, a data structure for the layout hierarchy is created. The
|
|
layout data structure has two main components: a structure for the
|
|
instances of sub-modules contained in the layout, and a structure for
|
|
the objects (such as shapes, labels, etc...) contained in the layout.
|
|
The functions included in the \verb|layout| class are:
|
|
\begin{itemize}
|
|
\item \verb|def add_inst(self,name,mod,offset,mirror):| adds an
|
|
instance of a physical layout (library cell, module, or
|
|
parameterized cell) to the module. The input parameters are :
|
|
\begin{description}
|
|
\item[name] - name for the instance.
|
|
\item[mod] - the associated spice module.
|
|
\item[offset] - the x-y coordinates, in microns, where the instance
|
|
should be placed in the layout.
|
|
\item[mirror] - mirror or rotate the instance before it is added to
|
|
the layout. Accepted values for mirror are:
|
|
\verb|"R0", "R90", "R180", "R270"| $^\ast$Currently, only ``R0'' works.\\
|
|
\verb|"MX" or "x", "MY" or "y", "XY" or "xy"| (``xy'' is
|
|
equivalent to ``R180'')
|
|
\end{description}
|
|
\item \verb|add_rect(self,layerNumber,offset,width,height):| adds a
|
|
rectangle to the module's layout. The inputs are:
|
|
\begin{description}
|
|
\item[layernumber] - the layer that the rectangle is to be drawn in.
|
|
\item[offset] - the x-y coordinates, in microns, where the
|
|
rectangle's origin will be placed in the layout.
|
|
\item[width] - the width of the rectangle, can be positive or
|
|
negative value.
|
|
\item[height] - the height of the rectangle, can be positive or
|
|
negative value.
|
|
\end{description}
|
|
\item \verb|add_label(self,text,layerNumber,offset,zoom):| adds a
|
|
label to the layout. The inputs are:
|
|
\begin{description}
|
|
\item[text] - the text for the label
|
|
\item[layernumber] - the layer that the label is to be drawn in .
|
|
\item[offset] - the x-y coordinates, in microns, where the label
|
|
will be placed in the layout.
|
|
\item[zoom] - magnification of the label (ex: ``1e9'').
|
|
\end{description}
|
|
\item \verb|add_path(self,layerNumber,coordinates,width):| this
|
|
function is under construction...
|
|
\item \verb|gds_read():| reads in a GDSII file and creates a
|
|
\verb|VlsiLayout()| class for it.
|
|
\item \verb|gds_write():| writes the entire GDS of the object to a
|
|
file by gdsMill \verb|vlsiLayout()| class and calling the
|
|
\verb|gds2writer()| (see Sections~\ref{sec:vlsilayout}
|
|
and~\ref{sec:gdsmill}.
|
|
\item \verb|gds_write_file():| recursively the instances and objects
|
|
in layout data structure to the gds file.
|
|
\item \verb|pdf_write():| this function is under construction...
|
|
\end{itemize}
|
|
|
|
|
|
\subsection{Creating a New Design Module}
|
|
\label{sec:new_design}
|
|
|
|
Each module in the SRAM is its own Python class, which contains a
|
|
design class, or data structure, for the layout and spice. The
|
|
\verb|design| class (\verb|design.py|) is initialized within the
|
|
module class, subsequently creating separate data structurse to hold
|
|
the layout (\verb|hierarchy_layout|) and spice
|
|
(\verb|hierarchy_spice|) information. By having a class for each
|
|
module, it is very easy to instatiate instances of the modules in any
|
|
level of the hierarchy. Follow these guidelines when creating a new
|
|
module:
|
|
|
|
|
|
\begin{itemize}
|
|
\item Derive your class from the design module:
|
|
\begin{verbatim}
|
|
class bitcell_array(design.design):
|
|
\end{verbatim}
|
|
\item Always use the python constructor \verb|__init__| method so that
|
|
your class is initialized when an object of the module is
|
|
instatiated. The module parameters should also be declared:
|
|
\begin{verbatim}
|
|
def __init__(self, cols, rows):
|
|
\end{verbatim}
|
|
\item In the constructor, call the base class constructor with the
|
|
name such as:
|
|
\begin{verbatim}
|
|
design.design.__init__(self,"bitcell_array")
|
|
\end{verbatim}
|
|
\item Add the pins that will be used in the spice netlist for your
|
|
module using the \verb|add_pin()| function from the
|
|
\verb|hierarchy_spice| class.
|
|
\begin{verbatim}
|
|
self.add_pin("vdd")
|
|
\end{verbatim}
|
|
\item Create an instance of the module/library\_cell/parameterized
|
|
cell that you want to add to your module:
|
|
\begin{verbatim}
|
|
cell=bitcell.bitcell(cell_6t)
|
|
\end{verbatim}
|
|
\item Add the subckt/submodule instance to the spice hierarchy using
|
|
the \verb|add_mod()| function from the \verb|hierarchy_spice| class:
|
|
\begin{verbatim}
|
|
self.add_mod(cell)
|
|
\end{verbatim}
|
|
\item Add layout instance into your module's layout hierarchy using
|
|
the \verb|add_instance|() function, which takes a name, mod, offset,
|
|
and mirror as inputs:
|
|
\begin{verbatim}
|
|
self.add_inst(name=name,mod=cell,offset=[x_off,y_off],mirror=x)
|
|
\end{verbatim}
|
|
\item Connect the pins of the instance that was just added by using
|
|
the \verb|connect_pins| function from the \verb|hierarchy_spice|
|
|
class:
|
|
\begin{verbatim}
|
|
self.connect_inst([BL[%d]%col, BR[%d]%col, WL[%d]%row, gnd, vdd]).
|
|
\end{verbatim}
|
|
The pins must be listed in the same order as they were added to the
|
|
submodule. Also, an assertion error will occur if there is a
|
|
mismatch in the number of net connections.
|
|
\item Do whatever else needs to be done. Add rectangles for
|
|
power/ground rails or routing, add labels, etc...
|
|
\item Every module needs to have ``self'' height and width variable
|
|
that can be accessed from outside of the module class. These
|
|
paramaters are commonly used for placing instances modules in a
|
|
layout. For library cells, the \verb|self.width| and
|
|
\verb|self.height| variables are automatically parsed from the GDSII
|
|
layout using the \verb|cell_size()| function in \verb|vlsi_layout|.
|
|
Users must define the width and height of dynamically generated
|
|
designs.
|
|
\item Add a call to the \verb|DRC_LVS()| function.
|
|
\end{itemize}
|
|
|
|
\subsection{GDSII Files and GdsMill)}
|
|
\label{sec:gds}
|
|
|
|
GDSII is the standard file used in indusrty to store the layout
|
|
information of an integrated circuit. The GDSII file is a stream file
|
|
that consists of records and data types that hold the data for the
|
|
various instances, shapes, labels, etc.. in the layout. In OpenRAM, we
|
|
utlize a nifty tool, called gdsMill, to read, write, and manipulate
|
|
GDSII files. GdsMill was developed by Michael Wieckowski at the
|
|
University of Michigan.
|
|
|
|
\subsubsection{GDSII File Format}
|
|
\label{sec:format}
|
|
|
|
The format of gds file contains several parts, as it could be shown in
|
|
Figure~\ref{fig:gds_file}.
|
|
|
|
\begin{figure}[htb]
|
|
\centering
|
|
\includegraphics[width=10cm]{./figs/gds_file}
|
|
\caption{example of a GDSII file}
|
|
\label{fig:gds_file}
|
|
\end{figure}
|
|
|
|
The first part is the gds file header, which the contains GDSII
|
|
version number, date modified, date last accessed, library, user
|
|
units, and database units.
|
|
|
|
The second part is the list of structures. These structures contain
|
|
geometries or references to other structures of the layout in
|
|
heirarchical form. Within a structure there are several kinds of
|
|
records:
|
|
|
|
\begin{itemize}
|
|
\item Rectangle - basic geometry unit in a design, represent one layer
|
|
of material in a circuit(i.e. a metal pin). Five coordinates and
|
|
layer number are stored in rectangle record.
|
|
\item Structure Reference - a structure that is used in this
|
|
structure. The information about this reference will be used store
|
|
as a structure in the same gds file.
|
|
\item Text - a text record used for labels.
|
|
\item Path - used to represent a wire.
|
|
\item Boundary - defines a filled polygon.
|
|
\item Array Reference - specifies an array of structure instances
|
|
\item Node - Electrical nets may be specified with the NODE record
|
|
\end{itemize}
|
|
|
|
The last part is the tail of the GDSII file which ends the GDS
|
|
Library.
|
|
|
|
\fixme{Provide a link to the complete GDSII specification.}
|
|
|
|
\subsubsection{GdsMill}
|
|
\label{sec:gdsmill}
|
|
|
|
As previously stated, GdsMill is a set of scripts that can be used to read, write, and manipulate GDSII files.
|
|
|
|
\paragraph{The gds2\_reader and gds2\_writer:}
|
|
|
|
In GdsMill, the \verb|gds2_reader| and \verb|gds2_writer| classes contain the various functions used to convert data between GDSII files and the \verb|vlsilayout| class. These classes process the data by iterating through every record in the GDS structures and check or write every data record. The record type (see Section~\ref{sec:format}),is tracked and identified using flags.
|
|
|
|
\fixme{Do we need more information of these classes, or should we just point to the GdsMill documentation?}
|
|
|
|
\paragraph{The VlsiLayout Class:}
|
|
\label{sec:vlsilayout}
|
|
|
|
After the \verb|gds2_reader| class reads in the records, the data has to be stored in a
|
|
way that can be easily used by our code. Thus, the
|
|
\verb|VlsiLayout| class is made to represent the layout.
|
|
\verb|VlsiLayout| contains the same information as GDSII file but in a
|
|
different way. \verb|VlsiLayout| stores records in data structures, which
|
|
are defined in \verb|gdsPrimitives.py|. Each record type has a corresponding class defined in \verb|gdsPrimitives|. Thus, a vlsilayout should at least
|
|
contains following member data:
|
|
\begin{itemize}
|
|
\item \verb|self.rootStructureName| - name of the top design.
|
|
\item \verb|self.structures| -list of structure that are used in the class.
|
|
\item \verb|self.xyTree| - contains a list of all structure names that appeared in the design.
|
|
\end{itemize}
|
|
|
|
The \verb|VlsiLayout| class also contains many functions for adding
|
|
structures and records to a layout class, but the important and most
|
|
useful functions have been aggregated into a wrapper file. This
|
|
wrapper is called \verb|geometry.py| and is located in the
|
|
\verb|compiler| directory.
|
|
|
|
\subsubsection{OpenRAM-GdsMill Interface}
|
|
\label{sec:wrapper}
|
|
|
|
Dynamically generated cells and arrays each need to build a
|
|
\verb|VlsiLayout| data structure to represent the hierarchical layout.
|
|
This is performed using various functions from the \verb|VlsiLayout|
|
|
class in GdsMill, but the GdsMill file is very large and can be
|
|
difficult to understand. To make things easier, OpenRAM has its own
|
|
wrapper class called \verb|geometry| in \verb|geometry.py|. This
|
|
wrapper class initializes data structures for the
|
|
instances and objects that will be added to the \verb|VlsiLayout|
|
|
class. The functions \verb|add_inst()|, \verb|add_rect()|,
|
|
\verb|add_label()| in \verb|hierarchy_layout|, add the structures to
|
|
the \verb|geometry| class, which is then written out to a GDSII file
|
|
using \verb|VlsiLayout| and the \verb|gds2_writer|.
|
|
|
|
User included library cells, which should be in gds files, can be used
|
|
as dynamically generated cells by using GDSMill.
|
|
Cell information such as cell size and pin location can be obtained by using
|
|
built in functions in the \verb|VlsiLayout| class.
|
|
|
|
Cell size can be finded by using the \verb|readLayoutBorder| function of the \verb|VlsiLayout| class.
|
|
A boundary layer should be drawn in each library cell to indicate the cell area.
|
|
The \verb|readLayoutBorder| function will return the width and height of the boundary.
|
|
If a boundary layer do not exist in the layout, then \verb|measureSize| can find the physical
|
|
size cell.
|
|
The first method is used as primary method in \verb|auto_Measure_libcell| the lib\_utility.py,
|
|
while the second method is used as a back up one.
|
|
Each technolgy setup will import this utility function and read the library cell.
|
|
|
|
Pin location can be find by using the \verb|readPin| function of the \verb|VlsiLayout| class.
|
|
The \verb|readPin| function will return the biggest boundary which covers the label and
|
|
is at the same layer as the label is.
|
|
|
|
|
|
\subsection{Technology Directory}
|
|
\label{sec:techdir}
|
|
|
|
The aim of creating technology directory is to make OpenRAM portable
|
|
to different technologies. This directory contains all the information
|
|
related to the specific process/technology that is being used. In
|
|
OpenRAM, the default technology is FreePDK45, which has it own
|
|
technolony directory in the trunk. The technology-specific directory
|
|
should consist of the following:
|
|
\begin{itemize}
|
|
\item Technology Setup FIle - In \verb|/techdir/setup_scripts|, there
|
|
should be a Python file that sets up the PDK and defines anything
|
|
necessary for a given technology. This file should be named
|
|
\verb|setup_openram_<techname>.py| where techname is the name used
|
|
to identify it in configuration scripts.
|
|
\item Technology-Specific Parameters - These parameters should include
|
|
layer numbers and any design rules that may be needed for generating
|
|
dynamic designs (DRC rules). The parameters should be added in
|
|
\verb|techname/tech/tech.py| and optinally in a \verb|techname/layer.map| for
|
|
DRC/LVS streaming.
|
|
\item Library Cells - The library cells and corresponding spice
|
|
netlists should be added to the \verb|techname/gds_lib| and
|
|
\verb|techname/sp_lib| directories.
|
|
\item Spice Models - If models are not supplied in the PDK, they can be
|
|
placed in the technology directory as done in SCMOS.
|
|
\end{itemize}
|
|
|
|
The height and width of library cells is determined by the bounding
|
|
box of all geometries. Sometimes this is not desired, for example,
|
|
when a rail must be shared. In this case, the boundary layer in the
|
|
technology file is used to define the height and width of the cell.
|
|
|
|
Pins are recognized in library cells by the largest rectangle that
|
|
encloses the pin label text. Multiple pins with the same name are
|
|
supported. Pins with the same name such as gnd are assumed to be
|
|
``must connect'' which requires that they later be connected.
|
|
|
|
For more information regarding the technology directory and how to set
|
|
one up for a new technology, refer to Section~\ref{sec:porting}
|
|
|
|
\subsection{DRC/LVS Interface}
|
|
\label{sec:drclvs}
|
|
|
|
Each design class contains a function \verb|DRC_LVS()| that performs both
|
|
DRC and LVS on the current design module. This enables bottom-up
|
|
correct-by-construction design and easy identification of where errors
|
|
occur. It does incur some run-time overhead and can be disabled on
|
|
the command line. The \verb|DRC_LVS()| function saves a GDSII file and a Spice
|
|
file into a temporary directory and then calls two functions to
|
|
perform DRC and LVS that are tool-dependent.
|
|
|
|
Wrapper implementation for DRC and LVS functions are provided for the
|
|
open-source tools Magic+Netgen and the commercial tool, Cadence
|
|
Calibre. Each of these functions generates a batch-mode script or runset
|
|
file which contains the options to correctly run DRC and LVS. The
|
|
functions then parse the batch mode output for any potential errors
|
|
and returns the number of errors encountered.
|
|
|
|
The function \verb|run_drc()| requires a cell name and a GDSII
|
|
file. The cell name corresponds to the top level cell in the GDSII
|
|
file. For Calibre, it also uses the layer map file for the technology
|
|
to correctly import the GDSII file into the Cadence database to
|
|
perform DRC. The function returns the number of DRC violations.
|
|
|
|
The function \verb|run_lvs()| requires a cell name, a GDSII file, and
|
|
a Spice file. Magic or Calibre will extract an extracted Spice netlist
|
|
from the GDSII file and will then compare this netlist with the
|
|
OpenRAM Spice netlist. The function returns the number of errors
|
|
encountered if there is an LVS mismatch.
|
|
|
|
|
|
For both DRC and LVS, the summary file and other report files are left
|
|
in the OpenRAM temporary directory after DRC/LVS is run. These report
|
|
files can be examined to further understand why errors were
|
|
encountered. In addition, by increasing the debug level with one or
|
|
more ``-v'' command-line parametres, the command to re-create the
|
|
DRC/LVS check can be obtained and run manually.
|
|
|
|
|
|
|
|
|
|
|