diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 488439fd..9c2b2add 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -329,13 +329,13 @@ class bank(design.design): self.input_control_signals = [] port_num = 0 for port in range(OPTS.num_rw_ports): - self.input_control_signals.append(["s_en{}".format(port_num), "w_en{}".format(port_num), "p_en_bar{}".format(port_num), "wl_en{}".format(port_num)]) + self.input_control_signals.append(["p_en_bar{}".format(port_num), "s_en{}".format(port_num), "w_en{}".format(port_num)]) port_num += 1 for port in range(OPTS.num_w_ports): - self.input_control_signals.append(["w_en{}".format(port_num), "p_en_bar{}".format(port_num), "wl_en{}".format(port_num)]) + self.input_control_signals.append(["p_en_bar{}".format(port_num), "w_en{}".format(port_num)]) port_num += 1 for port in range(OPTS.num_r_ports): - self.input_control_signals.append(["s_en{}".format(port_num), "p_en_bar{}".format(port_num), "wl_en{}".format(port_num)]) + self.input_control_signals.append(["p_en_bar{}".format(port_num), "s_en{}".format(port_num)]) port_num += 1 # Number of control lines in the bus for each port @@ -691,6 +691,8 @@ class bank(design.design): make_pins=(self.num_banks==1), pitch=self.m3_pitch) + self.copy_layout_pin(self.port_address_inst[0], "wl_en", self.prefix + "wl_en0") + # Port 1 if len(self.all_ports)==2: # The other control bus is routed up to two pitches above the bitcell array @@ -706,6 +708,8 @@ class bank(design.design): make_pins=(self.num_banks==1), pitch=self.m3_pitch) + self.copy_layout_pin(self.port_address_inst[1], "wl_en", self.prefix + "wl_en1") + def route_port_data_to_bitcell_array(self, port): """ Routing of BL and BR between port data and bitcell array """ @@ -1054,21 +1058,6 @@ class bank(design.design): to_layer="m2", offset=control_pos) - # clk to wordline_driver - control_signal = self.prefix + "wl_en{}".format(port) - if port % 2: - pin_pos = self.port_address_inst[port].get_pin("wl_en").uc() - control_y_offset = self.bus_pins[port][control_signal].by() - mid_pos = vector(pin_pos.x, control_y_offset + self.m1_pitch) - else: - pin_pos = self.port_address_inst[port].get_pin("wl_en").bc() - control_y_offset = self.bus_pins[port][control_signal].uy() - mid_pos = vector(pin_pos.x, control_y_offset - self.m1_pitch) - control_x_offset = self.bus_pins[port][control_signal].cx() - control_pos = vector(control_x_offset, mid_pos.y) - self.add_wire(self.m1_stack, [pin_pos, mid_pos, control_pos]) - self.add_via_center(layers=self.m1_stack, - offset=control_pos) def graph_exclude_precharge(self): """ diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 0c9d50bf..5aec6872 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -333,8 +333,9 @@ class control_logic(design.design): row += 1 self.place_gated_clk_buf_row(row) row += 1 - self.place_wlen_row(row) - row += 1 + if (self.port_type == "rw") or (self.port_type == "r"): + self.place_sen_row(row) + row += 1 if (self.port_type == "rw") or (self.port_type == "w"): self.place_wen_row(row) height = self.w_en_gate_inst.uy() @@ -345,9 +346,8 @@ class control_logic(design.design): if (self.port_type == "rw") or (self.port_type == "w"): self.place_rbl_delay_row(row) row += 1 - if (self.port_type == "rw") or (self.port_type == "r"): - self.place_sen_row(row) - row += 1 + self.place_wlen_row(row) + row += 1 self.place_delay(row) height = self.delay_inst.uy() control_center_y = self.delay_inst.by() diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index d831c047..6bc2cd43 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -340,6 +340,15 @@ class sram_1bank(sram_base): def route_dff(self, port, add_routes): + # This is only done when we add_routes because the data channel will be larger + # so that can be used for area estimation. + if add_routes: + self.route_col_addr_dffs(port) + + self.route_data_dffs(port, add_routes) + + def route_col_addr_dffs(self, port): + route_map = [] # column mux dff is routed on it's own since it is to the far end @@ -351,6 +360,38 @@ class sram_1bank(sram_base): bank_pins = [self.bank_inst.get_pin(x) for x in bank_names] route_map.extend(list(zip(bank_pins, dff_pins))) + if len(route_map) > 0: + + layer_stack = self.m1_stack + + if port == 0: + offset = vector(self.control_logic_insts[port].rx() + self.dff.width, + - self.data_bus_size[port] + 2 * self.m3_pitch) + cr = channel_route(netlist=route_map, + offset=offset, + layer_stack=layer_stack, + parent=self) + # This causes problem in magic since it sometimes cannot extract connectivity of isntances + # with no active devices. + self.add_inst(cr.name, cr) + self.connect_inst([]) + #self.add_flat_inst(cr.name, cr) + else: + offset = vector(0, + self.bank.height + self.m3_pitch) + cr = channel_route(netlist=route_map, + offset=offset, + layer_stack=layer_stack, + parent=self) + # This causes problem in magic since it sometimes cannot extract connectivity of isntances + # with no active devices. + self.add_inst(cr.name, cr) + self.connect_inst([]) + #self.add_flat_inst(cr.name, cr) + + def route_data_dffs(self, port, add_routes): + route_map = [] + # wmask dff if self.num_wmasks > 0 and port in self.write_ports: dff_names = ["dout_{}".format(x) for x in range(self.num_wmasks)] @@ -377,6 +418,7 @@ class sram_1bank(sram_base): if len(route_map) > 0: + # The write masks will have blockages on M1 if self.num_wmasks > 0 and port in self.write_ports: layer_stack = self.m3_stack else: diff --git a/compiler/tests/20_sram_1bank_4mux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_4mux_1rw_1r_test.py new file mode 100755 index 00000000..8bcc0415 --- /dev/null +++ b/compiler/tests/20_sram_1bank_4mux_1rw_1r_test.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class sram_1bank_4mux_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + c = sram_config(word_size=4, + num_words=64, + num_banks=1) + + c.words_per_row=4 + c.recompute_sizes() + debug.info(1, "Layout test for {}rw,{}r,{}w sram " + "with {} bit words, {} words, {} words per " + "row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) + a = factory.create(module_type="sram", sram_config=c) + self.local_check(a, final_verification=True) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner())