Merge branch 'dev' into delay_ctrl

This commit is contained in:
Sam Crow 2023-07-06 08:45:03 -07:00
commit b91c628acf
20 changed files with 365 additions and 42 deletions

View File

@ -3,6 +3,9 @@ include $(TOP_DIR)/openram.mk
.DEFAULT_GOAL := install
# Set the shell here
SHELL := /bin/bash
# Skywater PDK SRAM library
SRAM_LIB_DIR ?= $(PDK_ROOT)/sky130_fd_bd_sram
# Use this for release

View File

@ -57,13 +57,13 @@ OpenRAM is licensed under the [BSD 3-Clause License](./LICENSE).
# Publications
+ [M. R. Guthaus, J. E. Stine, S. Ataei, B. Chen, B. Wu, M. Sarwar, "OpenRAM: An Open-Source Memory Compiler," Proceedings of the 35th International Conference on Computer-Aided Design (ICCAD), 2016.](https://escholarship.org/content/qt8x19c778/qt8x19c778_noSplash_b2b3fbbb57f1269f86d0de77865b0691.pdf)
+ [S. Ataei, J. Stine, M. Guthaus, A 64 kb differential single-port 12T SRAM design with a bit-interleaving scheme for low-voltage operation in 32 nm SOI CMOS, International Conference on Computer Design (ICCD), 2016, pp. 499-506.](https://escholarship.org/uc/item/99f6q9c9)
+ [E. Ebrahimi, M. Guthaus, J. Renau, “Timing Speculative SRAM”, IEEE International Symposium on Circuits and Systems (ISCAS), 2017.](https://escholarship.org/content/qt7nn0j5x3/qt7nn0j5x3_noSplash_172457455e1aceba20694c3d7aa489b4.pdf)
+ [B. Wu, J.E. Stine, M.R. Guthaus, "Fast and Area-Efficient Word-Line Optimization", IEEE International Symposium on Circuits and Systems (ISCAS), 2019.](https://escholarship.org/content/qt98s4c1hp/qt98s4c1hp_noSplash_753dcc3e218f60aafff98ef77fb56384.pdf)
+ [B. Wu, M. Guthaus, "Bottom Up Approach for High Speed SRAM Word-line Buffer Insertion Optimization", IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://ieeexplore.ieee.org/document/8920325)
+ [H. Nichols, M. Grimes, J. Sowash, J. Cirimelli-Low, M. Guthaus "Automated Synthesis of Multi-Port Memories and Control", IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://escholarship.org/content/qt7047n3k0/qt7047n3k0.pdf?t=q4gcij)
+ [H. Nichols, "Statistical Modeling of SRAMs", M.S. Thesis, UCSC, 2022.](https://escholarship.org/content/qt7vx9n089/qt7vx9n089_noSplash_cfc4ba479d8eb1b6ec25d7c92357bc18.pdf?t=ra9wzr)
+ [M. Guthaus, H. Nichols, J. Cirimelli-Low, J. Kunzler, B. Wu, "Enabling Design Technology Co-Optimization of SRAMs though Open-Source Software", IEEE International Electron Devices Meeting (IEDM), 2020.](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=9372047)
+ [S. Ataei, J. Stine, M. Guthaus, "A 64 kb differential single-port 12T SRAM design with a bit-interleaving scheme for low-voltage operation in 32 nm SOI CMOS," International Conference on Computer Design (ICCD), 2016, pp. 499-506.](https://escholarship.org/uc/item/99f6q9c9)
+ [E. Ebrahimi, M. Guthaus, J. Renau, "Timing Speculative SRAM," IEEE International Symposium on Circuits and Systems (ISCAS), 2017.](https://escholarship.org/content/qt7nn0j5x3/qt7nn0j5x3_noSplash_172457455e1aceba20694c3d7aa489b4.pdf)
+ [B. Wu, J.E. Stine, M.R. Guthaus, "Fast and Area-Efficient Word-Line Optimization," IEEE International Symposium on Circuits and Systems (ISCAS), 2019.](https://escholarship.org/content/qt98s4c1hp/qt98s4c1hp_noSplash_753dcc3e218f60aafff98ef77fb56384.pdf)
+ [B. Wu, M. Guthaus, "Bottom Up Approach for High Speed SRAM Word-line Buffer Insertion Optimization," IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://ieeexplore.ieee.org/document/8920325)
+ [H. Nichols, M. Grimes, J. Sowash, J. Cirimelli-Low, M. Guthaus "Automated Synthesis of Multi-Port Memories and Control," IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://escholarship.org/content/qt7047n3k0/qt7047n3k0.pdf?t=q4gcij)
+ [M. Guthaus, H. Nichols, J. Cirimelli-Low, J. Kunzler, B. Wu, "Enabling Design Technology Co-Optimization of SRAMs though Open-Source Software," IEEE International Electron Devices Meeting (IEDM), 2020.](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=9372047)
+ [H. Nichols, "Statistical Modeling of SRAMs," M.S. Thesis, UCSC, 2022.](https://escholarship.org/content/qt7vx9n089/qt7vx9n089_noSplash_cfc4ba479d8eb1b6ec25d7c92357bc18.pdf?t=ra9wzr)

View File

@ -1 +1 @@
1.2.15
1.2.18

View File

@ -16,6 +16,7 @@ from .lef import *
from .logical_effort import *
from .pin_layout import *
from .power_data import *
from .rom_verilog import *
from .route import *
from .timing_graph import *
from .utils import *

View File

@ -0,0 +1,173 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import math
from openram.tech import spice
class rom_verilog:
"""
Create a behavioral Verilog file for simulation.
This is inherited by the rom_base class.
"""
def __init__(self):
pass
def verilog_write(self, verilog_name):
""" Write a behavioral Verilog model. """
self.vf = open(verilog_name, "w")
self.vf.write("// OpenROM ROM model\n")
#basic info
self.vf.write("// Words: {0}\n".format(self.num_words))
self.vf.write("// Word size: {0}\n".format(self.word_size))
self.vf.write("// Word per Row: {0}\n".format(self.words_per_row))
self.vf.write("// Data Type: {0}\n".format(self.data_type))
self.vf.write("// Data File: {0}\n".format(self.rom_data))
self.vf.write("\n")
try:
self.vdd_name = spice["power"]
except KeyError:
self.vdd_name = "vdd"
try:
self.gnd_name = spice["ground"]
except KeyError:
self.gnd_name = "gnd"
#add multiple banks later
self.vf.write("module {0}(\n".format(self.name))
self.vf.write("`ifdef USE_POWER_PINS\n")
self.vf.write(" {},\n".format(self.vdd_name))
self.vf.write(" {},\n".format(self.gnd_name))
self.vf.write("`endif\n")
for port in self.all_ports:
if port in self.read_ports:
self.vf.write("// Port {0}: R\n".format(port))
self.vf.write(" clk{0},csb{0},addr{0},dout{0}".format(port))
# Continue for every port on a new line
if port != self.all_ports[-1]:
self.vf.write(",\n")
self.vf.write("\n );\n\n")
self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size))
self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(math.ceil(math.log(self.num_words,2))))
self.vf.write(" parameter ROM_DEPTH = 1 << ADDR_WIDTH;\n")
self.vf.write(" // FIXME: This delay is arbitrary.\n")
self.vf.write(" parameter DELAY = 3 ;\n")
self.vf.write(" parameter VERBOSE = 1 ; //Set to 0 to only display warnings\n")
self.vf.write(" parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary\n")
self.vf.write("\n")
self.vf.write("`ifdef USE_POWER_PINS\n")
self.vf.write(" inout {};\n".format(self.vdd_name))
self.vf.write(" inout {};\n".format(self.gnd_name))
self.vf.write("`endif\n")
for port in self.all_ports:
self.add_inputs_outputs(port)
self.vf.write("\n")
# This is the memory array itself
self.vf.write(" reg [DATA_WIDTH-1:0] mem [0:ROM_DEPTH-1];\n\n")
#write memory init here
self.vf.write(f" initial begin\n")
if self.data_type == "bin":
self.vf.write(f" $readmemb(\"{self.rom_data}\",mem,0,ROM_DEPTH-1);\n")
elif self.data_type == "hex":
self.vf.write(f" $readmemh(\"{self.rom_data}\",mem,0, ROM_DEPTH-1);\n")
else:
raise ValueError(f"Data type: {self.data_type} is not supported!")
self.vf.write(f" end\n\n")
for port in self.all_ports:
self.register_inputs(port)
for port in self.all_ports:
if port in self.read_ports:
self.add_read_block(port)
self.vf.write("\n")
self.vf.write("endmodule\n")
self.vf.close()
def register_inputs(self, port):
"""
Register the control signal, address and data inputs.
"""
self.add_regs(port)
self.add_flops(port)
def add_regs(self, port):
"""
Create the input regs for the given port.
"""
self.vf.write(" reg csb{0}_reg;\n".format(port))
self.vf.write(" reg [ADDR_WIDTH-1:0] addr{0}_reg;\n".format(port))
if port in self.read_ports:
self.vf.write(" reg [DATA_WIDTH-1:0] dout{0};\n".format(port))
def add_flops(self, port):
"""
Add the flop behavior logic for a port.
"""
self.vf.write("\n")
self.vf.write(" // All inputs are registers\n")
self.vf.write(" always @(posedge clk{0})\n".format(port))
self.vf.write(" begin\n")
self.vf.write(" csb{0}_reg = csb{0};\n".format(port))
self.vf.write(" addr{0}_reg = addr{0};\n".format(port))
if port in self.read_ports:
self.add_write_read_checks(port)
if port in self.read_ports:
self.vf.write(" #(T_HOLD) dout{0} = {1}'bx;\n".format(port, self.word_size))
self.vf.write(" if ( !csb{0}_reg && VERBOSE ) \n".format(port))
self.vf.write(" $display($time,\" Reading %m addr{0}=%b dout{0}=%b\",addr{0}_reg,mem[addr{0}_reg]);\n".format(port))
self.vf.write(" end\n\n")
def add_inputs_outputs(self, port):
"""
Add the module input and output declaration for a port.
"""
self.vf.write(" input clk{0}; // clock\n".format(port))
self.vf.write(" input csb{0}; // active low chip select\n".format(port))
self.vf.write(" input [ADDR_WIDTH-1:0] addr{0};\n".format(port))
if port in self.read_ports:
self.vf.write(" output [DATA_WIDTH-1:0] dout{0};\n".format(port))
def add_write_block(self, port):
"""
ROM does not take writes thus this function does nothing
"""
self.vf.write("\n")
def add_read_block(self, port):
"""
Add a read port block.
"""
self.vf.write("\n")
self.vf.write(" // Memory Read Block Port {0}\n".format(port))
self.vf.write(" // Read Operation : When web{0} = 1, csb{0} = 0\n".format(port))
self.vf.write(" always @ (negedge clk{0})\n".format(port))
self.vf.write(" begin : MEM_READ{0}\n".format(port))
self.vf.write(" if (!csb{0}_reg)\n".format(port))
self.vf.write(" dout{0} <= #(DELAY) mem[addr{0}_reg];\n".format(port))
self.vf.write(" end\n")
def add_write_read_checks(self, rport):
"""
Since ROMs dont have write ports this does nothing
"""
pass

View File

@ -10,13 +10,14 @@ import datetime
from math import ceil, log
from openram.base import vector
from openram.base import design
from openram.base import rom_verilog
from openram import OPTS, print_time
from openram.sram_factory import factory
from openram.tech import drc, layer, parameter
from openram.router import router_tech
class rom_bank(design):
class rom_bank(design,rom_verilog):
"""
Rom data bank with row and column decoder + control logic
@ -509,4 +510,4 @@ class rom_bank(design):
rtr=router(layers=self.m3_stack,
design=self,
bbox=bbox)
rtr.escape_route(pins_to_route)
rtr.escape_route(pins_to_route)

View File

@ -28,7 +28,6 @@ class sram_1bank(design, verilog, lef):
design.__init__(self, name)
lef.__init__(self, ["m1", "m2", "m3", "m4"])
verilog.__init__(self)
self.sram_config = sram_config
sram_config.set_local_config(self)

View File

@ -58,6 +58,7 @@ class options(optparse.Values):
###################
rom_endian = "little"
rom_data = None
data_type = "bin"
strap_spacing = 8
scramble_bits = True

View File

@ -26,7 +26,8 @@ class rom():
words_per_row=OPTS.words_per_row,
rom_endian=OPTS.rom_endian,
scramble_bits=OPTS.scramble_bits,
strap_spacing=OPTS.strap_spacing)
strap_spacing=OPTS.strap_spacing,
data_type=OPTS.data_type)
if name is None:
name = OPTS.output_name
@ -38,7 +39,7 @@ class rom():
from openram.base import design
design.name_map=[]
debug.info(2, "create rom of size {0} with {1} num of words".format(self.word_size,
debug.print_raw("create rom of word size {0} with {1} num of words".format(self.word_size,
self.num_words))
start_time = datetime.datetime.now()
@ -137,20 +138,22 @@ class rom():
# Write the config file
# Should also save the provided data file
start_time = datetime.datetime.now()
from shutil import copyfile
copyfile(OPTS.config_file, OPTS.output_path + OPTS.output_name + '.py')
copyfile(self.rom_data, OPTS.output_path + self.rom_data)
debug.print_raw("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py'))
print_time("Config", datetime.datetime.now(), start_time)
# TODO: Write the datasheet
# TODO: Write a verilog model
# start_time = datetime.datetime.now()
# vname = OPTS.output_path + self.r.name + '.v'
# debug.print_raw("Verilog: Writing to {0}".format(vname))
# self.verilog_write(vname)
# print_time("Verilog", datetime.datetime.now(), start_time)
#Write a verilog model
start_time = datetime.datetime.now()
vname = OPTS.output_path + self.r.name + '.v'
debug.print_raw("Verilog: Writing to {0}".format(vname))
self.verilog_write(vname)
print_time("Verilog", datetime.datetime.now(), start_time)
# Write out options if specified
if OPTS.output_extended_config:

View File

@ -16,14 +16,14 @@ from openram import OPTS
class rom_config:
""" This is a structure that is used to hold the ROM configuration options. """
def __init__(self, word_size, rom_data, words_per_row=None, rom_endian="little", scramble_bits=True, strap_spacing=8):
def __init__(self, word_size, rom_data, words_per_row=None, rom_endian="little", scramble_bits=True, strap_spacing=8, data_type="hex"):
self.word_size = word_size
self.word_bits = self.word_size * 8
self.rom_data = rom_data
self.strap_spacing = strap_spacing
# TODO: This currently does nothing. It should change the behavior of the chunk funciton.
self.endian = rom_endian
self.data_type = data_type
# This should pretty much always be true. If you want to make silicon art you might set to false
self.scramble_bits = scramble_bits
# This will get over-written when we determine the organization
@ -57,18 +57,12 @@ class rom_config:
def compute_sizes(self):
""" Computes the organization of the memory using data size by trying to make it a rectangle."""
# Read data as hexidecimal text file
hex_file = open(self.rom_data, 'r')
hex_data = hex_file.read()
# Convert from hex into an int
data_int = int(hex_data, 16)
# Then from int into a right aligned, zero padded string
bin_string = bin(data_int)[2:].zfill(len(hex_data) * 4)
# Then turn the string into a list of ints
bin_data = list(bin_string)
raw_data = [int(x) for x in bin_data]
if self.data_type == "hex":
raw_data = self.read_data_hex()
elif self.data_type == "bin":
raw_data = self.read_data_bin()
else:
debug.error(f"Invalid input data type: {self.data_type}", -1)
# data size in bytes
data_size = len(raw_data) / 8
@ -93,6 +87,35 @@ class rom_config:
OPTS.words_per_row = self.words_per_row
debug.info(1, "Read rom data file: length {0} bytes, {1} words, set number of cols to {2}, rows to {3}, with {4} words per row".format(data_size, self.num_words, self.cols, self.rows, self.words_per_row))
def read_data_hex(self) -> List[int]:
# Read data as hexidecimal text file
with open(self.rom_data, 'r') as hex_file:
hex_data = hex_file.read()
# Convert from hex into an int
data_int = int(hex_data, 16)
# Then from int into a right aligned, zero padded string
bin_string = bin(data_int)[2:].zfill(len(hex_data) * 4)
# Then turn the string into a list of ints
bin_data = list(bin_string)
raw_data = [int(x) for x in bin_data]
return raw_data
def read_data_bin(self) -> List[int]:
# Read data as a binary file
with open(self.rom_data, 'rb') as bin_file:
bin_data = bin_file.read()
# Convert from a list of bytes to a single string of bits
bin_string = "".join(f"{n:08b}" for n in bin_data)
# Then turn the string into a list of ints
bin_data = list(bin_string)
raw_data = [int(x) for x in bin_data]
return raw_data
def chunk_data(self, raw_data: List[int]):
"""

View File

@ -22,4 +22,14 @@ This page of the documentation explains the architecture of OpenRAM.
* Write Driver(s)
* Control Logic with Replica Bitline
![OpenRAM SRAM Architecture](../assets/images/architecture/sram_architecture.png)
![OpenRAM SRAM Architecture](../assets/images/architecture/sram_architecture.png)
## ROM Architecture
* Bit-cell Array
* 1T NAND Bitcell
* Row Address Decoder
* Wordline Driver(s)
* Column Multiplexer
* Column Pre-Decoder
* Bitline Precharge(s)
* Control Logic

View File

@ -0,0 +1,99 @@
### [Go Back](./index.md#table-of-contents)
# Basic Usage
This page of the documentation explains the basic usage of OpenRAM's ROM compiler (OpenROM). For usage of the RAM compiler see [here](./basic_usage.md#go-back)
## Table of Contents
1. [Environment Variable Setup](#environment-variable-setup-assuming-bash)
1. [Command Line Usage](#command-line-usage)
1. [Script Usage](#script-usage)
1. [Configuration Files](#configuration-files)
1. [Common Configuration File Options](#common-configuration-file-options)
1. [Output Files](#output-files)
## Environment Variable Setup (assuming bash)
Environment configuration is the same as described in [basic SRAM usage](./basic_usage#environment-variable-setup-assuming-bash)
## Accepted Data formats
OpenROM currently supports input data formatted as a binary file or a text file
of hexadecimal-encoded data. For hexadecimal data, the input file must contain
a single line of hexadecimal text. The data in any input file will be written
the ROM in the order it appears in the input file, ie. the first bit in the input
will be written to address 0.
## Command Line Usage
Once you have defined the environment, you can run OpenROM from the command line
using a single configuration file written in Python. You can then run OpenROM by
executing:
```
python3 $OPENRAM_HOME/../rom_compiler.py myconfig
```
You can see all of the options for the configuration file in
$OPENRAM\_HOME/options.py
To run macros, it is suggested to use, for example:
```
cd OpenRAM/macros/rom_configs
make sky130_rom_1kbyte
```
* Common arguments:
* `-h` print all arguments
* `-t` specify technology (currently only sky130 is supported)
* `-v` increase verbosity of output
* `-n` don't run DRC/LVS
* `-d` don't purge /tmp directory contents
## Configuration Files
* Shares some configuration options with SRAM compiler.
* Complete configuration options are in `$OPENRAM_HOME/options.py`
* Some options can be specified on the command line as well
* Not recommended for replicating results
* Example configuration file:
```python
# Data word size
word_size = 2
# Enable LVS/DRC checking
check_lvsdrc = True
# Path to input data. Either binary file or hex.
rom_data = "data_1kbyte.bin"
# Format type of input data
data_type = "bin"
# Technology to use in $OPENRAM_TECH, currently only sky130 is supported
tech_name = "sky130"
# Output directory for the results
output_path = "temp"
# Output file base name
output_name = "rom_1kbyte"
# Only nominal process corner generation is currently supported
nominal_corner_only = True
# Add a supply ring to the generated layout
route_supplies = "ring"
```
## Output Files
The output files are placed in the `output_dir` defined in the configuration
file.
The base name is specified by `output_name` and suffixes are added. Currently only layout and schematic files are generated.
The final results files are:
* GDS (.gds)
* SPICE (.sp)
* Log (.log)
* Configuration (.py) for replication of creation

View File

@ -1,7 +1,7 @@
### [Go Back](./index.md#table-of-contents)
# Basic Setup
This page shows the basic setup for using OpenRAM.
This page shows the basic setup for using OpenRAM to generate an SRAM.

View File

@ -1,7 +1,7 @@
### [Go Back](./index.md#table-of-contents)
# Basic Usage
This page of the documentation explains the basic usage of OpenRAM.
This page of the documentation explains the basic usage of OpenRAM's SRAM compiler. For usage of the ROM compiler see [here](./basic_rom_usage.md#go-back)

View File

@ -11,7 +11,8 @@ navigate through the documentation.
1. [Supported Technologies](#supported-technologies)
1. [Online Playground](./OpenRAM.ipynb)
1. [Basic Setup](./basic_setup.md#go-back)
1. [Basic Usage](./basic_usage.md#go-back)
1. [Basic SRAM Usage](./basic_usage.md#go-back)
1. [Basic ROM Usage](./basic_rom_usage.md#go-back)
1. [Python Library](./python_library.md#go-back)
1. [Bitcells](./bitcells.md#go-back)
1. [Architecture](./architecture.md#go-back)
@ -115,4 +116,5 @@ Commercial tools (optional):
* Tom Golubev
* Marcelo Sero
* Seokjoong Kim
* Sage Walker

View File

@ -6,6 +6,7 @@ include $(TOP_DIR)/openram.mk
SKY130_PDK ?= $(PDK_ROOT)/sky130A
OPENRAM_DIR = $(MACRO_DIR)
OPENRAM_OPTS := $(OPENRAM_OPTS)
# Define `OPENRAM_FULL` in your environment to run a full characterize
ifeq ($(OPENRAM_FULL),)
@ -40,7 +41,7 @@ configs:
.PHONY: configs
BROKEN :=
BROKEN :=
WORKING_SRAM_STAMPS=$(filter-out $(addsuffix .ok, $(BROKEN)), $(SRAM_STAMPS))
WORKING_ROM_STAMPS=$(filter-out $(addsuffix .ok, $(BROKEN)), $(ROM_STAMPS))
@ -50,7 +51,7 @@ SKY130_STAMPS=$(filter sky130%, $(WORKING_SRAM_STAMPS)) $(filter sky130%, $(WORK
FREEPDK45_STAMPS=$(filter freepdk45%, $(WORKING_STAMPS)) $(filter freepdk45%, $(WORKING_ROM_STAMPS))
SCN4M_SUBM_STAMPS=$(filter scn4m_subm%, $(WORKING_STAMPS)) $(filter scn4m_subm%, $(WORKING_ROM_STAMPS))
all: | configs
all: | configs
@echo
@echo "Building following working configs"
@for S in $(WORKING_STAMPS); do echo " - $$S"; done
@ -75,7 +76,7 @@ rom: $(WORKING_ROM_STAMPS)
sram: $(WORKING_SRAM_STAMPS)
.PHONY: sram
%.ok: sram_configs/%.py
@echo "Building $*"
@mkdir -p $*

Binary file not shown.

View File

@ -10,7 +10,8 @@ word_size = 1
check_lvsdrc = True
rom_data = "macros/rom_configs/example_1kbyte.dat"
rom_data = "rom_configs/example_1kbyte.bin"
data_type = "bin"
output_name = "rom_1kbyte"
output_path = "macro/{output_name}".format(**locals())

View File

@ -1,4 +1,10 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
tech_name = "sky130"
nominal_corner_only = True