Finished merge

This commit is contained in:
jsowash 2019-07-05 11:43:31 -07:00
commit f29631695c
8 changed files with 257 additions and 123 deletions

View File

@ -227,6 +227,9 @@ class layout():
You can optionally rename the pin to a new name. You can optionally rename the pin to a new name.
""" """
pins=instance.get_pins(pin_name) pins=instance.get_pins(pin_name)
debug.check(len(pins)>0,"Could not find pin {}".format(pin_name))
for pin in pins: for pin in pins:
if new_name=="": if new_name=="":
new_name = pin.name new_name = pin.name
@ -238,9 +241,7 @@ class layout():
You can optionally rename the pin to a new name. You can optionally rename the pin to a new name.
""" """
for pin_name in self.pin_map.keys(): for pin_name in self.pin_map.keys():
pins=instance.get_pins(pin_name) self.copy_layout_pin(instance, pin_name, prefix+pin_name)
for pin in pins:
self.add_layout_pin(prefix+pin_name, pin.layer, pin.ll(), pin.width(), pin.height())
def add_layout_pin_segment_center(self, text, layer, start, end): def add_layout_pin_segment_center(self, text, layer, start, end):
""" """

View File

@ -85,7 +85,7 @@ def log(str):
# use a static list of strings to store messages until the global paths are set up # use a static list of strings to store messages until the global paths are set up
log.setup_output = [] log.setup_output = []
log.create_file = 1 log.create_file = True
def info(lev, str): def info(lev, str):

View File

@ -110,8 +110,7 @@ class bank(design.design):
for port in self.all_ports: for port in self.all_ports:
self.route_bitlines(port) self.route_bitlines(port)
self.route_wordline_driver(port) self.route_port_address(port)
self.route_row_decoder(port)
self.route_column_address_lines(port) self.route_column_address_lines(port)
self.route_control_lines(port) self.route_control_lines(port)
if self.num_banks > 1: if self.num_banks > 1:
@ -134,8 +133,7 @@ class bank(design.design):
self.create_bitcell_array() self.create_bitcell_array()
self.create_port_data() self.create_port_data()
self.create_row_decoder() self.create_port_address()
self.create_wordline_driver()
self.create_column_decoder() self.create_column_decoder()
self.create_bank_select() self.create_bank_select()
@ -145,8 +143,7 @@ class bank(design.design):
""" """
self.port_data_offsets = [None]*len(self.all_ports) self.port_data_offsets = [None]*len(self.all_ports)
self.wordline_driver_offsets = [None]*len(self.all_ports) self.port_address_offsets = [None]*len(self.all_ports)
self.row_decoder_offsets = [None]*len(self.all_ports)
self.column_decoder_offsets = [None]*len(self.all_ports) self.column_decoder_offsets = [None]*len(self.all_ports)
self.bank_select_offsets = [None]*len(self.all_ports) self.bank_select_offsets = [None]*len(self.all_ports)
@ -183,16 +180,14 @@ class bank(design.design):
# UPPER LEFT QUADRANT # UPPER LEFT QUADRANT
# To the left of the bitcell array # To the left of the bitcell array
# The wordline driver is placed to the right of the main decoder width. # The wordline driver is placed to the right of the main decoder width.
x_offset = self.m2_gap + self.wordline_driver.width x_offset = self.m2_gap + self.port_address.width
self.wordline_driver_offsets[port] = vector(-x_offset,0) self.port_address_offsets[port] = vector(-x_offset,0)
x_offset += self.row_decoder.width + self.m2_gap
self.row_decoder_offsets[port] = vector(-x_offset,0)
# LOWER LEFT QUADRANT # LOWER LEFT QUADRANT
# Place the col decoder left aligned with wordline driver plus halfway under row decoder # Place the col decoder left aligned with wordline driver plus halfway under row decoder
# Place the col decoder left aligned with row decoder (x_offset doesn't change) # Place the col decoder left aligned with row decoder (x_offset doesn't change)
# Below the bitcell array with well spacing # Below the bitcell array with well spacing
x_offset = self.central_bus_width[port] + self.wordline_driver.width x_offset = self.central_bus_width[port] + self.port_address.wordline_driver.width
if self.col_addr_size > 0: if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width x_offset += self.column_decoder.width + self.col_addr_bus_width
y_offset = self.m2_gap + self.column_decoder.height y_offset = self.m2_gap + self.column_decoder.height
@ -205,7 +200,7 @@ class bank(design.design):
if self.col_addr_size > 0: if self.col_addr_size > 0:
y_offset = min(self.column_decoder_offsets[port].y, self.port_data[port].column_mux_offset.y) y_offset = min(self.column_decoder_offsets[port].y, self.port_data[port].column_mux_offset.y)
else: else:
y_offset = self.row_decoder_offsets[port].y y_offset = self.port_address_offsets[port].y
if self.num_banks > 1: if self.num_banks > 1:
y_offset += self.bank_select.height + drc("well_to_well") y_offset += self.bank_select.height + drc("well_to_well")
self.bank_select_offsets[port] = vector(-x_offset,-y_offset) self.bank_select_offsets[port] = vector(-x_offset,-y_offset)
@ -227,15 +222,13 @@ class bank(design.design):
# LOWER RIGHT QUADRANT # LOWER RIGHT QUADRANT
# To the left of the bitcell array # To the left of the bitcell array
# The wordline driver is placed to the right of the main decoder width. # The wordline driver is placed to the right of the main decoder width.
x_offset = self.bitcell_array_right + self.wordline_driver.width x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap
self.wordline_driver_offsets[port] = vector(x_offset,0) self.port_address_offsets[port] = vector(x_offset,0)
x_offset += self.row_decoder.width + self.m2_gap
self.row_decoder_offsets[port] = vector(x_offset,0)
# UPPER RIGHT QUADRANT # UPPER RIGHT QUADRANT
# Place the col decoder right aligned with wordline driver plus halfway under row decoder # Place the col decoder right aligned with wordline driver plus halfway under row decoder
# Above the bitcell array with a well spacing # Above the bitcell array with a well spacing
x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.wordline_driver.width x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.port_address.wordline_driver.width
if self.col_addr_size > 0: if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width x_offset += self.column_decoder.width + self.col_addr_bus_width
y_offset = self.bitcell_array_top + self.m2_gap + self.column_decoder.height y_offset = self.bitcell_array_top + self.m2_gap + self.column_decoder.height
@ -249,7 +242,7 @@ class bank(design.design):
y_offset = max(self.column_decoder_offsets[port].y + self.column_decoder.height, y_offset = max(self.column_decoder_offsets[port].y + self.column_decoder.height,
self.port_data[port].column_mux_offset.y + self.port_data[port].column_mux_array.height) self.port_data[port].column_mux_offset.y + self.port_data[port].column_mux_array.height)
else: else:
y_offset = self.row_decoder_offsets[port].y y_offset = self.port_address_offsets[port].y
self.bank_select_offsets[port] = vector(x_offset,y_offset) self.bank_select_offsets[port] = vector(x_offset,y_offset)
def place_instances(self): def place_instances(self):
@ -264,8 +257,7 @@ class bank(design.design):
self.place_port_data(self.port_data_offsets) self.place_port_data(self.port_data_offsets)
# UPPER LEFT QUADRANT # UPPER LEFT QUADRANT
self.place_row_decoder(self.row_decoder_offsets) self.place_port_address(self.port_address_offsets)
self.place_wordline_driver(self.wordline_driver_offsets)
# LOWER LEFT QUADRANT # LOWER LEFT QUADRANT
self.place_column_decoder(self.column_decoder_offsets) self.place_column_decoder(self.column_decoder_offsets)
@ -352,18 +344,12 @@ class bank(design.design):
self.port_data.append(temp_pre) self.port_data.append(temp_pre)
self.add_mod(self.port_data[port]) self.add_mod(self.port_data[port])
self.row_decoder = factory.create(module_type="decoder",
rows=self.num_rows)
self.add_mod(self.row_decoder)
self.wordline_driver = factory.create(module_type="wordline_driver",
rows=self.num_rows,
cols=self.num_cols)
self.add_mod(self.wordline_driver)
self.inv = factory.create(module_type="pinv")
self.add_mod(self.inv)
self.port_address = factory.create(module_type="port_address",
cols=self.num_cols,
rows=self.num_rows)
self.add_mod(self.port_address)
if(self.num_banks > 1): if(self.num_banks > 1):
self.bank_select = factory.create(module_type="bank_select") self.bank_select = factory.create(module_type="bank_select")
self.add_mod(self.bank_select) self.add_mod(self.bank_select)
@ -436,24 +422,25 @@ class bank(design.design):
mirror = "MX" mirror = "MX"
self.port_data_inst[port].place(offset=offsets[port], mirror=mirror) self.port_data_inst[port].place(offset=offsets[port], mirror=mirror)
def create_row_decoder(self): def create_port_address(self):
""" Create the hierarchical row decoder """ """ Create the hierarchical row decoder """
self.row_decoder_inst = [None]*len(self.all_ports) self.port_address_inst = [None]*len(self.all_ports)
for port in self.all_ports: for port in self.all_ports:
self.row_decoder_inst[port] = self.add_inst(name="row_decoder{}".format(port), self.port_address_inst[port] = self.add_inst(name="port_address{}".format(port),
mod=self.row_decoder) mod=self.port_address)
temp = [] temp = []
for bit in range(self.row_addr_size): for bit in range(self.row_addr_size):
temp.append("addr{0}_{1}".format(port,bit+self.col_addr_size)) temp.append("addr{0}_{1}".format(port,bit+self.col_addr_size))
temp.append("wl_en{0}".format(port))
for row in range(self.num_rows): for row in range(self.num_rows):
temp.append("dec_out{0}_{1}".format(port,row)) temp.append(self.wl_names[port]+"_{0}".format(row))
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_row_decoder(self, offsets): def place_port_address(self, offsets):
""" Place the hierarchical row decoder """ """ Place the hierarchical row decoder """
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place row decoder array.") debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place row decoder array.")
@ -469,39 +456,7 @@ class bank(design.design):
mirror = "MY" mirror = "MY"
else: else:
mirror = "R0" mirror = "R0"
self.row_decoder_inst[port].place(offset=offsets[port], mirror=mirror) self.port_address_inst[port].place(offset=offsets[port], mirror=mirror)
def create_wordline_driver(self):
""" Create the Wordline Driver """
self.wordline_driver_inst = [None]*len(self.all_ports)
for port in self.all_ports:
self.wordline_driver_inst[port] = self.add_inst(name="wordline_driver{}".format(port),
mod=self.wordline_driver)
temp = []
for row in range(self.num_rows):
temp.append("dec_out{0}_{1}".format(port,row))
for row in range(self.num_rows):
temp.append(self.wl_names[port]+"_{0}".format(row))
temp.append(self.prefix+"wl_en{0}".format(port))
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
def place_wordline_driver(self, offsets):
""" Place the Wordline Driver """
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place wordline driver array.")
for port in self.all_ports:
if port%2 == 1:
mirror = "MY"
else:
mirror = "R0"
self.wordline_driver_inst[port].place(offset=offsets[port], mirror=mirror)
def create_column_decoder(self): def create_column_decoder(self):
@ -705,7 +660,7 @@ class bank(design.design):
width=data_pin.width()) width=data_pin.width())
def route_row_decoder(self, port): def route_port_address_in(self, port):
""" Routes the row decoder inputs and supplies """ """ Routes the row decoder inputs and supplies """
# Create inputs for the row address lines # Create inputs for the row address lines
@ -713,7 +668,7 @@ class bank(design.design):
addr_idx = row + self.col_addr_size addr_idx = row + self.col_addr_size
decoder_name = "addr_{}".format(row) decoder_name = "addr_{}".format(row)
addr_name = "addr{0}_{1}".format(port,addr_idx) addr_name = "addr{0}_{1}".format(port,addr_idx)
self.copy_layout_pin(self.row_decoder_inst[port], decoder_name, addr_name) self.copy_layout_pin(self.port_address_inst[port], decoder_name, addr_name)
def route_port_data_in(self, port): def route_port_data_in(self, port):
@ -782,47 +737,36 @@ class bank(design.design):
vector(top_br.x,yoffset), top_br]) vector(top_br.x,yoffset), top_br])
def route_wordline_driver(self, port): def route_port_address(self, port):
""" Connect Wordline driver to bitcell array wordline """ """ Connect Wordline driver to bitcell array wordline """
self.route_port_address_in(port)
if port%2: if port%2:
self.route_wordline_driver_right(port) self.route_port_address_right(port)
else: else:
self.route_wordline_driver_left(port) self.route_port_address_left(port)
def route_wordline_driver_left(self, port): def route_port_address_left(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """ """ Connecting Wordline driver output to Bitcell WL connection """
for row in range(self.num_rows): for row in range(self.num_rows):
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
decoder_out_pos = self.row_decoder_inst[port].get_pin("decode_{}".format(row)).rc()
driver_in_pos = self.wordline_driver_inst[port].get_pin("in_{}".format(row)).lc()
mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
# The mid guarantees we exit the input cell to the right. # The mid guarantees we exit the input cell to the right.
driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).rc() driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).rc()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).lc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).lc()
mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].rx() + 0.5*self.bitcell_array_inst.lx(),0) mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.port_address_inst[port].rx() + 0.5*self.bitcell_array_inst.lx(),0)
mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0.5,1) mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0.5,1)
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
def route_wordline_driver_right(self, port): def route_port_address_right(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """ """ Connecting Wordline driver output to Bitcell WL connection """
for row in range(self.num_rows): for row in range(self.num_rows):
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
decoder_out_pos = self.row_decoder_inst[port].get_pin("decode_{}".format(row)).lc()
driver_in_pos = self.wordline_driver_inst[port].get_pin("in_{}".format(row)).rc()
mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
# The mid guarantees we exit the input cell to the right. # The mid guarantees we exit the input cell to the right.
driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).lc() driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).lc()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).rc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).rc()
mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0) mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.port_address_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0)
mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0,1) mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0,1)
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
@ -937,10 +881,10 @@ class bank(design.design):
# clk to wordline_driver # clk to wordline_driver
control_signal = self.prefix+"wl_en{}".format(port) control_signal = self.prefix+"wl_en{}".format(port)
if port%2: if port%2:
pin_pos = self.wordline_driver_inst[port].get_pin("en_bar").uc() pin_pos = self.port_address_inst[port].get_pin("wl_en").uc()
mid_pos = pin_pos + vector(0,self.m2_gap) # to route down to the top of the bus mid_pos = pin_pos + vector(0,self.m2_gap) # to route down to the top of the bus
else: else:
pin_pos = self.wordline_driver_inst[port].get_pin("en_bar").bc() pin_pos = self.port_address_inst[port].get_pin("wl_en").bc()
mid_pos = pin_pos - vector(0,self.m2_gap) # to route down to the top of the bus mid_pos = pin_pos - vector(0,self.m2_gap) # to route down to the top of the bus
control_x_offset = self.bus_xoffset[port][control_signal].x control_x_offset = self.bus_xoffset[port][control_signal].x
control_pos = vector(control_x_offset, mid_pos.y) control_pos = vector(control_x_offset, mid_pos.y)
@ -986,14 +930,14 @@ class bank(design.design):
#Decoder is assumed to have settled before the negative edge of the clock. Delay model relies on this assumption #Decoder is assumed to have settled before the negative edge of the clock. Delay model relies on this assumption
stage_effort_list = [] stage_effort_list = []
wordline_cout = self.bitcell_array.get_wordline_cin() + external_cout wordline_cout = self.bitcell_array.get_wordline_cin() + external_cout
stage_effort_list += self.wordline_driver.determine_wordline_stage_efforts(wordline_cout,inp_is_rise) stage_effort_list += self.port_address.wordline_driver.determine_wordline_stage_efforts(wordline_cout,inp_is_rise)
return stage_effort_list return stage_effort_list
def get_wl_en_cin(self): def get_wl_en_cin(self):
"""Get the relative capacitance of all the clk connections in the bank""" """Get the relative capacitance of all the clk connections in the bank"""
#wl_en only used in the wordline driver. #wl_en only used in the wordline driver.
return self.wordline_driver.get_wl_en_cin() return self.port_address.wordline_driver.get_wl_en_cin()
def get_w_en_cin(self): def get_w_en_cin(self):
"""Get the relative capacitance of all the clk connections in the bank""" """Get the relative capacitance of all the clk connections in the bank"""

View File

@ -0,0 +1,163 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California
# All rights reserved.
#
import sys
from tech import drc, parameter
from math import log
import debug
import design
from sram_factory import factory
from vector import vector
from globals import OPTS
class port_address(design.design):
"""
Create the address port (row decoder and wordline driver)..
"""
def __init__(self, cols, rows, name=""):
self.num_cols = cols
self.num_rows = rows
self.addr_size = int(log(self.num_rows, 2))
if name == "":
name = "port_address_{0}_{1}".format(cols,rows)
design.design.__init__(self, name)
debug.info(2, "create data port of cols {0} rows {1}".format(cols,rows))
self.create_netlist()
if not OPTS.netlist_only:
debug.check(len(self.all_ports)<=2,"Bank layout cannot handle more than two ports.")
self.create_layout()
self.add_boundary()
def create_netlist(self):
self.add_pins()
self.add_modules()
self.create_row_decoder()
self.create_wordline_driver()
def create_layout(self):
self.place_instances()
self.route_layout()
self.DRC_LVS()
def add_pins(self):
""" Adding pins for port address module"""
for bit in range(self.addr_size):
self.add_pin("addr_{0}".format(bit),"INPUT")
self.add_pin("wl_en", "INPUT")
for bit in range(self.num_rows):
self.add_pin("wl_{0}".format(bit),"OUTPUT")
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
def route_layout(self):
""" Create routing amoung the modules """
self.route_pins()
self.route_internal()
self.route_supplies()
def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
for inst in self.insts:
self.copy_power_pins(inst,"vdd")
self.copy_power_pins(inst,"gnd")
def route_pins(self):
for row in range(self.addr_size):
decoder_name = "addr_{}".format(row)
self.copy_layout_pin(self.row_decoder_inst, decoder_name)
for row in range(self.num_rows):
driver_name = "wl_{}".format(row)
self.copy_layout_pin(self.wordline_driver_inst, driver_name)
# FIXME: Is this still inverted!?
self.copy_layout_pin(self.wordline_driver_inst, "en_bar", "wl_en")
def route_internal(self):
for row in range(self.num_rows):
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
decoder_out_pos = self.row_decoder_inst.get_pin("decode_{}".format(row)).rc()
driver_in_pos = self.wordline_driver_inst.get_pin("in_{}".format(row)).lc()
mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
def add_modules(self):
self.row_decoder = factory.create(module_type="decoder",
rows=self.num_rows)
self.add_mod(self.row_decoder)
self.wordline_driver = factory.create(module_type="wordline_driver",
rows=self.num_rows,
cols=self.num_cols)
self.add_mod(self.wordline_driver)
def create_row_decoder(self):
""" Create the hierarchical row decoder """
self.row_decoder_inst = self.add_inst(name="row_decoder",
mod=self.row_decoder)
temp = []
for bit in range(self.addr_size):
temp.append("addr_{0}".format(bit))
for row in range(self.num_rows):
temp.append("dec_out_{0}".format(row))
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def create_wordline_driver(self):
""" Create the Wordline Driver """
self.wordline_driver_inst = self.add_inst(name="wordline_driver",
mod=self.wordline_driver)
temp = []
for row in range(self.num_rows):
temp.append("dec_out_{0}".format(row))
for row in range(self.num_rows):
temp.append("wl_{0}".format(row))
temp.append("wl_en")
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
def place_instances(self):
"""
Compute the offsets and place the instances.
"""
# A space for wells or jogging m2
self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"),
3*self.m2_pitch)
row_decoder_offset = vector(0,0)
wordline_driver_offset = vector(self.row_decoder.width + self.m2_gap,0)
self.wordline_driver_inst.place(wordline_driver_offset)
self.row_decoder_inst.place(row_decoder_offset)
self.height = self.row_decoder.height
self.width = self.wordline_driver_inst.rx()

View File

@ -1,8 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2019 Regents of the University of California and The Board # Copyright (c) 2016-2019 Regents of the University of California
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import sys import sys
@ -16,7 +14,7 @@ from globals import OPTS
class port_data(design.design): class port_data(design.design):
""" """
Create the data port (column mux, sense amps, write driver, etc.) Create the data port (column mux, sense amps, write driver, etc.) for the given port number.
""" """
def __init__(self, sram_config, port, name=""): def __init__(self, sram_config, port, name=""):
@ -25,9 +23,9 @@ class port_data(design.design):
self.port = port self.port = port
if name == "": if name == "":
name = "bank_{0}_{1}".format(self.word_size, self.num_words) name = "port_data_{0}".format(self.port)
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words)) debug.info(2, "create data port of size {0} with {1} words per row".format(self.word_size,self.words_per_row))
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -37,7 +35,7 @@ class port_data(design.design):
def create_netlist(self): def create_netlist(self):
self.compute_sizes() self.precompute_constants()
self.add_pins() self.add_pins()
self.add_modules() self.add_modules()
self.create_instances() self.create_instances()
@ -72,7 +70,7 @@ class port_data(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
""" Adding pins for Bank module""" """ Adding pins for port address module"""
for bit in range(self.num_cols): for bit in range(self.num_cols):
self.add_pin(self.bl_names[self.port]+"_{0}".format(bit),"INOUT") self.add_pin(self.bl_names[self.port]+"_{0}".format(bit),"INOUT")
self.add_pin(self.br_names[self.port]+"_{0}".format(bit),"INOUT") self.add_pin(self.br_names[self.port]+"_{0}".format(bit),"INOUT")
@ -161,7 +159,7 @@ class port_data(design.design):
self.column_mux_array = None self.column_mux_array = None
if self.port in self.write_ports or self.port in self.readwrite_ports: if self.port in self.write_ports:
self.write_driver_array = factory.create(module_type="write_driver_array", self.write_driver_array = factory.create(module_type="write_driver_array",
columns=self.num_cols, columns=self.num_cols,
word_size=self.word_size) word_size=self.word_size)
@ -170,17 +168,15 @@ class port_data(design.design):
self.write_driver_array = None self.write_driver_array = None
def compute_sizes(self): def precompute_constants(self):
""" Computes the required sizes to create the bank """ """ Get some preliminary data ready """
self.num_cols = int(self.words_per_row*self.word_size)
self.num_rows = int(self.num_words / self.words_per_row)
# The central bus is the column address (one hot) and row address (binary) # The central bus is the column address (one hot) and row address (binary)
if self.col_addr_size>0: if self.col_addr_size>0:
self.num_col_addr_lines = 2**self.col_addr_size self.num_col_addr_lines = 2**self.col_addr_size
else: else:
self.num_col_addr_lines = 0 self.num_col_addr_lines = 0
# A space for wells or jogging m2 between modules # A space for wells or jogging m2 between modules
self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"), self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"),

View File

@ -41,7 +41,7 @@ class sram_config:
def compute_sizes(self): def compute_sizes(self):
""" Computes the organization of the memory using bitcell size by trying to make it square.""" """ Computes the organization of the memory using bitcell size by trying to make it square."""
self.bitcell = factory.create(module_type="bitcell") bitcell = factory.create(module_type="bitcell")
debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.") debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.")
@ -52,11 +52,11 @@ class sram_config:
# If this was hard coded, don't dynamically compute it! # If this was hard coded, don't dynamically compute it!
if not self.words_per_row: if not self.words_per_row:
# Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry) # Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry)
self.bank_area = self.bitcell.width*self.bitcell.height*self.num_bits_per_bank self.bank_area = bitcell.width*bitcell.height*self.num_bits_per_bank
self.bank_side_length = sqrt(self.bank_area) self.bank_side_length = sqrt(self.bank_area)
# Estimate the words per row given the height of the bitcell and the square side length # Estimate the words per row given the height of the bitcell and the square side length
self.tentative_num_cols = int(self.bank_side_length/self.bitcell.width) self.tentative_num_cols = int(self.bank_side_length/bitcell.width)
self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size) self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size)
# Estimate the number of rows given the tentative words per row # Estimate the number of rows given the tentative words per row

View File

@ -0,0 +1,32 @@
#!/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_address_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(1, "Port address 16 rows")
a = factory.create("port_address", cols=16, rows=16)
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())

View File

@ -1,9 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2019 Regents of the University of California and The Board # Copyright (c) 2016-2019 Regents of the University of California
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import unittest import unittest