From d36f14b40877b7435dc409d65f6733cb83ba7bde Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 7 Aug 2019 17:14:33 -0700 Subject: [PATCH] New control logic, netlist only working --- compiler/modules/bank.py | 74 +++++++---------------- compiler/modules/control_logic.py | 58 ++++++++++-------- compiler/modules/port_data.py | 59 +++++++----------- compiler/modules/replica_bitcell_array.py | 2 +- compiler/sram/sram_base.py | 6 +- 5 files changed, 82 insertions(+), 117 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 4fa95c44..6b7462de 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -82,7 +82,7 @@ class bank(design.design): for port in self.read_ports: for bit in range(self.word_size): self.add_pin("dout{0}_{1}".format(port,bit),"OUTPUT") - for port in self.read_ports: + for port in self.all_ports: self.add_pin(self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]),"OUTPUT") for port in self.write_ports: for bit in range(self.word_size): @@ -128,14 +128,13 @@ class bank(design.design): def route_rbl(self,port): """ Route the rbl_bl and rbl_wl """ - if self.port_data[port].has_rbl(): - bl_pin_name = self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]) - bl_pin = self.bitcell_array_inst.get_pin(bl_pin_name) - self.add_layout_pin(text="rbl_bl{0}".format(port), - layer=bl_pin.layer, - offset=bl_pin.ll(), - height=bl_pin.height(), - width=bl_pin.width()) + bl_pin_name = self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]) + bl_pin = self.bitcell_array_inst.get_pin(bl_pin_name) + self.add_layout_pin(text="rbl_bl{0}".format(port), + layer=bl_pin.layer, + offset=bl_pin.ll(), + height=bl_pin.height(), + width=bl_pin.width()) @@ -202,10 +201,7 @@ class bank(design.design): # LOWER RIGHT QUADRANT # Below the bitcell array - if self.port_data[port].has_rbl(): - self.port_data_offsets[port] = vector(self.main_bitcell_array_left - self.bitcell_array.cell.width,0) - else: - self.port_data_offsets[port] = vector(self.main_bitcell_array_left,0) + self.port_data_offsets[port] = vector(self.main_bitcell_array_left - self.bitcell_array.cell.width,0) # UPPER LEFT QUADRANT # To the left of the bitcell array @@ -364,36 +360,15 @@ class bank(design.design): self.add_mod(self.port_address) - # The number of replica lines depends on the port configuration - rbl_counts = [self.read_ports.count(p) for p in self.all_ports] - self.num_rbl = sum(rbl_counts) - - # The replica array indices always start at 0, so this will map them to - # the correct SRAM port - # (e.g. if port 0 is w, then port 1 will use RBL 0 in replica bitcell array - # because write ports don't use an RBL) - self.port_rbl_map = {} - index = 0 - for (i,num) in enumerate(rbl_counts): - if num>0: - self.port_rbl_map[i]=index - index += 1 - if len(rbl_counts)<2: - rbl_counts.append(0) - - - # Which bitcell port should be used in the RBL - # For now (since only 2 ports), if port 0 is not a read port, skip it in the RBLs - bitcell_ports=list(range(len(self.read_ports))) - if 0 not in self.read_ports: - bitcell_ports = [x+1 for x in bitcell_ports] + self.port_rbl_map = self.all_ports + self.num_rbl = len(self.all_ports) self.bitcell_array = factory.create(module_type="replica_bitcell_array", cols=self.num_cols, rows=self.num_rows, - left_rbl=rbl_counts[0], - right_rbl=rbl_counts[1], - bitcell_ports=bitcell_ports) + left_rbl=1, + right_rbl=1 if len(self.all_ports)>1 else 0, + bitcell_ports=self.all_ports) self.add_mod(self.bitcell_array) @@ -421,8 +396,7 @@ class bank(design.design): for wordline in self.wl_names: temp.append("{0}_{1}".format(wordline,row)) for port in self.all_ports: - if self.port_data[port].has_rbl(): - temp.append("wl_en{0}".format(port)) + temp.append("wl_en{0}".format(port)) temp.append("vdd") temp.append("gnd") self.connect_inst(temp) @@ -442,11 +416,10 @@ class bank(design.design): mod=self.port_data[port]) temp = [] - if self.port_data[port].has_rbl(): - rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]) - rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port]) - temp.append(rbl_bl_name) - temp.append(rbl_br_name) + rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]) + rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port]) + temp.append(rbl_bl_name) + temp.append(rbl_br_name) for col in range(self.num_cols): temp.append("{0}_{1}".format(self.bl_names[port],col)) temp.append("{0}_{1}".format(self.br_names[port],col)) @@ -710,11 +683,10 @@ class bank(design.design): inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name) # Connect the replica bitlines - if self.port_data[port].has_rbl(): - rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]) - rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port]) - self.connect_bitline(inst1, inst2, rbl_bl_name, "rbl_bl") - self.connect_bitline(inst1, inst2, rbl_br_name, "rbl_br") + rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]) + rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port]) + self.connect_bitline(inst1, inst2, rbl_bl_name, "rbl_bl") + self.connect_bitline(inst1, inst2, rbl_br_name, "rbl_br") diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index a5c5dc12..c2d86da8 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -125,10 +125,10 @@ class control_logic(design.design): self.add_mod(self.wl_en_driver) # w_en drives every write driver - self.wen_and2 = factory.create(module_type="pand2", + self.wen_and = factory.create(module_type="pand3", size=self.word_size+8, height=dff_height) - self.add_mod(self.wen_and2) + self.add_mod(self.wen_and) # s_en drives every sense amp self.sen_and2 = factory.create(module_type="pand2", @@ -141,17 +141,19 @@ class control_logic(design.design): size=1, height=dff_height) self.add_mod(self.inv) - + # p_en_bar drives every column in the bitcell array # but it is sized the same as the wl_en driver with # prepended 3 inverter stages to guarantee it is slower and odd polarity self.p_en_bar_driver = factory.create(module_type="pdriver", fanout=self.num_cols, - neg_polarity=True, height=dff_height) self.add_mod(self.p_en_bar_driver) - + + self.nand2 = factory.create(module_type="pnand2", + height=dff_height) + self.add_mod(self.nand2) # if (self.port_type == "rw") or (self.port_type == "r"): # from importlib import reload @@ -330,12 +332,9 @@ class control_logic(design.design): if self.port_type == "rw": self.input_list = ["csb", "web"] self.rbl_list = ["rbl_bl"] - elif self.port_type == "r": - self.input_list = ["csb"] - self.rbl_list = ["rbl_bl"] else: self.input_list = ["csb"] - self.rbl_list = [] + self.rbl_list = ["rbl_bl"] if self.port_type == "rw": self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"] @@ -385,7 +384,7 @@ class control_logic(design.design): self.create_wen_row() if (self.port_type == "rw") or (self.port_type == "r"): self.create_sen_row() - self.create_delay() + self.create_delay() self.create_pen_row() @@ -422,9 +421,9 @@ class control_logic(design.design): if (self.port_type == "rw") or (self.port_type == "r"): self.place_sen_row(row) row += 1 - self.place_delay(row) - height = self.delay_inst.uy() - control_center_y = self.delay_inst.by() + self.place_delay(row) + height = self.delay_inst.uy() + control_center_y = self.delay_inst.by() # This offset is used for placement of the control logic in the SRAM level. self.control_logic_center = vector(self.ctrl_dff_inst.rx(), control_center_y) @@ -446,6 +445,7 @@ class control_logic(design.design): self.route_wen() if (self.port_type == "rw") or (self.port_type == "r"): self.route_sen() + self.route_delay() self.route_pen() self.route_clk_buf() self.route_gated_clk_bar() @@ -457,7 +457,7 @@ class control_logic(design.design): """ Create the replica bitline """ self.delay_inst=self.add_inst(name="delay_chain", mod=self.delay_chain) - self.connect_inst(["rbl_bl", "pre_s_en", "vdd", "gnd"]) + self.connect_inst(["rbl_bl", "rbl_bl_delay", "vdd", "gnd"]) def place_delay(self,row): """ Place the replica bitline """ @@ -468,6 +468,11 @@ class control_logic(design.design): offset = vector(self.delay_chain.width, y_off) self.delay_inst.place(offset, mirror="MY") + def route_delay(self): + + # Input from RBL goes to the delay line for futher delay + self.copy_layout_pin(self.delay_inst, "in", "rbl_bl") + def create_clk_buf_row(self): """ Create the multistage and gated clock buffer """ @@ -604,10 +609,14 @@ class control_logic(design.design): self.connect_output(self.wl_en_inst, "Z", "wl_en") def create_pen_row(self): - # input: gated_clk_bar, output: p_en_bar - self.p_en_bar_inst=self.add_inst(name="inv_p_en_bar", + self.p_en_bar_inst=self.add_inst(name="nand_p_en_bar", + mod=self.nand2) + self.connect_inst(["gated_clk_buf", "rbl_bl_delay", "p_en_bar_unbuf", "vdd", "gnd"]) + + self.p_en_bar_inst=self.add_inst(name="buf_p_en_bar", mod=self.p_en_bar_driver) - self.connect_inst(["gated_clk_buf", "p_en_bar", "vdd", "gnd"]) + self.connect_inst(["p_en_bar_unbuf", "p_en_bar", "vdd", "gnd"]) + def place_pen_row(self,row): @@ -633,7 +642,7 @@ class control_logic(design.design): # GATE FOR S_EN self.s_en_gate_inst = self.add_inst(name="buf_s_en_and", mod=self.sen_and2) - self.connect_inst(["pre_s_en", input_name, "s_en", "vdd", "gnd"]) + self.connect_inst(["rbl_bl_delay", input_name, "s_en", "vdd", "gnd"]) def place_sen_row(self,row): @@ -667,12 +676,13 @@ class control_logic(design.design): self.connect_output(self.s_en_gate_inst, "Z", "s_en") - # Input from RBL goes to the delay line for futher delay - self.copy_layout_pin(self.delay_inst, "in", "rbl_bl") - - def create_wen_row(self): + + self.rbl_bl_delay_inv_inst = self.add_inst(name="rbl_bl_delay_inv", + mod=self.inv) + self.connect_inst(["rbl_bl_delay", "rbl_bl_delay_bar", "vdd", "gnd"]) + # input: we (or cs) output: w_en if self.port_type == "rw": input_name = "we" @@ -682,8 +692,8 @@ class control_logic(design.design): # GATE THE W_EN self.w_en_gate_inst = self.add_inst(name="w_en_and", - mod=self.wen_and2) - self.connect_inst([input_name, "gated_clk_bar", "w_en", "vdd", "gnd"]) + mod=self.wen_and) + self.connect_inst([input_name, "rbl_bl_delay_bar", "gated_clk_bar", "w_en", "vdd", "gnd"]) def place_wen_row(self,row): diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 3e4caf57..b4027be9 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -82,9 +82,8 @@ class port_data(design.design): def add_pins(self): """ Adding pins for port address module""" - if self.has_rbl(): - self.add_pin("rbl_bl","INOUT") - self.add_pin("rbl_br","INOUT") + self.add_pin("rbl_bl","INOUT") + self.add_pin("rbl_br","INOUT") for bit in range(self.num_cols): self.add_pin("{0}_{1}".format(self.bl_names[self.port], bit),"INOUT") self.add_pin("{0}_{1}".format(self.br_names[self.port], bit),"INOUT") @@ -150,30 +149,18 @@ class port_data(design.design): def add_modules(self): - if self.port in self.read_ports: - # Extra column +1 is for RBL - # Precharge will be shifted left if needed - self.precharge_array = factory.create(module_type="precharge_array", - columns=self.num_cols + 1, - bitcell_bl=self.bl_names[self.port], - bitcell_br=self.br_names[self.port]) - self.add_mod(self.precharge_array) - - self.sense_amp_array = factory.create(module_type="sense_amp_array", - word_size=self.word_size, - words_per_row=self.words_per_row) - self.add_mod(self.sense_amp_array) - else: - # Precharge is needed when we have a column mux or for byte writes - # to prevent corruption of half-selected cells, so just always add it - # This is a little power inefficient for write ports without a column mux, - # but it is simpler. - self.precharge_array = factory.create(module_type="precharge_array", - columns=self.num_cols, - bitcell_bl=self.bl_names[self.port], - bitcell_br=self.br_names[self.port]) - self.add_mod(self.precharge_array) - self.sense_amp_array = None + # Extra column +1 is for RBL + # Precharge will be shifted left if needed + self.precharge_array = factory.create(module_type="precharge_array", + columns=self.num_cols + 1, + bitcell_bl=self.bl_names[self.port], + bitcell_br=self.br_names[self.port]) + self.add_mod(self.precharge_array) + + self.sense_amp_array = factory.create(module_type="sense_amp_array", + word_size=self.word_size, + words_per_row=self.words_per_row) + self.add_mod(self.sense_amp_array) if self.col_addr_size > 0: @@ -238,14 +225,14 @@ class port_data(design.design): temp = [] # Use left BLs for RBL - if self.has_rbl() and self.port==0: + if self.port==0: temp.append("rbl_bl") temp.append("rbl_br") for bit in range(self.num_cols): temp.append(self.bl_names[self.port]+"_{0}".format(bit)) temp.append(self.br_names[self.port]+"_{0}".format(bit)) # Use right BLs for RBL - if self.has_rbl() and self.port==1: + if self.port==1: temp.append("rbl_bl") temp.append("rbl_br") temp.extend(["p_en_bar", "vdd"]) @@ -368,7 +355,7 @@ class port_data(design.design): vertical_port_order.append(self.write_driver_array_inst) # Add one column for the the RBL - if self.has_rbl() and self.port==0: + if self.port==0: x_offset = self.bitcell.width else: x_offset = 0 @@ -438,7 +425,7 @@ class port_data(design.design): inst1 = self.column_mux_array_inst inst2 = self.precharge_array_inst - if self.has_rbl() and self.port==0: + if self.port==0: self.connect_bitlines(inst1, inst2, self.num_cols, inst2_start_bit=1) else: self.connect_bitlines(inst1, inst2, self.num_cols) @@ -460,7 +447,7 @@ class port_data(design.design): inst1 = self.precharge_array_inst inst1_bl_name = "bl_{}" inst1_br_name = "br_{}" - if self.has_rbl() and self.port==0: + if self.port==0: start_bit=1 else: start_bit=0 @@ -484,7 +471,7 @@ class port_data(design.design): inst1 = self.precharge_array_inst inst1_bl_name = "bl_{}" inst1_br_name = "br_{}" - if self.has_rbl() and self.port==0: + if self.port==0: start_bit=1 else: start_bit=0 @@ -507,11 +494,11 @@ class port_data(design.design): """ Add the bitline pins for the given port """ # Connect one bitline to the RBL and offset the indices for the other BLs - if self.has_rbl() and self.port==0: + if self.port==0: self.copy_layout_pin(self.precharge_array_inst, "bl_0", "rbl_bl") self.copy_layout_pin(self.precharge_array_inst, "br_0", "rbl_br") bit_offset=1 - elif self.has_rbl() and self.port==1: + elif self.port==1: self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(self.num_cols), "rbl_bl") self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(self.num_cols), "rbl_br") bit_offset=0 @@ -603,5 +590,3 @@ class port_data(design.design): if self.precharge_array_inst: self.graph_inst_exclude.add(self.precharge_array_inst) - def has_rbl(self): - return self.port in self.read_ports diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 6f4e96c5..39d9c6e7 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -35,7 +35,7 @@ class replica_bitcell_array(design.design): self.right_rbl = right_rbl self.bitcell_ports = bitcell_ports - debug.check(left_rbl+right_rbl==len(self.read_ports),"Invalid number of RBLs for port configuration.") + debug.check(left_rbl+right_rbl==len(self.all_ports),"Invalid number of RBLs for port configuration.") debug.check(left_rbl+right_rbl==len(self.bitcell_ports),"Bitcell ports must match total RBLs.") # Two dummy rows/cols plus replica for each port diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index f34d058e..7cc60fab 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -339,7 +339,7 @@ class sram_base(design, verilog, lef): for port in self.read_ports: for bit in range(self.word_size): temp.append("DOUT{0}[{1}]".format(port,bit)) - for port in self.read_ports: + for port in self.all_ports: temp.append("rbl_bl{0}".format(port)) for port in self.write_ports: for bit in range(self.word_size): @@ -499,9 +499,7 @@ class sram_base(design, verilog, lef): if port in self.readwrite_ports: temp.append("web{}".format(port)) temp.append("clk{}".format(port)) - - if port in self.read_ports: - temp.append("rbl_bl{}".format(port)) + temp.append("rbl_bl{}".format(port)) # Ouputs if port in self.read_ports: