From f3cca7eea0e2f2e209e590f147343524dcf2d8f4 Mon Sep 17 00:00:00 2001 From: Michael Timothy Grimes Date: Fri, 31 Aug 2018 23:28:06 -0700 Subject: [PATCH 1/5] Altering sense amp array and write driver array so spacing between amps/drivers accomodates multiport. Also altering sense amp array and write driver array tests to include multiport cases. --- compiler/modules/sense_amp_array.py | 15 +++++++++++++-- compiler/modules/write_driver_array.py | 19 +++++++++++++++++-- compiler/tests/09_sense_amp_array_test.py | 14 ++++++++++++++ compiler/tests/10_write_driver_array_test.py | 17 ++++++++++++++++- 4 files changed, 60 insertions(+), 5 deletions(-) mode change 100755 => 100644 compiler/tests/09_sense_amp_array_test.py mode change 100755 => 100644 compiler/tests/10_write_driver_array_test.py 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/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/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py old mode 100755 new mode 100644 index 51620495..ca07f884 --- a/compiler/tests/09_sense_amp_array_test.py +++ b/compiler/tests/09_sense_amp_array_test.py @@ -17,7 +17,21 @@ 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) + debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4") + 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.rw_ports = 1 + OPTS.w_ports = 1 + OPTS.r_ports = 1 + 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) 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..f4a484cc --- 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,7 +26,21 @@ class write_driver_test(openram_test): a = write_driver_array.write_driver_array(columns=16, word_size=8) self.local_check(a) - globals.end_openram() + # check write driver array in multi-port + OPTS.bitcell = "pbitcell" + OPTS.rw_ports = 1 + OPTS.w_ports = 1 + OPTS.r_ports = 1 + + 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) + + debug.info(2, "Testing write_driver_array for columns=16, word_size=8") + 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 if __name__ == "__main__": From d3441c7ba4373193bf4608b5b6805fcf8941bea9 Mon Sep 17 00:00:00 2001 From: Michael Timothy Grimes Date: Mon, 3 Sep 2018 17:31:12 -0700 Subject: [PATCH 2/5] Altering wordline driver to size for any bitcell. Editting multi-port test cases for sense amp array, write driver array, and wordline driver to least number of ports as a better test of spacing betwwen amps/drivers --- compiler/modules/wordline_driver.py | 20 +++++++++++++++----- compiler/tests/08_wordline_driver_test.py | 11 +++++++++++ compiler/tests/09_sense_amp_array_test.py | 8 ++++---- compiler/tests/10_write_driver_array_test.py | 10 +++++----- 4 files changed, 35 insertions(+), 14 deletions(-) mode change 100755 => 100644 compiler/tests/08_wordline_driver_test.py 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/tests/08_wordline_driver_test.py b/compiler/tests/08_wordline_driver_test.py old mode 100755 new mode 100644 index 9c91c7dd..1e0ae018 --- 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.rw_ports = 1 + OPTS.w_ports = 0 + OPTS.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 index ca07f884..a85a1ea3 100644 --- a/compiler/tests/09_sense_amp_array_test.py +++ b/compiler/tests/09_sense_amp_array_test.py @@ -29,14 +29,14 @@ class sense_amp_test(openram_test): # check sense amp array in multi-port OPTS.bitcell = "pbitcell" OPTS.rw_ports = 1 - OPTS.w_ports = 1 - OPTS.r_ports = 1 + OPTS.w_ports = 0 + OPTS.r_ports = 0 - debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2") + 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") + 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) diff --git a/compiler/tests/10_write_driver_array_test.py b/compiler/tests/10_write_driver_array_test.py index f4a484cc..9c68cf5f 100644 --- a/compiler/tests/10_write_driver_array_test.py +++ b/compiler/tests/10_write_driver_array_test.py @@ -29,18 +29,18 @@ class write_driver_test(openram_test): # check write driver array in multi-port OPTS.bitcell = "pbitcell" OPTS.rw_ports = 1 - OPTS.w_ports = 1 - OPTS.r_ports = 1 + OPTS.w_ports = 0 + OPTS.r_ports = 0 - debug.info(2, "Testing write_driver_array for columns=8, word_size=8") + 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") + 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() + globals.end_openram() # instantiate a copy of the class to actually run the test if __name__ == "__main__": From 1e5924d1b7cfe04b115425e0530215ddf4284c17 Mon Sep 17 00:00:00 2001 From: Michael Timothy Grimes Date: Mon, 3 Sep 2018 17:35:00 -0700 Subject: [PATCH 3/5] Adding multiported bank_sel pins --- compiler/modules/bank.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 9e711d22..1bc78fd6 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -83,7 +83,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 k in range(self.total_read): self.add_pin("s_en{0}".format(k), "INPUT") for k in range(self.total_write): @@ -514,13 +515,13 @@ class bank(design.design): return self.bank_select_inst = [] - for k in range(self.total_ports): - self.bank_select_inst.append(self.add_inst(name="bank_select", + for port in range(self.total_ports): + 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) From 341a3ee68d7d95738878740f3f0e080d41030edc Mon Sep 17 00:00:00 2001 From: Michael Timothy Grimes Date: Mon, 3 Sep 2018 17:44:32 -0700 Subject: [PATCH 4/5] Adding multiport pin names to sram_base for netlist only use --- compiler/sram_base.py | 75 +++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/compiler/sram_base.py b/compiler/sram_base.py index da6403db..ae4f1abe 100644 --- a/compiler/sram_base.py +++ b/compiler/sram_base.py @@ -32,6 +32,10 @@ class sram_base(design): 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.bank_insts = [] def compute_sizes(self): @@ -97,11 +101,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() @@ -109,8 +116,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") @@ -279,16 +287,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) @@ -312,20 +320,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] @@ -370,9 +386,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 @@ -385,9 +402,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 @@ -400,9 +418,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 From 774c14ad750fbbdb3b32be19a9a565a610a1dbe0 Mon Sep 17 00:00:00 2001 From: Michael Timothy Grimes Date: Mon, 3 Sep 2018 17:47:29 -0700 Subject: [PATCH 5/5] changing 19_psingle_bank_test to test layout for a single bank using pbitcell with 1 RW port (equivalent to using 6T cell) --- compiler/tests/19_psingle_bank_test.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) mode change 100755 => 100644 compiler/tests/19_psingle_bank_test.py 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 fad2b100..45745b2f --- a/compiler/tests/19_psingle_bank_test.py +++ b/compiler/tests/19_psingle_bank_test.py @@ -22,14 +22,29 @@ class psingle_bank_test(openram_test): from bank import bank 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 + + 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") + 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.rw_ports = 0 OPTS.w_ports = 2