diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index f8e76a8b..4f7e7fd1 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -67,13 +67,27 @@ class bank(design.design): self.DRC_LVS() def add_pins(self): + self.din_list = [] + self.dout_list = [] + port_number = 0 + for port in range(OPTS.num_rw_ports): + self.din_list.append("din{}".format(port_number)) + self.dout_list.append("dout{}".format(port_number)) + port_number += 1 + for port in range(OPTS.num_w_ports): + self.din_list.append("din{}".format(port_number)) + port_number += 1 + for port in range(OPTS.num_r_ports): + self.dout_list.append("dout{}".format(port_number)) + port_number += 1 + """ Adding pins for Bank module""" for port in range(self.total_read): for bit in range(self.word_size): - self.add_pin("dout{0}[{1}]".format(port,bit),"OUT") + self.add_pin(self.dout_list[port]+"[{0}]".format(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") + self.add_pin(self.din_list[port]+"[{0}]".format(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") @@ -350,7 +364,7 @@ class bank(design.design): temp = [] for bit in range(self.word_size): - temp.append("dout{0}[{1}]".format(port,bit)) + temp.append(self.dout_list[port]+"[{0}]".format(bit)) if self.words_per_row == 1: temp.append(self.read_bl_list[port]+"[{0}]".format(bit)) temp.append(self.read_br_list[port]+"[{0}]".format(bit)) @@ -379,7 +393,7 @@ class bank(design.design): temp = [] for bit in range(self.word_size): - temp.append("din{0}[{1}]".format(port,bit)) + temp.append(self.din_list[port]+"[{0}]".format(bit)) for bit in range(self.word_size): if (self.words_per_row == 1): temp.append(self.write_bl_list[port]+"[{0}]".format(bit)) @@ -547,29 +561,35 @@ class bank(design.design): # These are the instances that every bank has top_instances = [self.bitcell_array_inst] - + for port in range(self.total_read): + #top_instances.append(self.precharge_array_inst[port]) + top_instances.append(self.sense_amp_array_inst[port]) + for port in range(self.total_write): + top_instances.append(self.write_driver_array_inst[port]) 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], + top_instances.extend([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[port]) - top_instances.append(self.col_mux_array_inst[port]) + #top_instances.append(self.col_mux_array_inst[port]) if self.num_banks > 1: top_instances.append(self.bank_select_inst[port]) - + + if self.col_addr_size > 0: + for port in range(self.total_ports): + self.copy_layout_pin(self.col_mux_array_inst[port], "gnd") + for port in range(self.total_read): + self.copy_layout_pin(self.precharge_array_inst[port], "vdd") for inst in top_instances: # Column mux has no vdd - if self.col_addr_size==0 or (self.col_addr_size>0 and inst != self.col_mux_array_inst[0]): - self.copy_layout_pin(inst, "vdd") + #if self.col_addr_size==0 or (self.col_addr_size>0 and inst != self.col_mux_array_inst[0]): + self.copy_layout_pin(inst, "vdd") # Precharge has no gnd - if inst != self.precharge_array_inst[0]: - self.copy_layout_pin(inst, "gnd") + #if inst != self.precharge_array_inst[port]: + self.copy_layout_pin(inst, "gnd") def route_bank_select(self): """ Route the bank select logic. """ diff --git a/compiler/modules/replica_bitline.py b/compiler/modules/replica_bitline.py index 6ca4a829..b3365f3f 100644 --- a/compiler/modules/replica_bitline.py +++ b/compiler/modules/replica_bitline.py @@ -128,7 +128,21 @@ class replica_bitline(design.design): self.rbl_inst=self.add_inst(name="load", mod=self.rbl) - self.connect_inst(["bl[0]", "br[0]"] + ["gnd"]*self.bitcell_loads + ["vdd", "gnd"]) + + total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports + temp = [] + temp.append("bl[0]") + temp.append("br[0]") + for port in range(total_ports - 1): + temp.append("gnd") + temp.append("gnd") + for wl in range(self.bitcell_loads): + for port in range(total_ports): + temp.append("gnd") + temp.append("vdd") + temp.append("gnd") + self.connect_inst(temp) + #self.connect_inst(["bl[0]", "br[0]"] + ["gnd"]*self.bitcell_loads + ["vdd", "gnd"]) def place_modules(self): """ Add all of the module instances in the logical netlist """ diff --git a/compiler/sram_1bank.py b/compiler/sram_1bank.py index 03791089..0f625e15 100644 --- a/compiler/sram_1bank.py +++ b/compiler/sram_1bank.py @@ -34,7 +34,9 @@ class sram_1bank(sram_base): self.bank_inst=self.create_bank(0) - self.control_logic_inst = self.create_control_logic() + self.control_logic_inst = [None] * self.total_ports + for port in range(self.total_ports): + self.control_logic_inst[port] = self.create_control_logic(port) self.row_addr_dff_inst = self.create_row_addr_dff() @@ -59,11 +61,11 @@ class sram_1bank(sram_base): # up to the row address DFFs. control_pos = vector(-self.control_logic.width - 2*self.m2_pitch, self.bank.bank_center.y - self.control_logic.control_logic_center.y) - self.control_logic_inst.place(control_pos) + self.control_logic_inst[0].place(control_pos) # The row address bits are placed above the control logic aligned on the right. - row_addr_pos = vector(self.control_logic_inst.rx() - self.row_addr_dff.width, - self.control_logic_inst.uy()) + row_addr_pos = vector(self.control_logic_inst[0].rx() - self.row_addr_dff.width, + self.control_logic_inst[0].uy()) self.row_addr_dff_inst.place(row_addr_pos) # This is M2 pitch even though it is on M1 to help stem via spacings on the trunk @@ -95,7 +97,7 @@ class sram_1bank(sram_base): """ # Connect the control pins as inputs for n in self.control_logic_inputs + ["clk"]: - self.copy_layout_pin(self.control_logic_inst, n) + self.copy_layout_pin(self.control_logic_inst[0], n) for i in range(self.word_size): dout_name = "dout0[{}]".format(i) @@ -134,7 +136,7 @@ class sram_1bank(sram_base): """ Route the clock network """ # This is the actual input to the SRAM - self.copy_layout_pin(self.control_logic_inst, "clk") + self.copy_layout_pin(self.control_logic_inst[0], "clk") # Connect all of these clock pins to the clock in the central bus # This is something like a "spine" clock distribution. The two spines @@ -158,7 +160,7 @@ class sram_1bank(sram_base): # This uses a metal2 track to the right of the control/row addr DFF # to route vertically. - control_clk_buf_pin = self.control_logic_inst.get_pin("clk_buf") + control_clk_buf_pin = self.control_logic_inst[0].get_pin("clk_buf") control_clk_buf_pos = control_clk_buf_pin.rc() row_addr_clk_pin = self.row_addr_dff_inst.get_pin("clk") row_addr_clk_pos = row_addr_clk_pin.rc() @@ -177,7 +179,7 @@ class sram_1bank(sram_base): top_instances = [self.bank_inst, self.row_addr_dff_inst, self.data_dff_inst, - self.control_logic_inst] + self.control_logic_inst[0]] if self.col_addr_dff: top_instances.append(self.col_addr_dff_inst) @@ -193,7 +195,7 @@ class sram_1bank(sram_base): top_instances = [self.bank_inst, self.row_addr_dff_inst, self.data_dff_inst, - self.control_logic_inst] + self.control_logic_inst[0]] if self.col_addr_dff: top_instances.append(self.col_addr_dff_inst) @@ -267,7 +269,7 @@ class sram_1bank(sram_base): def route_control_logic(self): """ Route the outputs from the control logic module """ for n in self.control_logic_outputs: - src_pin = self.control_logic_inst.get_pin(n) + src_pin = self.control_logic_inst[0].get_pin(n) dest_pin = self.bank_inst.get_pin(n) self.connect_rail_from_left_m2m3(src_pin, dest_pin) self.add_via_center(layers=("metal1","via1","metal2"), @@ -332,7 +334,7 @@ class sram_1bank(sram_base): """ for n in self.control_logic_outputs: - pin = self.control_logic_inst.get_pin(n) + pin = self.control_logic_inst[0].get_pin(n) self.add_label(text=n, layer=pin.layer, offset=pin.center()) diff --git a/compiler/sram_base.py b/compiler/sram_base.py index ca3351b5..302c34ed 100644 --- a/compiler/sram_base.py +++ b/compiler/sram_base.py @@ -19,6 +19,7 @@ class sram_base(design): self.sram_config = sram_config sram_config.set_local_config(self) + print("PORTS: {} - {} - {}".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)) self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports @@ -28,10 +29,29 @@ class sram_base(design): def add_pins(self): """ Add pins for entire SRAM. """ + self.din_list = [] + self.DIN_list = [] + self.dout_list = [] + self.DOUT_list = [] + port_number = 0 + for port in range(OPTS.num_rw_ports): + self.din_list.append("din{}".format(port_number)) + self.dout_list.append("dout{}".format(port_number)) + self.DIN_list.append("DIN{}".format(port_number)) + self.DOUT_list.append("DOUT{}".format(port_number)) + port_number += 1 + for port in range(OPTS.num_w_ports): + self.din_list.append("din{}".format(port_number)) + self.DIN_list.append("DIN{}".format(port_number)) + port_number += 1 + for port in range(OPTS.num_r_ports): + self.dout_list.append("dout{}".format(port_number)) + self.DOUT_list.append("DOUT{}".format(port_number)) + port_number += 1 for port in range(self.total_write): for bit in range(self.word_size): - self.add_pin("DIN{0}[{1}]".format(port,bit),"INPUT") + self.add_pin(self.DIN_list[port]+"[{0}]".format(bit),"INPUT") for port in range(self.total_ports): for bit in range(self.addr_size): @@ -41,11 +61,15 @@ class sram_base(design): self.control_logic_inputs=self.control_logic.get_inputs() self.control_logic_outputs=self.control_logic.get_outputs() - self.add_pin_list(self.control_logic_inputs,"INPUT") + #self.add_pin_list(self.control_logic_inputs,"INPUT") + self.add_pin("csb","INPUT") + for port in range(self.total_write): + self.add_pin("web{}".format(port),"INPUT") + self.add_pin("clk","INPUT") for port in range(self.total_read): for bit in range(self.word_size): - self.add_pin("DOUT{0}[{1}]".format(port,bit),"OUTPUT") + self.add_pin(self.DOUT_list[port]+"[{0}]".format(bit),"OUTPUT") self.add_pin("vdd","POWER") self.add_pin("gnd","GROUND") @@ -234,9 +258,11 @@ class sram_base(design): else: self.col_addr_dff = None - self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size*self.total_ports) + self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size*self.total_write) self.add_mod(self.data_dff) + print("PORTS: {} - {} - {}".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)) + # Create the bank module (up to four are instantiated) from bank import bank self.bank = bank(self.sram_config, @@ -262,7 +288,7 @@ class sram_base(design): temp = [] for port in range(self.total_read): for bit in range(self.word_size): - temp.append("DOUT{0}[{1}]".format(port,bit)) + temp.append(self.DOUT_list[port]+"[{0}]".format(bit)) for port in range(self.total_write): for bit in range(self.word_size): temp.append("BANK_DIN{0}[{1}]".format(port,bit)) @@ -321,10 +347,10 @@ class sram_base(design): # inputs, outputs/output/bar inputs = [] outputs = [] - for k in range(self.total_ports): + for port in range(self.total_ports): for i in range(self.row_addr_size): - inputs.append("ADDR{}[{}]".format(k,i+self.col_addr_size)) - outputs.append("A{}[{}]".format(k,i+self.col_addr_size)) + inputs.append("ADDR{}[{}]".format(port,i+self.col_addr_size)) + outputs.append("A{}[{}]".format(port,i+self.col_addr_size)) self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"]) return inst @@ -337,10 +363,10 @@ class sram_base(design): # inputs, outputs/output/bar inputs = [] outputs = [] - for k in range(self.total_ports): + for port in range(self.total_ports): for i in range(self.col_addr_size): - inputs.append("ADDR{}[{}]".format(k,i)) - outputs.append("A{}[{}]".format(k,i)) + inputs.append("ADDR{}[{}]".format(port,i)) + outputs.append("A{}[{}]".format(port,i)) self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"]) return inst @@ -353,20 +379,24 @@ class sram_base(design): # inputs, outputs/output/bar inputs = [] outputs = [] - for k in range(self.total_write): + for port in range(self.total_write): for i in range(self.word_size): - inputs.append("DIN{}[{}]".format(k,i)) - outputs.append("BANK_DIN{}[{}]".format(k,i)) + inputs.append("DIN{}[{}]".format(port,i)) + outputs.append("BANK_DIN{}[{}]".format(port,i)) self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"]) return inst - def create_control_logic(self): + def create_control_logic(self, port): """ Add and place control logic """ inst = self.add_inst(name="control", mod=self.control_logic) - self.connect_inst(self.control_logic_inputs + self.control_logic_outputs + ["vdd", "gnd"]) + self.connect_inst(["csb", "web{}".format(port), "clk", + "s_en{}".format(port), "w_en{}".format(port), "clk_buf_bar", "clk_buf", + "vdd", "gnd"]) + + #self.connect_inst(self.control_logic_inputs + self.control_logic_outputs + ["vdd", "gnd"]) return inst diff --git a/compiler/tests/20_psram_1bank_test.py b/compiler/tests/20_psram_1bank_test.py new file mode 100644 index 00000000..2a6bf4ed --- /dev/null +++ b/compiler/tests/20_psram_1bank_test.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +""" +Run a regression test on a 1 bank SRAM +""" + +import unittest +from testutils import header,openram_test +import sys,os +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +from globals import OPTS +import debug + +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) + + c.words_per_row=1 + + OPTS.bitcell = "pbitcell" + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 1 + OPTS.num_r_ports = 1 + OPTS.netlist_only = True + + debug.info(1, "Single bank, no column mux with control logic") + a = sram(c, "sram1") + 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, "sram2") + 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, "sram3") + 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, "sram4") + self.local_check(a, final_verification=True) + """ + #globals.end_openram() + +# instantiate a copy of the class to actually run the test +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main()