\section{Implementation} \label{sec:implementation} % source langauge OpenRAM's methodology is implemented using an object-oriented approach in the Python programming language. Python is a simple, yet powerful language that is easy to learn and very human-readable. Moreover, Python enables portability to most operating systems. OpenRAM has no additional dependencies except a DRC/LVS tool, but that is disabled with a warning if the tools are unavailable. % portability of tools and technologies In addition to system portability, OpenRAM is also translatable across numerous process technologies. This is accomplished by using generalized routines to generate the memory based on common features across all technologies. To facilitate user modification and technology interoperability, OpenRAM provides a reference implementation in $45$nm FreePDK45~\cite{4231502} and a fabricable option using the MOSIS Scalable CMOS (SCMOS) design rules~\cite{scmos}. FreePDK45 uses many design rules found in modern technologies, but is non-fabricable, while SCMOS enables fabrication of designs using the MOSIS foundry services. SCMOS is not confidential and an implementation using it is included, however, it does not include many advanced DSM design rules. OpenRAM has also been ported to other commercial technologies, but these are not directly included due to licensing issues. % methodology overview OpenRAM's framework is divided into \enquote{front-end} and \enquote{back-end} methodologies as shown in Figure~\ref{fig:methodology}. The front-end has the compiler and the characterizer. The compiler generates SPICE models and its GDSII layouts based on user inputs. The characterizer calls a SPICE simulator to produce timing and power results. The back-end uses a spice netlist extracted from the GDSII layout using to generate annotated timing and power models. \begin{figure}[tb] \centering \includegraphics[width=8cm]{./figs/methodology.pdf} \caption{Overall Compilation and Characterization Methodology} \label{fig:methodology} \end{figure} %\fixme{We actually dont have back end done yet.} \subsection{Base Data Structures} The design modules in OpenRAM are derived from the {\it design} class (design.py). The design class has a name, a SPICE model (netlist), and a layout. Both the SPICE model and the layout inherit their capabilities from a hierarchical class. The design class also provides inherited functions to perform DRC and LVS verification of any sub-design for hierarchical debugging. The design class derives from the {\it spice} class (hierarchy\_\allowbreak spice.py) which has a data structure to maintain the circuit hierarchy. This class maintains the design instances, their pins, and their connections as well as helper functions to maintain the structure and connectivity of the circuit hierarchy. The design class also derives from a {\it layout} class (hierarchy\_layout.py). This class has a list of physical instances of sub-modules in the layout and a structure for simple objects such as shapes and labels in the current hierarchy level. In addition, there are helper functions that maintain the physical layout structures. OpenRAM has an integrated, custom GDSII library to read, write, and manipulate GDSII files. The library, originally called GdsMill~\cite{gdsmill}, has been modified, debugged, and extended for OpenRAM. Full rights were given to include the GdsMill source with OpenRAM, but to make the interfacing easier and porting to other physical layout databases possible, OpenRAM implements a {\it geometry} wrapper class (geometry.py) that abstracts the GdsMill library. \subsection{Technology and Tool Portability} % technology overview OpenRAM is technology-independent by using a technology directory that includes the technology's specific information, rules, and library cells. Technology parameters such as the design rule check (DRC) rules and the GDS layer map are required to ensure that the dynamically generated designs are DRC clean. Custom designed library cells such as the memory cell and the sense amplifier are also placed in this directory. A very simple design rule parameter file has the most important design rules for constructing basic interconnect and transistor devices. FreePDK45 and SCMOS reference technologies are provided. % hand-optimized cells OpenRAM uses some custom-designed library primitives as technology input. Since density is extremely important, the following cells are pre-designed in each technology: 6T cell, sense amplifier, master-slave flip-flop, tri-state gate, and write driver. All other cells are generated on-the-fly using parameterizable transistor and gate primitives. % technology specific features OpenRAM can be used for various technologies since it creates the basic components of memory designs that are common over these technologies. For technologies that have specific design requirements, such as specialized well contacts, the user can include call-back helper functions in the technology directory. This is done so that the main compiler remains free of dependencies to specific technologies. % DRC and LVS OpenRAM has two functions that provide a wrapper interface with DRC and LVS tools. These two functions perform DRC and LVS using the GDSII layout and SPICE netlist files. Since each DRC and LVS tool has different output, this routine is customized per tool to parse DRC/LVS reports and return the number of errors while also outputting debug information. These routines allow flexibility of any DRC/LVS tool, but the default implementation calls Calibre nmDRC and nmLVS. In OpenRAM, both DRC and LVS are performed at all levels of the design hierarchy to enhance bug tracking. DRC and LVS can be disabled for improved run-time or if tool licenses are not available. \subsection{Class Hierarchy} \subsubsection{High-Level Classes} The {\it openram} class (openram.py) organizes execution and instantiates a single memory design using the {\it sram} class. It accepts user-provided parameters to generate the design, performs the optional extraction, performs characterization, and saves the resulting design files. The {\it sram} class (sram.py) decides the appropriate internal parameter dependencies shown in Table~\ref{table:variables}. They are dependent on the user-desired data word size, number of words, and number of banks. It is responsible for instantiation of the single control logic module which controls the SRAM banks. The control logic ensures that only one bank is active in a given address range. The {\it bank} class (bank.py) does the bulk of the non-control memory layout. It instantiates $1$, $2$, or $4$ bit-cell arrays and coordinates the row and column address decoders along with their pre-charge, sense amplifiers, and input/output data flops. \begin{table} \centering \caption{Dependencies required for sub-modules} \begin{tabular}{|c|l|} \hline Variable&Equation \\ \hline \texttt{Total Bits} & $word\_size*num\_words$ \\ \hline \texttt{Words Per Row} & $\sqrt(num\_words)/word\_size$ \\ \hline \texttt{Num of Rows} & $num\_words/words\_per\_row$ \\ \hline \texttt{Num of Cols} & $words\_per\_row*word\_size$ \\ \hline \texttt{Col Addr Size} & $\log_2(words\_per\_row)$ \\ \hline \texttt{Row Addr Size} & $\log_2(num\_of\_rows)$ \\ \hline \texttt{Total Addr Size} & $row\_addr\_size + col\_addr\_size$ \\ \hline \texttt{Data Size} & $word\_size$ \\ \hline \texttt{Num of Bank} & $num\_banks$ \\ \hline \end{tabular} \label{table:variables} \end{table} \subsubsection{Block Classes} Every other block in the memory design has a class for its base cell (e.g., sense\_amplifier.py) and an array class (e.g., sense\_amplifier\_array.py) that is responsible for tiling the base cell. Each class is responsible for physically placing and logically connecting its own sub-circuits while passing its dimensions and port locations up to higher-level modules. \subsubsection{Low-Level Classes} OpenRAM provides parameterized transistor and logic gate classes that help with technology portability. These classes generate a technology-specific transistor and simple logic gate layouts so that many modules do not rely on library cells. It is also used when a module such as the write driver needs transistor sizing to optimize performance. The parameterized transistor (ptx.py) generates a basic transistor of specified type and size. The parameterized transistor class is used to provide several parameterized gates including pinv.py, nand2.py, nand3.py, and nor2.py. % FIXME % crude fix to preven widow Section %\clearpage \subsection{Characterization} % overview OpenRAM includes a memory characterizer that measures the timing and power characteristics through SPICE simulation. The characterizer has four main stages: generating the SPICE stimulus, running the circuit simulations, parsing the simulator's output, and producing the characteristics in a Liberty (.lib) file. % standard format of stimulus The stimulus is written in standard SPICE format and can be used with any simulator that supports this. The stimulus only uses the interface of the memory (e.g., bi-directional data bus, address bus, and control signals) to perform \enquote{black box} timing measurements. % what is measured and how Results from simulations are used to produce the average power, setup/hold times, and timing delay of the memory design. Setup and hold times are obtained by analyzing the flip-flop library cell because OpenRAM uses a completely synchronous input interface. The setup time, hold time, and delay are found using a fast bisection search. \subsection{Unit Tests} Probably the most important feature of OpenRAM is the set of thorough regression tests implemented with the Python unit test framework. These unit tests allow users to add features and easily verifying if functionality is broken. The tests also work in multiple technologies so they can guide users when porting to new technologies. Every module has its own regression test and there are also regression tests for memory functionality, verifying library cells, timing characterization, and technology verification.