diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 3af935a3..f8e76a8b 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -81,7 +81,8 @@ class bank(design.design): # For more than one bank, we have a bank select and name # the signals gated_*. if self.num_banks > 1: - self.add_pin("bank_sel","INPUT") + for port in range(self.total_ports): + self.add_pin("bank_sel{}".format(port),"INPUT") for port in range(self.total_read): self.add_pin("s_en{0}".format(port), "INPUT") for port in range(self.total_write): @@ -513,12 +514,12 @@ class bank(design.design): self.bank_select_inst = [] for port in range(self.total_ports): - self.bank_select_inst.append(self.add_inst(name="bank_select", + self.bank_select_inst.append(self.add_inst(name="bank_select{}".format(port), mod=self.bank_select)) temp = [] temp.extend(self.input_control_signals) - temp.append("bank_sel") + temp.append("bank_sel{}".format(port)) temp.extend(self.control_signals) temp.extend(["vdd", "gnd"]) self.connect_inst(temp) diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 47bcf023..a02ffd9d 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -30,7 +30,11 @@ class sense_amp_array(design.design): def create_layout(self): self.height = self.amp.height - self.width = self.amp.width * self.word_size * self.words_per_row + + if self.bitcell.width > self.amp.width: + self.width = self.bitcell.width * self.word_size * self.words_per_row + else: + self.width = self.amp.width * self.word_size * self.words_per_row self.place_sense_amp_array() self.add_layout_pins() @@ -53,6 +57,10 @@ class sense_amp_array(design.design): self.amp = self.mod_sense_amp("sense_amp") self.add_mod(self.amp) + c = reload(__import__(OPTS.bitcell)) + self.mod_bitcell = getattr(c, OPTS.bitcell) + self.bitcell = self.mod_bitcell() + self.add_mod(self.bitcell) def create_sense_amp_array(self): self.local_insts = [] @@ -68,7 +76,10 @@ class sense_amp_array(design.design): def place_sense_amp_array(self): - amp_spacing = self.amp.width * self.words_per_row + if self.bitcell.width > self.amp.width: + amp_spacing = self.bitcell.width * self.words_per_row + else: + amp_spacing = self.amp.width * self.words_per_row for i in range(0,self.word_size): amp_position = vector(amp_spacing * i, 0) self.local_insts[i].place(amp_position) diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index 709e3e45..87b0430e 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -58,6 +58,12 @@ class wordline_driver(design.design): self.nand2 = pnand2() self.add_mod(self.nand2) + + from importlib import reload + c = reload(__import__(OPTS.bitcell)) + self.mod_bitcell = getattr(c, OPTS.bitcell) + self.bitcell = self.mod_bitcell() + self.add_mod(self.bitcell) def route_vdd_gnd(self): """ Add a pin for each row of vdd/gnd which are must-connects next level up. """ @@ -125,16 +131,20 @@ class wordline_driver(design.design): nand2_xoffset = inv1_xoffset + self.inv.width inv2_xoffset = nand2_xoffset + self.nand2.width - self.width = inv2_xoffset + self.inv.width - self.height = self.inv.height * self.rows - + self.width = inv2_xoffset + self.inv.height + if self.bitcell.height > self.inv.height: + self.height = self.bitcell.height * self.rows + driver_height = self.bitcell.height + else: + self.height = self.inv.height * self.rows + driver_height = self.inv.height for row in range(self.rows): if (row % 2): - y_offset = self.inv.height*(row + 1) + y_offset = driver_height*(row + 1) inst_mirror = "MX" else: - y_offset = self.inv.height*row + y_offset = driver_height*row inst_mirror = "R0" inv1_offset = [inv1_xoffset, y_offset] diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 965f1735..88d40c86 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -30,7 +30,12 @@ class write_driver_array(design.design): self.create_write_array() def create_layout(self): - self.width = self.columns * self.driver.width + + if self.bitcell.width > self.driver.width: + self.width = self.columns * self.bitcell.width + else: + self.width = self.columns * self.driver.width + self.height = self.driver.height self.place_write_array() @@ -53,6 +58,11 @@ class write_driver_array(design.design): self.mod_write_driver = getattr(c, OPTS.write_driver) self.driver = self.mod_write_driver("write_driver") self.add_mod(self.driver) + + c = reload(__import__(OPTS.bitcell)) + self.mod_bitcell = getattr(c, OPTS.bitcell) + self.bitcell = self.mod_bitcell() + self.add_mod(self.bitcell) def create_write_array(self): self.driver_insts = {} @@ -69,9 +79,14 @@ class write_driver_array(design.design): def place_write_array(self): + if self.bitcell.width > self.driver.width: + driver_spacing = self.bitcell.width + else: + driver_spacing = self.driver.width + for i in range(0,self.columns,self.words_per_row): index = int(i/self.words_per_row) - base = vector(i * self.driver.width,0) + base = vector(i * driver_spacing,0) self.driver_insts[index].place(base) diff --git a/compiler/sram_1bank.py b/compiler/sram_1bank.py index e27eb2b3..03791089 100644 --- a/compiler/sram_1bank.py +++ b/compiler/sram_1bank.py @@ -99,18 +99,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_base.py b/compiler/sram_base.py index af21d704..23412f05 100644 --- a/compiler/sram_base.py +++ b/compiler/sram_base.py @@ -24,11 +24,14 @@ class sram_base(design): def add_pins(self): """ Add pins for entire SRAM. """ - - for i in range(self.word_size): - self.add_pin("DIN[{0}]".format(i),"INPUT") - for i in range(self.addr_size): - self.add_pin("ADDR[{0}]".format(i),"INPUT") + + for port in range(self.total_write): + for bit in range(self.word_size): + self.add_pin("DIN{0}[{1}]".format(port,bit),"INPUT") + + for port in range(self.total_ports): + for bit in range(self.addr_size): + self.add_pin("ADDR{0}[{1}]".format(port,bit),"INPUT") # These are used to create the physical pins too self.control_logic_inputs=self.control_logic.get_inputs() @@ -36,8 +39,9 @@ class sram_base(design): self.add_pin_list(self.control_logic_inputs,"INPUT") - for i in range(self.word_size): - self.add_pin("DOUT[{0}]".format(i),"OUTPUT") + 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("vdd","POWER") self.add_pin("gnd","GROUND") @@ -217,16 +221,16 @@ class sram_base(design): # Create the address and control flops (but not the clk) from dff_array import dff_array - self.row_addr_dff = dff_array(name="row_addr_dff", rows=self.row_addr_size, columns=1) + self.row_addr_dff = dff_array(name="row_addr_dff", rows=self.row_addr_size*self.total_ports, columns=1) self.add_mod(self.row_addr_dff) if self.col_addr_size > 0: - self.col_addr_dff = dff_array(name="col_addr_dff", rows=1, columns=self.col_addr_size) + self.col_addr_dff = dff_array(name="col_addr_dff", rows=1, columns=self.col_addr_size*self.total_ports) self.add_mod(self.col_addr_dff) else: self.col_addr_dff = None - self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size) + self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size*self.total_ports) self.add_mod(self.data_dff) # Create the bank module (up to four are instantiated) @@ -247,20 +251,28 @@ class sram_base(design): def create_bank(self,bank_num): - """ Create a bank """ + """ Create a bank """ self.bank_insts.append(self.add_inst(name="bank{0}".format(bank_num), mod=self.bank)) temp = [] - for i in range(self.word_size): - temp.append("DOUT[{0}]".format(i)) - for i in range(self.word_size): - temp.append("BANK_DIN[{0}]".format(i)) - for i in range(self.bank_addr_size): - temp.append("A[{0}]".format(i)) + for port in range(self.total_read): + for bit in range(self.word_size): + temp.append("DOUT{0}[{1}]".format(port,bit)) + for port in range(self.total_write): + for bit in range(self.word_size): + temp.append("BANK_DIN{0}[{1}]".format(port,bit)) + for port in range(self.total_ports): + for bit in range(self.bank_addr_size): + temp.append("A{0}[{1}]".format(port,bit)) if(self.num_banks > 1): - temp.append("bank_sel[{0}]".format(bank_num)) - temp.extend(["s_en0", "w_en0", "clk_buf_bar","clk_buf" , "vdd", "gnd"]) + for port in range(self.total_ports): + temp.append("bank_sel{0}[{1}]".format(port,bank_num)) + for port in range(self.total_read): + temp.append("s_en{0}".format(port)) + for port in range(self.total_write): + temp.append("w_en{0}".format(port)) + temp.extend(["clk_buf_bar","clk_buf" , "vdd", "gnd"]) self.connect_inst(temp) return self.bank_insts[-1] @@ -305,9 +317,10 @@ class sram_base(design): # inputs, outputs/output/bar inputs = [] outputs = [] - for i in range(self.row_addr_size): - inputs.append("ADDR[{}]".format(i+self.col_addr_size)) - outputs.append("A[{}]".format(i+self.col_addr_size)) + for k 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)) self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"]) return inst @@ -320,9 +333,10 @@ class sram_base(design): # inputs, outputs/output/bar inputs = [] outputs = [] - for i in range(self.col_addr_size): - inputs.append("ADDR[{}]".format(i)) - outputs.append("A[{}]".format(i)) + for k 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)) self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"]) return inst @@ -335,9 +349,10 @@ class sram_base(design): # inputs, outputs/output/bar inputs = [] outputs = [] - for i in range(self.word_size): - inputs.append("DIN[{}]".format(i)) - outputs.append("BANK_DIN[{}]".format(i)) + for k 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)) self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"]) return inst diff --git a/compiler/tests/08_wordline_driver_test.py b/compiler/tests/08_wordline_driver_test.py old mode 100755 new mode 100644 index 9c91c7dd..3a19a2ec --- a/compiler/tests/08_wordline_driver_test.py +++ b/compiler/tests/08_wordline_driver_test.py @@ -20,10 +20,21 @@ class wordline_driver_test(openram_test): import wordline_driver import tech + # check wordline driver array in single port debug.info(2, "Checking driver") tx = wordline_driver.wordline_driver(rows=8) self.local_check(tx) + # check wordline driver array in multi-port + OPTS.bitcell = "pbitcell" + 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) + self.local_check(tx) + globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py old mode 100755 new mode 100644 index 51620495..f6f9e14f --- a/compiler/tests/09_sense_amp_array_test.py +++ b/compiler/tests/09_sense_amp_array_test.py @@ -17,7 +17,7 @@ class sense_amp_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) import sense_amp_array - + # check sense amp array in single port debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2") a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2) self.local_check(a) @@ -26,6 +26,20 @@ class sense_amp_test(openram_test): a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4) self.local_check(a) + # check sense amp array in multi-port + OPTS.bitcell = "pbitcell" + 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) + self.local_check(a) + + debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)") + a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4) + self.local_check(a) + globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/10_write_driver_array_test.py b/compiler/tests/10_write_driver_array_test.py old mode 100755 new mode 100644 index 27538d0b..67978f11 --- a/compiler/tests/10_write_driver_array_test.py +++ b/compiler/tests/10_write_driver_array_test.py @@ -17,6 +17,7 @@ class write_driver_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) import write_driver_array + # check write driver array in single port debug.info(2, "Testing write_driver_array for columns=8, word_size=8") a = write_driver_array.write_driver_array(columns=8, word_size=8) self.local_check(a) @@ -25,6 +26,20 @@ class write_driver_test(openram_test): a = write_driver_array.write_driver_array(columns=16, word_size=8) self.local_check(a) + # check write driver array in multi-port + OPTS.bitcell = "pbitcell" + 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) + self.local_check(a) + + debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)") + a = write_driver_array.write_driver_array(columns=16, word_size=8) + self.local_check(a) + globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/19_psingle_bank_test.py b/compiler/tests/19_psingle_bank_test.py old mode 100755 new mode 100644 index fd68409a..bdb64f9e --- a/compiler/tests/19_psingle_bank_test.py +++ b/compiler/tests/19_psingle_bank_test.py @@ -20,21 +20,32 @@ class psingle_bank_test(openram_test): import verify from bank import bank - OPTS.bitcell = "pbitcell" from sram_config import sram_config - - # testing all port configurations (with no column mux) to verify layout between bitcell array and peripheral circuitry + OPTS.bitcell = "pbitcell" + + # testing layout of bank using pbitcell with 1 RW port (a 6T-cell equivalent) OPTS.num_rw_ports = 1 - OPTS.num_w_ports = 1 - OPTS.num_r_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(c, name="bank1_1rw_0w_0r_single") + self.local_check(a) + """ + # multiport can't generate layout yet on the bank level + OPTS.netlist_only = True + + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 1 + OPTS.num_r_ports = 1 + 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.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