diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index a5ab4909..445cafc9 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -121,7 +121,7 @@ class bank(design.design): self.route_column_address_lines(port) self.route_control_lines(port) if self.num_banks > 1: - self.route_bank_select(port) + self.route_bank_select(port) self.route_supplies() @@ -700,6 +700,15 @@ class bank(design.design): offset=data_pin.center(), height=data_pin.height(), width=data_pin.width()) + # + # if self.word_size is not None: + # for bit in range(self.num_wmasks): + # wmask_pin = self.port_data_inst[port].get_pin("bank_wmask_{0}".format(bit)) + # self.add_layout_pin_rect_center(text="bank_wmask{0}_{1}".format(port, bit), + # layer=wmask_pin.layer, + # offset=wmask_pin.center(), + # height=wmask_pin.height(), + # width=wmask_pin.width()) def route_port_address_in(self, port): @@ -711,8 +720,9 @@ class bank(design.design): decoder_name = "addr_{}".format(row) addr_name = "addr{0}_{1}".format(port,addr_idx) self.copy_layout_pin(self.port_address_inst[port], decoder_name, addr_name) - - + + + def route_port_data_in(self, port): """ Connecting port data in """ @@ -720,6 +730,14 @@ class bank(design.design): data_name = "din_{}".format(row) din_name = "din{0}_{1}".format(port,row) self.copy_layout_pin(self.port_data_inst[port], data_name, din_name) + + if self.word_size is not None: + for row in range(self.num_wmasks): + wmask_name = "bank_wmask_{}".format(row) + bank_wmask_name = "bank_wmask{0}_{1}".format(port, row) + self.copy_layout_pin(self.port_data_inst[port], wmask_name, bank_wmask_name) + + def channel_route_bitlines(self, inst1, inst2, num_bits, inst1_bl_name="bl_{}", inst1_br_name="br_{}", diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 1100f2cb..b5534226 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -86,9 +86,19 @@ class sram_1bank(sram_base): data_pos[port] = vector(self.bank.bank_array_ll.x, -max_gap_size - self.dff.height) self.data_dff_insts[port].place(data_pos[port]) + else: data_pos[port] = vector(self.bank.bank_array_ll.x,0) + # Add the write mask flops below the din flops. + if self.write_size is not None: + if port in self.write_ports: + wmask_pos[port] = vector(self.bank.bank_array_ll.x, + - 2*max_gap_size - 2*self.dff.height) + self.wmask_dff_insts[port].place(wmask_pos[port]) + else: + wmask_pos[port] = vector(self.bank.bank_array_ll.x, 0) + # Add the col address flops below the bank to the left of the lower-left of bank array if self.col_addr_dff: col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap, @@ -125,14 +135,14 @@ class sram_1bank(sram_base): -max_gap_size - self.data_dff_insts[port].height) self.data_dff_insts[port].place(data_pos[port]) - # Add the write mask flops below the din flops. - if self.write_size is not None: - if port in self.write_ports: - wmask_pos[port] = vector(self.bank.bank_array_ll.x, - -max_gap_size - self.wmask_dff_insts[port].height) - # wmask_pos[port] = vector(self.bank.bank_array_ll.x - self.control_logic_insts[port].width, - # -max_gap_size - self.wmask_dff_insts[port].height) - self.wmask_dff_insts[port].place(wmask_pos[port]) + # # Add the write mask flops below the din flops. + # if self.write_size is not None: + # if port in self.write_ports: + # wmask_pos[port] = vector(self.bank.bank_array_ll.x, + # -max_gap_size - self.wmask_dff_insts[port].height) + # # wmask_pos[port] = vector(self.bank.bank_array_ll.x - self.control_logic_insts[port].width, + # # -max_gap_size - self.wmask_dff_insts[port].height) + # self.wmask_dff_insts[port].place(wmask_pos[port]) if len(self.all_ports)>1: @@ -149,6 +159,13 @@ class sram_1bank(sram_base): self.bank.height + max_gap_size + self.dff.height) self.data_dff_insts[port].place(data_pos[port], mirror="MX") + # Add the write mask flops below the din flops. + if self.write_size is not None: + if port in self.write_ports: + wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width, + self.bank.height + 2*max_gap_size + 2*self.dff.height) + self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX") + # Add the write mask flops to the left of the din flops. if self.write_size is not None: if port in self.write_ports: @@ -191,13 +208,13 @@ class sram_1bank(sram_base): self.bank.height + max_gap_size + self.dff.height) self.data_dff_insts[port].place(data_pos[port], mirror="MX") - # Add the write mask flops to the left of the din flops. - if self.write_size is not None: - if port in self.write_ports: - wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width, - self.bank.height + max_gap_size + self.data_dff_insts[port].height) - self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX") - + # # Add the write mask flops to the left of the din flops. + # if self.write_size is not None: + # if port in self.write_ports: + # wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width, + # self.bank.height + max_gap_size + self.data_dff_insts[port].height) + # self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX") + # def add_layout_pins(self): """ @@ -222,6 +239,10 @@ class sram_1bank(sram_base): if port in self.write_ports: for bit in range(self.word_size): self.copy_layout_pin(self.data_dff_insts[port], "din_{}".format(bit), "DIN{0}[{1}]".format(port,bit)) + if self.write_size is not None: + for bit in range(self.num_wmasks): + self.copy_layout_pin(self.wmask_dff_insts[port], "din_{}".format(bit), "wmask{0}[{1}]".format(port,bit)) + def route_layout(self): """ Route a single bank SRAM """ @@ -238,6 +259,7 @@ class sram_1bank(sram_base): self.route_col_addr_dff() self.route_data_dff() + self.route_wmask_dff() def route_clk(self): """ Route the clock network """ @@ -290,6 +312,15 @@ class sram_1bank(sram_base): self.add_path("metal2",[mid_pos, clk_steiner_pos], width=max(m2m3.width,m2m3.height)) self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, clk_steiner_pos]) + if self.write_size is not None: + wmask_dff_clk_pin = self.wmask_dff_insts[port].get_pin("clk") + wmask_dff_clk_pos = wmask_dff_clk_pin.center() + mid_pos = vector(clk_steiner_pos.x, wmask_dff_clk_pos.y) + # In some designs, the steiner via will be too close to the mid_pos via + # so make the wire as wide as the contacts + self.add_path("metal2", [mid_pos, clk_steiner_pos], width=max(m2m3.width, m2m3.height)) + self.add_wire(("metal3", "via2", "metal2"), [wmask_dff_clk_pos, mid_pos, clk_steiner_pos]) + def route_control_logic(self): """ Route the control logic pins that are not inputs """ @@ -367,7 +398,24 @@ class sram_1bank(sram_base): route_map = list(zip(bank_pins, dff_pins)) self.create_horizontal_channel_route(route_map, offset) - + + def route_wmask_dff(self): + """ Connect the output of the wmask flops to the write mask AND array """ + # This is where the channel will start (y-dimension at least) + for port in self.write_ports: + if port % 2: + offset = self.wmask_dff_insts[port].ll() - vector(0, (self.word_size + 2) * self.m1_pitch) + else: + offset = self.wmask_dff_insts[port].ul() + vector(0, 2 * self.m1_pitch) + + dff_names = ["dout_{}".format(x) for x in range(self.num_wmasks)] + dff_pins = [self.wmask_dff_insts[port].get_pin(x) for x in dff_names] + + bank_names = ["bank_wmask{0}_{1}".format(port, x) for x in range(self.num_wmasks)] + bank_pins = [self.bank_inst.get_pin(x) for x in bank_names] + + route_map = list(zip(bank_pins, dff_pins)) + self.create_horizontal_channel_route(route_map, offset) def add_lvs_correspondence_points(self): diff --git a/compiler/tests/20_sram_1bank_nomux_wmask_test.py b/compiler/tests/20_sram_1bank_nomux_wmask_test.py new file mode 100644 index 00000000..e0292e95 --- /dev/null +++ b/compiler/tests/20_sram_1bank_nomux_wmask_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 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 + + +# @unittest.skip("SKIPPING 20_sram_1bank_nomux_wmask_test") +class sram_1bank_nomux_wmask_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + from sram_config import sram_config + c = sram_config(word_size=8, + write_size=4, + num_words=16, + num_banks=1) + + c.words_per_row = 1 + c.recompute_sizes() + debug.info(1, "Layout test for {}rw,{}r,{}w sram " + "with {} bit words, {} words, {} bit writes, {} words per " + "row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.write_size, + 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()) \ No newline at end of file