Merge pull request #282 from ruhai-lin/stable

Attempt to fix LVS mismatch and SRAM creation with banks for sky130
This commit is contained in:
Jesse Cirimelli-Low 2026-03-12 10:47:23 -07:00 committed by GitHub
commit ab33017fe2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 35 additions and 19 deletions

View File

@ -1388,11 +1388,15 @@ class delay(simulation):
def calculate_inverse_address(self): def calculate_inverse_address(self):
"""Determine dummy test address based on probe address and column mux size.""" """Determine dummy test address based on probe address and column mux size."""
# The inverse address needs to share the same bitlines as the probe address as the trimming will remove all other bitlines # The inverse address needs to share the same bitlines as the probe address as the trimming will remove all other bitlines.
# This is only an issue when there is a column mux and the address maps to different bitlines. # This is only an issue when there is a column mux and the address maps to different bitlines.
column_addr = self.get_column_addr() # do not invert this part column_addr = self.get_column_addr() # do not invert this part
inverse_address = "" inverse_address = ""
for c in self.probe_address[self.sram.col_addr_size:]: # invert everything else if self.sram.col_addr_size > 0:
row_address = self.probe_address[:-self.sram.col_addr_size]
else:
row_address = self.probe_address
for c in row_address: # invert row bits only
if c=="0": if c=="0":
inverse_address += "1" inverse_address += "1"
elif c=="1": elif c=="1":

View File

@ -126,8 +126,10 @@ class simulation():
def get_data_bit_column_number(self, probe_address, probe_data): def get_data_bit_column_number(self, probe_address, probe_data):
"""Calculates bitline column number of data bit under test using bit position and mux size""" """Calculates bitline column number of data bit under test using bit position and mux size"""
if self.sram.col_addr_size>0: # Address pins are ordered a*_0 ... a*_N, where a*_0 is the LSB.
col_address = int(probe_address[0:self.sram.col_addr_size], 2) # So the column mux select bits are the rightmost bits in the binary address string.
if self.sram.col_addr_size > 0:
col_address = int(probe_address[-self.sram.col_addr_size:], 2)
else: else:
col_address = 0 col_address = 0
bl_column = int(self.sram.words_per_row * probe_data + col_address) bl_column = int(self.sram.words_per_row * probe_data + col_address)
@ -136,7 +138,11 @@ class simulation():
def get_address_row_number(self, probe_address): def get_address_row_number(self, probe_address):
"""Calculates wordline row number of data bit under test using address and column mux size""" """Calculates wordline row number of data bit under test using address and column mux size"""
return int(probe_address[self.sram.col_addr_size:], 2) if self.sram.col_addr_size > 0:
row_address = probe_address[:-self.sram.col_addr_size]
else:
row_address = probe_address
return int(row_address, 2) if row_address else 0
def add_control_one_port(self, port, op): def add_control_one_port(self, port, op):
"""Appends control signals for operation to a given port""" """Appends control signals for operation to a given port"""
@ -484,7 +490,9 @@ class simulation():
def get_column_addr(self): def get_column_addr(self):
"""Returns column address of probe bit""" """Returns column address of probe bit"""
return self.probe_address[:self.sram.col_addr_size] if self.sram.col_addr_size == 0:
return ""
return self.probe_address[-self.sram.col_addr_size:]
def add_graph_exclusions(self): def add_graph_exclusions(self):
""" """

View File

@ -56,12 +56,15 @@ class trim_spice():
# Always start fresh if we do multiple reductions # Always start fresh if we do multiple reductions
self.sp_buffer = self.spice self.sp_buffer = self.spice
# Split up the address and convert to an int # Address pins are ordered with bit 0 as LSB, so mux column bits
wl_address = int(address[self.col_addr_size:], 2) # are the rightmost bits in the binary address string.
if self.col_addr_size > 0: if self.col_addr_size > 0:
col_address = int(address[0:self.col_addr_size], 2) row_address = address[:-self.col_addr_size]
col_address = int(address[-self.col_addr_size:], 2)
else: else:
row_address = address
col_address = 0 col_address = 0
wl_address = int(row_address, 2) if row_address else 0
# 1. Keep cells in the bitcell array based on WL and BL # 1. Keep cells in the bitcell array based on WL and BL
wl_name = "wl_{}".format(wl_address) wl_name = "wl_{}".format(wl_address)

View File

@ -100,14 +100,15 @@ class sky130_bitcell_base_array(bitcell_base_array):
strap_pins = [] strap_pins = []
for port in self.all_ports: for port in self.all_ports:
strap_pins.extend([x for x in self.get_bitline_names(port) if "bl" in x and x.endswith("_{0}".format(col))]) strap_pins.extend([x for x in self.get_bitline_names(port) if "bl" in x and x.endswith("_{0}".format(col))])
strap_pins.extend(["vdd", "gnd"])
for port in self.all_ports: for port in self.all_ports:
strap_pins.extend([x for x in self.get_bitline_names(port) if "br" in x and x.endswith("_{0}".format(col))]) strap_pins.extend([x for x in self.get_bitline_names(port) if "br" in x and x.endswith("_{0}".format(col))])
# col_cap_1port_bitcell port order:
# [bl, br, vdd, gnd, vpb, vnb, gate]
strap_pins.extend(["vdd", "gnd", "vdd", "gnd"])
if row == 0: if row == 0:
strap_pins.extend(["top_gate"]) strap_pins.append("top_gate")
else: else:
strap_pins.extend(["bot_gate"]) strap_pins.append("bot_gate")
strap_pins.extend(["vdd", "gnd"])
return strap_pins return strap_pins
def get_row_cap_pins(self, row, col): def get_row_cap_pins(self, row, col):

View File

@ -75,12 +75,12 @@ class sky130_col_cap_array(sky130_bitcell_base_array):
row_layout.append(self.colend1) row_layout.append(self.colend1)
self.cell_inst[col]=self.add_inst(name=name, mod=self.colend1) self.cell_inst[col]=self.add_inst(name=name, mod=self.colend1)
pins.append("fake_bl_{}".format(bitline)) pins.append("fake_bl_{}".format(bitline))
pins.append("vdd")
pins.append("gnd")
pins.append("fake_br_{}".format(bitline)) pins.append("fake_br_{}".format(bitline))
pins.append("gate")
pins.append("vdd") pins.append("vdd")
pins.append("gnd") pins.append("gnd")
pins.append("vdd")
pins.append("gnd")
pins.append("gate")
bitline += 1 bitline += 1
elif col % 4 == 1: elif col % 4 == 1:
row_layout.append(self.colend2) row_layout.append(self.colend2)
@ -92,12 +92,12 @@ class sky130_col_cap_array(sky130_bitcell_base_array):
row_layout.append(self.colend1) row_layout.append(self.colend1)
self.cell_inst[col]=self.add_inst(name=name, mod=self.colend1) self.cell_inst[col]=self.add_inst(name=name, mod=self.colend1)
pins.append("fake_bl_{}".format(bitline)) pins.append("fake_bl_{}".format(bitline))
pins.append("vdd")
pins.append("gnd")
pins.append("fake_br_{}".format(bitline)) pins.append("fake_br_{}".format(bitline))
pins.append("gate")
pins.append("vdd") pins.append("vdd")
pins.append("gnd") pins.append("gnd")
pins.append("vdd")
pins.append("gnd")
pins.append("gate")
bitline += 1 bitline += 1
elif col % 4 ==3: elif col % 4 ==3:
row_layout.append(self.colend2) row_layout.append(self.colend2)