New port_data module works in SCMOS

This commit is contained in:
mrg 2019-07-03 13:17:12 -07:00
parent 244604fb0d
commit bc4a3ee2b7
7 changed files with 276 additions and 417 deletions

View File

@ -28,6 +28,7 @@ class bank(design.design):
def __init__(self, sram_config, name=""): def __init__(self, sram_config, name=""):
self.sram_config = sram_config
sram_config.set_local_config(self) sram_config.set_local_config(self)
if name == "": if name == "":
@ -118,40 +119,21 @@ class bank(design.design):
def route_bitlines(self, port): def route_bitlines(self, port):
""" Route the bitlines depending on the port type rw, w, or r. """ """ Route the bitlines depending on the port type rw, w, or r. """
if port in self.readwrite_ports: if port in self.write_ports:
# write_driver -> sense_amp -> (column_mux) -> precharge -> bitcell_array self.route_port_data_in(port)
self.route_write_driver_in(port) if port in self.read_ports:
self.route_sense_amp_out(port) self.route_port_data_out(port)
self.route_write_driver_to_sense_amp(port) self.route_port_data_to_bitcell_array(port)
self.route_sense_amp_to_column_mux_or_precharge_array(port)
self.route_column_mux_to_precharge_array(port)
self.route_precharge_to_bitcell_array(port)
elif port in self.read_ports:
# sense_amp -> (column_mux) -> precharge -> bitcell_array
self.route_sense_amp_out(port)
self.route_sense_amp_to_column_mux_or_precharge_array(port)
self.route_column_mux_to_precharge_array(port)
self.route_precharge_to_bitcell_array(port)
else:
# write_driver -> (column_mux) -> bitcell_array
self.route_write_driver_in(port)
self.route_write_driver_to_column_mux_or_bitcell_array(port)
self.route_column_mux_to_bitcell_array(port)
def create_instances(self): def create_instances(self):
""" Create the instances of the netlist. """ """ Create the instances of the netlist. """
self.create_bitcell_array() self.create_bitcell_array()
self.create_port_data()
self.create_precharge_array()
self.create_column_mux_array()
self.create_sense_amp_array()
self.create_write_driver_array()
self.create_row_decoder() self.create_row_decoder()
self.create_wordline_driver() self.create_wordline_driver()
self.create_column_decoder() self.create_column_decoder()
self.create_bank_select() self.create_bank_select()
def compute_instance_offsets(self): def compute_instance_offsets(self):
@ -159,34 +141,7 @@ class bank(design.design):
Compute the empty instance offsets for port0 and port1 (if needed) Compute the empty instance offsets for port0 and port1 (if needed)
""" """
# These are created even if the port type (e.g. read only) self.port_data_offsets = [None]*len(self.all_ports)
# doesn't need the instance (e.g. write driver).
# Create the bottom-up and left to right order of components in each port
# which deepends on the port type rw, w, r
self.vertical_port_order = []
self.vertical_port_offsets = []
for port in self.all_ports:
self.vertical_port_order.append([])
self.vertical_port_offsets.append([None]*4)
# For later placement, these are fixed in the order: write driver,
# sense amp, clumn mux, precharge, even if the item is not used
# in a given port (it will be None then)
self.vertical_port_order[port].append(self.write_driver_array_inst[port])
self.vertical_port_order[port].append(self.sense_amp_array_inst[port])
self.vertical_port_order[port].append(self.column_mux_array_inst[port])
self.vertical_port_order[port].append(self.precharge_array_inst[port])
# For the odd ones they will go on top, so reverse in place
if port%2:
self.vertical_port_order[port]=self.vertical_port_order[port][::-1]
self.write_driver_offsets = [None]*len(self.all_ports)
self.sense_amp_offsets = [None]*len(self.all_ports)
self.column_mux_offsets = [None]*len(self.all_ports)
self.precharge_offsets = [None]*len(self.all_ports)
self.wordline_driver_offsets = [None]*len(self.all_ports) self.wordline_driver_offsets = [None]*len(self.all_ports)
self.row_decoder_offsets = [None]*len(self.all_ports) self.row_decoder_offsets = [None]*len(self.all_ports)
@ -199,7 +154,7 @@ class bank(design.design):
# The decoder/driver logic is placed on the right and mirrored on Y-axis. # The decoder/driver logic is placed on the right and mirrored on Y-axis.
# The write/sense/precharge/mux is placed on the top and mirrored on the X-axis. # The write/sense/precharge/mux is placed on the top and mirrored on the X-axis.
self.bitcell_array_top = self.bitcell_array.height + self.m2_gap + drc("well_enclosure_active") + self.m1_width self.bitcell_array_top = self.bitcell_array.height
self.bitcell_array_right = self.bitcell_array.width + self.m1_width + self.m2_gap self.bitcell_array_right = self.bitcell_array.width + self.m1_width + self.m2_gap
self.compute_instance_port0_offsets() self.compute_instance_port0_offsets()
@ -220,23 +175,7 @@ class bank(design.design):
# LOWER RIGHT QUADRANT # LOWER RIGHT QUADRANT
# Below the bitcell array # Below the bitcell array
y_height = 0 self.port_data_offsets[port] = vector(0,0)
for p in self.vertical_port_order[port]:
if p==None:
continue
y_height += p.height + self.m2_gap
y_offset = -y_height
for i,p in enumerate(self.vertical_port_order[port]):
if p==None:
continue
self.vertical_port_offsets[port][i]=vector(0,y_offset)
y_offset += (p.height + self.m2_gap)
self.write_driver_offsets[port] = self.vertical_port_offsets[port][0]
self.sense_amp_offsets[port] = self.vertical_port_offsets[port][1]
self.column_mux_offsets[port] = self.vertical_port_offsets[port][2]
self.precharge_offsets[port] = self.vertical_port_offsets[port][3]
# UPPER LEFT QUADRANT # UPPER LEFT QUADRANT
# To the left of the bitcell array # To the left of the bitcell array
@ -261,7 +200,7 @@ class bank(design.design):
# Bank select gets placed below the column decoder (x_offset doesn't change) # Bank select gets placed below the column decoder (x_offset doesn't change)
if self.col_addr_size > 0: if self.col_addr_size > 0:
y_offset = min(self.column_decoder_offsets[port].y, self.column_mux_offsets[port].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.row_decoder_offsets[port].y
if self.num_banks > 1: if self.num_banks > 1:
@ -280,18 +219,7 @@ class bank(design.design):
# UPPER LEFT QUADRANT # UPPER LEFT QUADRANT
# Above the bitcell array # Above the bitcell array
y_offset = self.bitcell_array_top self.port_data_offsets[port] = vector(0,self.bitcell_array_top)
for i,p in enumerate(self.vertical_port_order[port]):
if p==None:
continue
y_offset += (p.height + self.m2_gap)
self.vertical_port_offsets[port][i]=vector(0,y_offset)
# Reversed order
self.write_driver_offsets[port] = self.vertical_port_offsets[port][3]
self.sense_amp_offsets[port] = self.vertical_port_offsets[port][2]
self.column_mux_offsets[port] = self.vertical_port_offsets[port][1]
self.precharge_offsets[port] = self.vertical_port_offsets[port][0]
# LOWER RIGHT QUADRANT # LOWER RIGHT QUADRANT
# To the left of the bitcell array # To the left of the bitcell array
@ -307,7 +235,7 @@ class bank(design.design):
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.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.column_decoder.height y_offset = self.bitcell_array_top + self.m2_gap + self.column_decoder.height
else: else:
y_offset = self.bitcell_array_top y_offset = self.bitcell_array_top
y_offset += 2*drc("well_to_well") y_offset += 2*drc("well_to_well")
@ -316,7 +244,7 @@ class bank(design.design):
# Bank select gets placed above the column decoder (x_offset doesn't change) # Bank select gets placed above the column decoder (x_offset doesn't change)
if self.col_addr_size > 0: if self.col_addr_size > 0:
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.column_mux_offsets[port].y + self.column_mux_array[port].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.row_decoder_offsets[port].y
self.bank_select_offsets[port] = vector(x_offset,y_offset) self.bank_select_offsets[port] = vector(x_offset,y_offset)
@ -330,12 +258,7 @@ class bank(design.design):
self.place_bitcell_array(self.bitcell_array_offset) self.place_bitcell_array(self.bitcell_array_offset)
# LOWER RIGHT QUADRANT # LOWER RIGHT QUADRANT
# These are fixed in the order: write driver, sense amp, clumn mux, precharge, self.place_port_data(self.port_data_offsets)
# even if the item is not used in a given port (it will be None then)
self.place_write_driver_array(self.write_driver_offsets)
self.place_sense_amp_array(self.sense_amp_offsets)
self.place_column_mux_array(self.column_mux_offsets)
self.place_precharge_array(self.precharge_offsets)
# UPPER LEFT QUADRANT # UPPER LEFT QUADRANT
self.place_row_decoder(self.row_decoder_offsets) self.place_row_decoder(self.row_decoder_offsets)
@ -419,39 +342,13 @@ class bank(design.design):
self.wl_names = self.bitcell.list_all_wl_names() self.wl_names = self.bitcell.list_all_wl_names()
self.bitline_names = self.bitcell.list_all_bitline_names() self.bitline_names = self.bitcell.list_all_bitline_names()
self.precharge_array = [] self.port_data = []
for port in self.all_ports: for port in self.all_ports:
if port in self.read_ports: temp_pre = factory.create(module_type="port_data",
temp_pre = factory.create(module_type="precharge_array", sram_config=self.sram_config,
columns=self.num_cols, port=port)
bitcell_bl=self.bl_names[port], self.port_data.append(temp_pre)
bitcell_br=self.br_names[port]) self.add_mod(self.port_data[port])
self.precharge_array.append(temp_pre)
self.add_mod(self.precharge_array[port])
else:
self.precharge_array.append(None)
if self.col_addr_size > 0:
self.column_mux_array = []
for port in self.all_ports:
temp_col = factory.create(module_type="column_mux_array",
columns=self.num_cols,
word_size=self.word_size,
bitcell_bl=self.bl_names[port],
bitcell_br=self.br_names[port])
self.column_mux_array.append(temp_col)
self.add_mod(self.column_mux_array[port])
self.sense_amp_array = factory.create(module_type="sense_amp_array",
word_size=self.word_size,
words_per_row=self.words_per_row)
self.add_mod(self.sense_amp_array)
self.write_driver_array = factory.create(module_type="write_driver_array",
columns=self.num_cols,
word_size=self.word_size)
self.add_mod(self.write_driver_array)
self.row_decoder = factory.create(module_type="decoder", self.row_decoder = factory.create(module_type="decoder",
rows=self.num_rows) rows=self.num_rows)
@ -494,142 +391,48 @@ class bank(design.design):
self.bitcell_array_inst.place(offset) self.bitcell_array_inst.place(offset)
def create_precharge_array(self): def create_port_data(self):
""" Creating Precharge """ """ Creating Port Data """
self.precharge_array_inst = [None]*len(self.all_ports)
for port in self.read_ports:
self.precharge_array_inst[port]=self.add_inst(name="precharge_array{}".format(port),
mod=self.precharge_array[port])
temp = []
for i in range(self.num_cols):
temp.append(self.bl_names[port]+"_{0}".format(i))
temp.append(self.br_names[port]+"_{0}".format(i))
temp.extend([self.prefix+"p_en_bar{0}".format(port), "vdd"])
self.connect_inst(temp)
def place_precharge_array(self, offsets):
""" Placing Precharge """
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place precharge array.")
for port in self.read_ports:
if port%2 == 1:
mirror = "MX"
else:
mirror = "R0"
self.precharge_array_inst[port].place(offset=offsets[port], mirror=mirror)
def create_column_mux_array(self):
""" Creating Column Mux when words_per_row > 1 . """
self.column_mux_array_inst = [None]*len(self.all_ports)
if self.col_addr_size == 0:
return
self.port_data_inst = [None]*len(self.all_ports)
for port in self.all_ports: for port in self.all_ports:
self.column_mux_array_inst[port] = self.add_inst(name="column_mux_array{}".format(port), self.port_data_inst[port]=self.add_inst(name="port_data{}".format(port),
mod=self.column_mux_array[port]) mod=self.port_data[port])
temp = [] temp = []
for col in range(self.num_cols): for col in range(self.num_cols):
temp.append(self.bl_names[port]+"_{0}".format(col)) temp.append("{0}_{1}".format(self.bl_names[port],col))
temp.append(self.br_names[port]+"_{0}".format(col)) temp.append("{0}_{1}".format(self.br_names[port],col))
for word in range(self.words_per_row): if port in self.read_ports:
temp.append("sel{0}_{1}".format(port,word)) for bit in range(self.word_size):
for bit in range(self.word_size): temp.append("dout{0}_{1}".format(port,bit))
temp.append(self.bl_names[port]+"_out_{0}".format(bit)) if port in self.write_ports:
temp.append(self.br_names[port]+"_out_{0}".format(bit)) for bit in range(self.word_size):
temp.append("gnd") temp.append("din{0}_{1}".format(port,bit))
# Will be empty if no col addr lines
sel_names = ["sel{0}_{1}".format(port,x) for x in range(self.num_col_addr_lines)]
temp.extend(sel_names)
if port in self.read_ports:
temp.append("s_en{0}".format(port))
if port in self.read_ports:
temp.append("p_en_bar{0}".format(port))
if port in self.write_ports:
temp.append("w_en{0}".format(port))
temp.extend(["vdd","gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_port_data(self, offsets):
def place_column_mux_array(self, offsets): """ Placing Port Data """
""" Placing Column Mux when words_per_row > 1 . """
if self.col_addr_size == 0:
return
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place column mux array.")
for port in self.all_ports: for port in self.all_ports:
# Top one is unflipped, bottom is flipped along X direction
if port%2 == 1: if port%2 == 1:
mirror = "MX"
else:
mirror = "R0" mirror = "R0"
self.column_mux_array_inst[port].place(offset=offsets[port], mirror=mirror)
def create_sense_amp_array(self):
""" Creating Sense amp """
self.sense_amp_array_inst = [None]*len(self.all_ports)
for port in self.read_ports:
self.sense_amp_array_inst[port] = self.add_inst(name="sense_amp_array{}".format(port),
mod=self.sense_amp_array)
temp = []
for bit in range(self.word_size):
temp.append("dout{0}_{1}".format(port,bit))
if self.words_per_row == 1:
temp.append(self.bl_names[port]+"_{0}".format(bit))
temp.append(self.br_names[port]+"_{0}".format(bit))
else:
temp.append(self.bl_names[port]+"_out_{0}".format(bit))
temp.append(self.br_names[port]+"_out_{0}".format(bit))
temp.extend([self.prefix+"s_en{}".format(port), "vdd", "gnd"])
self.connect_inst(temp)
def place_sense_amp_array(self, offsets):
""" Placing Sense amp """
debug.check(len(offsets)>=len(self.read_ports), "Insufficient offsets to place sense amp array.")
for port in self.read_ports:
if port%2 == 1:
mirror = "MX"
else: else:
mirror = "R0"
self.sense_amp_array_inst[port].place(offset=offsets[port], mirror=mirror)
def create_write_driver_array(self):
""" Creating Write Driver """
self.write_driver_array_inst = [None]*len(self.all_ports)
for port in self.write_ports:
self.write_driver_array_inst[port] = self.add_inst(name="write_driver_array{}".format(port),
mod=self.write_driver_array)
temp = []
for bit in range(self.word_size):
temp.append("din{0}_{1}".format(port,bit))
for bit in range(self.word_size):
if (self.words_per_row == 1):
temp.append(self.bl_names[port]+"_{0}".format(bit))
temp.append(self.br_names[port]+"_{0}".format(bit))
else:
temp.append(self.bl_names[port]+"_out_{0}".format(bit))
temp.append(self.br_names[port]+"_out_{0}".format(bit))
temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"])
self.connect_inst(temp)
def place_write_driver_array(self, offsets):
""" Placing Write Driver """
debug.check(len(offsets)>=len(self.write_ports), "Insufficient offsets to place write driver array.")
for port in self.write_ports:
if port%2 == 1:
mirror = "MX" mirror = "MX"
else: self.port_data_inst[port].place(offset=offsets[port], mirror=mirror)
mirror = "R0"
self.write_driver_array_inst[port].place(offset=offsets[port], mirror=mirror)
def create_row_decoder(self): def create_row_decoder(self):
""" Create the hierarchical row decoder """ """ Create the hierarchical row decoder """
@ -877,10 +680,10 @@ class bank(design.design):
make_pins=(self.num_banks==1)) make_pins=(self.num_banks==1))
def route_precharge_to_bitcell_array(self, port): def route_port_data_to_bitcell_array(self, port):
""" Routing of BL and BR between pre-charge and bitcell array """ """ Routing of BL and BR between port data and bitcell array """
inst2 = self.precharge_array_inst[port] inst2 = self.port_data_inst[port]
inst1 = self.bitcell_array_inst inst1 = self.bitcell_array_inst
inst1_bl_name = self.bl_names[port]+"_{}" inst1_bl_name = self.bl_names[port]+"_{}"
inst1_br_name = self.br_names[port]+"_{}" inst1_br_name = self.br_names[port]+"_{}"
@ -888,90 +691,11 @@ class bank(design.design):
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name) inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
def route_port_data_out(self, port):
def route_column_mux_to_precharge_array(self, port): """ Add pins for the port data out """
""" Routing of BL and BR between col mux and precharge array """
# Only do this if we have a column mux!
if self.col_addr_size==0:
return
inst1 = self.column_mux_array_inst[port]
inst2 = self.precharge_array_inst[port]
self.connect_bitlines(inst1, inst2, self.num_cols)
def route_column_mux_to_bitcell_array(self, port):
""" Routing of BL and BR between col mux bitcell array """
# Only do this if we have a column mux!
if self.col_addr_size==0:
return
inst2 = self.column_mux_array_inst[port]
inst1 = self.bitcell_array_inst
inst1_bl_name = self.bl_names[port]+"_{}"
inst1_br_name = self.br_names[port]+"_{}"
# The column mux is constructed to match the bitline pitch, so we can directly connect
# here and not channel route the bitlines.
self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.num_cols,
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
def route_sense_amp_to_column_mux_or_precharge_array(self, port):
""" Routing of BL and BR between sense_amp and column mux or precharge array """
inst2 = self.sense_amp_array_inst[port]
if self.col_addr_size>0:
# Sense amp is connected to the col mux
inst1 = self.column_mux_array_inst[port]
inst1_bl_name = "bl_out_{}"
inst1_br_name = "br_out_{}"
else:
# Sense amp is directly connected to the precharge array
inst1 = self.precharge_array_inst[port]
inst1_bl_name = "bl_{}"
inst1_br_name = "br_{}"
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
def route_write_driver_to_column_mux_or_bitcell_array(self, port):
""" Routing of BL and BR between sense_amp and column mux or bitcell array """
inst2 = self.write_driver_array_inst[port]
if self.col_addr_size>0:
# Write driver is connected to the col mux
inst1 = self.column_mux_array_inst[port]
inst1_bl_name = "bl_out_{}"
inst1_br_name = "br_out_{}"
else:
# Write driver is directly connected to the bitcell array
inst1 = self.bitcell_array_inst
inst1_bl_name = self.bl_names[port]+"_{}"
inst1_br_name = self.br_names[port]+"_{}"
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
def route_write_driver_to_sense_amp(self, port):
""" Routing of BL and BR between write driver and sense amp """
inst1 = self.write_driver_array_inst[port]
inst2 = self.sense_amp_array_inst[port]
# These should be pitch matched in the cell library,
# but just in case, do a channel route.
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size)
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):
data_pin = self.sense_amp_array_inst[port].get_pin("data_{}".format(bit)) data_pin = self.port_data_inst[port].get_pin("dout_{0}".format(bit))
self.add_layout_pin_rect_center(text="dout{0}_{1}".format(port,bit), self.add_layout_pin_rect_center(text="dout{0}_{1}".format(port,bit),
layer=data_pin.layer, layer=data_pin.layer,
offset=data_pin.center(), offset=data_pin.center(),
@ -990,13 +714,13 @@ class bank(design.design):
self.copy_layout_pin(self.row_decoder_inst[port], decoder_name, addr_name) self.copy_layout_pin(self.row_decoder_inst[port], decoder_name, addr_name)
def route_write_driver_in(self, port): def route_port_data_in(self, port):
""" Connecting write driver """ """ Connecting port data in """
for row in range(self.word_size): for row in range(self.word_size):
data_name = "data_{}".format(row) data_name = "din_{}".format(row)
din_name = "din{0}_{1}".format(port,row) din_name = "din{0}_{1}".format(port,row)
self.copy_layout_pin(self.write_driver_array_inst[port], data_name, din_name) self.copy_layout_pin(self.port_data_inst[port], data_name, din_name)
def channel_route_bitlines(self, inst1, inst2, num_bits, def channel_route_bitlines(self, inst1, inst2, num_bits,
inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_bl_name="bl_{}", inst1_br_name="br_{}",
@ -1131,7 +855,7 @@ class bank(design.design):
decode_pins = [self.column_decoder_inst[port].get_pin(x) for x in decode_names] decode_pins = [self.column_decoder_inst[port].get_pin(x) for x in decode_names]
sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)] sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)]
column_mux_pins = [self.column_mux_array_inst[port].get_pin(x) for x in sel_names] column_mux_pins = [self.port_data_inst[port].get_pin(x) for x in sel_names]
route_map = list(zip(decode_pins, column_mux_pins)) route_map = list(zip(decode_pins, column_mux_pins))
self.create_vertical_channel_route(route_map, offset) self.create_vertical_channel_route(route_map, offset)
@ -1194,13 +918,13 @@ class bank(design.design):
connection = [] connection = []
if port in self.read_ports: if port in self.read_ports:
connection.append((self.prefix+"p_en_bar{}".format(port), self.precharge_array_inst[port].get_pin("en_bar").lc())) connection.append((self.prefix+"p_en_bar{}".format(port), self.port_data_inst[port].get_pin("p_en_bar").lc()))
if port in self.write_ports: if port in self.write_ports:
connection.append((self.prefix+"w_en{}".format(port), self.write_driver_array_inst[port].get_pin("en").lc())) connection.append((self.prefix+"w_en{}".format(port), self.port_data_inst[port].get_pin("w_en").lc()))
if port in self.read_ports: if port in self.read_ports:
connection.append((self.prefix+"s_en{}".format(port), self.sense_amp_array_inst[port].get_pin("en").lc())) connection.append((self.prefix+"s_en{}".format(port), self.port_data_inst[port].get_pin("s_en").lc()))
for (control_signal, pin_pos) in connection: for (control_signal, pin_pos) in connection:
control_pos = vector(self.bus_xoffset[port][control_signal].x ,pin_pos.y) control_pos = vector(self.bus_xoffset[port][control_signal].x ,pin_pos.y)
@ -1232,26 +956,26 @@ class bank(design.design):
#FIXME: Array delay is the same for every port. #FIXME: Array delay is the same for every port.
word_driver_slew = 0 word_driver_slew = 0
if self.words_per_row > 1: if self.words_per_row > 1:
bitline_ext_load = self.column_mux_array[port].get_drain_cin() bitline_ext_load = self.port_data[port].column_mux_array.get_drain_cin()
else: else:
bitline_ext_load = self.sense_amp_array.get_drain_cin() bitline_ext_load = self.port_data[port].sense_amp_array.get_drain_cin()
bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_slew, bitline_ext_load) bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_slew, bitline_ext_load)
bitcell_array_slew = 0 bitcell_array_slew = 0
#This also essentially creates the same delay for each port. Good structure, no substance #This also essentially creates the same delay for each port. Good structure, no substance
if self.words_per_row > 1: if self.words_per_row > 1:
sa_load = self.sense_amp_array.get_drain_cin() sa_load = self.port_data[port].sense_amp_array.get_drain_cin()
column_mux_delay = self.column_mux_array[port].analytical_delay(corner, column_mux_delay = self.port_data[port].column_mux_array.analytical_delay(corner,
bitcell_array_slew, bitcell_array_slew,
sa_load) sa_load)
else: else:
column_mux_delay = [] column_mux_delay = []
column_mux_slew = 0 column_mux_slew = 0
sense_amp_delay = self.sense_amp_array.analytical_delay(corner, sense_amp_delay = self.port_data[port].sense_amp_array.analytical_delay(corner,
column_mux_slew, column_mux_slew,
load) load)
# output load of bitcell_array is set to be only small part of bl for sense amp. # output load of bitcell_array is set to be only small part of bl for sense amp.
return bitcell_array_delay + column_mux_delay + sense_amp_delay return bitcell_array_delay + column_mux_delay + sense_amp_delay
@ -1272,7 +996,8 @@ class bank(design.design):
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"""
#wl_en only used in the wordline driver. #wl_en only used in the wordline driver.
return self.write_driver.get_w_en_cin() port = self.write_ports[0]
return self.port_data[port].write_driver.get_w_en_cin()
def get_clk_bar_cin(self): def get_clk_bar_cin(self):
"""Get the relative capacitance of all the clk_bar connections in the bank""" """Get the relative capacitance of all the clk_bar connections in the bank"""
@ -1280,9 +1005,10 @@ class bank(design.design):
#Precharges are the all the same in Mulitport, one is picked #Precharges are the all the same in Mulitport, one is picked
port = self.read_ports[0] port = self.read_ports[0]
return self.precharge_array[port].get_en_cin() return self.port_data[port].precharge_array.get_en_cin()
def get_sen_cin(self): def get_sen_cin(self):
"""Get the relative capacitance of all the sense amp enable connections in the bank""" """Get the relative capacitance of all the sense amp enable connections in the bank"""
#Current bank only uses sen as an enable for the sense amps. #Current bank only uses sen as an enable for the sense amps.
return self.sense_amp_array.get_en_cin() port = self.read_ports[0]
return self.port_data[port].sense_amp_array.get_en_cin()

View File

@ -73,29 +73,41 @@ class port_data(design.design):
def add_pins(self): def add_pins(self):
""" Adding pins for Bank module""" """ Adding pins for Bank module"""
for bit in range(self.num_cols):
self.add_pin(self.bl_names[self.port]+"_{0}".format(bit),"INOUT")
self.add_pin(self.br_names[self.port]+"_{0}".format(bit),"INOUT")
if self.port in self.read_ports: if self.port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.add_pin("dout{0}_{1}".format(self.port,bit),"OUT") self.add_pin("dout_{}".format(bit),"OUTPUT")
if self.port in self.write_ports: if self.port in self.write_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.add_pin("din{0}_{1}".format(self.port,bit),"IN") 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)]
for pin_name in sel_names:
self.add_pin(pin_name,"INPUT")
if self.port in self.read_ports: if self.port in self.read_ports:
self.add_pin("s_en{0}".format(self.port), "INPUT") self.add_pin("s_en", "INPUT")
if self.port in self.read_ports: if self.port in self.read_ports:
self.add_pin("p_en_bar{0}".format(self.port), "INPUT") self.add_pin("p_en_bar", "INPUT")
if self.port in self.write_ports: if self.port in self.write_ports:
self.add_pin("w_en{0}".format(self.port), "INPUT") self.add_pin("w_en", "INPUT")
self.add_pin("vdd","POWER") self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND") self.add_pin("gnd","GROUND")
def route_layout(self): def route_layout(self):
""" Create routing amoung the modules """ """ Create routing amoung the modules """
self.route_bitlines() self.route_data_lines()
self.route_layout_pins()
self.route_supplies() self.route_supplies()
def route_bitlines(self): def route_layout_pins(self):
""" Add the pins """
self.route_bitline_pins()
self.route_control_pins()
def route_data_lines(self):
""" Route the bitlines depending on the port type rw, w, or r. """ """ Route the bitlines depending on the port type rw, w, or r. """
if self.port in self.readwrite_ports: if self.port in self.readwrite_ports:
@ -164,6 +176,12 @@ class port_data(design.design):
self.num_cols = int(self.words_per_row*self.word_size) self.num_cols = int(self.words_per_row*self.word_size)
self.num_rows = int(self.num_words / self.words_per_row) self.num_rows = int(self.num_words / self.words_per_row)
# The central bus is the column address (one hot) and row address (binary)
if self.col_addr_size>0:
self.num_col_addr_lines = 2**self.col_addr_size
else:
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"),
3*self.m2_pitch) 3*self.m2_pitch)
@ -174,7 +192,6 @@ class port_data(design.design):
self.bl_names = self.bitcell.list_all_bl_names() self.bl_names = self.bitcell.list_all_bl_names()
self.br_names = self.bitcell.list_all_br_names() self.br_names = self.bitcell.list_all_br_names()
self.wl_names = self.bitcell.list_all_wl_names() self.wl_names = self.bitcell.list_all_wl_names()
self.bitline_names = self.bitcell.list_all_bitline_names()
def create_precharge_array(self): def create_precharge_array(self):
""" Creating Precharge """ """ Creating Precharge """
@ -185,10 +202,10 @@ class port_data(design.design):
self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port), self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port),
mod=self.precharge_array) mod=self.precharge_array)
temp = [] temp = []
for i in range(self.num_cols): for bit in range(self.num_cols):
temp.append(self.bl_names[self.port]+"_{0}".format(i)) temp.append(self.bl_names[self.port]+"_{0}".format(bit))
temp.append(self.br_names[self.port]+"_{0}".format(i)) temp.append(self.br_names[self.port]+"_{0}".format(bit))
temp.extend(["p_en_bar{0}".format(self.port), "vdd"]) temp.extend(["p_en_bar", "vdd"])
self.connect_inst(temp) self.connect_inst(temp)
@ -207,7 +224,7 @@ class port_data(design.design):
temp.append(self.bl_names[self.port]+"_{0}".format(col)) temp.append(self.bl_names[self.port]+"_{0}".format(col))
temp.append(self.br_names[self.port]+"_{0}".format(col)) temp.append(self.br_names[self.port]+"_{0}".format(col))
for word in range(self.words_per_row): for word in range(self.words_per_row):
temp.append("sel{0}_{1}".format(self.port,word)) temp.append("sel_{}".format(word))
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append(self.bl_names[self.port]+"_out_{0}".format(bit)) temp.append(self.bl_names[self.port]+"_out_{0}".format(bit))
temp.append(self.br_names[self.port]+"_out_{0}".format(bit)) temp.append(self.br_names[self.port]+"_out_{0}".format(bit))
@ -231,7 +248,7 @@ class port_data(design.design):
temp = [] temp = []
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("dout{0}_{1}".format(self.port,bit)) temp.append("dout_{}".format(bit))
if self.words_per_row == 1: if self.words_per_row == 1:
temp.append(self.bl_names[self.port]+"_{0}".format(bit)) temp.append(self.bl_names[self.port]+"_{0}".format(bit))
temp.append(self.br_names[self.port]+"_{0}".format(bit)) temp.append(self.br_names[self.port]+"_{0}".format(bit))
@ -239,7 +256,7 @@ class port_data(design.design):
temp.append(self.bl_names[self.port]+"_out_{0}".format(bit)) temp.append(self.bl_names[self.port]+"_out_{0}".format(bit))
temp.append(self.br_names[self.port]+"_out_{0}".format(bit)) temp.append(self.br_names[self.port]+"_out_{0}".format(bit))
temp.extend(["s_en{}".format(self.port), "vdd", "gnd"]) temp.extend(["s_en", "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
@ -255,7 +272,7 @@ class port_data(design.design):
temp = [] temp = []
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("din{0}_{1}".format(self.port,bit)) temp.append("din_{}".format(bit))
for bit in range(self.word_size): for bit in range(self.word_size):
if (self.words_per_row == 1): if (self.words_per_row == 1):
temp.append(self.bl_names[self.port]+"_{0}".format(bit)) temp.append(self.bl_names[self.port]+"_{0}".format(bit))
@ -263,7 +280,7 @@ class port_data(design.design):
else: else:
temp.append(self.bl_names[self.port]+"_out_{0}".format(bit)) temp.append(self.bl_names[self.port]+"_out_{0}".format(bit))
temp.append(self.br_names[self.port]+"_out_{0}".format(bit)) temp.append(self.br_names[self.port]+"_out_{0}".format(bit))
temp.extend(["w_en{0}".format(self.port), "vdd", "gnd"]) temp.extend(["w_en", "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
@ -320,7 +337,7 @@ class port_data(design.design):
for bit in range(self.word_size): for bit in range(self.word_size):
data_pin = self.sense_amp_array_inst.get_pin("data_{}".format(bit)) data_pin = self.sense_amp_array_inst.get_pin("data_{}".format(bit))
self.add_layout_pin_rect_center(text="dout{0}_{1}".format(port,bit), self.add_layout_pin_rect_center(text="dout_{0}".format(bit),
layer=data_pin.layer, layer=data_pin.layer,
offset=data_pin.center(), offset=data_pin.center(),
height=data_pin.height(), height=data_pin.height(),
@ -331,7 +348,7 @@ class port_data(design.design):
for row in range(self.word_size): for row in range(self.word_size):
data_name = "data_{}".format(row) data_name = "data_{}".format(row)
din_name = "din{0}_{1}".format(self.port,row) din_name = "din_{}".format(row)
self.copy_layout_pin(self.write_driver_array_inst, data_name, din_name) self.copy_layout_pin(self.write_driver_array_inst, data_name, din_name)
def route_column_mux_to_precharge_array(self, port): def route_column_mux_to_precharge_array(self, port):
@ -392,6 +409,34 @@ class port_data(design.design):
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size) self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size)
def route_bitline_pins(self):
""" Add the bitline pins for the given port """
for bit in range(self.num_cols):
if self.port in self.read_ports:
self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(bit))
self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(bit))
elif self.column_mux_array_inst:
self.copy_layout_pin(self.column_mux_array_inst, "bl_{}".format(bit))
self.copy_layout_pin(self.column_mux_array_inst, "br_{}".format(bit))
else:
self.copy_layout_pin(self.write_driver_array_inst, "bl_{}".format(bit))
self.copy_layout_pin(self.write_driver_array_inst, "br_{}".format(bit))
def route_control_pins(self):
""" Add the control pins: s_en, p_en_bar, w_en """
if self.precharge_array_inst:
self.copy_layout_pin(self.precharge_array_inst, "en_bar", "p_en_bar")
if self.column_mux_array_inst:
sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)]
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")
if self.write_driver_array_inst:
self.copy_layout_pin(self.write_driver_array_inst, "en", "w_en")
def channel_route_bitlines(self, inst1, inst2, num_bits, def channel_route_bitlines(self, inst1, inst2, num_bits,
inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_bl_name="bl_{}", inst1_br_name="br_{}",
inst2_bl_name="bl_{}", inst2_br_name="br_{}"): inst2_bl_name="bl_{}", inst2_br_name="br_{}"):

View File

@ -26,7 +26,7 @@ class ptx(design.design):
# will use the last record with a given name. I.e., you will # will use the last record with a given name. I.e., you will
# over-write a design in GDS if one has and the other doesn't # over-write a design in GDS if one has and the other doesn't
# have poly connected, for example. # have poly connected, for example.
name = "{0}_m{1}_w{2}".format(tx_type, mults, width) name = "{0}_m{1}_w{2:.3f}".format(tx_type, mults, width)
if connect_active: if connect_active:
name += "_a" name += "_a"
if connect_poly: if connect_poly:

View File

@ -46,6 +46,7 @@ class sram_1bank(sram_base):
self.data_dff_insts = self.create_data_dff() self.data_dff_insts = self.create_data_dff()
def place_instances(self): def place_instances(self):
""" """
This places the instances for a single bank SRAM with control This places the instances for a single bank SRAM with control
@ -72,25 +73,6 @@ class sram_1bank(sram_base):
# Port 0 # Port 0
port = 0 port = 0
# This includes 2 M2 pitches for the row addr clock line.
# It is also placed to align with the column decoder (if it exists hence the bank gap)
control_pos[port] = vector(-self.control_logic_insts[port].width - 2*self.m2_pitch,
self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y - self.bank.m2_gap)
self.control_logic_insts[port].place(control_pos[port])
# The row address bits are placed above the control logic aligned on the right.
x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width
# It is aove the control logic but below the top of the bitcell array
y_offset = max(self.control_logic_insts[port].uy(), self.bank.bank_array_ur.y - self.row_addr_dff_insts[port].height)
row_addr_pos[port] = vector(x_offset, y_offset)
self.row_addr_dff_insts[port].place(row_addr_pos[port])
# Add the col address flops below the bank to the left of the lower-left of bank array
if self.col_addr_dff:
col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap,
-max_gap_size - self.col_addr_dff_insts[port].height)
self.col_addr_dff_insts[port].place(col_addr_pos[port])
# Add the data flops below the bank to the right of the lower-left of bank array # Add the data flops below the bank to the right of the lower-left of bank array
# This relies on the lower-left of the array of the bank # This relies on the lower-left of the array of the bank
# decoder in upper left, bank in upper right, sensing in lower right. # decoder in upper left, bank in upper right, sensing in lower right.
@ -98,33 +80,36 @@ class sram_1bank(sram_base):
# sense amps. # sense amps.
if port in self.write_ports: if port in self.write_ports:
data_pos[port] = vector(self.bank.bank_array_ll.x, data_pos[port] = vector(self.bank.bank_array_ll.x,
-max_gap_size - self.data_dff_insts[port].height) -max_gap_size - self.dff.height)
self.data_dff_insts[port].place(data_pos[port]) self.data_dff_insts[port].place(data_pos[port])
else:
data_pos[port] = vector(self.bank.bank_array_ll.x,0)
# Add the col address flops below the bank to the left of the lower-left of bank array
if self.col_addr_dff:
col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap,
-max_gap_size - self.col_addr_dff_insts[port].height)
self.col_addr_dff_insts[port].place(col_addr_pos[port])
else:
col_addr_pos[port] = vector(self.bank.bank_array_ll.x,0)
# This includes 2 M2 pitches for the row addr clock line.
control_pos[port] = vector(-self.control_logic_insts[port].width - 2*self.m2_pitch,
self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y - self.bank.m2_gap)
self.control_logic_insts[port].place(control_pos[port])
# The row address bits are placed above the control logic aligned on the right.
x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width
# It is aove the control logic but below the top of the bitcell array
y_offset = self.control_logic_insts[port].uy()
row_addr_pos[port] = vector(x_offset, y_offset)
self.row_addr_dff_insts[port].place(row_addr_pos[port])
if len(self.all_ports)>1: if len(self.all_ports)>1:
# Port 1 # Port 1
port = 1 port = 1
# This includes 2 M2 pitches for the row addr clock line
# It is also placed to align with the column decoder (if it exists hence the bank gap)
control_pos[port] = vector(self.bank_inst.rx() + self.control_logic_insts[port].width + 2*self.m2_pitch,
self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y + self.bank.m2_gap)
self.control_logic_insts[port].place(control_pos[port], mirror="MY")
# The row address bits are placed above the control logic aligned on the left.
x_offset = control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
# It is above the control logic but below the top of the bitcell array
y_offset = max(self.control_logic_insts[port].uy(), self.bank.bank_array_ur.y - self.row_addr_dff_insts[port].height)
row_addr_pos[port] = vector(x_offset, y_offset)
self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="MY")
# Add the col address flops above the bank to the right of the upper-right of bank array
if self.col_addr_dff:
col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
self.bank.height + max_gap_size + self.col_addr_dff_insts[port].height)
self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX")
# Add the data flops above the bank to the left of the upper-right of bank array # Add the data flops above the bank to the left of the upper-right of bank array
# This relies on the upper-right of the array of the bank # This relies on the upper-right of the array of the bank
# decoder in upper left, bank in upper right, sensing in lower right. # decoder in upper left, bank in upper right, sensing in lower right.
@ -132,8 +117,31 @@ class sram_1bank(sram_base):
# sense amps. # sense amps.
if port in self.write_ports: if port in self.write_ports:
data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width, data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
self.bank.height + max_gap_size + self.data_dff_insts[port].height) self.bank.height + max_gap_size + self.dff.height)
self.data_dff_insts[port].place(data_pos[port], mirror="MX") self.data_dff_insts[port].place(data_pos[port], mirror="MX")
else:
data_pos[port] = self.bank_inst.ur()
# Add the col address flops above the bank to the right of the upper-right of bank array
if self.col_addr_dff:
col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
self.bank.height + max_gap_size + self.dff.height)
self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX")
else:
col_addr_pos[port] = self.bank_inst.ur()
# This includes 2 M2 pitches for the row addr clock line
control_pos[port] = vector(self.bank_inst.rx() + self.control_logic_insts[port].width + 2*self.m2_pitch,
self.bank.bank_array_ur.y + self.control_logic_insts[port].mod.control_logic_center.y + self.bank.m2_gap)
self.control_logic_insts[port].place(control_pos[port], mirror="XY")
# The row address bits are placed above the control logic aligned on the left.
x_offset = control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
# It is above the control logic but below the top of the bitcell array
y_offset = self.control_logic_insts[port].by()
row_addr_pos[port] = vector(x_offset, y_offset)
self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="XY")
def add_layout_pins(self): def add_layout_pins(self):
@ -260,10 +268,15 @@ class sram_1bank(sram_base):
def route_col_addr_dff(self): def route_col_addr_dff(self):
""" Connect the output of the row flops to the bank pins """ """ Connect the output of the row flops to the bank pins """
for port in self.all_ports: for port in self.all_ports:
if port%2:
offset = self.col_addr_dff_insts[port].ll() - vector(0, (self.word_size+2)*self.m1_pitch)
else:
offset = self.col_addr_dff_insts[port].ul() + vector(0, 2*self.m1_pitch)
bus_names = ["addr_{}".format(x) for x in range(self.col_addr_size)] bus_names = ["addr_{}".format(x) for x in range(self.col_addr_size)]
col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1", col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch, pitch=self.m1_pitch,
offset=self.col_addr_dff_insts[port].ul() + vector(0, self.m1_pitch), offset=offset,
names=bus_names, names=bus_names,
length=self.col_addr_dff_insts[port].width) length=self.col_addr_dff_insts[port].width)

View File

@ -262,6 +262,7 @@ class sram_base(design, verilog, lef):
def add_modules(self): def add_modules(self):
self.bitcell = factory.create(module_type=OPTS.bitcell) self.bitcell = factory.create(module_type=OPTS.bitcell)
self.dff = factory.create(module_type="dff")
# Create the address and control flops (but not the clk) # Create the address and control flops (but not the clk)
from dff_array import dff_array from dff_array import dff_array
@ -277,6 +278,8 @@ class sram_base(design, verilog, lef):
self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size) self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size)
self.add_mod(self.data_dff) self.add_mod(self.data_dff)
# Create the bank module (up to four are instantiated) # Create the bank module (up to four are instantiated)
from bank import bank from bank import bank
self.bank = bank(self.sram_config, self.bank = bank(self.sram_config,

View File

@ -13,6 +13,7 @@ from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
@unittest.skip("SKIPPING 05_replica_bitcell_array_test")
class replica_bitcell_array_test(openram_test): class replica_bitcell_array_test(openram_test):
def runTest(self): def runTest(self):

View File

@ -0,0 +1,71 @@
#!/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 single_bank_1w_1r_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.bitcell = "bitcell_1w_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
from sram_config import sram_config
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(module_type="bank", sram_config=c)
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(module_type="bank", sram_config=c)
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(module_type="bank", sram_config=c)
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(module_type="bank", sram_config=c)
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())