mirror of https://github.com/VLSIDA/OpenRAM.git
changes to support spare columns
This commit is contained in:
parent
b75eeb7688
commit
2661a42726
|
|
@ -27,6 +27,10 @@ class port_data(design.design):
|
|||
else:
|
||||
self.num_wmasks = 0
|
||||
|
||||
if self.num_spare_cols is None:
|
||||
self.num_spare_cols = 0
|
||||
|
||||
|
||||
if name == "":
|
||||
name = "port_data_{0}".format(self.port)
|
||||
design.design.__init__(self, name)
|
||||
|
|
@ -102,7 +106,7 @@ class port_data(design.design):
|
|||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
""" Adding pins for port address module"""
|
||||
""" Adding pins for port data module"""
|
||||
|
||||
self.add_pin("rbl_bl", "INOUT")
|
||||
self.add_pin("rbl_br", "INOUT")
|
||||
|
|
@ -111,11 +115,18 @@ class port_data(design.design):
|
|||
br_name = self.get_br_name(self.port)
|
||||
self.add_pin("{0}_{1}".format(bl_name, bit), "INOUT")
|
||||
self.add_pin("{0}_{1}".format(br_name, bit), "INOUT")
|
||||
|
||||
for bit in range(self.num_spare_cols):
|
||||
bl_name = self.get_bl_name(self.port)
|
||||
br_name = self.get_br_name(self.port)
|
||||
self.add_pin("spare{0}_{1}".format(bl_name, bit), "INOUT")
|
||||
self.add_pin("spare{0}_{1}".format(br_name, bit), "INOUT")
|
||||
|
||||
if self.port in self.read_ports:
|
||||
for bit in range(self.word_size):
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
self.add_pin("dout_{}".format(bit), "OUTPUT")
|
||||
if self.port in self.write_ports:
|
||||
for bit in range(self.word_size):
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
self.add_pin("din_{}".format(bit), "INPUT")
|
||||
# Will be empty if no col addr lines
|
||||
sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)]
|
||||
|
|
@ -128,6 +139,8 @@ class port_data(design.design):
|
|||
self.add_pin("w_en", "INPUT")
|
||||
for bit in range(self.num_wmasks):
|
||||
self.add_pin("bank_wmask_{}".format(bit), "INPUT")
|
||||
for bit in range(self.num_spare_cols):
|
||||
self.add_pin("spare_wen{}".format(bit), "INPUT")
|
||||
self.add_pin("vdd", "POWER")
|
||||
self.add_pin("gnd", "GROUND")
|
||||
|
||||
|
|
@ -179,7 +192,7 @@ class port_data(design.design):
|
|||
# Extra column +1 is for RBL
|
||||
# Precharge will be shifted left if needed
|
||||
self.precharge_array = factory.create(module_type="precharge_array",
|
||||
columns=self.num_cols + 1,
|
||||
columns=self.num_cols + self.num_spare_cols + 1,
|
||||
bitcell_bl=self.bl_names[self.port],
|
||||
bitcell_br=self.br_names[self.port])
|
||||
self.add_mod(self.precharge_array)
|
||||
|
|
@ -187,7 +200,8 @@ class port_data(design.design):
|
|||
if self.port in self.read_ports:
|
||||
self.sense_amp_array = factory.create(module_type="sense_amp_array",
|
||||
word_size=self.word_size,
|
||||
words_per_row=self.words_per_row)
|
||||
words_per_row=self.words_per_row,
|
||||
num_spare_cols=self.num_spare_cols)
|
||||
self.add_mod(self.sense_amp_array)
|
||||
else:
|
||||
self.sense_amp_array = None
|
||||
|
|
@ -206,7 +220,8 @@ class port_data(design.design):
|
|||
self.write_driver_array = factory.create(module_type="write_driver_array",
|
||||
columns=self.num_cols,
|
||||
word_size=self.word_size,
|
||||
write_size=self.write_size)
|
||||
write_size=self.write_size,
|
||||
num_spare_cols=self.num_spare_cols)
|
||||
self.add_mod(self.write_driver_array)
|
||||
if self.write_size is not None:
|
||||
self.write_mask_and_array = factory.create(module_type="write_mask_and_array",
|
||||
|
|
@ -249,7 +264,7 @@ class port_data(design.design):
|
|||
# We create a dummy here to get bl/br names to add those pins to this
|
||||
# module, which happens before we create the real precharge_array
|
||||
self.precharge_array = factory.create(module_type="precharge_array",
|
||||
columns=self.num_cols + 1,
|
||||
columns=self.num_cols + self.num_spare_cols + 1,
|
||||
bitcell_bl=self.bl_names[self.port],
|
||||
bitcell_br=self.br_names[self.port])
|
||||
|
||||
|
|
@ -272,6 +287,10 @@ class port_data(design.design):
|
|||
for bit in range(self.num_cols):
|
||||
temp.append("{0}_{1}".format(bl_name, bit))
|
||||
temp.append("{0}_{1}".format(br_name, bit))
|
||||
|
||||
for bit in range(self.num_spare_cols):
|
||||
temp.append("sparebl{0}_{1}".format(self.port, bit))
|
||||
temp.append("sparebr{0}_{1}".format(self.port, bit))
|
||||
|
||||
# Use right BLs for RBL
|
||||
if self.port==1:
|
||||
|
|
@ -297,7 +316,6 @@ class port_data(design.design):
|
|||
for col in range(self.num_cols):
|
||||
temp.append("{0}_{1}".format(bl_name, col))
|
||||
temp.append("{0}_{1}".format(br_name, col))
|
||||
|
||||
for word in range(self.words_per_row):
|
||||
temp.append("sel_{}".format(word))
|
||||
for bit in range(self.word_size):
|
||||
|
|
@ -330,8 +348,14 @@ class port_data(design.design):
|
|||
else:
|
||||
temp.append("{0}_out_{1}".format(bl_name, bit))
|
||||
temp.append("{0}_out_{1}".format(br_name, bit))
|
||||
|
||||
temp.extend(["s_en", "vdd", "gnd"])
|
||||
|
||||
for bit in range(self.num_spare_cols):
|
||||
temp.append("dout_{}".format(self.word_size + bit))
|
||||
temp.append("sparebl{0}_{1}".format(self.port, bit))
|
||||
temp.append("sparebr{0}_{1}".format(self.port, bit))
|
||||
|
||||
temp.append("s_en")
|
||||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
def place_sense_amp_array(self, offset):
|
||||
|
|
@ -346,7 +370,7 @@ class port_data(design.design):
|
|||
br_name = self.get_br_name(self.port)
|
||||
|
||||
temp = []
|
||||
for bit in range(self.word_size):
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
temp.append("din_{}".format(bit))
|
||||
|
||||
for bit in range(self.word_size):
|
||||
|
|
@ -355,11 +379,20 @@ class port_data(design.design):
|
|||
temp.append("{0}_{1}".format(br_name, bit))
|
||||
else:
|
||||
temp.append("{0}_out_{1}".format(bl_name, bit))
|
||||
temp.append("{0}_out_{1}".format(br_name, bit))
|
||||
temp.append("{0}_out_{1}".format(br_name, bit))
|
||||
|
||||
for bit in range(self.num_spare_cols):
|
||||
temp.append("sparebl{0}_{1}".format(self.port, bit))
|
||||
temp.append("sparebr{0}_{1}".format(self.port, bit))
|
||||
|
||||
if self.write_size is not None:
|
||||
for i in range(self.num_wmasks):
|
||||
temp.append("wdriver_sel_{}".format(i))
|
||||
|
||||
elif self.num_spare_cols:
|
||||
temp.append("w_en")
|
||||
for i in range(self.num_spare_cols):
|
||||
temp.append("spare_wen{}".format(i))
|
||||
else:
|
||||
temp.append("w_en")
|
||||
temp.extend(["vdd", "gnd"])
|
||||
|
|
@ -445,7 +478,7 @@ class port_data(design.design):
|
|||
def route_sense_amp_out(self, port):
|
||||
""" Add pins for the sense amp output """
|
||||
|
||||
for bit in range(self.word_size):
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
data_pin = self.sense_amp_array_inst.get_pin("data_{}".format(bit))
|
||||
self.add_layout_pin_rect_center(text="dout_{0}".format(bit),
|
||||
layer=data_pin.layer,
|
||||
|
|
@ -456,7 +489,7 @@ class port_data(design.design):
|
|||
def route_write_driver_in(self, port):
|
||||
""" Connecting write driver """
|
||||
|
||||
for row in range(self.word_size):
|
||||
for row in range(self.word_size + self.num_spare_cols):
|
||||
data_name = "data_{}".format(row)
|
||||
din_name = "din_{}".format(row)
|
||||
self.copy_layout_pin(self.write_driver_array_inst, data_name, din_name)
|
||||
|
|
@ -545,12 +578,36 @@ class port_data(design.design):
|
|||
else:
|
||||
start_bit=0
|
||||
|
||||
self.channel_route_bitlines(inst1=inst1,
|
||||
inst1_bls_template=inst1_bls_templ,
|
||||
inst2=inst2,
|
||||
num_bits=self.word_size,
|
||||
inst1_start_bit=start_bit)
|
||||
if self.port==0:
|
||||
off = 1
|
||||
else:
|
||||
off = 0
|
||||
|
||||
|
||||
if self.num_spare_cols != 0 and self.col_addr_size>0:
|
||||
self.channel_route_bitlines(inst1=self.column_mux_array_inst,
|
||||
inst1_bls_template="{inst}_out_{bit}",
|
||||
inst2=inst2,
|
||||
num_bits=self.word_size,
|
||||
inst1_start_bit=start_bit)
|
||||
|
||||
self.channel_route_bitlines(inst1=self.precharge_array_inst,
|
||||
inst1_bls_template="{inst}_{bit}",
|
||||
inst2=inst2,
|
||||
num_bits=self.num_spare_cols,
|
||||
inst1_start_bit=self.num_cols + off,
|
||||
inst2_start_bit=self.word_size)
|
||||
|
||||
else:
|
||||
self.channel_route_bitlines(inst1=inst1,
|
||||
inst1_bls_template=inst1_bls_templ,
|
||||
inst2=inst2,
|
||||
num_bits=self.word_size + self.num_spare_cols,
|
||||
inst1_start_bit=start_bit)
|
||||
|
||||
|
||||
# spare cols connected to precharge array since they are read independently
|
||||
|
||||
def route_write_driver_to_column_mux_or_precharge_array(self, port):
|
||||
""" Routing of BL and BR between sense_amp and column mux or precharge array """
|
||||
inst2 = self.write_driver_array_inst
|
||||
|
|
@ -569,10 +626,33 @@ class port_data(design.design):
|
|||
else:
|
||||
start_bit=0
|
||||
|
||||
self.channel_route_bitlines(inst1=inst1, inst2=inst2,
|
||||
num_bits=self.word_size,
|
||||
inst1_bls_template=inst1_bls_templ,
|
||||
inst1_start_bit=start_bit)
|
||||
if self.port==0:
|
||||
off=1
|
||||
else:
|
||||
off=0
|
||||
|
||||
|
||||
if self.num_spare_cols != 0 and self.col_addr_size>0:
|
||||
self.channel_route_bitlines(inst1=self.column_mux_array_inst,
|
||||
inst1_bls_template="{inst}_out_{bit}",
|
||||
inst2=inst2,
|
||||
num_bits=self.word_size,
|
||||
inst1_start_bit=start_bit)
|
||||
|
||||
self.channel_route_bitlines(inst1=self.precharge_array_inst,
|
||||
inst1_bls_template="{inst}_{bit}",
|
||||
inst2=inst2,
|
||||
num_bits=self.num_spare_cols,
|
||||
inst1_start_bit=self.num_cols + off,
|
||||
inst2_start_bit=self.word_size)
|
||||
|
||||
else:
|
||||
self.channel_route_bitlines(inst1=inst1,
|
||||
inst1_bls_template=inst1_bls_templ,
|
||||
inst2=inst2,
|
||||
num_bits=self.word_size + self.num_spare_cols,
|
||||
inst1_start_bit=start_bit)
|
||||
|
||||
|
||||
def route_write_driver_to_sense_amp(self, port):
|
||||
""" Routing of BL and BR between write driver and sense amp """
|
||||
|
|
@ -584,7 +664,7 @@ class port_data(design.design):
|
|||
# but just in case, do a channel route.
|
||||
self.channel_route_bitlines(inst1=inst1,
|
||||
inst2=inst2,
|
||||
num_bits=self.word_size)
|
||||
num_bits=self.word_size + self.num_spare_cols)
|
||||
|
||||
def route_bitline_pins(self):
|
||||
""" Add the bitline pins for the given port """
|
||||
|
|
@ -595,13 +675,13 @@ class port_data(design.design):
|
|||
self.copy_layout_pin(self.precharge_array_inst, "br_0", "rbl_br")
|
||||
bit_offset=1
|
||||
elif self.port==1:
|
||||
self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(self.num_cols), "rbl_bl")
|
||||
self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(self.num_cols), "rbl_br")
|
||||
self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(self.num_cols + self.num_spare_cols), "rbl_bl")
|
||||
self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(self.num_cols + self.num_spare_cols), "rbl_br")
|
||||
bit_offset=0
|
||||
else:
|
||||
bit_offset=0
|
||||
|
||||
for bit in range(self.num_cols):
|
||||
for bit in range(self.num_cols + self.num_spare_cols):
|
||||
if self.precharge_array_inst:
|
||||
self.copy_layout_pin(self.precharge_array_inst,
|
||||
"bl_{}".format(bit + bit_offset),
|
||||
|
|
@ -621,12 +701,16 @@ class port_data(design.design):
|
|||
for pin_name in sel_names:
|
||||
self.copy_layout_pin(self.column_mux_array_inst, pin_name)
|
||||
if self.sense_amp_array_inst:
|
||||
self.copy_layout_pin(self.sense_amp_array_inst, "en", "s_en")
|
||||
self.copy_layout_pin(self.sense_amp_array_inst, "en", "s_en")
|
||||
if self.write_driver_array_inst:
|
||||
if self.write_mask_and_array_inst:
|
||||
for bit in range(self.num_wmasks):
|
||||
# Add write driver's en_{} pins
|
||||
self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit), "wdriver_sel_{}".format(bit))
|
||||
elif self.num_spare_cols:
|
||||
self.copy_layout_pin(self.write_driver_array_inst, "en_0", "w_en")
|
||||
for bit in range(self.num_spare_cols):
|
||||
self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit + 1), "spare_wen{}".format(bit))
|
||||
else:
|
||||
self.copy_layout_pin(self.write_driver_array_inst, "en", "w_en")
|
||||
if self.write_mask_and_array_inst:
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class sense_amp_array(design.design):
|
|||
Dynamically generated sense amp array for all bitlines.
|
||||
"""
|
||||
|
||||
def __init__(self, name, word_size, words_per_row):
|
||||
def __init__(self, name, word_size, words_per_row, num_spare_cols=None):
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {0}".format(self.name))
|
||||
self.add_comment("word_size {0}".format(word_size))
|
||||
|
|
@ -27,8 +27,12 @@ class sense_amp_array(design.design):
|
|||
|
||||
self.word_size = word_size
|
||||
self.words_per_row = words_per_row
|
||||
self.row_size = self.word_size * self.words_per_row
|
||||
|
||||
|
||||
if not num_spare_cols:
|
||||
self.num_spare_cols = 0
|
||||
else:
|
||||
self.num_spare_cols = num_spare_cols
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
|
@ -58,9 +62,9 @@ class sense_amp_array(design.design):
|
|||
self.height = self.amp.height
|
||||
|
||||
if self.bitcell.width > self.amp.width:
|
||||
self.width = self.bitcell.width * self.word_size * self.words_per_row
|
||||
self.width = self.bitcell.width * (self.word_size * self.words_per_row + self.num_spare_cols)
|
||||
else:
|
||||
self.width = self.amp.width * self.word_size * self.words_per_row
|
||||
self.width = self.amp.width * (self.word_size * self.words_per_row + self.num_spare_cols)
|
||||
|
||||
self.place_sense_amp_array()
|
||||
self.add_layout_pins()
|
||||
|
|
@ -69,7 +73,7 @@ class sense_amp_array(design.design):
|
|||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
for i in range(0,self.word_size):
|
||||
for i in range(0,self.word_size + self.num_spare_cols):
|
||||
self.add_pin(self.data_name + "_{0}".format(i), "OUTPUT")
|
||||
self.add_pin(self.get_bl_name() + "_{0}".format(i), "INPUT")
|
||||
self.add_pin(self.get_br_name() + "_{0}".format(i), "INPUT")
|
||||
|
|
@ -88,8 +92,7 @@ class sense_amp_array(design.design):
|
|||
|
||||
def create_sense_amp_array(self):
|
||||
self.local_insts = []
|
||||
for i in range(0,self.word_size):
|
||||
|
||||
for i in range(0,self.word_size + self.num_spare_cols):
|
||||
name = "sa_d{0}".format(i)
|
||||
self.local_insts.append(self.add_inst(name=name,
|
||||
mod=self.amp))
|
||||
|
|
@ -102,13 +105,14 @@ class sense_amp_array(design.design):
|
|||
from tech import cell_properties
|
||||
if self.bitcell.width > self.amp.width:
|
||||
amp_spacing = self.bitcell.width * self.words_per_row
|
||||
spare_cols_spacing = self.bitcell.width
|
||||
else:
|
||||
amp_spacing = self.amp.width * self.words_per_row
|
||||
spare_cols_spacing = self.amp.width
|
||||
|
||||
for i in range(0,self.word_size):
|
||||
xoffset = amp_spacing * i
|
||||
|
||||
# align the xoffset to the grid of bitcells. This way we
|
||||
# align the xoffset to the grid of bitcells. This way we
|
||||
# know when to do the mirroring.
|
||||
grid_x = int(xoffset / self.amp.width)
|
||||
|
||||
|
|
@ -120,6 +124,23 @@ class sense_amp_array(design.design):
|
|||
|
||||
amp_position = vector(xoffset, 0)
|
||||
self.local_insts[i].place(offset=amp_position,mirror=mirror)
|
||||
|
||||
# place spare sense amps (will share the same enable as regular sense amps)
|
||||
for i in range(0,self.num_spare_cols):
|
||||
index = self.word_size + i
|
||||
xoffset = ((self.word_size * self.words_per_row) + i) * spare_cols_spacing
|
||||
# align the xoffset to the grid of bitcells. This way we
|
||||
# know when to do the mirroring.
|
||||
grid_x = int(xoffset / self.amp.width)
|
||||
|
||||
if cell_properties.bitcell.mirror.y and grid_x % 2:
|
||||
mirror = "MY"
|
||||
xoffset = xoffset + self.amp.width
|
||||
else:
|
||||
mirror = ""
|
||||
|
||||
amp_position = vector(xoffset, 0)
|
||||
self.local_insts[index].place(offset=amp_position,mirror=mirror)
|
||||
|
||||
|
||||
def add_layout_pins(self):
|
||||
|
|
@ -173,7 +194,7 @@ class sense_amp_array(design.design):
|
|||
def get_en_cin(self):
|
||||
"""Get the relative capacitance of all the sense amp enable connections in the array"""
|
||||
sense_amp_en_cin = self.amp.get_en_cin()
|
||||
return sense_amp_en_cin * self.word_size
|
||||
return sense_amp_en_cin * (self.word_size + self.num_spare_cols)
|
||||
|
||||
def get_drain_cin(self):
|
||||
"""Get the relative capacitance of the drain of the PMOS isolation TX"""
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class write_driver_array(design.design):
|
|||
Dynamically generated write driver array of all bitlines.
|
||||
"""
|
||||
|
||||
def __init__(self, name, columns, word_size,write_size=None):
|
||||
def __init__(self, name, columns, word_size, num_spare_cols=None, write_size=None):
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {0}".format(self.name))
|
||||
self.add_comment("columns: {0}".format(columns))
|
||||
|
|
@ -29,6 +29,10 @@ class write_driver_array(design.design):
|
|||
self.word_size = word_size
|
||||
self.write_size = write_size
|
||||
self.words_per_row = int(columns / word_size)
|
||||
if not num_spare_cols:
|
||||
self.num_spare_cols = 0
|
||||
else:
|
||||
self.num_spare_cols = num_spare_cols
|
||||
|
||||
if self.write_size:
|
||||
self.num_wmasks = int(self.word_size/self.write_size)
|
||||
|
|
@ -61,9 +65,13 @@ class write_driver_array(design.design):
|
|||
def create_layout(self):
|
||||
|
||||
if self.bitcell.width > self.driver.width:
|
||||
self.width = self.columns * self.bitcell.width
|
||||
self.width = (self.columns + self.num_spare_cols) * self.bitcell.width
|
||||
self.width_regular_cols = self.columns * self.bitcell.width
|
||||
self.single_col_width = self.bitcell.width
|
||||
else:
|
||||
self.width = self.columns * self.driver.width
|
||||
self.width = (self.columns + self.num_spare_cols) * self.driver.width
|
||||
self.width_regular_cols = self.columns * self.driver.width
|
||||
self.single_col_width = self.driver.width
|
||||
self.height = self.driver.height
|
||||
|
||||
self.place_write_array()
|
||||
|
|
@ -72,14 +80,17 @@ class write_driver_array(design.design):
|
|||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
for i in range(self.word_size):
|
||||
for i in range(self.word_size + self.num_spare_cols):
|
||||
self.add_pin(self.data_name + "_{0}".format(i), "INPUT")
|
||||
for i in range(self.word_size):
|
||||
for i in range(self.word_size + self.num_spare_cols):
|
||||
self.add_pin(self.get_bl_name() + "_{0}".format(i), "OUTPUT")
|
||||
self.add_pin(self.get_br_name() + "_{0}".format(i), "OUTPUT")
|
||||
if self.write_size:
|
||||
for i in range(self.num_wmasks):
|
||||
self.add_pin(self.en_name + "_{0}".format(i), "INPUT")
|
||||
elif self.num_spare_cols:
|
||||
for i in range(self.num_spare_cols + 1):
|
||||
self.add_pin(self.en_name + "_{0}".format(i), "INPUT")
|
||||
else:
|
||||
self.add_pin(self.en_name, "INPUT")
|
||||
self.add_pin("vdd", "POWER")
|
||||
|
|
@ -113,12 +124,30 @@ class write_driver_array(design.design):
|
|||
if w == self.write_size:
|
||||
w = 0
|
||||
windex+=1
|
||||
|
||||
elif self.num_spare_cols:
|
||||
self.connect_inst([self.data_name + "_{0}".format(index),
|
||||
self.get_bl_name() + "_{0}".format(index),
|
||||
self.get_br_name() + "_{0}".format(index),
|
||||
self.en_name + "_{0}".format(0), "vdd", "gnd"])
|
||||
|
||||
else:
|
||||
self.connect_inst([self.data_name + "_{0}".format(index),
|
||||
self.get_bl_name() + "_{0}".format(index),
|
||||
self.get_br_name() + "_{0}".format(index),
|
||||
self.en_name, "vdd", "gnd"])
|
||||
|
||||
for i in range(self.num_spare_cols):
|
||||
index = self.word_size + i
|
||||
name = "write_driver{}".format(index)
|
||||
self.driver_insts[index]=self.add_inst(name=name,
|
||||
mod=self.driver)
|
||||
|
||||
self.connect_inst([self.data_name + "_{0}".format(index),
|
||||
self.get_bl_name() + "_{0}".format(index),
|
||||
self.get_br_name() + "_{0}".format(index),
|
||||
self.en_name + "_{0}".format(i + 1), "vdd", "gnd"])
|
||||
|
||||
|
||||
def place_write_array(self):
|
||||
from tech import cell_properties
|
||||
|
|
@ -139,9 +168,23 @@ class write_driver_array(design.design):
|
|||
base = vector(xoffset, 0)
|
||||
self.driver_insts[index].place(offset=base, mirror=mirror)
|
||||
|
||||
# place spare write drivers (if spare columns are specified)
|
||||
for i in range(self.num_spare_cols):
|
||||
index = self.word_size + i
|
||||
xoffset = (self.columns + i) * self.driver_spacing
|
||||
|
||||
if cell_properties.bitcell.mirror.y and i % 2:
|
||||
mirror = "MY"
|
||||
xoffset = xoffset + self.driver.width
|
||||
else:
|
||||
mirror = ""
|
||||
|
||||
base = vector(xoffset, 0)
|
||||
self.driver_insts[index].place(offset=base, mirror=mirror)
|
||||
|
||||
|
||||
def add_layout_pins(self):
|
||||
for i in range(self.word_size):
|
||||
for i in range(self.word_size + self.num_spare_cols):
|
||||
inst = self.driver_insts[i]
|
||||
din_pin = inst.get_pin(inst.mod.din_name)
|
||||
self.add_layout_pin(text=self.data_name + "_{0}".format(i),
|
||||
|
|
@ -186,14 +229,29 @@ class write_driver_array(design.design):
|
|||
offset=en_pin.ll(),
|
||||
width=wmask_en_len-en_gap,
|
||||
height=en_pin.height())
|
||||
|
||||
elif self.num_spare_cols:
|
||||
# shorten enable rail to accomodate those for spare write drivers
|
||||
inst = self.driver_insts[0]
|
||||
self.add_layout_pin(text=self.en_name + "_{0}".format(0),
|
||||
layer="m1",
|
||||
offset=inst.get_pin(inst.mod.en_name).ll(),
|
||||
width=self.width_regular_cols - (self.words_per_row * inst.get_pin(inst.mod.en_name).width()))
|
||||
|
||||
# individual enables for every spare write driver
|
||||
for i in range(self.num_spare_cols):
|
||||
inst = self.driver_insts[self.word_size + i]
|
||||
self.add_layout_pin(text=self.en_name + "_{0}".format(i + 1),
|
||||
layer="m1",
|
||||
offset=inst.get_pin(inst.mod.en_name).ll(),
|
||||
width=self.single_col_width - inst.get_pin(inst.mod.en_name).width())
|
||||
|
||||
else:
|
||||
inst = self.driver_insts[0]
|
||||
self.add_layout_pin(text=self.en_name,
|
||||
layer="m1",
|
||||
offset=inst.get_pin(inst.mod.en_name).ll().scale(0,1),
|
||||
width=self.width)
|
||||
|
||||
|
||||
|
||||
|
||||
def get_w_en_cin(self):
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ class options(optparse.Values):
|
|||
# You can manually specify banks, but it is better to auto-detect it.
|
||||
num_banks = 1
|
||||
num_spare_rows = 0
|
||||
# num_spare_cols = 0
|
||||
|
||||
###################
|
||||
# Optimization options
|
||||
|
|
|
|||
|
|
@ -14,19 +14,18 @@ from sram_factory import factory
|
|||
class sram_config:
|
||||
""" This is a structure that is used to hold the SRAM configuration options. """
|
||||
|
||||
def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None, num_spare_rows=0):
|
||||
def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=None):
|
||||
self.word_size = word_size
|
||||
self.num_words = num_words
|
||||
self.write_size = write_size
|
||||
self.num_banks = num_banks
|
||||
self.num_spare_rows = num_spare_rows
|
||||
self.num_spare_cols = num_spare_cols
|
||||
|
||||
# This will get over-written when we determine the organization
|
||||
self.words_per_row = words_per_row
|
||||
|
||||
self.compute_sizes()
|
||||
|
||||
|
||||
self.compute_sizes()
|
||||
|
||||
def set_local_config(self, module):
|
||||
""" Copy all of the member variables to the given module for convenience """
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
#!/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
|
||||
|
||||
class sense_amp_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
globals.init_openram(config_file)
|
||||
|
||||
# check sense amp array for single port
|
||||
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")
|
||||
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=1, num_spare_cols=3)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4")
|
||||
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4, num_spare_cols=2)
|
||||
self.local_check(a)
|
||||
|
||||
# check sense amp array for multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
factory.reset()
|
||||
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)")
|
||||
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=2, num_spare_cols=2)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)")
|
||||
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4, num_spare_cols=3)
|
||||
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())
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
#!/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
|
||||
|
||||
class write_driver_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
globals.init_openram(config_file)
|
||||
|
||||
# check write driver array for single port
|
||||
debug.info(2, "Testing write_driver_array for columns=8, word_size=8")
|
||||
a = factory.create(module_type="write_driver_array", columns=8, word_size=8, num_spare_cols=3)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(2, "Testing write_driver_array for columns=16, word_size=8")
|
||||
a = factory.create(module_type="write_driver_array", columns=16, word_size=8, num_spare_cols=3)
|
||||
self.local_check(a)
|
||||
|
||||
# check write driver array for multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
factory.reset()
|
||||
debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)")
|
||||
a = factory.create(module_type="write_driver_array", columns=8, word_size=8, num_spare_cols=3)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)")
|
||||
a = factory.create(module_type="write_driver_array", columns=16, word_size=8, num_spare_cols=3)
|
||||
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())
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
#!/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_spare_cols_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
|
||||
|
||||
c = sram_config(word_size=8,
|
||||
num_words=16,
|
||||
num_spare_rows=1,
|
||||
num_spare_cols=1)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
c.num_words=64
|
||||
c.words_per_row=4
|
||||
c.num_spare_cols=3
|
||||
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)
|
||||
|
||||
c.word_size=2
|
||||
c.num_words=128
|
||||
c.words_per_row=8
|
||||
c.num_spare_cols=4
|
||||
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)
|
||||
|
||||
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()
|
||||
|
||||
# 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())
|
||||
Loading…
Reference in New Issue