From c2629edc1b0cfe3cf5570dc50667b0b711ac609f Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 6 Oct 2020 16:27:02 -0700 Subject: [PATCH] Allow 16-way column mux --- compiler/modules/bank.py | 3 ++ compiler/modules/port_address.py | 4 +- compiler/modules/replica_column.py | 6 ++- compiler/sram/sram.py | 14 +++--- compiler/sram/sram_config.py | 74 +++++++++++++++--------------- 5 files changed, 53 insertions(+), 48 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 41433e46..a1c6c251 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -533,6 +533,9 @@ class bank(design.design): elif self.col_addr_size == 3: self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", height=self.dff.height) + elif self.col_addr_size == 4: + self.column_decoder = factory.create(module_type="hierarchical_predecode4x16", + height=self.dff.height) else: # No error checking before? debug.error("Invalid column decoder?", -1) diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index f7e85afd..8146e7b6 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -79,8 +79,8 @@ class port_address(design.design): self.copy_power_pins(inst, "vdd") self.copy_power_pins(inst, "gnd") - rbl_vdd_pin = self.rbl_driver_inst.get_pin("vdd") - self.add_power_pin("vdd", rbl_vdd_pin.lc()) + for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"): + self.add_power_pin("vdd", rbl_vdd_pin.center()) def route_pins(self): for row in range(self.addr_size): diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index dafe51e6..6d084261 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -221,8 +221,10 @@ class replica_column(bitcell_base_array): bitcell_pins = [] for port in self.all_ports: bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))]) - bitcell_pins.append("vdd") - bitcell_pins.append("gnd") + if len(self.edge_cell.get_pins("vdd")) > 0: + bitcell_pins.append("vdd") + if len(self.edge_cell.get_pins("gnd")) > 0: + bitcell_pins.append("gnd") return bitcell_pins diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index 992919f0..63d971f3 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -79,13 +79,6 @@ class sram(): """ Save all the output files while reporting time to do it as well. """ if not OPTS.netlist_only: - # Create a LEF physical model - start_time = datetime.datetime.now() - lefname = OPTS.output_path + self.s.name + ".lef" - debug.print_raw("LEF: Writing to {0}".format(lefname)) - self.lef_write(lefname) - print_time("LEF", datetime.datetime.now(), start_time) - # Write the layout start_time = datetime.datetime.now() gdsname = OPTS.output_path + self.s.name + ".gds" @@ -93,6 +86,13 @@ class sram(): self.gds_write(gdsname) print_time("GDS", datetime.datetime.now(), start_time) + # Create a LEF physical model + start_time = datetime.datetime.now() + lefname = OPTS.output_path + self.s.name + ".lef" + debug.print_raw("LEF: Writing to {0}".format(lefname)) + self.lef_write(lefname) + print_time("LEF", datetime.datetime.now(), start_time) + # Save the spice file start_time = datetime.datetime.now() spname = OPTS.output_path + self.s.name + ".sp" diff --git a/compiler/sram/sram_config.py b/compiler/sram/sram_config.py index fa70d730..573e7514 100644 --- a/compiler/sram/sram_config.py +++ b/compiler/sram/sram_config.py @@ -6,15 +6,15 @@ # All rights reserved. # import debug -from math import log,sqrt,ceil -from importlib import reload +from math import log, sqrt, ceil from globals import OPTS 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, num_spare_cols=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=0): self.word_size = word_size self.num_words = num_words self.write_size = write_size @@ -25,7 +25,7 @@ class sram_config: # 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 """ @@ -34,31 +34,31 @@ class sram_config: # Copy all the variables to the local module for member in members: - setattr(module,member,getattr(self,member)) + setattr(module, member, getattr(self, member)) def compute_sizes(self): """ Computes the organization of the memory using bitcell size by trying to make it square.""" 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.") - self.num_words_per_bank = self.num_words/self.num_banks - self.num_bits_per_bank = self.word_size*self.num_words_per_bank + self.num_words_per_bank = self.num_words / self.num_banks + self.num_bits_per_bank = self.word_size * self.num_words_per_bank # If this was hard coded, don't dynamically compute it! if not self.words_per_row: # Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry) - self.bank_area = bitcell.width*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) # 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/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) # Estimate the number of rows given the tentative words per row - self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size) + self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row * self.word_size) self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row) self.recompute_sizes() @@ -70,57 +70,57 @@ class sram_config: SRAM for testing. """ - debug.info(1,"Recomputing with words per row: {}".format(self.words_per_row)) + debug.info(1, "Recomputing with words per row: {}".format(self.words_per_row)) # If the banks changed - self.num_words_per_bank = self.num_words/self.num_banks - self.num_bits_per_bank = self.word_size*self.num_words_per_bank + self.num_words_per_bank = self.num_words / self.num_banks + self.num_bits_per_bank = self.word_size * self.num_words_per_bank # Fix the number of columns and rows - self.num_cols = int(self.words_per_row*self.word_size) - self.num_rows_temp = int(self.num_words_per_bank/self.words_per_row) + self.num_cols = int(self.words_per_row * self.word_size) + self.num_rows_temp = int(self.num_words_per_bank / self.words_per_row) self.num_rows = self.num_rows_temp + self.num_spare_rows - debug.info(1,"Rows: {} Cols: {}".format(self.num_rows_temp,self.num_cols)) + debug.info(1, "Rows: {} Cols: {}".format(self.num_rows_temp, self.num_cols)) # Compute the address and bank sizes self.row_addr_size = ceil(log(self.num_rows, 2)) self.col_addr_size = int(log(self.words_per_row, 2)) self.bank_addr_size = self.col_addr_size + self.row_addr_size self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2)) - debug.info(1,"Row addr size: {}".format(self.row_addr_size) + debug.info(1, "Row addr size: {}".format(self.row_addr_size) + " Col addr size: {}".format(self.col_addr_size) + " Bank addr size: {}".format(self.bank_addr_size)) - - def estimate_words_per_row(self,tentative_num_cols, word_size): + def estimate_words_per_row(self, tentative_num_cols, word_size): """ This provides a heuristic rounded estimate for the number of words per row. """ + tentative_column_ways = tentative_num_cols / word_size + column_mux_sizes = [1, 2, 4, 8, 16] + # If we are double, we may want a larger column mux + if tentative_column_ways > 2 * column_mux_sizes[-1]: + debug.warning("Extremely large number of columns for 16-way maximum column mux.") - if tentative_num_cols < 1.5*word_size: - return 1 - elif tentative_num_cols < 3*word_size: - return 2 - elif tentative_num_cols < 6*word_size: - return 4 - else: - if tentative_num_cols > 16*word_size: - debug.warning("Reaching column mux size limit. Consider increasing above 8-way.") - return 8 + closest_way = min(column_mux_sizes, key=lambda x: abs(x - tentative_column_ways)) - def amend_words_per_row(self,tentative_num_rows, words_per_row): + return closest_way + + def amend_words_per_row(self, tentative_num_rows, words_per_row): """ This picks the number of words per row more accurately by limiting it to a minimum and maximum. """ # Recompute the words per row given a hard max if(not OPTS.is_unit_test and tentative_num_rows > 512): - debug.check(tentative_num_rows*words_per_row <= 2048, "Number of words exceeds 2048") - return int(words_per_row*tentative_num_rows/512) + debug.check(tentative_num_rows * words_per_row <= 4096, + "Number of words exceeds 2048") + return int(words_per_row * tentative_num_rows / 512) + # Recompute the words per row given a hard min - if(not OPTS.is_unit_test and tentative_num_rows < 16): - debug.check(tentative_num_rows*words_per_row >= 16, "Minimum number of rows is 16, but given {0}".format(tentative_num_rows)) - return int(words_per_row*tentative_num_rows/16) + if (not OPTS.is_unit_test and tentative_num_rows < 16): + debug.check(tentative_num_rows * words_per_row >= 16, + "Minimum number of rows is 16, but given {0}".format(tentative_num_rows)) + return int(words_per_row * tentative_num_rows / 16) return words_per_row