mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'tech_migration' into dev
This commit is contained in:
commit
90fdaf902c
|
|
@ -974,6 +974,7 @@ class layout():
|
||||||
def create_channel_route(self, netlist,
|
def create_channel_route(self, netlist,
|
||||||
offset,
|
offset,
|
||||||
layer_stack,
|
layer_stack,
|
||||||
|
layer_dirs=None,
|
||||||
vertical=False):
|
vertical=False):
|
||||||
"""
|
"""
|
||||||
The net list is a list of the nets. Each net is a list of pins
|
The net list is a list of the nets. Each net is a list of pins
|
||||||
|
|
@ -1012,25 +1013,38 @@ class layout():
|
||||||
|
|
||||||
def vcg_pin_overlap(pin1, pin2, vertical, pitch):
|
def vcg_pin_overlap(pin1, pin2, vertical, pitch):
|
||||||
""" Check for vertical or horizontal overlap of the two pins """
|
""" Check for vertical or horizontal overlap of the two pins """
|
||||||
|
|
||||||
# FIXME: If the pins are not in a row, this may break.
|
# FIXME: If the pins are not in a row, this may break.
|
||||||
# However, a top pin shouldn't overlap another top pin,
|
# However, a top pin shouldn't overlap another top pin,
|
||||||
# for example, so the
|
# for example, so the
|
||||||
# extra comparison *shouldn't* matter.
|
# extra comparison *shouldn't* matter.
|
||||||
|
|
||||||
# Pin 1 must be in the "BOTTOM" set
|
# Pin 1 must be in the "BOTTOM" set
|
||||||
x_overlap = pin1.by() < pin2.by() and abs(pin1.center().x-pin2.center().x)<pitch
|
x_overlap = pin1.by() < pin2.by() and abs(pin1.center().x - pin2.center().x) < pitch
|
||||||
|
|
||||||
# Pin 1 must be in the "LEFT" set
|
# Pin 1 must be in the "LEFT" set
|
||||||
y_overlap = pin1.lx() < pin2.lx() and abs(pin1.center().y-pin2.center().y)<pitch
|
y_overlap = pin1.lx() < pin2.lx() and abs(pin1.center().y - pin2.center().y) < pitch
|
||||||
overlaps = (not vertical and x_overlap) or (vertical and y_overlap)
|
overlaps = (not vertical and x_overlap) or (vertical and y_overlap)
|
||||||
return overlaps
|
return overlaps
|
||||||
|
|
||||||
if self.get_preferred_direction(layer_stack[0]) == "V":
|
if not layer_dirs:
|
||||||
self.vertical_layer = layer_stack[0]
|
# Use the preferred layer directions
|
||||||
self.horizontal_layer = layer_stack[2]
|
if self.get_preferred_direction(layer_stack[0]) == "V":
|
||||||
|
self.vertical_layer = layer_stack[0]
|
||||||
|
self.horizontal_layer = layer_stack[2]
|
||||||
|
else:
|
||||||
|
self.vertical_layer = layer_stack[2]
|
||||||
|
self.horizontal_layer = layer_stack[0]
|
||||||
else:
|
else:
|
||||||
self.vertical_layer = layer_stack[2]
|
# Use the layer directions specified to the router rather than
|
||||||
self.horizontal_layer = layer_stack[0]
|
# the preferred directions
|
||||||
|
debug.check(layer_dirs[0] != layer_dirs[1], "Must have unique layer directions.")
|
||||||
|
if layer_dirs[0] == "V":
|
||||||
|
self.vertical_layer = layer_stack[0]
|
||||||
|
self.horizontal_layer = layer_stack[2]
|
||||||
|
else:
|
||||||
|
self.horizontal_layer = layer_stack[0]
|
||||||
|
self.vertical_layer = layer_stack[2]
|
||||||
|
|
||||||
layer_stuff = self.get_layer_pitch(self.vertical_layer)
|
layer_stuff = self.get_layer_pitch(self.vertical_layer)
|
||||||
(self.vertical_pitch, self.vertical_width, self.vertical_space) = layer_stuff
|
(self.vertical_pitch, self.vertical_width, self.vertical_space) = layer_stuff
|
||||||
|
|
@ -1113,17 +1127,17 @@ class layout():
|
||||||
self.horizontal_pitch)
|
self.horizontal_pitch)
|
||||||
offset += vector(0, self.horizontal_pitch)
|
offset += vector(0, self.horizontal_pitch)
|
||||||
|
|
||||||
def create_vertical_channel_route(self, netlist, offset, layer_stack):
|
def create_vertical_channel_route(self, netlist, offset, layer_stack, layer_dirs=None):
|
||||||
"""
|
"""
|
||||||
Wrapper to create a vertical channel route
|
Wrapper to create a vertical channel route
|
||||||
"""
|
"""
|
||||||
self.create_channel_route(netlist, offset, layer_stack, vertical=True)
|
self.create_channel_route(netlist, offset, layer_stack, layer_dirs, vertical=True)
|
||||||
|
|
||||||
def create_horizontal_channel_route(self, netlist, offset, layer_stack):
|
def create_horizontal_channel_route(self, netlist, offset, layer_stack, layer_dirs=None):
|
||||||
"""
|
"""
|
||||||
Wrapper to create a horizontal channel route
|
Wrapper to create a horizontal channel route
|
||||||
"""
|
"""
|
||||||
self.create_channel_route(netlist, offset, layer_stack, vertical=False)
|
self.create_channel_route(netlist, offset, layer_stack, layer_dirs, vertical=False)
|
||||||
|
|
||||||
def add_boundary(self, ll=vector(0, 0), ur=None):
|
def add_boundary(self, ll=vector(0, 0), ur=None):
|
||||||
""" Add boundary for debugging dimensions """
|
""" Add boundary for debugging dimensions """
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ class bitcell_array(bitcell_base_array):
|
||||||
# the replica bitcell in the control logic
|
# the replica bitcell in the control logic
|
||||||
# self.offset_all_coordinates()
|
# self.offset_all_coordinates()
|
||||||
|
|
||||||
|
|
||||||
def create_netlist(self):
|
def create_netlist(self):
|
||||||
""" Create and connect the netlist """
|
""" Create and connect the netlist """
|
||||||
self.add_modules()
|
self.add_modules()
|
||||||
|
|
@ -56,22 +55,21 @@ class bitcell_array(bitcell_base_array):
|
||||||
for col in range(self.column_size):
|
for col in range(self.column_size):
|
||||||
for row in range(self.row_size):
|
for row in range(self.row_size):
|
||||||
name = "bit_r{0}_c{1}".format(row, col)
|
name = "bit_r{0}_c{1}".format(row, col)
|
||||||
self.cell_inst[row,col]=self.add_inst(name=name,
|
self.cell_inst[row, col]=self.add_inst(name=name,
|
||||||
mod=self.cell)
|
mod=self.cell)
|
||||||
self.connect_inst(self.get_bitcell_pins(col, row))
|
self.connect_inst(self.get_bitcell_pins(col, row))
|
||||||
|
|
||||||
def analytical_power(self, corner, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Power of Bitcell array and bitline in nW."""
|
"""Power of Bitcell array and bitline in nW."""
|
||||||
from tech import drc, parameter
|
|
||||||
|
|
||||||
# Dynamic Power from Bitline
|
# Dynamic Power from Bitline
|
||||||
bl_wire = self.gen_bl_wire()
|
bl_wire = self.gen_bl_wire()
|
||||||
cell_load = 2 * bl_wire.return_input_cap()
|
cell_load = 2 * bl_wire.return_input_cap()
|
||||||
bl_swing = OPTS.rbl_delay_percentage
|
bl_swing = OPTS.rbl_delay_percentage
|
||||||
freq = spice["default_event_frequency"]
|
freq = spice["default_event_frequency"]
|
||||||
bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing)
|
bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing)
|
||||||
|
|
||||||
# Calculate the bitcell power which currently only includes leakage
|
# Calculate the bitcell power which currently only includes leakage
|
||||||
cell_power = self.cell.analytical_power(corner, load)
|
cell_power = self.cell.analytical_power(corner, load)
|
||||||
|
|
||||||
# Leakage power grows with entire array and bitlines.
|
# Leakage power grows with entire array and bitlines.
|
||||||
|
|
@ -85,7 +83,7 @@ class bitcell_array(bitcell_base_array):
|
||||||
else:
|
else:
|
||||||
width = self.width
|
width = self.width
|
||||||
wl_wire = self.generate_rc_net(int(self.column_size), width, drc("minwidth_m1"))
|
wl_wire = self.generate_rc_net(int(self.column_size), width, drc("minwidth_m1"))
|
||||||
wl_wire.wire_c = 2*spice["min_tx_gate_c"] + wl_wire.wire_c # 2 access tx gate per cell
|
wl_wire.wire_c = 2 * spice["min_tx_gate_c"] + wl_wire.wire_c # 2 access tx gate per cell
|
||||||
return wl_wire
|
return wl_wire
|
||||||
|
|
||||||
def gen_bl_wire(self):
|
def gen_bl_wire(self):
|
||||||
|
|
@ -94,26 +92,26 @@ class bitcell_array(bitcell_base_array):
|
||||||
else:
|
else:
|
||||||
height = self.height
|
height = self.height
|
||||||
bl_pos = 0
|
bl_pos = 0
|
||||||
bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), height, drc("minwidth_m1"))
|
bl_wire = self.generate_rc_net(int(self.row_size - bl_pos), height, drc("minwidth_m1"))
|
||||||
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
|
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
|
||||||
return bl_wire
|
return bl_wire
|
||||||
|
|
||||||
def get_wordline_cin(self):
|
def get_wordline_cin(self):
|
||||||
"""Get the relative input capacitance from the wordline connections in all the bitcell"""
|
"""Get the relative input capacitance from the wordline connections in all the bitcell"""
|
||||||
#A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns
|
# A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns
|
||||||
bitcell_wl_cin = self.cell.get_wl_cin()
|
bitcell_wl_cin = self.cell.get_wl_cin()
|
||||||
total_cin = bitcell_wl_cin * self.column_size
|
total_cin = bitcell_wl_cin * self.column_size
|
||||||
return total_cin
|
return total_cin
|
||||||
|
|
||||||
def graph_exclude_bits(self, targ_row, targ_col):
|
def graph_exclude_bits(self, targ_row, targ_col):
|
||||||
"""Excludes bits in column from being added to graph except target"""
|
"""Excludes bits in column from being added to graph except target"""
|
||||||
#Function is not robust with column mux configurations
|
# Function is not robust with column mux configurations
|
||||||
for row in range(self.row_size):
|
for row in range(self.row_size):
|
||||||
for col in range(self.column_size):
|
for col in range(self.column_size):
|
||||||
if row == targ_row and col == targ_col:
|
if row == targ_row and col == targ_col:
|
||||||
continue
|
continue
|
||||||
self.graph_inst_exclude.add(self.cell_inst[row,col])
|
self.graph_inst_exclude.add(self.cell_inst[row, col])
|
||||||
|
|
||||||
def get_cell_name(self, inst_name, row, col):
|
def get_cell_name(self, inst_name, row, col):
|
||||||
"""Gets the spice name of the target bitcell."""
|
"""Gets the spice name of the target bitcell."""
|
||||||
return inst_name+'.x'+self.cell_inst[row,col].name, self.cell_inst[row,col]
|
return inst_name + '.x' + self.cell_inst[row, col].name, self.cell_inst[row, col]
|
||||||
|
|
|
||||||
|
|
@ -699,8 +699,13 @@ class port_data(design.design):
|
||||||
bottom_names = self._get_bitline_pins(bot_inst_group, bit)
|
bottom_names = self._get_bitline_pins(bot_inst_group, bit)
|
||||||
top_names = self._get_bitline_pins(top_inst_group, bit)
|
top_names = self._get_bitline_pins(top_inst_group, bit)
|
||||||
|
|
||||||
|
if bottom_names[0].layer == "m2":
|
||||||
|
bitline_dirs = ("H", "V")
|
||||||
|
elif bottom_names[0].layer == "m1":
|
||||||
|
bitline_dirs = ("V", "H")
|
||||||
|
|
||||||
route_map = list(zip(bottom_names, top_names))
|
route_map = list(zip(bottom_names, top_names))
|
||||||
self.create_horizontal_channel_route(route_map, offset, self.m1_stack)
|
self.create_horizontal_channel_route(route_map, offset, self.m1_stack, bitline_dirs)
|
||||||
|
|
||||||
def connect_bitlines(self, inst1, inst2, num_bits,
|
def connect_bitlines(self, inst1, inst2, num_bits,
|
||||||
inst1_bls_template="{inst}_{bit}",
|
inst1_bls_template="{inst}_{bit}",
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,14 @@
|
||||||
# (acting for and on behalf of Oklahoma State University)
|
# (acting for and on behalf of Oklahoma State University)
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
from math import log
|
|
||||||
import design
|
import design
|
||||||
import contact
|
|
||||||
from tech import drc
|
|
||||||
import debug
|
import debug
|
||||||
import math
|
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
import logical_effort
|
import logical_effort
|
||||||
|
|
||||||
|
|
||||||
class single_level_column_mux_array(design.design):
|
class single_level_column_mux_array(design.design):
|
||||||
"""
|
"""
|
||||||
Dynamically generated column mux array.
|
Dynamically generated column mux array.
|
||||||
|
|
@ -56,7 +53,7 @@ class single_level_column_mux_array(design.design):
|
||||||
self.add_routing()
|
self.add_routing()
|
||||||
# Find the highest shapes to determine height before adding well
|
# Find the highest shapes to determine height before adding well
|
||||||
highest = self.find_highest_coords()
|
highest = self.find_highest_coords()
|
||||||
self.height = highest.y
|
self.height = highest.y
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
self.add_enclosure(self.mux_inst, "pwell")
|
self.add_enclosure(self.mux_inst, "pwell")
|
||||||
|
|
||||||
|
|
@ -74,22 +71,18 @@ class single_level_column_mux_array(design.design):
|
||||||
self.add_pin("br_out_{}".format(i))
|
self.add_pin("br_out_{}".format(i))
|
||||||
self.add_pin("gnd")
|
self.add_pin("gnd")
|
||||||
|
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.mux = factory.create(module_type="single_level_column_mux",
|
self.mux = factory.create(module_type="single_level_column_mux",
|
||||||
bitcell_bl=self.bitcell_bl,
|
bitcell_bl=self.bitcell_bl,
|
||||||
bitcell_br=self.bitcell_br)
|
bitcell_br=self.bitcell_br)
|
||||||
self.add_mod(self.mux)
|
self.add_mod(self.mux)
|
||||||
|
|
||||||
|
|
||||||
def setup_layout_constants(self):
|
def setup_layout_constants(self):
|
||||||
self.column_addr_size = num_of_inputs = int(self.words_per_row / 2)
|
self.column_addr_size = int(self.words_per_row / 2)
|
||||||
self.width = self.columns * self.mux.width
|
self.width = self.columns * self.mux.width
|
||||||
# one set of metal1 routes for select signals and a pair to interconnect the mux outputs bl/br
|
# one set of metal1 routes for select signals and a pair to interconnect the mux outputs bl/br
|
||||||
# one extra route pitch is to space from the sense amp
|
# one extra route pitch is to space from the sense amp
|
||||||
self.route_height = (self.words_per_row + 3)*self.m1_pitch
|
self.route_height = (self.words_per_row + 3) * self.m1_pitch
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_array(self):
|
def create_array(self):
|
||||||
self.mux_inst = []
|
self.mux_inst = []
|
||||||
|
|
@ -101,8 +94,8 @@ class single_level_column_mux_array(design.design):
|
||||||
|
|
||||||
self.connect_inst(["bl_{}".format(col_num),
|
self.connect_inst(["bl_{}".format(col_num),
|
||||||
"br_{}".format(col_num),
|
"br_{}".format(col_num),
|
||||||
"bl_out_{}".format(int(col_num/self.words_per_row)),
|
"bl_out_{}".format(int(col_num / self.words_per_row)),
|
||||||
"br_out_{}".format(int(col_num/self.words_per_row)),
|
"br_out_{}".format(int(col_num / self.words_per_row)),
|
||||||
"sel_{}".format(col_num % self.words_per_row),
|
"sel_{}".format(col_num % self.words_per_row),
|
||||||
"gnd"])
|
"gnd"])
|
||||||
|
|
||||||
|
|
@ -117,11 +110,9 @@ class single_level_column_mux_array(design.design):
|
||||||
else:
|
else:
|
||||||
mirror = ""
|
mirror = ""
|
||||||
|
|
||||||
name = "XMUX{0}".format(col_num)
|
|
||||||
offset = vector(xoffset, self.route_height)
|
offset = vector(xoffset, self.route_height)
|
||||||
self.mux_inst[col_num].place(offset=offset, mirror=mirror)
|
self.mux_inst[col_num].place(offset=offset, mirror=mirror)
|
||||||
|
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
""" Add the pins after we determine the height. """
|
""" Add the pins after we determine the height. """
|
||||||
# For every column, add a pass gate
|
# For every column, add a pass gate
|
||||||
|
|
@ -131,18 +122,17 @@ class single_level_column_mux_array(design.design):
|
||||||
self.add_layout_pin(text="bl_{}".format(col_num),
|
self.add_layout_pin(text="bl_{}".format(col_num),
|
||||||
layer="m2",
|
layer="m2",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
height=self.height-offset.y)
|
height=self.height - offset.y)
|
||||||
|
|
||||||
offset = mux_inst.get_pin("br").ll()
|
offset = mux_inst.get_pin("br").ll()
|
||||||
self.add_layout_pin(text="br_{}".format(col_num),
|
self.add_layout_pin(text="br_{}".format(col_num),
|
||||||
layer="m2",
|
layer="m2",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
height=self.height-offset.y)
|
height=self.height - offset.y)
|
||||||
|
|
||||||
for inst in self.mux_inst:
|
for inst in self.mux_inst:
|
||||||
self.copy_layout_pin(inst, "gnd")
|
self.copy_layout_pin(inst, "gnd")
|
||||||
|
|
||||||
|
|
||||||
def add_routing(self):
|
def add_routing(self):
|
||||||
self.add_horizontal_input_rail()
|
self.add_horizontal_input_rail()
|
||||||
self.add_vertical_poly_rail()
|
self.add_vertical_poly_rail()
|
||||||
|
|
@ -151,7 +141,7 @@ class single_level_column_mux_array(design.design):
|
||||||
def add_horizontal_input_rail(self):
|
def add_horizontal_input_rail(self):
|
||||||
""" Create address input rails on M1 below the mux transistors """
|
""" Create address input rails on M1 below the mux transistors """
|
||||||
for j in range(self.words_per_row):
|
for j in range(self.words_per_row):
|
||||||
offset = vector(0, self.route_height + (j-self.words_per_row)*self.m1_pitch)
|
offset = vector(0, self.route_height + (j - self.words_per_row) * self.m1_pitch)
|
||||||
self.add_layout_pin(text="sel_{}".format(j),
|
self.add_layout_pin(text="sel_{}".format(j),
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -167,9 +157,10 @@ class single_level_column_mux_array(design.design):
|
||||||
# Add the column x offset to find the right select bit
|
# Add the column x offset to find the right select bit
|
||||||
gate_offset = self.mux_inst[col].get_pin("sel").bc()
|
gate_offset = self.mux_inst[col].get_pin("sel").bc()
|
||||||
# height to connect the gate to the correct horizontal row
|
# height to connect the gate to the correct horizontal row
|
||||||
sel_height = self.get_pin("sel_{}".format(sel_index)).by()
|
# sel_height = self.get_pin("sel_{}".format(sel_index)).by()
|
||||||
# use the y offset from the sel pin and the x offset from the gate
|
# use the y offset from the sel pin and the x offset from the gate
|
||||||
offset = vector(gate_offset.x,self.get_pin("sel_{}".format(sel_index)).cy())
|
offset = vector(gate_offset.x,
|
||||||
|
self.get_pin("sel_{}".format(sel_index)).cy())
|
||||||
# Add the poly contact with a shift to account for the rotation
|
# Add the poly contact with a shift to account for the rotation
|
||||||
self.add_via_center(layers=("m1", "contact", "poly"),
|
self.add_via_center(layers=("m1", "contact", "poly"),
|
||||||
offset=offset)
|
offset=offset)
|
||||||
|
|
@ -182,11 +173,11 @@ class single_level_column_mux_array(design.design):
|
||||||
bl_offset = self.mux_inst[j].get_pin("bl_out").bc()
|
bl_offset = self.mux_inst[j].get_pin("bl_out").bc()
|
||||||
br_offset = self.mux_inst[j].get_pin("br_out").bc()
|
br_offset = self.mux_inst[j].get_pin("br_out").bc()
|
||||||
|
|
||||||
bl_out_offset = bl_offset - vector(0,(self.words_per_row+1)*self.m1_pitch)
|
bl_out_offset = bl_offset - vector(0, (self.words_per_row + 1) * self.m1_pitch)
|
||||||
br_out_offset = br_offset - vector(0,(self.words_per_row+2)*self.m1_pitch)
|
br_out_offset = br_offset - vector(0, (self.words_per_row + 2) * self.m1_pitch)
|
||||||
|
|
||||||
bl_out_offset_end = bl_out_offset + vector(0,self.route_height)
|
bl_out_offset_end = bl_out_offset + vector(0, self.route_height)
|
||||||
br_out_offset_end = br_out_offset + vector(0,self.route_height)
|
br_out_offset_end = br_out_offset + vector(0, self.route_height)
|
||||||
|
|
||||||
if cell_properties.bitcell.mirror.y and j % 2:
|
if cell_properties.bitcell.mirror.y and j % 2:
|
||||||
tmp_bl_out_end = br_out_offset_end
|
tmp_bl_out_end = br_out_offset_end
|
||||||
|
|
@ -208,21 +199,20 @@ class single_level_column_mux_array(design.design):
|
||||||
else:
|
else:
|
||||||
dist = 0
|
dist = 0
|
||||||
|
|
||||||
self.add_path("m1", [bl_out_offset, bl_out_offset+vector(width+dist,0)])
|
self.add_path("m1", [bl_out_offset, bl_out_offset + vector(width + dist, 0)])
|
||||||
self.add_path("m1", [br_out_offset, br_out_offset+vector(width-dist,0)])
|
self.add_path("m1", [br_out_offset, br_out_offset + vector(width - dist, 0)])
|
||||||
|
|
||||||
# Extend the bitline output rails and gnd downward on the first bit of each n-way mux
|
# Extend the bitline output rails and gnd downward on the first bit of each n-way mux
|
||||||
self.add_layout_pin_segment_center(text="bl_out_{}".format(int(j/self.words_per_row)),
|
self.add_layout_pin_segment_center(text="bl_out_{}".format(int(j / self.words_per_row)),
|
||||||
layer="m2",
|
layer="m2",
|
||||||
start=bl_out_offset,
|
start=bl_out_offset,
|
||||||
end=tmp_bl_out_end)
|
end=tmp_bl_out_end)
|
||||||
self.add_layout_pin_segment_center(text="br_out_{}".format(int(j/self.words_per_row)),
|
self.add_layout_pin_segment_center(text="br_out_{}".format(int(j / self.words_per_row)),
|
||||||
layer="m2",
|
layer="m2",
|
||||||
start=br_out_offset,
|
start=br_out_offset,
|
||||||
end=tmp_br_out_end)
|
end=tmp_br_out_end)
|
||||||
|
|
||||||
|
# This via is on the right of the wire
|
||||||
# This via is on the right of the wire
|
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=bl_out_offset)
|
offset=bl_out_offset)
|
||||||
|
|
||||||
|
|
@ -231,20 +221,19 @@ class single_level_column_mux_array(design.design):
|
||||||
offset=br_out_offset)
|
offset=br_out_offset)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
self.add_path("m2", [bl_out_offset, tmp_bl_out_end])
|
||||||
self.add_path("m2", [ bl_out_offset, tmp_bl_out_end])
|
self.add_path("m2", [br_out_offset, tmp_br_out_end])
|
||||||
self.add_path("m2", [ br_out_offset, tmp_br_out_end])
|
|
||||||
|
|
||||||
# This via is on the right of the wire
|
# This via is on the right of the wire
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=bl_out_offset)
|
offset=bl_out_offset)
|
||||||
# This via is on the left of the wire
|
# This via is on the left of the wire
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
offset=br_out_offset)
|
offset=br_out_offset)
|
||||||
|
|
||||||
def get_drain_cin(self):
|
def get_drain_cin(self):
|
||||||
"""Get the relative capacitance of the drain of the NMOS pass TX"""
|
"""Get the relative capacitance of the drain of the NMOS pass TX"""
|
||||||
from tech import parameter
|
from tech import parameter
|
||||||
#Bitcell drain load being used to estimate mux NMOS drain load
|
# Bitcell drain load being used to estimate mux NMOS drain load
|
||||||
drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])
|
drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])
|
||||||
return drain_load
|
return drain_load
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# See LICENSE for licensing information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016-2019 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 unittest
|
||||||
|
from testutils import *
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
#@unittest.skip("SKIPPING 04_driver_test")
|
||||||
|
|
||||||
|
class single_level_column_mux_pbitcell_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
# check single level column mux in multi-port
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Checking column mux for pbitcell (innermost connections)")
|
||||||
|
tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0")
|
||||||
|
self.local_check(tx)
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Checking column mux for pbitcell (outermost connections)")
|
||||||
|
tx = factory.create(module_type="single_level_column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2")
|
||||||
|
self.local_check(tx)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# run the test from the command line
|
||||||
|
if __name__ == "__main__":
|
||||||
|
(OPTS, args) = globals.parse_args()
|
||||||
|
del sys.argv[1:]
|
||||||
|
header(__file__, OPTS.tech_name)
|
||||||
|
unittest.main(testRunner=debugTestRunner())
|
||||||
|
|
@ -28,22 +28,6 @@ class single_level_column_mux_test(openram_test):
|
||||||
tx = factory.create(module_type="single_level_column_mux", tx_size=8)
|
tx = factory.create(module_type="single_level_column_mux", tx_size=8)
|
||||||
self.local_check(tx)
|
self.local_check(tx)
|
||||||
|
|
||||||
# check single level column mux in multi-port
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_r_ports = 1
|
|
||||||
OPTS.num_w_ports = 1
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(2, "Checking column mux for pbitcell (innermost connections)")
|
|
||||||
tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0")
|
|
||||||
self.local_check(tx)
|
|
||||||
|
|
||||||
factory.reset()
|
|
||||||
debug.info(2, "Checking column mux for pbitcell (outermost connections)")
|
|
||||||
tx = factory.create(module_type="single_level_column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2")
|
|
||||||
self.local_check(tx)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# See LICENSE for licensing information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016-2019 Regents of the University of California
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
import unittest
|
||||||
|
from testutils import *
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class port_data_1rw_1r_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
from sram_config import sram_config
|
||||||
|
|
||||||
|
OPTS.bitcell = "bitcell_1w_1r"
|
||||||
|
OPTS.num_rw_ports = 0
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
|
|
||||||
|
c = sram_config(word_size=4,
|
||||||
|
num_words=16)
|
||||||
|
|
||||||
|
c.words_per_row=1
|
||||||
|
factory.reset()
|
||||||
|
c.recompute_sizes()
|
||||||
|
debug.info(1, "No column mux")
|
||||||
|
a = factory.create("port_data", sram_config=c, port=0)
|
||||||
|
self.local_check(a)
|
||||||
|
a = factory.create("port_data", sram_config=c, port=1)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
c.num_words=32
|
||||||
|
c.words_per_row=2
|
||||||
|
factory.reset()
|
||||||
|
c.recompute_sizes()
|
||||||
|
debug.info(1, "Two way column mux")
|
||||||
|
a = factory.create("port_data", sram_config=c, port=0)
|
||||||
|
self.local_check(a)
|
||||||
|
a = factory.create("port_data", sram_config=c, port=1)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
c.num_words=64
|
||||||
|
c.words_per_row=4
|
||||||
|
factory.reset()
|
||||||
|
c.recompute_sizes()
|
||||||
|
debug.info(1, "Four way column mux")
|
||||||
|
a = factory.create("port_data", sram_config=c, port=0)
|
||||||
|
self.local_check(a)
|
||||||
|
a = factory.create("port_data", sram_config=c, port=1)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
c.word_size=2
|
||||||
|
c.num_words=128
|
||||||
|
c.words_per_row=8
|
||||||
|
factory.reset()
|
||||||
|
c.recompute_sizes()
|
||||||
|
debug.info(1, "Eight way column mux")
|
||||||
|
a = factory.create("port_data", sram_config=c, port=0)
|
||||||
|
self.local_check(a)
|
||||||
|
a = factory.create("port_data", sram_config=c, port=1)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# run the test from the command line
|
||||||
|
if __name__ == "__main__":
|
||||||
|
(OPTS, args) = globals.parse_args()
|
||||||
|
del sys.argv[1:]
|
||||||
|
header(__file__, OPTS.tech_name)
|
||||||
|
unittest.main(testRunner=debugTestRunner())
|
||||||
|
|
@ -55,52 +55,6 @@ class port_data_test(openram_test):
|
||||||
a = factory.create("port_data", sram_config=c, port=0)
|
a = factory.create("port_data", sram_config=c, port=0)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
OPTS.bitcell = "bitcell_1w_1r"
|
|
||||||
OPTS.num_rw_ports = 0
|
|
||||||
OPTS.num_r_ports = 1
|
|
||||||
OPTS.num_w_ports = 1
|
|
||||||
|
|
||||||
c.num_words=16
|
|
||||||
c.words_per_row=1
|
|
||||||
factory.reset()
|
|
||||||
c.recompute_sizes()
|
|
||||||
debug.info(1, "No column mux")
|
|
||||||
a = factory.create("port_data", sram_config=c, port=0)
|
|
||||||
self.local_check(a)
|
|
||||||
a = factory.create("port_data", sram_config=c, port=1)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
c.num_words=32
|
|
||||||
c.words_per_row=2
|
|
||||||
factory.reset()
|
|
||||||
c.recompute_sizes()
|
|
||||||
debug.info(1, "Two way column mux")
|
|
||||||
a = factory.create("port_data", sram_config=c, port=0)
|
|
||||||
self.local_check(a)
|
|
||||||
a = factory.create("port_data", sram_config=c, port=1)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
c.num_words=64
|
|
||||||
c.words_per_row=4
|
|
||||||
factory.reset()
|
|
||||||
c.recompute_sizes()
|
|
||||||
debug.info(1, "Four way column mux")
|
|
||||||
a = factory.create("port_data", sram_config=c, port=0)
|
|
||||||
self.local_check(a)
|
|
||||||
a = factory.create("port_data", sram_config=c, port=1)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
c.word_size=2
|
|
||||||
c.num_words=128
|
|
||||||
c.words_per_row=8
|
|
||||||
factory.reset()
|
|
||||||
c.recompute_sizes()
|
|
||||||
debug.info(1, "Eight way column mux")
|
|
||||||
a = factory.create("port_data", sram_config=c, port=0)
|
|
||||||
self.local_check(a)
|
|
||||||
a = factory.create("port_data", sram_config=c, port=1)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue