diff --git a/compiler/globals.py b/compiler/globals.py index 9acfc945..991ec1ad 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -204,26 +204,30 @@ def read_config(config_file, is_unit_test=True): # Note that if we re-read a config file, nothing will get read again! if not k in OPTS.__dict__ or k=="tech_name": OPTS.__dict__[k]=v - + + # Massage the output path to be an absolute one if not OPTS.output_path.endswith('/'): OPTS.output_path += "/" if not OPTS.output_path.startswith('/'): OPTS.output_path = os.getcwd() + "/" + OPTS.output_path debug.info(1, "Output saved in " + OPTS.output_path) + # Remember if we are running unit tests to reduce output OPTS.is_unit_test=is_unit_test # If we are only generating a netlist, we can't do DRC/LVS if OPTS.netlist_only: OPTS.check_lvsdrc=False - + # If config didn't set output name, make a reasonable default. if (OPTS.output_name == ""): - OPTS.output_name = "sram_{0}rw_{1}b_{2}w_{3}bank_{4}".format(OPTS.rw_ports, - OPTS.word_size, - OPTS.num_words, - OPTS.num_banks, - OPTS.tech_name) + OPTS.output_name = "sram_{0}b_{1}w_{2}bank_{3}rw_{4}w_{5}r_{6}".format(OPTS.word_size, + OPTS.num_words, + OPTS.num_banks, + OPTS.num_rw_ports, + OPTS.num_w_ports, + OPTS.num_r_ports, + OPTS.tech_name) # Don't delete the output dir, it may have other files! # make the directory if it doesn't exist diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 1bc78fd6..6c22070a 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -20,22 +20,16 @@ class bank(design.design): write driver and sense amplifiers. """ - def __init__(self, word_size, num_words, words_per_row, num_banks=1, name=""): + def __init__(self, sram_config, name=""): - if name == "": - name = "bank_{0}_{1}".format(word_size, num_words) - design.design.__init__(self, name) - debug.info(2, "create sram of size {0} with {1} words".format(word_size,num_words)) - - self.word_size = word_size - self.num_words = num_words - self.words_per_row = words_per_row - self.num_banks = num_banks + sram_config.set_local_config(self) - self.total_write = OPTS.rw_ports + OPTS.w_ports - self.total_read = OPTS.rw_ports + OPTS.r_ports - self.total_ports = OPTS.rw_ports + OPTS.w_ports + OPTS.r_ports + if name == "": + name = "bank_{0}_{1}".format(self.word_size, self.num_words) + design.design.__init__(self, name) + debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words)) + # The local control signals are gated when we have bank select logic, # so this prefix will be added to all of the input signals to create # the internal gated signals. @@ -70,25 +64,25 @@ class bank(design.design): def add_pins(self): """ Adding pins for Bank module""" - for k in range(self.total_read): - for i in range(self.word_size): - self.add_pin("dout{0}[{1}]".format(k,i),"OUT") - for k in range(self.total_write): - for i in range(self.word_size): - self.add_pin("din{0}[{1}]".format(k,i),"IN") - for k in range(self.total_ports): - for i in range(self.addr_size): - self.add_pin("addr{0}[{1}]".format(k,i),"INPUT") + for port in range(self.total_read): + for bit in range(self.word_size): + self.add_pin("dout{0}[{1}]".format(port,bit),"OUT") + for port in range(self.total_write): + for bit in range(self.word_size): + self.add_pin("din{0}[{1}]".format(port,bit),"IN") + for port in range(self.total_ports): + for bit in range(self.addr_size): + self.add_pin("addr{0}[{1}]".format(port,bit),"INPUT") # For more than one bank, we have a bank select and name # the signals gated_*. if self.num_banks > 1: for port in range(self.total_ports): self.add_pin("bank_sel{}".format(port),"INPUT") - for k in range(self.total_read): - self.add_pin("s_en{0}".format(k), "INPUT") - for k in range(self.total_write): - self.add_pin("w_en{0}".format(k), "INPUT") + for port in range(self.total_read): + self.add_pin("s_en{0}".format(port), "INPUT") + for port in range(self.total_write): + self.add_pin("w_en{0}".format(port), "INPUT") for pin in ["clk_buf_bar","clk_buf"]: self.add_pin(pin,"INPUT") self.add_pin("vdd","POWER") @@ -229,9 +223,9 @@ class bank(design.design): self.total_bitline_list = self.bitcell.list_all_bitline_names() self.precharge_array = [] - for k in range(self.total_read): - self.precharge_array.append(self.mod_precharge_array(columns=self.num_cols, bitcell_bl=self.read_bl_list[k], bitcell_br=self.read_br_list[k])) - self.add_mod(self.precharge_array[k]) + for port in range(self.total_read): + self.precharge_array.append(self.mod_precharge_array(columns=self.num_cols, bitcell_bl=self.read_bl_list[port], bitcell_br=self.read_br_list[port])) + self.add_mod(self.precharge_array[port]) if self.col_addr_size > 0: self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols, @@ -288,13 +282,13 @@ class bank(design.design): """ Creating Precharge """ self.precharge_array_inst = [] - for k in range(self.total_read): - self.precharge_array_inst.append(self.add_inst(name="precharge_array{}".format(k), - mod=self.precharge_array[k])) + for port in range(self.total_read): + self.precharge_array_inst.append(self.add_inst(name="precharge_array{}".format(port), + mod=self.precharge_array[port])) temp = [] for i in range(self.num_cols): - temp.append(self.read_bl_list[k]+"[{0}]".format(i)) - temp.append(self.read_br_list[k]+"[{0}]".format(i)) + temp.append(self.read_bl_list[port]+"[{0}]".format(i)) + temp.append(self.read_br_list[port]+"[{0}]".format(i)) temp.extend([self.prefix+"clk_buf_bar", "vdd"]) self.connect_inst(temp) @@ -302,11 +296,11 @@ class bank(design.design): """ Placing Precharge """ # FIXME: place for multiport - for k in range(self.total_read): + for port in range(self.total_read): # The wells must be far enough apart # The enclosure is for the well and the spacing is to the bitcell wells y_offset = self.bitcell_array.height + self.m2_gap - self.precharge_array_inst[k].place(vector(0,y_offset)) + self.precharge_array_inst[port].place(vector(0,y_offset)) def create_column_mux_array(self): """ Creating Column Mux when words_per_row > 1 . """ @@ -314,19 +308,19 @@ class bank(design.design): return self.col_mux_array_inst = [] - for k in range(self.total_ports): - self.col_mux_array_inst.append(self.add_inst(name="column_mux_array{}".format(k), + for port in range(self.total_ports): + self.col_mux_array_inst.append(self.add_inst(name="column_mux_array{}".format(port), mod=self.column_mux_array)) temp = [] - for i in range(self.num_cols): - temp.append(self.total_bl_list[k]+"[{0}]".format(i)) - temp.append(self.total_br_list[k]+"[{0}]".format(i)) - for h in range(self.words_per_row): - temp.append("sel{0}[{1}]".format(k,h)) - for j in range(self.word_size): - temp.append(self.total_bl_list[k]+"_out[{0}]".format(j)) - temp.append(self.total_br_list[k]+"_out[{0}]".format(j)) + for col in range(self.num_cols): + temp.append(self.total_bl_list[port]+"[{0}]".format(col)) + temp.append(self.total_br_list[port]+"[{0}]".format(col)) + for word in range(self.words_per_row): + temp.append("sel{0}[{1}]".format(port,word)) + for bit in range(self.word_size): + temp.append(self.total_bl_list[port]+"_out[{0}]".format(bit)) + temp.append(self.total_br_list[port]+"_out[{0}]".format(bit)) temp.append("gnd") self.connect_inst(temp) @@ -338,68 +332,68 @@ class bank(design.design): self.column_mux_height = 0 return - for k in range(self.total_ports): + for port in range(self.total_ports): y_offset = self.column_mux_height - self.col_mux_array_inst[k].place(vector(0,y_offset).scale(-1,-1)) + self.col_mux_array_inst[port].place(vector(0,y_offset).scale(-1,-1)) def create_sense_amp_array(self): """ Creating Sense amp """ self.sense_amp_array_inst = [] - for k in range(self.total_read): - self.sense_amp_array_inst.append(self.add_inst(name="sense_amp_array{}".format(k), + for port in range(self.total_read): + self.sense_amp_array_inst.append(self.add_inst(name="sense_amp_array{}".format(port), mod=self.sense_amp_array)) temp = [] - for i in range(self.word_size): - temp.append("dout{0}[{1}]".format(k,i)) + for bit in range(self.word_size): + temp.append("dout{0}[{1}]".format(port,bit)) if self.words_per_row == 1: - temp.append(self.read_bl_list[k]+"[{0}]".format(i)) - temp.append(self.read_br_list[k]+"[{0}]".format(i)) + temp.append(self.read_bl_list[port]+"[{0}]".format(bit)) + temp.append(self.read_br_list[port]+"[{0}]".format(bit)) else: - temp.append(self.read_bl_list[k]+"_out[{0}]".format(i)) - temp.append(self.read_br_list[k]+"_out[{0}]".format(i)) + temp.append(self.read_bl_list[port]+"_out[{0}]".format(bit)) + temp.append(self.read_br_list[port]+"_out[{0}]".format(bit)) - temp.extend([self.prefix+"s_en{0}".format(k), "vdd", "gnd"]) + temp.extend([self.prefix+"s_en{0}".format(port), "vdd", "gnd"]) self.connect_inst(temp) def place_sense_amp_array(self): """ Placing Sense amp """ # FIXME: place for multiport - for k in range(self.total_read): + for port in range(self.total_read): y_offset = self.column_mux_height + self.sense_amp_array.height + self.m2_gap - self.sense_amp_array_inst[k].place(vector(0,y_offset).scale(-1,-1)) + self.sense_amp_array_inst[port].place(vector(0,y_offset).scale(-1,-1)) def create_write_driver_array(self): """ Creating Write Driver """ self.write_driver_array_inst = [] - for k in range(self.total_write): - self.write_driver_array_inst.append(self.add_inst(name="write_driver_array{}".format(k), + for port in range(self.total_write): + self.write_driver_array_inst.append(self.add_inst(name="write_driver_array{}".format(port), mod=self.write_driver_array)) temp = [] - for i in range(self.word_size): - temp.append("din{0}[{1}]".format(k,i)) - for i in range(self.word_size): + 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.write_bl_list[k]+"[{0}]".format(i)) - temp.append(self.write_br_list[k]+"[{0}]".format(i)) + temp.append(self.write_bl_list[port]+"[{0}]".format(bit)) + temp.append(self.write_br_list[port]+"[{0}]".format(bit)) else: - temp.append(self.write_bl_list[k]+"_out[{0}]".format(i)) - temp.append(self.write_br_list[k]+"_out[{0}]".format(i)) - temp.extend([self.prefix+"w_en{0}".format(k), "vdd", "gnd"]) + temp.append(self.write_bl_list[port]+"_out[{0}]".format(bit)) + temp.append(self.write_br_list[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): """ Placing Write Driver """ # FIXME: place for multiport - for k in range(self.total_write): + for port in range(self.total_write): y_offset = self.sense_amp_array.height + self.column_mux_height \ + self.m2_gap + self.write_driver_array.height - self.write_driver_array_inst[k].place(vector(0,y_offset).scale(-1,-1)) + self.write_driver_array_inst[port].place(vector(0,y_offset).scale(-1,-1)) @@ -407,15 +401,15 @@ class bank(design.design): """ Create the hierarchical row decoder """ self.row_decoder_inst = [] - for k in range(self.total_ports): - self.row_decoder_inst.append(self.add_inst(name="row_decoder{}".format(k), + for port in range(self.total_ports): + self.row_decoder_inst.append(self.add_inst(name="row_decoder{}".format(port), mod=self.row_decoder)) temp = [] - for i in range(self.row_addr_size): - temp.append("addr{0}[{1}]".format(k,i+self.col_addr_size)) - for j in range(self.num_rows): - temp.append("dec_out{0}[{1}]".format(k,j)) + for bit in range(self.row_addr_size): + temp.append("addr{0}[{1}]".format(port,bit+self.col_addr_size)) + for row in range(self.num_rows): + temp.append("dec_out{0}[{1}]".format(port,row)) temp.extend(["vdd", "gnd"]) self.connect_inst(temp) @@ -429,24 +423,24 @@ class bank(design.design): # The address flop and decoder are aligned in the x coord. # FIXME: place for multiport - for k in range(self.total_ports): + for port in range(self.total_ports): x_offset = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width) - self.row_decoder_inst[k].place(vector(x_offset,0)) + self.row_decoder_inst[port].place(vector(x_offset,0)) def create_wordline_driver(self): """ Create the Wordline Driver """ self.wordline_driver_inst = [] - for k in range(self.total_ports): - self.wordline_driver_inst.append(self.add_inst(name="wordline_driver{}".format(k), + for port in range(self.total_ports): + self.wordline_driver_inst.append(self.add_inst(name="wordline_driver{}".format(port), mod=self.wordline_driver)) temp = [] - for i in range(self.num_rows): - temp.append("dec_out{0}[{1}]".format(k,i)) - for i in range(self.num_rows): - temp.append(self.total_wl_list[k]+"[{0}]".format(i)) + for row in range(self.num_rows): + temp.append("dec_out{0}[{1}]".format(port,row)) + for row in range(self.num_rows): + temp.append(self.total_wl_list[port]+"[{0}]".format(row)) temp.append(self.prefix+"clk_buf") temp.append("vdd") temp.append("gnd") @@ -456,10 +450,10 @@ class bank(design.design): """ Place the Wordline Driver """ # FIXME: place for multiport - for k in range(self.total_ports): + for port in range(self.total_ports): # The wordline driver is placed to the right of the main decoder width. x_offset = -(self.central_bus_width + self.wordline_driver.width) + self.m2_pitch - self.wordline_driver_inst[k].place(vector(x_offset,0)) + self.wordline_driver_inst[port].place(vector(x_offset,0)) def create_column_decoder(self): @@ -481,15 +475,15 @@ class bank(design.design): debug.error("Invalid column decoder?",-1) self.col_decoder_inst = [] - for k in range(self.total_ports): - self.col_decoder_inst.append(self.add_inst(name="col_address_decoder{}".format(k), + for port in range(self.total_ports): + self.col_decoder_inst.append(self.add_inst(name="col_address_decoder{}".format(port), mod=self.col_decoder)) temp = [] - for i in range(self.col_addr_size): - temp.append("addr{0}[{1}]".format(k,i)) - for j in range(self.num_col_addr_lines): - temp.append("sel{0}[{1}]".format(k,j)) + for bit in range(self.col_addr_size): + temp.append("addr{0}[{1}]".format(port,bit)) + for bit in range(self.num_col_addr_lines): + temp.append("sel{0}[{1}]".format(port,bit)) temp.extend(["vdd", "gnd"]) self.connect_inst(temp) @@ -501,11 +495,11 @@ class bank(design.design): return # FIXME: place for multiport - for k in range(self.total_ports): + for port in range(self.total_ports): # Place the col decoder right aligned with row decoder x_off = -(self.central_bus_width + self.wordline_driver.width + self.col_decoder.width) y_off = -(self.col_decoder.height + 2*drc["well_to_well"]) - self.col_decoder_inst[k].place(vector(x_off,y_off)) + self.col_decoder_inst[port].place(vector(x_off,y_off)) def create_bank_select(self): @@ -533,7 +527,7 @@ class bank(design.design): return # FIXME: place for multiport - for k in range(self.total_ports): + for port in range(self.total_ports): x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width) if self.col_addr_size > 0: y_off = min(self.col_decoder_inst[0].by(), self.col_mux_array_inst[0].by()) @@ -541,7 +535,7 @@ class bank(design.design): y_off = self.row_decoder_inst[0].by() y_off -= (self.bank_select.height + drc["well_to_well"]) self.bank_select_pos = vector(x_off,y_off) - self.bank_select_inst[k].place(self.bank_select_pos) + self.bank_select_inst[port].place(self.bank_select_pos) def route_vdd_gnd(self): @@ -550,19 +544,19 @@ class bank(design.design): # These are the instances that every bank has top_instances = [self.bitcell_array_inst] - for k in range(self.total_ports): - top_instances.extend([self.precharge_array_inst[k], - self.sense_amp_array_inst[k], - self.write_driver_array_inst[k], - self.row_decoder_inst[k], - self.wordline_driver_inst[k]]) + for port in range(self.total_ports): + top_instances.extend([self.precharge_array_inst[port], + self.sense_amp_array_inst[port], + self.write_driver_array_inst[port], + self.row_decoder_inst[port], + self.wordline_driver_inst[port]]) # Add these if we use the part... if self.col_addr_size > 0: - top_instances.append(self.col_decoder_inst[k]) - top_instances.append(self.col_mux_array_inst[k]) + top_instances.append(self.col_decoder_inst[port]) + top_instances.append(self.col_mux_array_inst[port]) if self.num_banks > 1: - top_instances.append(self.bank_select_inst[k]) + top_instances.append(self.bank_select_inst[port]) for inst in top_instances: @@ -576,13 +570,13 @@ class bank(design.design): def route_bank_select(self): """ Route the bank select logic. """ - for k in range(self.total_ports): + for port in range(self.total_ports): for input_name in self.input_control_signals+["bank_sel"]: - self.copy_layout_pin(self.bank_select_inst[k], input_name) + self.copy_layout_pin(self.bank_select_inst[port], input_name) for gated_name in self.control_signals: # Connect the inverter output to the central bus - out_pos = self.bank_select_inst[k].get_pin(gated_name).rc() + out_pos = self.bank_select_inst[port].get_pin(gated_name).rc() bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y) self.add_path("metal3",[out_pos, bus_pos]) self.add_via_center(layers=("metal2", "via2", "metal3"), @@ -660,12 +654,12 @@ class bank(design.design): """ Routing of BL and BR between pre-charge and bitcell array """ # FIXME: Update for multiport - for k in range(self.total_read): - for i in range(self.num_cols): - precharge_bl = self.precharge_array_inst[k].get_pin("bl[{}]".format(i)).bc() - precharge_br = self.precharge_array_inst[k].get_pin("br[{}]".format(i)).bc() - bitcell_bl = self.bitcell_array_inst.get_pin(self.read_bl_list[k]+"[{}]".format(i)).uc() - bitcell_br = self.bitcell_array_inst.get_pin(self.read_br_list[k]+"[{}]".format(i)).uc() + for port in range(self.total_read): + for col in range(self.num_cols): + precharge_bl = self.precharge_array_inst[port].get_pin("bl[{}]".format(col)).bc() + precharge_br = self.precharge_array_inst[port].get_pin("br[{}]".format(col)).bc() + bitcell_bl = self.bitcell_array_inst.get_pin(self.read_bl_list[port]+"[{}]".format(col)).uc() + bitcell_br = self.bitcell_array_inst.get_pin(self.read_br_list[port]+"[{}]".format(col)).uc() yoffset = 0.5*(precharge_bl.y+bitcell_bl.y) self.add_path("metal2",[precharge_bl, vector(precharge_bl.x,yoffset), @@ -682,12 +676,12 @@ class bank(design.design): return # FIXME: Update for multiport - for k in range(self.total_ports): - for i in range(self.num_cols): - col_mux_bl = self.col_mux_array_inst[k].get_pin("bl[{}]".format(i)).uc() - col_mux_br = self.col_mux_array_inst[k].get_pin("br[{}]".format(i)).uc() - bitcell_bl = self.bitcell_array_inst.get_pin(self.total_bl_list[k]+"[{}]".format(i)).bc() - bitcell_br = self.bitcell_array_inst.get_pin(self.total_br_list[k]+"[{}]".format(i)).bc() + for port in range(self.total_ports): + for col in range(self.num_cols): + col_mux_bl = self.col_mux_array_inst[port].get_pin("bl[{}]".format(col)).uc() + col_mux_br = self.col_mux_array_inst[port].get_pin("br[{}]".format(col)).uc() + bitcell_bl = self.bitcell_array_inst.get_pin(self.total_bl_list[port]+"[{}]".format(col)).bc() + bitcell_br = self.bitcell_array_inst.get_pin(self.total_br_list[port]+"[{}]".format(col)).bc() yoffset = 0.5*(col_mux_bl.y+bitcell_bl.y) self.add_path("metal2",[col_mux_bl, vector(col_mux_bl.x,yoffset), @@ -698,19 +692,19 @@ class bank(design.design): def route_sense_amp_to_col_mux_or_bitcell_array(self): """ Routing of BL and BR between sense_amp and column mux or bitcell array """ - for k in range(self.total_read): - for i in range(self.word_size): - sense_amp_bl = self.sense_amp_array_inst[k].get_pin("bl[{}]".format(i)).uc() - sense_amp_br = self.sense_amp_array_inst[k].get_pin("br[{}]".format(i)).uc() + for port in range(self.total_read): + for bit in range(self.word_size): + sense_amp_bl = self.sense_amp_array_inst[port].get_pin("bl[{}]".format(bit)).uc() + sense_amp_br = self.sense_amp_array_inst[port].get_pin("br[{}]".format(bit)).uc() if self.col_addr_size>0: # Sense amp is connected to the col mux - connect_bl = self.col_mux_array_inst[k].get_pin("bl_out[{}]".format(i)).bc() - connect_br = self.col_mux_array_inst[k].get_pin("br_out[{}]".format(i)).bc() + connect_bl = self.col_mux_array_inst[port].get_pin("bl_out[{}]".format(bit)).bc() + connect_br = self.col_mux_array_inst[port].get_pin("br_out[{}]".format(bit)).bc() else: # Sense amp is directly connected to the bitcell array - connect_bl = self.bitcell_array_inst.get_pin(self.read_bl_list[k]+"[{}]".format(i)).bc() - connect_br = self.bitcell_array_inst.get_pin(self.read_br_list[k]+"[{}]".format(i)).bc() + connect_bl = self.bitcell_array_inst.get_pin(self.read_bl_list[port]+"[{}]".format(bit)).bc() + connect_br = self.bitcell_array_inst.get_pin(self.read_br_list[port]+"[{}]".format(bit)).bc() yoffset = 0.5*(sense_amp_bl.y+connect_bl.y) @@ -722,9 +716,11 @@ class bank(design.design): def route_sense_amp_out(self): """ Add pins for the sense amp output """ - for i in range(self.word_size): - data_pin = self.sense_amp_array_inst[0].get_pin("data[{}]".format(i)) - self.add_layout_pin_rect_center(text="dout0[{}]".format(i), + + # FIXME: Update for multiport + for bit in range(self.word_size): + data_pin = self.sense_amp_array_inst[0].get_pin("data[{}]".format(bit)) + self.add_layout_pin_rect_center(text="dout0[{}]".format(bit), layer=data_pin.layer, offset=data_pin.center(), height=data_pin.height(), @@ -734,10 +730,11 @@ class bank(design.design): def route_row_decoder(self): """ Routes the row decoder inputs and supplies """ + # FIXME: Update for multiport # Create inputs for the row address lines - for i in range(self.row_addr_size): - addr_idx = i + self.col_addr_size - decoder_name = "addr[{}]".format(i) + for row in range(self.row_addr_size): + addr_idx = row + self.col_addr_size + decoder_name = "addr[{}]".format(row) addr_name = "addr0[{}]".format(addr_idx) self.copy_layout_pin(self.row_decoder_inst[0], decoder_name, addr_name) @@ -745,9 +742,9 @@ class bank(design.design): def route_write_driver(self): """ Connecting write driver """ - for i in range(self.word_size): - data_name = "data[{}]".format(i) - din_name = "din0[{}]".format(i) + for row in range(self.word_size): + data_name = "data[{}]".format(row) + din_name = "din0[{}]".format(row) self.copy_layout_pin(self.write_driver_array_inst[0], data_name, din_name) @@ -755,17 +752,17 @@ class bank(design.design): def route_wordline_driver(self): """ Connecting Wordline driver output to Bitcell WL connection """ - for i in range(self.num_rows): + for row in range(self.num_rows): # The pre/post is to access the pin from "outside" the cell to avoid DRCs - decoder_out_pos = self.row_decoder_inst[0].get_pin("decode[{}]".format(i)).rc() - driver_in_pos = self.wordline_driver_inst[0].get_pin("in[{}]".format(i)).lc() + decoder_out_pos = self.row_decoder_inst[0].get_pin("decode[{}]".format(row)).rc() + driver_in_pos = self.wordline_driver_inst[0].get_pin("in[{}]".format(row)).lc() mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0) mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1) self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos]) # The mid guarantees we exit the input cell to the right. - driver_wl_pos = self.wordline_driver_inst[0].get_pin("wl[{}]".format(i)).rc() - bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[0]+"[{}]".format(i)).lc() + driver_wl_pos = self.wordline_driver_inst[0].get_pin("wl[{}]".format(row)).rc() + bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[0]+"[{}]".format(row)).lc() mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0) mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) diff --git a/compiler/openram.py b/compiler/openram.py index 9045e8e7..a6db154d 100755 --- a/compiler/openram.py +++ b/compiler/openram.py @@ -38,7 +38,8 @@ report_status() # Start importing design modules after we have the config file import verify -import sram +from sram import sram +from sram_config import sram_config output_extensions = ["sp","v","lib"] if not OPTS.netlist_only: @@ -51,11 +52,14 @@ print(*output_files,sep="\n") start_time = datetime.datetime.now() print_time("Start",start_time) +c = sram_config(word_size=OPTS.word_size, + num_words=OPTS.num_words, + num_rw_ports=OPTS.num_rw_ports, + num_w_ports=OPTS.num_w_ports, + num_r_ports=OPTS.num_r_ports) + # import SRAM test generation -s = sram.sram(word_size=OPTS.word_size, - num_words=OPTS.num_words, - num_banks=OPTS.num_banks, - name=OPTS.output_name) +s = sram(c, OPTS.output_name) # Output the files for the resulting SRAM s.save() diff --git a/compiler/options.py b/compiler/options.py index 04d546d4..a81f7fae 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -52,9 +52,9 @@ class options(optparse.Values): purge_temp = True # These are the configuration parameters - rw_ports = 1 - r_ports = 0 - w_ports = 0 + num_rw_ports = 1 + num_r_ports = 0 + num_w_ports = 0 # These will get initialized by the the file supply_voltages = "" temperatures = "" diff --git a/compiler/pgates/pbitcell.py b/compiler/pgates/pbitcell.py index ddd998b6..0b2ec27d 100644 --- a/compiler/pgates/pbitcell.py +++ b/compiler/pgates/pbitcell.py @@ -16,18 +16,18 @@ class pbitcell(pgate.pgate): width = None height = None - unique_id = 1 - - def __init__(self, num_readwrite=OPTS.rw_ports, num_write=OPTS.w_ports, num_read=OPTS.r_ports): - name = "pbitcell_{0}RW_{1}W_{2}R_{3}".format(num_readwrite, num_write, num_read, pbitcell.unique_id) - pbitcell.unique_id += 1 - pgate.pgate.__init__(self, name) - debug.info(2, "create a multi-port bitcell with {0} write ports and {1} read ports".format(num_write, num_read)) + def __init__(self, num_rw_ports=OPTS.num_rw_ports, num_w_ports=OPTS.num_w_ports, num_r_ports=OPTS.num_r_ports): - self.num_readwrite = num_readwrite - self.num_write = num_write - self.num_read = num_read + name = "pbitcell_{0}RW_{1}W_{2}R".format(num_rw_ports, num_w_ports, num_r_ports) + pgate.pgate.__init__(self, name) + debug.info(2, "create a multi-port bitcell with {0} rw ports, {1} w ports and {2} r ports".format(num_rw_ports, + num_w_ports, + num_r_ports)) + self.num_rw_ports = num_rw_ports + self.num_w_ports = num_w_ports + self.num_r_ports = num_r_ports + self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -41,11 +41,11 @@ class pbitcell(pgate.pgate): self.add_modules() self.create_storage() - if(self.num_readwrite > 0): + if(self.num_rw_ports > 0): self.create_readwrite_ports() - if(self.num_write > 0): + if(self.num_w_ports > 0): self.create_write_ports() - if(self.num_read > 0): + if(self.num_r_ports > 0): self.create_read_ports() def create_layout(self): @@ -56,11 +56,11 @@ class pbitcell(pgate.pgate): self.route_storage() self.route_rails() - if(self.num_readwrite > 0): + if(self.num_rw_ports > 0): self.place_readwrite_ports() - if(self.num_write > 0): + if(self.num_w_ports > 0): self.place_write_ports() - if(self.num_read > 0): + if(self.num_r_ports > 0): self.place_read_ports() self.extend_well() @@ -68,21 +68,21 @@ class pbitcell(pgate.pgate): self.DRC_LVS() def add_pins(self): - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): self.add_pin("rwbl{}".format(k)) self.add_pin("rwbl_bar{}".format(k)) - for k in range(self.num_write): + for k in range(self.num_w_ports): self.add_pin("wbl{}".format(k)) self.add_pin("wbl_bar{}".format(k)) - for k in range(self.num_read): + for k in range(self.num_r_ports): self.add_pin("rbl{}".format(k)) self.add_pin("rbl_bar{}".format(k)) - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): self.add_pin("rwwl{}".format(k)) - for k in range(self.num_write): + for k in range(self.num_w_ports): self.add_pin("wwl{}".format(k)) - for k in range(self.num_read): + for k in range(self.num_r_ports): self.add_pin("rwl{}".format(k)) self.add_pin("vdd") @@ -90,8 +90,8 @@ class pbitcell(pgate.pgate): def add_modules(self): # if there are any read/write ports, then the inverter nmos is sized based the number of them - if(self.num_readwrite > 0): - inverter_nmos_width = self.num_readwrite*3*parameter["min_tx_size"] + if(self.num_rw_ports > 0): + inverter_nmos_width = self.num_rw_ports*3*parameter["min_tx_size"] inverter_pmos_width = parameter["min_tx_size"] readwrite_nmos_width = 1.5*parameter["min_tx_size"] write_nmos_width = parameter["min_tx_size"] @@ -167,7 +167,7 @@ class pbitcell(pgate.pgate): # write to read transistor spacing (also acts as readwrite to read transistor spacing) # calculation is dependent on whether the read transistor is adjacent to a write transistor or a readwrite transistor - if(self.num_write > 0): + if(self.num_w_ports > 0): if(self.write_nmos_contact_extension > self.gate_contact_thres): write_portion = drc["minwidth_metal2"] + self.write_nmos_contact_extension else: @@ -206,23 +206,23 @@ class pbitcell(pgate.pgate): Calculate positions that describe the edges of the cell """ # create flags for excluding readwrite, write, or read port calculations if they are not included in the bitcell - if(self.num_readwrite > 0): + if(self.num_rw_ports > 0): self.readwrite_port_flag = True else: self.readwrite_port_flag = False - if(self.num_write > 0): + if(self.num_w_ports > 0): self.write_port_flag = True else: self.write_port_flag = False - if(self.num_read > 0): + if(self.num_r_ports > 0): self.read_port_flag = True else: self.read_port_flag = False # determine the distance of the leftmost/rightmost transistor gate connection - if (self.num_read > 0): + if (self.num_r_ports > 0): if(self.read_nmos_contact_extension > self.gate_contact_thres): end_connection = drc["minwidth_metal2"] + self.read_nmos_contact_extension + contact.m1m2.height else: @@ -236,11 +236,11 @@ class pbitcell(pgate.pgate): # leftmost position = storage width + read/write ports width + write ports width + read ports width + end transistor gate connections + metal spacing necessary for tiling the bitcell self.leftmost_xpos = -self.inverter_tile_width \ - self.inverter_to_write_spacing \ - - self.readwrite_port_flag*(self.readwrite_nmos.active_height + (self.num_readwrite-1)*self.readwrite_tile_width) \ + - self.readwrite_port_flag*(self.readwrite_nmos.active_height + (self.num_rw_ports-1)*self.readwrite_tile_width) \ - self.write_port_flag*self.readwrite_port_flag*self.write_to_write_spacing \ - - self.write_port_flag*(self.write_nmos.active_height + (self.num_write-1)*self.write_tile_width) \ + - self.write_port_flag*(self.write_nmos.active_height + (self.num_w_ports-1)*self.write_tile_width) \ - self.read_port_flag*self.write_to_read_spacing \ - - self.read_port_flag*(self.read_nmos.active_height + (self.num_read-1)*self.read_tile_width) \ + - self.read_port_flag*(self.read_nmos.active_height + (self.num_r_ports-1)*self.read_tile_width) \ - end_connection \ - 0.5*drc["poly_to_polycontact"] @@ -249,9 +249,9 @@ class pbitcell(pgate.pgate): # bottommost position = gnd height + rwwl height + wwl height + rwl height + space needed between tiled bitcells array_tiling_offset = 0.5*drc["minwidth_metal2"] self.botmost_ypos = -self.rail_tile_height \ - - self.num_readwrite*self.rowline_tile_height \ - - self.num_write*self.rowline_tile_height \ - - self.num_read*self.rowline_tile_height \ + - self.num_rw_ports*self.rowline_tile_height \ + - self.num_w_ports*self.rowline_tile_height \ + - self.num_r_ports*self.rowline_tile_height \ - array_tiling_offset # topmost position = height of the inverter + height of vdd @@ -390,11 +390,11 @@ class pbitcell(pgate.pgate): """ # define write transistor variables as empty arrays based on the number of write ports - self.readwrite_nmos_left = [None] * self.num_readwrite - self.readwrite_nmos_right = [None] * self.num_readwrite + self.readwrite_nmos_left = [None] * self.num_rw_ports + self.readwrite_nmos_right = [None] * self.num_rw_ports # iterate over the number of read/write ports - for k in range(0,self.num_readwrite): + for k in range(0,self.num_rw_ports): # add read/write transistors self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k), mod=self.readwrite_nmos) @@ -411,15 +411,15 @@ class pbitcell(pgate.pgate): """ # Define variables relevant to write transistors - self.rwwl_positions = [None] * self.num_readwrite - self.rwbl_positions = [None] * self.num_readwrite - self.rwbl_bar_positions = [None] * self.num_readwrite + self.rwwl_positions = [None] * self.num_rw_ports + self.rwbl_positions = [None] * self.num_rw_ports + self.rwbl_bar_positions = [None] * self.num_rw_ports # define offset correction due to rotation of the ptx module readwrite_rotation_correct = self.readwrite_nmos.active_height # iterate over the number of read/write ports - for k in range(0,self.num_readwrite): + for k in range(0,self.num_rw_ports): # Add transistors # calculate read/write transistor offsets left_readwrite_transistor_xpos = self.left_building_edge \ @@ -529,7 +529,7 @@ class pbitcell(pgate.pgate): # Drain/Storage connections # this path only needs to be drawn once on the last iteration of the loop - if(k == self.num_readwrite-1): + if(k == self.num_rw_ports-1): # add contacts to connect gate of inverters to drain of read/write transistors left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x - drc["poly_to_polycontact"] - 0.5*contact.poly.width, self.cross_couple_lower_ypos) self.add_contact_center(layers=("poly", "contact", "metal1"), @@ -580,11 +580,11 @@ class pbitcell(pgate.pgate): write_rotation_correct = self.write_nmos.active_height # define write transistor variables as empty arrays based on the number of write ports - self.write_nmos_left = [None] * self.num_write - self.write_nmos_right = [None] * self.num_write + self.write_nmos_left = [None] * self.num_w_ports + self.write_nmos_right = [None] * self.num_w_ports # iterate over the number of write ports - for k in range(0,self.num_write): + for k in range(0,self.num_w_ports): # add write transistors self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k), mod=self.write_nmos) @@ -601,15 +601,15 @@ class pbitcell(pgate.pgate): """ # Define variables relevant to write transistors - self.wwl_positions = [None] * self.num_write - self.wbl_positions = [None] * self.num_write - self.wbl_bar_positions = [None] * self.num_write + self.wwl_positions = [None] * self.num_w_ports + self.wbl_positions = [None] * self.num_w_ports + self.wbl_bar_positions = [None] * self.num_w_ports # define offset correction due to rotation of the ptx module write_rotation_correct = self.write_nmos.active_height # iterate over the number of write ports - for k in range(0,self.num_write): + for k in range(0,self.num_w_ports): # Add transistors # calculate write transistor offsets left_write_transistor_xpos = self.left_building_edge \ @@ -634,7 +634,7 @@ class pbitcell(pgate.pgate): # Add WWL lines # calculate WWL position wwl_ypos = self.gnd_position.y \ - - self.num_readwrite*self.rowline_tile_height \ + - self.num_rw_ports*self.rowline_tile_height \ - (k+1)*self.rowline_tile_height self.wwl_positions[k] = vector(self.leftmost_xpos, wwl_ypos) @@ -723,7 +723,7 @@ class pbitcell(pgate.pgate): # Drain/Storage connections # this path only needs to be drawn once on the last iteration of the loop - if(k == self.num_write-1): + if(k == self.num_w_ports-1): # add contacts to connect gate of inverters to drain of write transistors left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x - drc["poly_to_polycontact"] - 0.5*contact.poly.width, self.cross_couple_lower_ypos) self.add_contact_center(layers=("poly", "contact", "metal1"), @@ -771,13 +771,13 @@ class pbitcell(pgate.pgate): """ # define read transistor variables as empty arrays based on the number of read ports - self.read_nmos_left = [None] * self.num_read - self.read_nmos_right = [None] * self.num_read - self.read_access_nmos_left = [None] * self.num_read - self.read_access_nmos_right = [None] * self.num_read + self.read_nmos_left = [None] * self.num_r_ports + self.read_nmos_right = [None] * self.num_r_ports + self.read_access_nmos_left = [None] * self.num_r_ports + self.read_access_nmos_right = [None] * self.num_r_ports # iterate over the number of read ports - for k in range(0,self.num_read): + for k in range(0,self.num_r_ports): # add read-access transistors self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k), mod=self.read_nmos) @@ -802,9 +802,9 @@ class pbitcell(pgate.pgate): """ # Define variables relevant to read transistors - self.rwl_positions = [None] * self.num_read - self.rbl_positions = [None] * self.num_read - self.rbl_bar_positions = [None] * self.num_read + self.rwl_positions = [None] * self.num_r_ports + self.rbl_positions = [None] * self.num_r_ports + self.rbl_bar_positions = [None] * self.num_r_ports # define offset correction due to rotation of the ptx module read_rotation_correct = self.read_nmos.active_height @@ -813,7 +813,7 @@ class pbitcell(pgate.pgate): overlap_offset = self.read_nmos.get_pin("D").ll() - self.read_nmos.get_pin("S").ll() # iterate over the number of read ports - for k in range(0,self.num_read): + for k in range(0,self.num_r_ports): # Add transistors # calculate transistor offsets left_read_transistor_xpos = self.left_building_edge \ @@ -843,8 +843,8 @@ class pbitcell(pgate.pgate): # Add RWL lines # calculate RWL position rwl_ypos = self.gnd_position.y \ - - self.num_readwrite*self.rowline_tile_height \ - - self.num_write*self.rowline_tile_height \ + - self.num_rw_ports*self.rowline_tile_height \ + - self.num_w_ports*self.rowline_tile_height \ - (k+1)*self.rowline_tile_height self.rwl_positions[k] = vector(self.leftmost_xpos, rwl_ypos) @@ -1003,7 +1003,7 @@ class pbitcell(pgate.pgate): # extend pwell over read/write and write transistors to the # height of the write transistor well (read/write and write # transistors are the same height) - if(self.num_write > 0): + if(self.num_w_ports > 0): # calculate the edge of the write transistor well closest to the center left_write_well_xpos = self.write_nmos_left[0].offset.x + drc["well_enclosure_active"] right_write_well_xpos = self.write_nmos_right[0].offset.x - self.write_nmos.active_height - drc["well_enclosure_active"] @@ -1029,7 +1029,7 @@ class pbitcell(pgate.pgate): height=write_well_height) # extend pwell over the read transistors to the height of the bitcell - if(self.num_read > 0): + if(self.num_r_ports > 0): # calculate the edge of the read transistor well clostest to the center left_read_well_xpos = self.read_nmos_left[0].offset.x + drc["well_enclosure_active"] right_read_well_xpos = self.read_nmos_right[0].offset.x - self.read_nmos.active_height - drc["well_enclosure_active"] @@ -1088,20 +1088,20 @@ class pbitcell(pgate.pgate): def list_bitcell_pins(self, col, row): """ Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """ bitcell_pins = [] - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): bitcell_pins.append("rwbl{0}[{1}]".format(k,col)) bitcell_pins.append("rwbl_bar{0}[{1}]".format(k,col)) - for k in range(self.num_write): + for k in range(self.num_w_ports): bitcell_pins.append("wbl{0}[{1}]".format(k,col)) bitcell_pins.append("wbl_bar{0}[{1}]".format(k,col)) - for k in range(self.num_read): + for k in range(self.num_r_ports): bitcell_pins.append("rbl{0}[{1}]".format(k,col)) bitcell_pins.append("rbl_bar{0}[{1}]".format(k,col)) - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): bitcell_pins.append("rwwl{0}[{1}]".format(k,row)) - for k in range(self.num_write): + for k in range(self.num_w_ports): bitcell_pins.append("wwl{0}[{1}]".format(k,row)) - for k in range(self.num_read): + for k in range(self.num_r_ports): bitcell_pins.append("rwl{0}[{1}]".format(k,row)) bitcell_pins.append("vdd") bitcell_pins.append("gnd") @@ -1111,11 +1111,11 @@ class pbitcell(pgate.pgate): def list_all_wl_names(self): """ Creates a list of all wordline pin names """ row_pins = [] - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): row_pins.append("rwwl{0}".format(k)) - for k in range(self.num_write): + for k in range(self.num_w_ports): row_pins.append("wwl{0}".format(k)) - for k in range(self.num_read): + for k in range(self.num_r_ports): row_pins.append("rwl{0}".format(k)) return row_pins @@ -1123,9 +1123,9 @@ class pbitcell(pgate.pgate): def list_read_wl_names(self): """ Creates a list of wordline pin names associated with read ports """ row_pins = [] - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): row_pins.append("rwwl{0}".format(k)) - for k in range(self.num_read): + for k in range(self.num_r_ports): row_pins.append("rwl{0}".format(k)) return row_pins @@ -1133,9 +1133,9 @@ class pbitcell(pgate.pgate): def list_write_wl_names(self): """ Creates a list of wordline pin names associated with write ports """ row_pins = [] - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): row_pins.append("rwwl{0}".format(k)) - for k in range(self.num_write): + for k in range(self.num_w_ports): row_pins.append("wwl{0}".format(k)) return row_pins @@ -1144,13 +1144,13 @@ class pbitcell(pgate.pgate): def list_all_bitline_names(self): """ Creates a list of all bitline pin names (both bl and br) """ column_pins = [] - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): column_pins.append("rwbl{0}".format(k)) column_pins.append("rwbl_bar{0}".format(k)) - for k in range(self.num_write): + for k in range(self.num_w_ports): column_pins.append("wbl{0}".format(k)) column_pins.append("wbl_bar{0}".format(k)) - for k in range(self.num_read): + for k in range(self.num_r_ports): column_pins.append("rbl{0}".format(k)) column_pins.append("rbl_bar{0}".format(k)) @@ -1159,11 +1159,11 @@ class pbitcell(pgate.pgate): def list_all_bl_names(self): """ Creates a list of all bl pins names """ column_pins = [] - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): column_pins.append("rwbl{0}".format(k)) - for k in range(self.num_write): + for k in range(self.num_w_ports): column_pins.append("wbl{0}".format(k)) - for k in range(self.num_read): + for k in range(self.num_r_ports): column_pins.append("rbl{0}".format(k)) return column_pins @@ -1171,11 +1171,11 @@ class pbitcell(pgate.pgate): def list_all_br_names(self): """ Creates a list of all br pins names """ column_pins = [] - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): column_pins.append("rwbl_bar{0}".format(k)) - for k in range(self.num_write): + for k in range(self.num_w_ports): column_pins.append("wbl_bar{0}".format(k)) - for k in range(self.num_read): + for k in range(self.num_r_ports): column_pins.append("rbl_bar{0}".format(k)) return column_pins @@ -1183,9 +1183,9 @@ class pbitcell(pgate.pgate): def list_read_bl_names(self): """ Creates a list of bl pin names associated with read ports """ column_pins = [] - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): column_pins.append("rwbl{0}".format(k)) - for k in range(self.num_read): + for k in range(self.num_r_ports): column_pins.append("rbl{0}".format(k)) return column_pins @@ -1193,9 +1193,9 @@ class pbitcell(pgate.pgate): def list_read_br_names(self): """ Creates a list of br pin names associated with read ports """ column_pins = [] - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): column_pins.append("rwbl_bar{0}".format(k)) - for k in range(self.num_read): + for k in range(self.num_r_ports): column_pins.append("rbl_bar{0}".format(k)) return column_pins @@ -1203,9 +1203,9 @@ class pbitcell(pgate.pgate): def list_write_bl_names(self): """ Creates a list of bl pin names associated with write ports """ column_pins = [] - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): column_pins.append("rwbl{0}".format(k)) - for k in range(self.num_write): + for k in range(self.num_w_ports): column_pins.append("wbl{0}".format(k)) return column_pins @@ -1213,9 +1213,9 @@ class pbitcell(pgate.pgate): def list_write_br_names(self): """ Creates a list of br pin names asscociated with write ports""" column_pins = [] - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): column_pins.append("rwbl_bar{0}".format(k)) - for k in range(self.num_write): + for k in range(self.num_w_ports): column_pins.append("wbl_bar{0}".format(k)) return column_pins diff --git a/compiler/sram.py b/compiler/sram.py index 653a3a03..3891150b 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -3,7 +3,7 @@ import datetime import getpass import debug from globals import OPTS, print_time - +from sram_config import sram_config class sram(): """ @@ -12,31 +12,31 @@ class sram(): results. We can later add visualizer and other high-level functions as needed. """ - def __init__(self, word_size, num_words, num_banks, name): + def __init__(self, sram_config, name="sram"): + sram_config.set_local_config(self) + # reset the static duplicate name checker for unit tests # in case we create more than one SRAM from design import design design.name_map=[] - debug.info(2, "create sram of size {0} with {1} num of words".format(word_size, - num_words)) + debug.info(2, "create sram of size {0} with {1} num of words {2} banks".format(self.word_size, + self.num_words, + self.num_banks)) start_time = datetime.datetime.now() self.name = name - - if num_banks == 1: - from sram_1bank import sram_1bank - self.s=sram_1bank(word_size, num_words, name) - elif num_banks == 2: - from sram_2bank import sram_2bank - self.s=sram_2bank(word_size, num_words, name) - elif num_banks == 4: - from sram_4bank import sram_4bank - self.s=sram_4bank(word_size, num_words, name) + if self.num_banks == 1: + from sram_1bank import sram_1bank as sram + elif self.num_banks == 2: + from sram_2bank import sram_2bank as sram + elif self.num_banks == 4: + from sram_4bank import sram_4bank as sram else: debug.error("Invalid number of banks.",-1) - + + self.s = sram(sram_config, name) self.s.create_netlist() if not OPTS.netlist_only: self.s.create_layout() diff --git a/compiler/sram_1bank.py b/compiler/sram_1bank.py index 93903551..d7ea47fb 100644 --- a/compiler/sram_1bank.py +++ b/compiler/sram_1bank.py @@ -18,8 +18,9 @@ class sram_1bank(sram_base): """ Procedures specific to a one bank SRAM. """ - def __init__(self, word_size, num_words, name): - sram_base.__init__(self, word_size, num_words, 1, name) + def __init__(self, sram_config, name): + sram_base.__init__(self, sram_config, name) + def create_netlist(self): self.compute_sizes() @@ -99,18 +100,18 @@ class sram_1bank(sram_base): for i in range(self.word_size): dout_name = "dout0[{}]".format(i) - self.copy_layout_pin(self.bank_inst, dout_name, "DOUT[{}]".format(i)) + self.copy_layout_pin(self.bank_inst, dout_name, "DOUT0[{}]".format(i)) # Lower address bits for i in range(self.col_addr_size): - self.copy_layout_pin(self.col_addr_dff_inst, "din[{}]".format(i),"ADDR[{}]".format(i)) + self.copy_layout_pin(self.col_addr_dff_inst, "din[{}]".format(i),"ADDR0[{}]".format(i)) # Upper address bits for i in range(self.row_addr_size): - self.copy_layout_pin(self.row_addr_dff_inst, "din[{}]".format(i),"ADDR[{}]".format(i+self.col_addr_size)) + self.copy_layout_pin(self.row_addr_dff_inst, "din[{}]".format(i),"ADDR0[{}]".format(i+self.col_addr_size)) for i in range(self.word_size): din_name = "din[{}]".format(i) - self.copy_layout_pin(self.data_dff_inst, din_name, din_name.upper()) + self.copy_layout_pin(self.data_dff_inst, din_name, "DIN0[{}]".format(i)) def route(self): """ Route a single bank SRAM """ diff --git a/compiler/sram_2bank.py b/compiler/sram_2bank.py index ba10525c..ff0d7868 100644 --- a/compiler/sram_2bank.py +++ b/compiler/sram_2bank.py @@ -16,8 +16,8 @@ class sram_2bank(sram_base): """ Procedures specific to a two bank SRAM. """ - def __init__(self, word_size, num_words, name): - sram_base.__init__(self, word_size, num_words, 2, name) + def __init__(self, sram_config, name): + sram_base.__init__(self, sram_config, name) def compute_bank_offsets(self): """ Compute the overall offsets for a two bank SRAM """ diff --git a/compiler/sram_4bank.py b/compiler/sram_4bank.py index 14e597d5..64163e9f 100644 --- a/compiler/sram_4bank.py +++ b/compiler/sram_4bank.py @@ -16,8 +16,8 @@ class sram_4bank(sram_base): """ Procedures specific to a four bank SRAM. """ - def __init__(self, word_size, num_words, name): - sram_base.__init__(self, word_size, num_words, 4, name) + def __init__(self, sram_config, name): + sram_base.__init__(self, sram_config, name) def compute_bank_offsets(self): """ Compute the overall offsets for a four bank SRAM """ diff --git a/compiler/sram_base.py b/compiler/sram_base.py index ae4f1abe..d3122063 100644 --- a/compiler/sram_base.py +++ b/compiler/sram_base.py @@ -2,6 +2,7 @@ import sys import datetime import getpass import debug +from importlib import reload from math import log,sqrt,ceil from vector import vector from globals import OPTS, print_time @@ -13,28 +14,17 @@ class sram_base(design): Dynamically generated SRAM by connecting banks to control logic. The number of banks should be 1 , 2 or 4 """ - def __init__(self, word_size, num_words, num_banks, name): + def __init__(self, sram_config, name): design.__init__(self, name) - - from importlib import reload - c = reload(__import__(OPTS.control_logic)) - self.mod_control_logic = getattr(c, OPTS.control_logic) + # This is used to compute the sizes of the SRAM + # and must be loaded before netlist creation c = reload(__import__(OPTS.bitcell)) self.mod_bitcell = getattr(c, OPTS.bitcell) self.bitcell = self.mod_bitcell() - c = reload(__import__(OPTS.ms_flop)) - self.mod_ms_flop = getattr(c, OPTS.ms_flop) - self.ms_flop = self.mod_ms_flop() - - self.word_size = word_size - self.num_words = num_words - self.num_banks = num_banks - - self.total_write = OPTS.rw_ports + OPTS.w_ports - self.total_read = OPTS.rw_ports + OPTS.r_ports - self.total_ports = OPTS.rw_ports + OPTS.w_ports + OPTS.r_ports + self.sram_config = sram_config + self.sram_config.set_local_config(self) self.bank_insts = [] @@ -45,18 +35,22 @@ class sram_base(design): 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 self.sram_config.words_per_row: + self.words_per_row = self.sram_config.words_per_row + else: + # Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry) + self.bank_area = self.bitcell.width*self.bitcell.height*self.num_bits_per_bank + self.bank_side_length = sqrt(self.bank_area) - # Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry) - self.bank_area = self.bitcell.width*self.bitcell.height*self.num_bits_per_bank - self.bank_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/self.bitcell.width) + self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size) - # Estimate the words per row given the height of the bitcell and the square side length - self.tentative_num_cols = int(self.bank_side_length/self.bitcell.width) - self.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.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row) + # 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.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row) # Fix the number of columns and rows self.num_cols = int(self.words_per_row*self.word_size) @@ -67,7 +61,8 @@ class sram_base(design): 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)) - + + self.sram_config.words_per_row = self.words_per_row debug.info(1,"Words per row: {}".format(self.words_per_row)) def estimate_words_per_row(self,tentative_num_cols, word_size): @@ -279,7 +274,15 @@ class sram_base(design): def add_modules(self): """ Create all the modules that will be used """ + + c = reload(__import__(OPTS.control_logic)) + self.mod_control_logic = getattr(c, OPTS.control_logic) + c = reload(__import__(OPTS.ms_flop)) + self.mod_ms_flop = getattr(c, OPTS.ms_flop) + self.ms_flop = self.mod_ms_flop() + + from control_logic import control_logic # Create the control logic module self.control_logic = self.mod_control_logic(num_rows=self.num_rows) @@ -301,10 +304,7 @@ class sram_base(design): # Create the bank module (up to four are instantiated) from bank import bank - self.bank = bank(word_size=self.word_size, - num_words=self.num_words_per_bank, - words_per_row=self.words_per_row, - num_banks=self.num_banks, + self.bank = bank(self.sram_config, name="bank") self.add_mod(self.bank) diff --git a/compiler/sram_config.py b/compiler/sram_config.py new file mode 100644 index 00000000..e7c58905 --- /dev/null +++ b/compiler/sram_config.py @@ -0,0 +1,36 @@ +from globals import OPTS + +class sram_config: + """ This is a structure that is used to hold the SRAM configuration options. """ + + def __init__(self, word_size, num_words, num_banks=1, num_rw_ports=OPTS.num_rw_ports, num_w_ports=OPTS.num_w_ports, num_r_ports=OPTS.num_r_ports): + self.word_size = word_size + self.num_words = num_words + self.num_banks = num_banks + self.num_rw_ports = num_rw_ports + self.num_w_ports = num_w_ports + self.num_r_ports = num_r_ports + + # This will get over-written when we determine the organization + self.num_banks = 1 + self.words_per_row = None + + self.total_write = num_rw_ports + num_w_ports + self.total_read = num_rw_ports + num_r_ports + self.total_ports = num_rw_ports + num_w_ports + num_r_ports + + + def set_local_config(self, module): + module.word_size = self.word_size + module.num_words = self.num_words + module.num_banks = self.num_banks + module.num_rw_ports = self.num_rw_ports + module.num_w_ports = self.num_w_ports + module.num_r_ports = self.num_r_ports + + module.words_per_row = self.words_per_row + + module.total_write = self.total_write + module.total_read = self.total_read + module.total_ports = self.total_ports + diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py index 0f74b42a..070637f9 100755 --- a/compiler/tests/04_pbitcell_test.py +++ b/compiler/tests/04_pbitcell_test.py @@ -22,43 +22,43 @@ class pbitcell_test(openram_test): import tech debug.info(2, "Bitcell with 1 of each port: read/write, write, and read") - tx = pbitcell.pbitcell(num_readwrite=1,num_write=1,num_read=1) + tx = pbitcell.pbitcell(num_rw_ports=1,num_w_ports=1,num_r_ports=1) self.local_check(tx) debug.info(2, "Bitcell with 0 read/write ports") - tx = pbitcell.pbitcell(num_readwrite=0,num_write=1,num_read=1) + tx = pbitcell.pbitcell(num_rw_ports=0,num_w_ports=1,num_r_ports=1) self.local_check(tx) debug.info(2, "Bitcell with 0 write ports") - tx = pbitcell.pbitcell(num_readwrite=1,num_write=0,num_read=1) + tx = pbitcell.pbitcell(num_rw_ports=1,num_w_ports=0,num_r_ports=1) self.local_check(tx) debug.info(2, "Bitcell with 0 read ports") - tx = pbitcell.pbitcell(num_readwrite=1,num_write=1,num_read=0) + tx = pbitcell.pbitcell(num_rw_ports=1,num_w_ports=1,num_r_ports=0) self.local_check(tx) debug.info(2, "Bitcell with 0 read ports and 0 write ports") - tx = pbitcell.pbitcell(num_readwrite=1,num_write=0,num_read=0) + tx = pbitcell.pbitcell(num_rw_ports=1,num_w_ports=0,num_r_ports=0) self.local_check(tx) debug.info(2, "Bitcell with 2 of each port: read/write, write, and read") - tx = pbitcell.pbitcell(num_readwrite=2,num_write=2,num_read=2) + tx = pbitcell.pbitcell(num_rw_ports=2,num_w_ports=2,num_r_ports=2) self.local_check(tx) debug.info(2, "Bitcell with 0 read/write ports") - tx = pbitcell.pbitcell(num_readwrite=0,num_write=2,num_read=2) + tx = pbitcell.pbitcell(num_rw_ports=0,num_w_ports=2,num_r_ports=2) self.local_check(tx) debug.info(2, "Bitcell with 0 write ports") - tx = pbitcell.pbitcell(num_readwrite=2,num_write=0,num_read=2) + tx = pbitcell.pbitcell(num_rw_ports=2,num_w_ports=0,num_r_ports=2) self.local_check(tx) debug.info(2, "Bitcell with 0 read ports") - tx = pbitcell.pbitcell(num_readwrite=2,num_write=2,num_read=0) + tx = pbitcell.pbitcell(num_rw_ports=2,num_w_ports=2,num_r_ports=0) self.local_check(tx) debug.info(2, "Bitcell with 0 read ports and 0 write ports") - tx = pbitcell.pbitcell(num_readwrite=2,num_write=0,num_read=0) + tx = pbitcell.pbitcell(num_rw_ports=2,num_w_ports=0,num_r_ports=0) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_precharge_test.py b/compiler/tests/04_precharge_test.py index bcf11473..8e44aa52 100755 --- a/compiler/tests/04_precharge_test.py +++ b/compiler/tests/04_precharge_test.py @@ -24,9 +24,9 @@ class precharge_test(openram_test): debug.info(2, "Checking precharge for pbitcell") OPTS.bitcell = "pbitcell" - OPTS.rw_ports = 2 - OPTS.r_ports = 2 - OPTS.w_ports = 2 + OPTS.num_rw_ports = 2 + OPTS.num_r_ports = 2 + OPTS.num_w_ports = 2 tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="rwbl0", bitcell_br="rwbl_bar0") self.local_check(tx) diff --git a/compiler/tests/05_pbitcell_array_test.py b/compiler/tests/05_pbitcell_array_test.py index ad13cfbd..4fc75ac5 100755 --- a/compiler/tests/05_pbitcell_array_test.py +++ b/compiler/tests/05_pbitcell_array_test.py @@ -20,25 +20,25 @@ class pbitcell_array_test(openram_test): debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell") OPTS.bitcell = "pbitcell" - OPTS.rw_ports = 2 - OPTS.r_ports = 2 - OPTS.w_ports = 2 + OPTS.num_rw_ports = 2 + OPTS.num_r_ports = 2 + OPTS.num_w_ports = 2 a = bitcell_array.bitcell_array(name="pbitcell_array_Rport_edge", cols=4, rows=4) self.local_check(a) debug.info(2, "Testing 4x4 array for multiport bitcell, with write ports at the edge of the bit cell") OPTS.bitcell = "pbitcell" - OPTS.rw_ports = 2 - OPTS.r_ports = 0 - OPTS.w_ports = 2 + OPTS.num_rw_ports = 2 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 2 a = bitcell_array.bitcell_array(name="pbitcell_array_Wport_edge", cols=4, rows=4) self.local_check(a) debug.info(2, "Testing 4x4 array for multiport bitcell, with read/write ports at the edge of the bit cell") OPTS.bitcell = "pbitcell" - OPTS.rw_ports = 2 - OPTS.r_ports = 0 - OPTS.w_ports = 0 + OPTS.num_rw_ports = 2 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 a = bitcell_array.bitcell_array(name="pbitcell_array_RWport_edge", cols=4, rows=4) self.local_check(a) diff --git a/compiler/tests/08_precharge_array_test.py b/compiler/tests/08_precharge_array_test.py index 9592b6c5..49530410 100755 --- a/compiler/tests/08_precharge_array_test.py +++ b/compiler/tests/08_precharge_array_test.py @@ -24,9 +24,9 @@ class precharge_test(openram_test): debug.info(2, "Checking precharge for pbitcell") OPTS.bitcell = "pbitcell" - OPTS.rw_ports = 2 - OPTS.r_ports = 2 - OPTS.w_ports = 2 + OPTS.num_rw_ports = 2 + OPTS.num_r_ports = 2 + OPTS.num_w_ports = 2 pc = precharge_array.precharge_array(columns=3, bitcell_bl="rwbl0", bitcell_br="rwbl_bar0") self.local_check(pc) diff --git a/compiler/tests/08_wordline_driver_test.py b/compiler/tests/08_wordline_driver_test.py index 1e0ae018..3a19a2ec 100644 --- a/compiler/tests/08_wordline_driver_test.py +++ b/compiler/tests/08_wordline_driver_test.py @@ -27,9 +27,9 @@ class wordline_driver_test(openram_test): # check wordline driver array in multi-port OPTS.bitcell = "pbitcell" - OPTS.rw_ports = 1 - OPTS.w_ports = 0 - OPTS.r_ports = 0 + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 0 + OPTS.num_r_ports = 0 debug.info(2, "Checking driver (multi-port case)") tx = wordline_driver.wordline_driver(rows=8) diff --git a/compiler/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py index a85a1ea3..f6f9e14f 100644 --- a/compiler/tests/09_sense_amp_array_test.py +++ b/compiler/tests/09_sense_amp_array_test.py @@ -28,9 +28,9 @@ class sense_amp_test(openram_test): # check sense amp array in multi-port OPTS.bitcell = "pbitcell" - OPTS.rw_ports = 1 - OPTS.w_ports = 0 - OPTS.r_ports = 0 + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 0 + OPTS.num_r_ports = 0 debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)") a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2) diff --git a/compiler/tests/10_write_driver_array_test.py b/compiler/tests/10_write_driver_array_test.py index 9c68cf5f..67978f11 100644 --- a/compiler/tests/10_write_driver_array_test.py +++ b/compiler/tests/10_write_driver_array_test.py @@ -28,9 +28,9 @@ class write_driver_test(openram_test): # check write driver array in multi-port OPTS.bitcell = "pbitcell" - OPTS.rw_ports = 1 - OPTS.w_ports = 0 - OPTS.r_ports = 0 + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 0 + OPTS.num_r_ports = 0 debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)") a = write_driver_array.write_driver_array(columns=8, word_size=8) diff --git a/compiler/tests/19_multi_bank_test.py b/compiler/tests/19_multi_bank_test.py index 2169dcf1..9bab2a4f 100755 --- a/compiler/tests/19_multi_bank_test.py +++ b/compiler/tests/19_multi_bank_test.py @@ -16,21 +16,34 @@ class multi_bank_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) from bank import bank + from sram_config import sram_config + c = sram_config(word_size=4, + num_words=16) + c.num_banks=2 + + c.words_per_row=1 debug.info(1, "No column mux") - a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=2, name="bank1_multi") + a = bank(c, name="bank1_multi") self.local_check(a) + c.num_words=32 + c.words_per_row=2 debug.info(1, "Two way column mux") - a = bank(word_size=4, num_words=32, words_per_row=2, num_banks=2, name="bank2_multi") + a = bank(c, name="bank2_multi") self.local_check(a) + c.num_words=64 + c.words_per_row=4 debug.info(1, "Four way column mux") - a = bank(word_size=4, num_words=64, words_per_row=4, num_banks=2, name="bank3_multi") + a = bank(c, name="bank3_multi") self.local_check(a) + c.word_size=2 + c.num_words=128 + c.words_per_row=8 debug.info(1, "Eight way column mux") - a = bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="bank4_multi") + a = bank(c, name="bank4_multi") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/19_psingle_bank_test.py b/compiler/tests/19_psingle_bank_test.py index 45745b2f..bdb64f9e 100644 --- a/compiler/tests/19_psingle_bank_test.py +++ b/compiler/tests/19_psingle_bank_test.py @@ -20,80 +20,103 @@ class psingle_bank_test(openram_test): import verify from bank import bank + from sram_config import sram_config OPTS.bitcell = "pbitcell" # testing layout of bank using pbitcell with 1 RW port (a 6T-cell equivalent) - OPTS.rw_ports = 1 - OPTS.w_ports = 0 - OPTS.r_ports = 0 - + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 0 + OPTS.num_r_ports = 0 + c = sram_config(word_size=4, + num_words=16) + c.words_per_row=1 debug.info(1, "No column mux") - a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_1rw_0w_0r_single") + a = bank(c, name="bank1_1rw_0w_0r_single") self.local_check(a) - """ - # testing all port configurations (with no column mux) to verify layout between bitcell array and peripheral circuitry - OPTS.rw_ports = 2 - OPTS.w_ports = 2 - OPTS.r_ports = 2 - # multiport can't generate layout yet on the bank level OPTS.netlist_only = True - debug.info(1, "No column mux") - a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_2rw_2w_2r_single") - self.local_check(a) - """ + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 1 + OPTS.num_r_ports = 1 - """ - OPTS.rw_ports = 0 - OPTS.w_ports = 2 - OPTS.r_ports = 2 - debug.info(1, "No column mux") - a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_0rw_2w_2r_single") + name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports) + a = bank(c, name=name) self.local_check(a) - OPTS.rw_ports = 2 - OPTS.w_ports = 0 - OPTS.r_ports = 2 + OPTS.num_rw_ports = c.num_rw_ports = 2 + OPTS.num_w_ports = c.num_w_ports = 2 + OPTS.num_r_ports = c.num_r_ports = 2 debug.info(1, "No column mux") - a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_2rw_0w_2r_single") + name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports) + a = bank(c, name=name) + self.local_check(a) + + OPTS.num_rw_ports = c.num_rw_ports = 0 + OPTS.num_w_ports = c.num_w_ports = 2 + OPTS.num_r_ports = c.num_r_ports = 2 + + debug.info(1, "No column mux") + name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports) + a = bank(c, name=name) self.local_check(a) - OPTS.rw_ports = 2 - OPTS.w_ports = 2 - OPTS.r_ports = 0 + OPTS.num_rw_ports = c.num_rw_ports = 2 + OPTS.num_w_ports = c.num_w_ports = 0 + OPTS.num_r_ports = c.num_r_ports = 2 debug.info(1, "No column mux") - a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_2rw_2w_0r_single") + name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports) + a = bank(c, name=name) self.local_check(a) - OPTS.rw_ports = 2 - OPTS.w_ports = 0 - OPTS.r_ports = 0 + OPTS.num_rw_ports = c.num_rw_ports = 2 + OPTS.num_w_ports = c.num_w_ports = 2 + OPTS.num_r_ports = c.num_r_ports = 0 debug.info(1, "No column mux") - a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_2rw_0w_0r_single") + name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports) + a = bank(c, name=name) + self.local_check(a) + + OPTS.num_rw_ports = c.num_rw_ports = 2 + OPTS.num_w_ports = c.num_w_ports = 0 + OPTS.num_r_ports = c.num_r_ports = 0 + + debug.info(1, "No column mux") + name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports) + a = bank(c, name=name) self.local_check(a) # testing with various column muxes - OPTS.rw_ports = 2 - OPTS.w_ports = 2 - OPTS.r_ports = 2 + OPTS.num_rw_ports = c.num_rw_ports = 2 + OPTS.num_w_ports = c.num_w_ports = 2 + OPTS.num_r_ports = c.num_r_ports = 2 + c.num_words=32 + c.words_per_row=2 debug.info(1, "Two way column mux") - a = bank(word_size=4, num_words=32, words_per_row=2, num_banks=1, name="bank2_single") + name = "bank2_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports) + a = bank(c, name=name) self.local_check(a) + c.num_words=64 + c.words_per_row=4 debug.info(1, "Four way column mux") - a = bank(word_size=4, num_words=64, words_per_row=4, num_banks=1, name="bank3_single") + name = "bank3_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports) + a = bank(c, name=name) self.local_check(a) # Eight way has a short circuit of one column mux select to gnd rail + c.word_size=2 + c.num_words=128 + c.words_per_row=8 debug.info(1, "Eight way column mux") - a = bank(word_size=2, num_words=128, words_per_row=8, num_banks=1, name="bank4_single") + name = "bank4_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports) + a = bank(c, name=name) self.local_check(a) """ diff --git a/compiler/tests/19_single_bank_test.py b/compiler/tests/19_single_bank_test.py index 25567e82..3c32b30d 100755 --- a/compiler/tests/19_single_bank_test.py +++ b/compiler/tests/19_single_bank_test.py @@ -16,22 +16,34 @@ class single_bank_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) from bank import bank + from sram_config import sram_config + c = sram_config(word_size=4, + num_words=16) + + c.words_per_row=1 debug.info(1, "No column mux") - a = bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1_single") - self.local_check(a) - - debug.info(1, "Two way column mux") - a = bank(word_size=4, num_words=32, words_per_row=2, num_banks=1, name="bank2_single") + a = bank(c, name="bank1_single") self.local_check(a) + c.num_words=32 + c.words_per_row=2 + debug.info(1, "Two way column mux") + a = bank(c, name="bank2_single") + self.local_check(a) + + c.num_words=64 + c.words_per_row=4 debug.info(1, "Four way column mux") - a = bank(word_size=4, num_words=64, words_per_row=4, num_banks=1, name="bank3_single") + a = bank(c, name="bank3_single") self.local_check(a) # Eight way has a short circuit of one column mux select to gnd rail + c.word_size=2 + c.num_words=128 + c.words_per_row=8 debug.info(1, "Eight way column mux") - a = bank(word_size=2, num_words=128, words_per_row=8, num_banks=1, name="bank4_single") + a = bank(c, name="bank4_single") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/20_sram_1bank_test.py b/compiler/tests/20_sram_1bank_test.py index 7079b715..ad5732a6 100755 --- a/compiler/tests/20_sram_1bank_test.py +++ b/compiler/tests/20_sram_1bank_test.py @@ -16,22 +16,33 @@ class sram_1bank_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) from sram import sram - + from sram_config import sram_config + c = sram_config(word_size=4, + num_words=16, + num_banks=1) + debug.info(1, "Single bank, no column mux with control logic") - a = sram(word_size=4, num_words=16, num_banks=1, name="sram1") + a = sram(c, name="sram1") self.local_check(a, final_verification=True) - # debug.info(1, "Single bank two way column mux with control logic") - # a = sram(word_size=4, num_words=32, num_banks=1, name="sram2") - # self.local_check(a, final_verification=True) + c.num_words=32 + c.words_per_row=2 + debug.info(1, "Single bank two way column mux with control logic") + a = sram(c, name="sram2") + self.local_check(a, final_verification=True) - # debug.info(1, "Single bank, four way column mux with control logic") - # a = sram(word_size=4, num_words=64, num_banks=1, name="sram3") - # self.local_check(a, final_verification=True) + c.num_words=64 + c.words_per_row=4 + debug.info(1, "Single bank, four way column mux with control logic") + a = sram(c, name="sram3") + self.local_check(a, final_verification=True) - # debug.info(1, "Single bank, eight way column mux with control logic") - # a = sram(word_size=2, num_words=128, num_banks=1, name="sram4") - # self.local_check(a, final_verification=True) + c.word_size=2 + c.num_words=128 + c.words_per_row=8 + debug.info(1, "Single bank, eight way column mux with control logic") + a = sram(c, name="sram4") + self.local_check(a, final_verification=True) globals.end_openram() diff --git a/compiler/tests/20_sram_2bank_test.py b/compiler/tests/20_sram_2bank_test.py index 00be14df..fd701860 100755 --- a/compiler/tests/20_sram_2bank_test.py +++ b/compiler/tests/20_sram_2bank_test.py @@ -17,21 +17,32 @@ class sram_2bank_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) from sram import sram + from sram_config import sram_config + c = sram_config(word_size=16, + num_words=32, + num_banks=2) debug.info(1, "Two bank, no column mux with control logic") - a = sram(word_size=16, num_words=32, num_banks=2, name="sram1") + a = sram(c, name="sram1") self.local_check(a, final_verification=True) + c.num_words=64 + c.words_per_row=2 debug.info(1, "Two bank two way column mux with control logic") - a = sram(word_size=16, num_words=64, num_banks=2, name="sram2") + a = sram(c, name="sram2") self.local_check(a, final_verification=True) + c.num_words=128 + c.words_per_row=4 debug.info(1, "Two bank, four way column mux with control logic") - a = sram(word_size=16, num_words=128, num_banks=2, name="sram3") + a = sram(c, name="sram3") self.local_check(a, final_verification=True) + c.word_size=2 + c.num_words=256 + c.words_per_row=8 debug.info(1, "Two bank, eight way column mux with control logic") - a = sram(word_size=2, num_words=256, num_banks=2, name="sram4") + a = sram(c, name="sram4") self.local_check(a, final_verification=True) globals.end_openram() diff --git a/compiler/tests/20_sram_4bank_test.py b/compiler/tests/20_sram_4bank_test.py index e4a28090..19937d04 100755 --- a/compiler/tests/20_sram_4bank_test.py +++ b/compiler/tests/20_sram_4bank_test.py @@ -17,19 +17,30 @@ class sram_4bank_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) from sram import sram + from sram_config import sram_config + c = sram_config(word_size=16, + num_words=64, + num_banks=4) debug.info(1, "Four bank, no column mux with control logic") - a = sram(word_size=16, num_words=64, num_banks=4, name="sram1") + a = sram(c, name="sram1") self.local_check(a, final_verification=True) + c.num_words=128 + c.words_per_row=2 debug.info(1, "Four bank two way column mux with control logic") - a = sram(word_size=16, num_words=128, num_banks=4, name="sram2") + a = sram(c, name="sram2") self.local_check(a, final_verification=True) + c.num_words=256 + c.words_per_row=4 debug.info(1, "Four bank, four way column mux with control logic") a = sram(word_size=16, num_words=256, num_banks=4, name="sram3") self.local_check(a, final_verification=True) + c.word_size=2 + c.num_words=256 + c.words_per_row=8 debug.info(1, "Four bank, eight way column mux with control logic") a = sram.sram(word_size=2, num_words=256, num_banks=4, name="sram4") self.local_check(a, final_verification=True) diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index dd2d14de..cfcf3173 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -27,14 +27,14 @@ class timing_sram_test(openram_test): if not OPTS.spice_exe: debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) - import sram - import tech - debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") - s = sram.sram(word_size=OPTS.word_size, - num_words=OPTS.num_words, - num_banks=OPTS.num_banks, - name="sram1") + from sram import sram + from sram_config import sram_config + c = sram_config(word_size=1, + num_words=16, + num_banks=1) + debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") + s = sram(c, name="sram1") tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py index cd41c798..02557d96 100755 --- a/compiler/tests/21_ngspice_delay_test.py +++ b/compiler/tests/21_ngspice_delay_test.py @@ -27,13 +27,14 @@ class timing_sram_test(openram_test): if not OPTS.spice_exe: debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) - import sram - import tech + from sram import sram + from sram_config import sram_config + c = sram_config(word_size=1, + num_words=16, + num_banks=1) + debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") - s = sram.sram(word_size=OPTS.word_size, - num_words=OPTS.num_words, - num_banks=OPTS.num_banks, - name="sram1") + s = sram(c, name="sram1") tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) diff --git a/compiler/tests/23_lib_sram_model_test.py b/compiler/tests/23_lib_sram_model_test.py index 5d1d641c..cec8b85a 100755 --- a/compiler/tests/23_lib_sram_model_test.py +++ b/compiler/tests/23_lib_sram_model_test.py @@ -16,15 +16,16 @@ class lib_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - import sram from characterizer import lib + from sram import sram + from sram_config import sram_config + c = sram_config(word_size=2, + num_words=16, + num_banks=1) + + debug.info(1, "Testing analytical timing for sample 2 bit, 16 words SRAM with 1 bank") + s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name)) - debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank") - s = sram.sram(word_size=2, - num_words=16, - num_banks=1, - name="sram_2_16_1_{0}".format(OPTS.tech_name)) - tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) diff --git a/compiler/tests/23_lib_sram_prune_test.py b/compiler/tests/23_lib_sram_prune_test.py index 35de23aa..37974bf7 100755 --- a/compiler/tests/23_lib_sram_prune_test.py +++ b/compiler/tests/23_lib_sram_prune_test.py @@ -26,13 +26,14 @@ class lib_test(openram_test): if not OPTS.spice_exe: debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) - import sram + from sram import sram + from sram_config import sram_config + c = sram_config(word_size=2, + num_words=16, + num_banks=1) - debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank") - s = sram.sram(word_size=2, - num_words=16, - num_banks=1, - name="sram_2_16_1_{0}".format(OPTS.tech_name)) + debug.info(1, "Testing pruned timing for sample 2 bit, 16 words SRAM with 1 bank") + s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name)) tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) diff --git a/compiler/tests/23_lib_sram_test.py b/compiler/tests/23_lib_sram_test.py index 8dc5c7a0..5e6aa060 100755 --- a/compiler/tests/23_lib_sram_test.py +++ b/compiler/tests/23_lib_sram_test.py @@ -26,13 +26,14 @@ class lib_test(openram_test): if not OPTS.spice_exe: debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) - import sram + from sram import sram + from sram_config import sram_config + c = sram_config(word_size=2, + num_words=16, + num_banks=1) debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank") - s = sram.sram(word_size=2, - num_words=16, - num_banks=1, - name="sram_2_16_1_{0}".format(OPTS.tech_name)) + s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name)) tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) diff --git a/compiler/tests/24_lef_sram_test.py b/compiler/tests/24_lef_sram_test.py index 99f13d2d..b2566b84 100755 --- a/compiler/tests/24_lef_sram_test.py +++ b/compiler/tests/24_lef_sram_test.py @@ -17,13 +17,14 @@ class lef_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - import sram + from sram import sram + from sram_config import sram_config + c = sram_config(word_size=2, + num_words=16, + num_banks=1) debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank") - s = sram.sram(word_size=2, - num_words=OPTS.num_words, - num_banks=OPTS.num_banks, - name="sram_2_16_1_{0}".format(OPTS.tech_name)) + s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name)) gdsfile = s.name + ".gds" leffile = s.name + ".lef" diff --git a/compiler/tests/25_verilog_sram_test.py b/compiler/tests/25_verilog_sram_test.py index fe0be3d9..9412e8e8 100755 --- a/compiler/tests/25_verilog_sram_test.py +++ b/compiler/tests/25_verilog_sram_test.py @@ -16,13 +16,14 @@ class verilog_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - import sram + from sram import sram + from sram_config import sram_config + c = sram_config(word_size=2, + num_words=16, + num_banks=1) debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank") - s = sram.sram(word_size=2, - num_words=OPTS.num_words, - num_banks=OPTS.num_banks, - name="sram_2_16_1_{0}".format(OPTS.tech_name)) + s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name)) vfile = s.name + ".v" vname = OPTS.openram_temp + vfile