mirror of https://github.com/VLSIDA/OpenRAM.git
Remove carriage returns form python files
This commit is contained in:
parent
abacf6a2d0
commit
34736b7b3f
|
|
@ -1,115 +1,115 @@
|
|||
import gdsMill
|
||||
import tech
|
||||
import globals
|
||||
import math
|
||||
import debug
|
||||
import datetime
|
||||
from collections import defaultdict
|
||||
|
||||
class lef:
|
||||
"""
|
||||
SRAM LEF Class open GDS file, read pins information, obstruction
|
||||
and write them to LEF file
|
||||
"""
|
||||
def __init__(self,layers):
|
||||
# LEF db units per micron
|
||||
self.lef_units = 1000
|
||||
# These are the layers of the obstructions
|
||||
self.lef_layers = layers
|
||||
|
||||
def lef_write(self, lef_name):
|
||||
"""Write the entire lef of the object to the file."""
|
||||
debug.info(3, "Writing to {0}".format(lef_name))
|
||||
|
||||
self.indent = "" # To maintain the indent level easily
|
||||
|
||||
self.lef = open(lef_name,"w")
|
||||
self.lef_write_header()
|
||||
for pin in self.pins:
|
||||
self.lef_write_pin(pin)
|
||||
self.lef_write_obstructions()
|
||||
self.lef_write_footer()
|
||||
self.lef.close()
|
||||
|
||||
def lef_write_header(self):
|
||||
""" Header of LEF file """
|
||||
self.lef.write("VERSION 5.4 ;\n")
|
||||
self.lef.write("NAMESCASESENSITIVE ON ;\n")
|
||||
self.lef.write("BUSBITCHARS \"[]\" ;\n")
|
||||
self.lef.write("DIVIDERCHAR \"/\" ;\n")
|
||||
self.lef.write("UNITS\n")
|
||||
self.lef.write(" DATABASE MICRONS {0} ;\n".format(self.lef_units))
|
||||
self.lef.write("END UNITS\n")
|
||||
|
||||
self.lef.write("SITE MacroSite\n")
|
||||
self.indent += " "
|
||||
self.lef.write("{0}CLASS Core ;\n".format(self.indent))
|
||||
self.lef.write("{0}SIZE {1} by {2} ;\n".format(self.indent,
|
||||
self.lef_units*self.width,
|
||||
self.lef_units*self.height))
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("END MacroSite\n")
|
||||
|
||||
self.lef.write("{0}MACRO {1}\n".format(self.indent,self.name))
|
||||
self.indent += " "
|
||||
self.lef.write("{0}CLASS BLOCK ;\n".format(self.indent))
|
||||
self.lef.write("{0}SIZE {1} BY {2} ;\n" .format(self.indent,
|
||||
self.lef_units*self.width,
|
||||
self.lef_units*self.height))
|
||||
self.lef.write("{0}SYMMETRY X Y R90 ;\n".format(self.indent))
|
||||
self.lef.write("{0}SITE MacroSite ;\n".format(self.indent))
|
||||
|
||||
|
||||
def lef_write_footer(self):
|
||||
self.lef.write("{0}END {1}\n".format(self.indent,self.name))
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("END LIBRARY\n")
|
||||
|
||||
|
||||
def lef_write_pin(self, name):
|
||||
pin_dir = self.get_pin_dir(name)
|
||||
pin_type = self.get_pin_type(name)
|
||||
self.lef.write("{0}PIN {1}\n".format(self.indent,name))
|
||||
self.indent += " "
|
||||
|
||||
self.lef.write("{0}DIRECTION {1} ;\n".format(self.indent,pin_dir))
|
||||
|
||||
if pin_type in ["POWER","GROUND"]:
|
||||
self.lef.write("{0}USE {1} ; \n".format(self.indent,pin_type))
|
||||
self.lef.write("{0}SHAPE ABUTMENT ; \n".format(self.indent))
|
||||
|
||||
self.lef.write("{0}PORT\n".format(self.indent))
|
||||
self.indent += " "
|
||||
|
||||
# We could sort these together to minimize different layer sections, but meh.
|
||||
pin_list = self.get_pins(name)
|
||||
for pin in pin_list:
|
||||
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,pin.layer))
|
||||
self.lef_write_rect(pin.rect)
|
||||
|
||||
# End the PORT
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("{0}END\n".format(self.indent))
|
||||
|
||||
# End the PIN
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("{0}END {1}\n".format(self.indent,name))
|
||||
|
||||
def lef_write_obstructions(self):
|
||||
""" Write all the obstructions on each layer """
|
||||
self.lef.write("{0}OBS\n".format(self.indent))
|
||||
for layer in self.lef_layers:
|
||||
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,layer))
|
||||
self.indent += " "
|
||||
blockages = self.get_blockages(layer,True)
|
||||
for b in blockages:
|
||||
self.lef_write_rect(b)
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("{0}END\n".format(self.indent))
|
||||
|
||||
def lef_write_rect(self, rect):
|
||||
""" Write a LEF rectangle """
|
||||
self.lef.write("{0}RECT ".format(self.indent))
|
||||
for item in rect:
|
||||
self.lef.write(" {0} {1}".format(self.lef_units*item[0], self.lef_units*item[1]))
|
||||
self.lef.write(" ;\n")
|
||||
import gdsMill
|
||||
import tech
|
||||
import globals
|
||||
import math
|
||||
import debug
|
||||
import datetime
|
||||
from collections import defaultdict
|
||||
|
||||
class lef:
|
||||
"""
|
||||
SRAM LEF Class open GDS file, read pins information, obstruction
|
||||
and write them to LEF file
|
||||
"""
|
||||
def __init__(self,layers):
|
||||
# LEF db units per micron
|
||||
self.lef_units = 1000
|
||||
# These are the layers of the obstructions
|
||||
self.lef_layers = layers
|
||||
|
||||
def lef_write(self, lef_name):
|
||||
"""Write the entire lef of the object to the file."""
|
||||
debug.info(3, "Writing to {0}".format(lef_name))
|
||||
|
||||
self.indent = "" # To maintain the indent level easily
|
||||
|
||||
self.lef = open(lef_name,"w")
|
||||
self.lef_write_header()
|
||||
for pin in self.pins:
|
||||
self.lef_write_pin(pin)
|
||||
self.lef_write_obstructions()
|
||||
self.lef_write_footer()
|
||||
self.lef.close()
|
||||
|
||||
def lef_write_header(self):
|
||||
""" Header of LEF file """
|
||||
self.lef.write("VERSION 5.4 ;\n")
|
||||
self.lef.write("NAMESCASESENSITIVE ON ;\n")
|
||||
self.lef.write("BUSBITCHARS \"[]\" ;\n")
|
||||
self.lef.write("DIVIDERCHAR \"/\" ;\n")
|
||||
self.lef.write("UNITS\n")
|
||||
self.lef.write(" DATABASE MICRONS {0} ;\n".format(self.lef_units))
|
||||
self.lef.write("END UNITS\n")
|
||||
|
||||
self.lef.write("SITE MacroSite\n")
|
||||
self.indent += " "
|
||||
self.lef.write("{0}CLASS Core ;\n".format(self.indent))
|
||||
self.lef.write("{0}SIZE {1} by {2} ;\n".format(self.indent,
|
||||
self.lef_units*self.width,
|
||||
self.lef_units*self.height))
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("END MacroSite\n")
|
||||
|
||||
self.lef.write("{0}MACRO {1}\n".format(self.indent,self.name))
|
||||
self.indent += " "
|
||||
self.lef.write("{0}CLASS BLOCK ;\n".format(self.indent))
|
||||
self.lef.write("{0}SIZE {1} BY {2} ;\n" .format(self.indent,
|
||||
self.lef_units*self.width,
|
||||
self.lef_units*self.height))
|
||||
self.lef.write("{0}SYMMETRY X Y R90 ;\n".format(self.indent))
|
||||
self.lef.write("{0}SITE MacroSite ;\n".format(self.indent))
|
||||
|
||||
|
||||
def lef_write_footer(self):
|
||||
self.lef.write("{0}END {1}\n".format(self.indent,self.name))
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("END LIBRARY\n")
|
||||
|
||||
|
||||
def lef_write_pin(self, name):
|
||||
pin_dir = self.get_pin_dir(name)
|
||||
pin_type = self.get_pin_type(name)
|
||||
self.lef.write("{0}PIN {1}\n".format(self.indent,name))
|
||||
self.indent += " "
|
||||
|
||||
self.lef.write("{0}DIRECTION {1} ;\n".format(self.indent,pin_dir))
|
||||
|
||||
if pin_type in ["POWER","GROUND"]:
|
||||
self.lef.write("{0}USE {1} ; \n".format(self.indent,pin_type))
|
||||
self.lef.write("{0}SHAPE ABUTMENT ; \n".format(self.indent))
|
||||
|
||||
self.lef.write("{0}PORT\n".format(self.indent))
|
||||
self.indent += " "
|
||||
|
||||
# We could sort these together to minimize different layer sections, but meh.
|
||||
pin_list = self.get_pins(name)
|
||||
for pin in pin_list:
|
||||
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,pin.layer))
|
||||
self.lef_write_rect(pin.rect)
|
||||
|
||||
# End the PORT
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("{0}END\n".format(self.indent))
|
||||
|
||||
# End the PIN
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("{0}END {1}\n".format(self.indent,name))
|
||||
|
||||
def lef_write_obstructions(self):
|
||||
""" Write all the obstructions on each layer """
|
||||
self.lef.write("{0}OBS\n".format(self.indent))
|
||||
for layer in self.lef_layers:
|
||||
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,layer))
|
||||
self.indent += " "
|
||||
blockages = self.get_blockages(layer,True)
|
||||
for b in blockages:
|
||||
self.lef_write_rect(b)
|
||||
self.indent = self.indent[:-3]
|
||||
self.lef.write("{0}END\n".format(self.indent))
|
||||
|
||||
def lef_write_rect(self, rect):
|
||||
""" Write a LEF rectangle """
|
||||
self.lef.write("{0}RECT ".format(self.indent))
|
||||
for item in rect:
|
||||
self.lef.write(" {0} {1}".format(self.lef_units*item[0], self.lef_units*item[1]))
|
||||
self.lef.write(" ;\n")
|
||||
|
|
|
|||
|
|
@ -1,202 +1,202 @@
|
|||
import debug
|
||||
import design
|
||||
from tech import drc, spice
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
|
||||
class bitcell_array(design.design):
|
||||
"""
|
||||
Creates a rows x cols array of memory cells. Assumes bit-lines
|
||||
and word line is connected by abutment.
|
||||
Connects the word lines and bit lines.
|
||||
"""
|
||||
|
||||
def __init__(self, cols, rows, name="bitcell_array"):
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
|
||||
|
||||
|
||||
self.column_size = cols
|
||||
self.row_size = rows
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.cell = self.mod_bitcell()
|
||||
self.add_mod(self.cell)
|
||||
|
||||
# We increase it by a well enclosure so the precharges don't overlap our wells
|
||||
self.height = self.row_size*self.cell.height + drc["well_enclosure_active"] + self.m1_width
|
||||
self.width = self.column_size*self.cell.width + self.m1_width
|
||||
|
||||
self.add_pins()
|
||||
self.create_layout()
|
||||
self.add_layout_pins()
|
||||
|
||||
# We don't offset this because we need to align
|
||||
# the replica bitcell in the control logic
|
||||
#self.offset_all_coordinates()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
row_list = self.cell.list_row_pins()
|
||||
column_list = self.cell.list_all_column_pins()
|
||||
for col in range(self.column_size):
|
||||
for cell_column in column_list:
|
||||
self.add_pin(cell_column+"[{0}]".format(col))
|
||||
for row in range(self.row_size):
|
||||
for cell_row in row_list:
|
||||
self.add_pin(cell_row+"[{0}]".format(row))
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def create_layout(self):
|
||||
xoffset = 0.0
|
||||
self.cell_inst = {}
|
||||
for col in range(self.column_size):
|
||||
yoffset = 0.0
|
||||
for row in range(self.row_size):
|
||||
name = "bit_r{0}_c{1}".format(row, col)
|
||||
|
||||
if row % 2:
|
||||
tempy = yoffset + self.cell.height
|
||||
dir_key = "MX"
|
||||
else:
|
||||
tempy = yoffset
|
||||
dir_key = ""
|
||||
|
||||
self.cell_inst[row,col]=self.add_inst(name=name,
|
||||
mod=self.cell,
|
||||
offset=[xoffset, tempy],
|
||||
mirror=dir_key)
|
||||
self.connect_inst(self.cell.list_bitcell_pins(col, row))
|
||||
|
||||
yoffset += self.cell.height
|
||||
xoffset += self.cell.width
|
||||
|
||||
|
||||
def add_layout_pins(self):
|
||||
""" Add the layout pins """
|
||||
|
||||
row_list = self.cell.list_row_pins()
|
||||
column_list = self.cell.list_all_column_pins()
|
||||
|
||||
offset = vector(0.0, 0.0)
|
||||
for col in range(self.column_size):
|
||||
for cell_column in column_list:
|
||||
bl_pin = self.cell_inst[0,col].get_pin(cell_column)
|
||||
self.add_layout_pin(text=cell_column+"[{0}]".format(col),
|
||||
layer="metal2",
|
||||
offset=bl_pin.ll(),
|
||||
width=bl_pin.width(),
|
||||
height=self.height)
|
||||
|
||||
# increments to the next column width
|
||||
offset.x += self.cell.width
|
||||
|
||||
offset.x = 0.0
|
||||
for row in range(self.row_size):
|
||||
for cell_row in row_list:
|
||||
wl_pin = self.cell_inst[row,0].get_pin(cell_row)
|
||||
self.add_layout_pin(text=cell_row+"[{0}]".format(row),
|
||||
layer="metal1",
|
||||
offset=wl_pin.ll(),
|
||||
width=self.width,
|
||||
height=wl_pin.height())
|
||||
|
||||
# increments to the next row height
|
||||
offset.y += self.cell.height
|
||||
|
||||
# For every second row and column, add a via for vdd
|
||||
for row in range(self.row_size):
|
||||
for col in range(self.column_size):
|
||||
inst = self.cell_inst[row,col]
|
||||
for vdd_pin in inst.get_pins("vdd"):
|
||||
# Drop to M1 if needed
|
||||
if vdd_pin.layer == "metal1":
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=vdd_pin.center(),
|
||||
rotate=90)
|
||||
# Always drop to M2
|
||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||
offset=vdd_pin.center())
|
||||
self.add_layout_pin_rect_center(text="vdd",
|
||||
layer="metal3",
|
||||
offset=vdd_pin.center())
|
||||
|
||||
|
||||
# For every second row and column (+1), add a via for gnd
|
||||
for row in range(self.row_size):
|
||||
for col in range(self.column_size):
|
||||
inst = self.cell_inst[row,col]
|
||||
for gnd_pin in inst.get_pins("gnd"):
|
||||
# Drop to M1 if needed
|
||||
if gnd_pin.layer == "metal1":
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=gnd_pin.center(),
|
||||
rotate=90)
|
||||
# Always drop to M2
|
||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||
offset=gnd_pin.center())
|
||||
self.add_layout_pin_rect_center(text="gnd",
|
||||
layer="metal3",
|
||||
offset=gnd_pin.center())
|
||||
|
||||
def analytical_delay(self, slew, load=0):
|
||||
from tech import drc
|
||||
wl_wire = self.gen_wl_wire()
|
||||
wl_wire.return_delay_over_wire(slew)
|
||||
|
||||
wl_to_cell_delay = wl_wire.return_delay_over_wire(slew)
|
||||
# hypothetical delay from cell to bl end without sense amp
|
||||
bl_wire = self.gen_bl_wire()
|
||||
cell_load = 2 * bl_wire.return_input_cap() # we ingore the wire r
|
||||
# hence just use the whole c
|
||||
bl_swing = 0.1
|
||||
cell_delay = self.cell.analytical_delay(wl_to_cell_delay.slew, cell_load, swing = bl_swing)
|
||||
|
||||
#we do not consider the delay over the wire for now
|
||||
return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
|
||||
wl_to_cell_delay.slew)
|
||||
|
||||
def analytical_power(self, proc, vdd, temp, load):
|
||||
"""Power of Bitcell array and bitline in nW."""
|
||||
from tech import drc
|
||||
|
||||
# Dynamic Power from Bitline
|
||||
bl_wire = self.gen_bl_wire()
|
||||
cell_load = 2 * bl_wire.return_input_cap()
|
||||
bl_swing = 0.1 #This should probably be defined in the tech file or input
|
||||
freq = spice["default_event_rate"]
|
||||
bitline_dynamic = bl_swing*cell_load*vdd*vdd*freq #not sure if calculation is correct
|
||||
|
||||
#Calculate the bitcell power which currently only includes leakage
|
||||
cell_power = self.cell.analytical_power(proc, vdd, temp, load)
|
||||
|
||||
#Leakage power grows with entire array and bitlines.
|
||||
total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size,
|
||||
cell_power.leakage * self.column_size * self.row_size)
|
||||
return total_power
|
||||
|
||||
def gen_wl_wire(self):
|
||||
wl_wire = self.generate_rc_net(int(self.column_size), self.width, drc["minwidth_metal1"])
|
||||
wl_wire.wire_c = 2*spice["min_tx_gate_c"] + wl_wire.wire_c # 2 access tx gate per cell
|
||||
return wl_wire
|
||||
|
||||
def gen_bl_wire(self):
|
||||
bl_pos = 0
|
||||
bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), self.height, drc["minwidth_metal1"])
|
||||
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
|
||||
return bl_wire
|
||||
|
||||
def output_load(self, bl_pos=0):
|
||||
bl_wire = self.gen_bl_wire()
|
||||
return bl_wire.wire_c # sense amp only need to charge small portion of the bl
|
||||
# set as one segment for now
|
||||
|
||||
def input_load(self):
|
||||
wl_wire = self.gen_wl_wire()
|
||||
return wl_wire.return_input_cap()
|
||||
import debug
|
||||
import design
|
||||
from tech import drc, spice
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
|
||||
class bitcell_array(design.design):
|
||||
"""
|
||||
Creates a rows x cols array of memory cells. Assumes bit-lines
|
||||
and word line is connected by abutment.
|
||||
Connects the word lines and bit lines.
|
||||
"""
|
||||
|
||||
def __init__(self, cols, rows, name="bitcell_array"):
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
|
||||
|
||||
|
||||
self.column_size = cols
|
||||
self.row_size = rows
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.cell = self.mod_bitcell()
|
||||
self.add_mod(self.cell)
|
||||
|
||||
# We increase it by a well enclosure so the precharges don't overlap our wells
|
||||
self.height = self.row_size*self.cell.height + drc["well_enclosure_active"] + self.m1_width
|
||||
self.width = self.column_size*self.cell.width + self.m1_width
|
||||
|
||||
self.add_pins()
|
||||
self.create_layout()
|
||||
self.add_layout_pins()
|
||||
|
||||
# We don't offset this because we need to align
|
||||
# the replica bitcell in the control logic
|
||||
#self.offset_all_coordinates()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
row_list = self.cell.list_row_pins()
|
||||
column_list = self.cell.list_all_column_pins()
|
||||
for col in range(self.column_size):
|
||||
for cell_column in column_list:
|
||||
self.add_pin(cell_column+"[{0}]".format(col))
|
||||
for row in range(self.row_size):
|
||||
for cell_row in row_list:
|
||||
self.add_pin(cell_row+"[{0}]".format(row))
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def create_layout(self):
|
||||
xoffset = 0.0
|
||||
self.cell_inst = {}
|
||||
for col in range(self.column_size):
|
||||
yoffset = 0.0
|
||||
for row in range(self.row_size):
|
||||
name = "bit_r{0}_c{1}".format(row, col)
|
||||
|
||||
if row % 2:
|
||||
tempy = yoffset + self.cell.height
|
||||
dir_key = "MX"
|
||||
else:
|
||||
tempy = yoffset
|
||||
dir_key = ""
|
||||
|
||||
self.cell_inst[row,col]=self.add_inst(name=name,
|
||||
mod=self.cell,
|
||||
offset=[xoffset, tempy],
|
||||
mirror=dir_key)
|
||||
self.connect_inst(self.cell.list_bitcell_pins(col, row))
|
||||
|
||||
yoffset += self.cell.height
|
||||
xoffset += self.cell.width
|
||||
|
||||
|
||||
def add_layout_pins(self):
|
||||
""" Add the layout pins """
|
||||
|
||||
row_list = self.cell.list_row_pins()
|
||||
column_list = self.cell.list_all_column_pins()
|
||||
|
||||
offset = vector(0.0, 0.0)
|
||||
for col in range(self.column_size):
|
||||
for cell_column in column_list:
|
||||
bl_pin = self.cell_inst[0,col].get_pin(cell_column)
|
||||
self.add_layout_pin(text=cell_column+"[{0}]".format(col),
|
||||
layer="metal2",
|
||||
offset=bl_pin.ll(),
|
||||
width=bl_pin.width(),
|
||||
height=self.height)
|
||||
|
||||
# increments to the next column width
|
||||
offset.x += self.cell.width
|
||||
|
||||
offset.x = 0.0
|
||||
for row in range(self.row_size):
|
||||
for cell_row in row_list:
|
||||
wl_pin = self.cell_inst[row,0].get_pin(cell_row)
|
||||
self.add_layout_pin(text=cell_row+"[{0}]".format(row),
|
||||
layer="metal1",
|
||||
offset=wl_pin.ll(),
|
||||
width=self.width,
|
||||
height=wl_pin.height())
|
||||
|
||||
# increments to the next row height
|
||||
offset.y += self.cell.height
|
||||
|
||||
# For every second row and column, add a via for vdd
|
||||
for row in range(self.row_size):
|
||||
for col in range(self.column_size):
|
||||
inst = self.cell_inst[row,col]
|
||||
for vdd_pin in inst.get_pins("vdd"):
|
||||
# Drop to M1 if needed
|
||||
if vdd_pin.layer == "metal1":
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=vdd_pin.center(),
|
||||
rotate=90)
|
||||
# Always drop to M2
|
||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||
offset=vdd_pin.center())
|
||||
self.add_layout_pin_rect_center(text="vdd",
|
||||
layer="metal3",
|
||||
offset=vdd_pin.center())
|
||||
|
||||
|
||||
# For every second row and column (+1), add a via for gnd
|
||||
for row in range(self.row_size):
|
||||
for col in range(self.column_size):
|
||||
inst = self.cell_inst[row,col]
|
||||
for gnd_pin in inst.get_pins("gnd"):
|
||||
# Drop to M1 if needed
|
||||
if gnd_pin.layer == "metal1":
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=gnd_pin.center(),
|
||||
rotate=90)
|
||||
# Always drop to M2
|
||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||
offset=gnd_pin.center())
|
||||
self.add_layout_pin_rect_center(text="gnd",
|
||||
layer="metal3",
|
||||
offset=gnd_pin.center())
|
||||
|
||||
def analytical_delay(self, slew, load=0):
|
||||
from tech import drc
|
||||
wl_wire = self.gen_wl_wire()
|
||||
wl_wire.return_delay_over_wire(slew)
|
||||
|
||||
wl_to_cell_delay = wl_wire.return_delay_over_wire(slew)
|
||||
# hypothetical delay from cell to bl end without sense amp
|
||||
bl_wire = self.gen_bl_wire()
|
||||
cell_load = 2 * bl_wire.return_input_cap() # we ingore the wire r
|
||||
# hence just use the whole c
|
||||
bl_swing = 0.1
|
||||
cell_delay = self.cell.analytical_delay(wl_to_cell_delay.slew, cell_load, swing = bl_swing)
|
||||
|
||||
#we do not consider the delay over the wire for now
|
||||
return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
|
||||
wl_to_cell_delay.slew)
|
||||
|
||||
def analytical_power(self, proc, vdd, temp, load):
|
||||
"""Power of Bitcell array and bitline in nW."""
|
||||
from tech import drc
|
||||
|
||||
# Dynamic Power from Bitline
|
||||
bl_wire = self.gen_bl_wire()
|
||||
cell_load = 2 * bl_wire.return_input_cap()
|
||||
bl_swing = 0.1 #This should probably be defined in the tech file or input
|
||||
freq = spice["default_event_rate"]
|
||||
bitline_dynamic = bl_swing*cell_load*vdd*vdd*freq #not sure if calculation is correct
|
||||
|
||||
#Calculate the bitcell power which currently only includes leakage
|
||||
cell_power = self.cell.analytical_power(proc, vdd, temp, load)
|
||||
|
||||
#Leakage power grows with entire array and bitlines.
|
||||
total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size,
|
||||
cell_power.leakage * self.column_size * self.row_size)
|
||||
return total_power
|
||||
|
||||
def gen_wl_wire(self):
|
||||
wl_wire = self.generate_rc_net(int(self.column_size), self.width, drc["minwidth_metal1"])
|
||||
wl_wire.wire_c = 2*spice["min_tx_gate_c"] + wl_wire.wire_c # 2 access tx gate per cell
|
||||
return wl_wire
|
||||
|
||||
def gen_bl_wire(self):
|
||||
bl_pos = 0
|
||||
bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), self.height, drc["minwidth_metal1"])
|
||||
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
|
||||
return bl_wire
|
||||
|
||||
def output_load(self, bl_pos=0):
|
||||
bl_wire = self.gen_bl_wire()
|
||||
return bl_wire.wire_c # sense amp only need to charge small portion of the bl
|
||||
# set as one segment for now
|
||||
|
||||
def input_load(self):
|
||||
wl_wire = self.gen_wl_wire()
|
||||
return wl_wire.return_input_cap()
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,78 +1,78 @@
|
|||
#!/usr/bin/env python2.7
|
||||
"""
|
||||
Run regresion tests on a parameterized bitcell
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 04_pbitcell_test")
|
||||
|
||||
|
||||
class pbitcell_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
|
||||
import pbitcell
|
||||
import tech
|
||||
|
||||
debug.info(2, "Bitcell with 1 of each port: read/write, write, and read")
|
||||
tx = pbitcell.pbitcell(num_readwrite=1,num_write=1,num_read=1)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 read/write ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=0,num_write=1,num_read=1)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 write ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=1,num_write=0,num_read=1)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 read ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=1,num_write=1,num_read=0)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 read ports and 0 write ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=1,num_write=0,num_read=0)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 2 of each port: read/write, write, and read")
|
||||
tx = pbitcell.pbitcell(num_readwrite=2,num_write=2,num_read=2)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 read/write ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=0,num_write=2,num_read=2)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 write ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=2,num_write=0,num_read=2)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 read ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=2,num_write=2,num_read=0)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 read ports and 0 write ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=2,num_write=0,num_read=0)
|
||||
self.local_check(tx)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
del sys.argv[1:]
|
||||
header(__file__, OPTS.tech_name)
|
||||
unittest.main()
|
||||
#!/usr/bin/env python2.7
|
||||
"""
|
||||
Run regresion tests on a parameterized bitcell
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 04_pbitcell_test")
|
||||
|
||||
|
||||
class pbitcell_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
|
||||
import pbitcell
|
||||
import tech
|
||||
|
||||
debug.info(2, "Bitcell with 1 of each port: read/write, write, and read")
|
||||
tx = pbitcell.pbitcell(num_readwrite=1,num_write=1,num_read=1)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 read/write ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=0,num_write=1,num_read=1)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 write ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=1,num_write=0,num_read=1)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 read ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=1,num_write=1,num_read=0)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 read ports and 0 write ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=1,num_write=0,num_read=0)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 2 of each port: read/write, write, and read")
|
||||
tx = pbitcell.pbitcell(num_readwrite=2,num_write=2,num_read=2)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 read/write ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=0,num_write=2,num_read=2)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 write ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=2,num_write=0,num_read=2)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 read ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=2,num_write=2,num_read=0)
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Bitcell with 0 read ports and 0 write ports")
|
||||
tx = pbitcell.pbitcell(num_readwrite=2,num_write=0,num_read=0)
|
||||
self.local_check(tx)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
del sys.argv[1:]
|
||||
header(__file__, OPTS.tech_name)
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Reference in New Issue