diff --git a/compiler/sram.py b/compiler/sram.py index 1b6b104f..752fd2aa 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -34,8 +34,6 @@ class sram(): from sram_1bank import sram_1bank as sram elif self.num_banks == 2: from sram_2bank import sram_2bank as sram - elif self.num_banks == 4: - from sram_4bank import sram_4bank as sram else: debug.error("Invalid number of banks.",-1) diff --git a/compiler/sram_4bank.py b/compiler/sram_4bank.py deleted file mode 100644 index c9309749..00000000 --- a/compiler/sram_4bank.py +++ /dev/null @@ -1,331 +0,0 @@ -import sys -from tech import drc, spice -import debug -from math import log,sqrt,ceil -import datetime -import getpass -from vector import vector -from globals import OPTS, print_time - -from sram_base import sram_base -from bank import bank -from dff_buf_array import dff_buf_array -from dff_array import dff_array - -class sram_4bank(sram_base): - """ - Procedures specific to a four bank SRAM. - """ - def __init__(self, name, sram_config): - sram_base.__init__(self, name, sram_config) - - def compute_bank_offsets(self): - """ Compute the overall offsets for a four bank SRAM """ - - # The main difference is that the four bank SRAM has the data bus in the middle of the four banks - # as opposed to the top of the banks. - - # In 4 bank SRAM, the height is determined by the bank decoder and address flop - self.vertical_bus_height = 2*self.bank.height + 4*self.bank_to_bus_distance + self.data_bus_height \ - + self.supply_bus_height + self.msb_decoder.height + self.msb_address.width - # The address bus extends down through the power rails, but control and bank_sel bus don't - self.addr_bus_height = self.vertical_bus_height - - self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 0) - self.data_bus_offset = vector(0, self.bank.height + self.bank_to_bus_distance) - self.supply_bus_offset = vector(0, self.data_bus_offset.y + self.data_bus_height \ - + self.bank.height + 2*self.bank_to_bus_distance) - self.control_bus_offset = vector(0, self.supply_bus_offset.y + self.supply_bus_height) - self.bank_sel_bus_offset = self.vertical_bus_offset + vector(self.m2_pitch*self.control_size,0) - self.addr_bus_offset = self.bank_sel_bus_offset.scale(1,0) + vector(self.m2_pitch*self.num_banks,0) - - # Control is placed at the top above the control bus and everything - self.control_logic_position = vector(0, self.control_bus_offset.y + self.control_bus_height + self.m1_pitch) - - # Bank select flops get put to the right of control logic above bank1 and the buses - # Leave a pitch to get the vdd rails up to M2 - self.msb_address_position = vector(self.bank_inst[1].lx() + 3*self.supply_rail_pitch, - self.supply_bus_offset.y + self.supply_bus_height \ - + 2*self.m1_pitch + self.msb_address.width) - - # Decoder goes above the MSB address flops, and is flipped in Y - # separate the two by a bank to bus distance for nwell rules, just in case - self.msb_decoder_position = self.msb_address_position + vector(self.msb_decoder.width, self.bank_to_bus_distance) - - - def add_modules(self): - """ Adds the modules and the buses to the top level """ - - self.compute_bus_sizes() - - self.add_banks() - - self.compute_bank_offsets() - - self.add_busses() - - self.add_logic() - - self.width = self.bank_inst[1].ur().x - self.height = max(self.control_logic_inst.uy(),self.msb_decoder_inst.uy()) - - def add_banks(self): - - # Placement of bank 0 (upper left) - bank_position_0 = vector(self.bank.width, - self.bank.height + self.data_bus_height + 2*self.bank_to_bus_distance) - self.bank_inst=[self.add_bank(0, bank_position_0, 1, -1)] - - # Placement of bank 1 (upper right) - x_off = self.bank.width + self.vertical_bus_width + 2*self.bank_to_bus_distance - bank_position_1 = vector(x_off, bank_position_0.y) - self.bank_inst.append(self.add_bank(1, bank_position_1, 1, 1)) - - # Placement of bank 2 (bottom left) - y_off = self.bank.height - bank_position_2 = vector(bank_position_0.x, y_off) - self.bank_inst.append(self.add_bank(2, bank_position_2, -1, -1)) - - # Placement of bank 3 (bottom right) - bank_position_3 = vector(bank_position_1.x, bank_position_2.y) - self.bank_inst.append(self.add_bank(3, bank_position_3, -1, 1)) - - - - def add_logic(self): - """ Add the control and MSB decode/bank select logic for four banks """ - - - self.add_control_logic(position=self.control_logic_position) - - self.msb_address_inst = self.add_inst(name="msb_address", - mod=self.msb_address, - offset=self.msb_address_position, - rotate=270) - - self.msb_bank_sel_addr = ["ADDR[{}]".format(i) for i in range(self.addr_size-2,self.addr_size,1)] - temp = list(self.msb_bank_sel_addr) - temp.extend(["msb{0}[{1}]".format(j,i) for i in range(2) for j in ["","_bar"]]) - temp.extend(["clk_buf", "vdd", "gnd"]) - self.connect_inst(temp) - - self.msb_decoder_inst = self.add_inst(name="msb_decoder", - mod=self.msb_decoder, - offset=self.msb_decoder_position, - mirror="MY") - temp = ["msb[{}]".format(i) for i in range(2)] - temp.extend(["bank_sel[{}]".format(i) for i in range(4)]) - temp.extend(["vdd", "gnd"]) - self.connect_inst(temp) - - def route_double_msb_address(self): - """ Route two MSB address bits and the bank decoder for 4-bank SRAM """ - - # connect the MSB flops to the address input bus - for i in [0,1]: - msb_pins = self.msb_address_inst.get_pins("din_{}".format(i)) - for msb_pin in msb_pins: - if msb_pin.layer == "metal3": - msb_pin_pos = msb_pin.lc() - break - rail_pos = vector(self.vert_control_bus_positions[self.msb_bank_sel_addr[i]].x,msb_pin_pos.y) - self.add_path("metal3",[msb_pin_pos,rail_pos]) - self.add_via_center(("metal2","via2","metal3"),rail_pos) - - # Connect clk - clk_pin = self.msb_address_inst.get_pin("clk") - clk_pos = clk_pin.bc() - rail_pos = self.horz_control_bus_positions["clk_buf"] - bend_pos = vector(clk_pos.x,self.horz_control_bus_positions["clk_buf"].y) - self.add_path("metal1",[clk_pos,bend_pos,rail_pos]) - - # Connect bank decoder outputs to the bank select vertical bus wires - for i in range(self.num_banks): - msb_pin = self.msb_decoder_inst.get_pin("out_{}".format(i)) - msb_pin_pos = msb_pin.lc() - rail_pos = vector(self.vert_control_bus_positions["bank_sel[{}]".format(i)].x,msb_pin_pos.y) - self.add_path("metal1",[msb_pin_pos,rail_pos]) - self.add_via_center(("metal1","via1","metal2"),rail_pos) - - # connect MSB flop outputs to the bank decoder inputs - msb_pin = self.msb_address_inst.get_pin("dout[0]") - msb_pin_pos = msb_pin.rc() - in_pin = self.msb_decoder_inst.get_pin("in[0]") - in_pos = in_pin.bc() + vector(0,1*self.m2_pitch,) # pin is up from bottom - out_pos = msb_pin_pos + vector(1*self.m2_pitch,0) # route out to the right - up_pos = vector(out_pos.x,in_pos.y) # and route up to the decoer - self.add_wire(("metal1","via1","metal2"),[msb_pin_pos,out_pos,up_pos,in_pos]) - self.add_via_center(("metal1","via1","metal2"),in_pos) - self.add_via_center(("metal1","via1","metal2"),msb_pin_pos,rotate=90) - - msb_pin = self.msb_address_inst.get_pin("dout[1]") - msb_pin_pos = msb_pin.rc() - in_pin = self.msb_decoder_inst.get_pin("in[1]") - in_pos = in_pin.bc() + vector(0,self.bitcell.height+self.m2_pitch) # route the next row up - out_pos = msb_pin_pos + vector(2*self.m2_pitch,0) # route out to the right - up_pos = vector(out_pos.x,in_pos.y) # and route up to the decoer - self.add_wire(("metal1","via1","metal2"),[msb_pin_pos,out_pos,up_pos,in_pos]) - self.add_via_center(("metal1","via1","metal2"),in_pos) - self.add_via_center(("metal1","via1","metal2"),msb_pin_pos,rotate=90) - - self.route_double_msb_address_supplies() - - def route_double_msb_address_supplies(self): - """ Route the vdd/gnd bits of the 2-bit bank decoder. """ - - # Route the right-most vdd/gnd of the right upper bank to the top of the decoder - vdd_pins = self.bank_inst[1].get_pins("vdd") - left_bank_vdd_pin = None - right_bank_vdd_pin = None - for vdd_pin in vdd_pins: - if vdd_pin.layer != "metal2": - continue - if left_bank_vdd_pin == None or vdd_pin.lx()right_bank_vdd_pin.lx(): - right_bank_vdd_pin = vdd_pin - # Route to top - self.add_rect(layer="metal2", - offset=vdd_pin.ul(), - height=self.height-vdd_pin.uy(), - width=vdd_pin.width()) - - gnd_pins = self.bank_inst[1].get_pins("gnd") - left_bank_gnd_pin = None - right_bank_gnd_pin = None - for gnd_pin in gnd_pins: - if gnd_pin.layer != "metal2": - continue - if left_bank_gnd_pin == None or gnd_pin.lx()right_bank_gnd_pin.lx(): - right_bank_gnd_pin = gnd_pin - # Route to top - self.add_rect(layer="metal2", - offset=gnd_pin.ul(), - height=self.height-gnd_pin.uy(), - width=gnd_pin.width()) - - # Connect bank decoder vdd/gnd supplies using the previous bank pins - vdd_pins = self.msb_decoder_inst.get_pins("vdd") - for vdd_pin in vdd_pins: - if vdd_pin.layer != "metal1": - continue - rail1_pos = vector(left_bank_vdd_pin.cx(),vdd_pin.cy()) - rail2_pos = vector(right_bank_vdd_pin.cx(),vdd_pin.cy()) - self.add_path("metal1",[rail1_pos,rail2_pos]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=rail1_pos, - rotate=90, - size=[1,3]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=rail2_pos, - rotate=90, - size=[1,3]) - gnd_pins = self.msb_decoder_inst.get_pins("gnd") - for gnd_pin in gnd_pins: - if gnd_pin.layer != "metal1": - continue - rail1_pos = vector(left_bank_gnd_pin.cx(),gnd_pin.cy()) - rail2_pos = vector(right_bank_gnd_pin.cx(),gnd_pin.cy()) - self.add_path("metal1",[rail1_pos,rail2_pos]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=rail1_pos, - rotate=90, - size=[1,3]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=rail2_pos, - rotate=90, - size=[1,3]) - - # connect the bank MSB flop supplies - vdd_pins = self.msb_address_inst.get_pins("vdd") - # vdd pins go down to the rail - for vdd_pin in vdd_pins: - if vdd_pin.layer != "metal1": - continue - vdd_pos = vdd_pin.bc() - down_pos = vdd_pos - vector(0,self.m1_pitch) - rail_pos = vector(vdd_pos.x,self.horz_control_bus_positions["vdd"].y) - self.add_path("metal1",[vdd_pos,down_pos]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=down_pos, - rotate=90) - self.add_path("metal2",[down_pos,rail_pos]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=rail_pos) - # gnd pins go right to the rail - gnd_pins = self.msb_address_inst.get_pins("gnd") - for gnd_pin in gnd_pins: - if gnd_pin.layer != "metal2": - continue - rail1_pos = vector(left_bank_gnd_pin.cx(),gnd_pin.cy()) - self.add_path("metal1",[rail1_pos,gnd_pin.lc()]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=gnd_pin.lc(), - rotate=90) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=rail1_pos, - rotate=90, - size=[1,3]) - - - def route(self): - """ Route all of the signals for the four bank SRAM. """ - - self.route_shared_banks() - - # connect the data output to the data bus - for n in self.data_bus_names: - for i in [0,1]: - pin_pos = self.bank_inst[i].get_pin(n).bc() - rail_pos = vector(pin_pos.x,self.data_bus_positions[n].y) - self.add_path("metal2",[pin_pos,rail_pos]) - self.add_via_center(("metal2","via2","metal3"),rail_pos) - - for i in [2,3]: - pin_pos = self.bank_inst[i].get_pin(n).uc() - rail_pos = vector(pin_pos.x,self.data_bus_positions[n].y) - self.add_path("metal2",[pin_pos,rail_pos]) - self.add_via_center(("metal2","via2","metal3"),rail_pos) - - # route msb address bits - # route 2:4 decoder - self.route_double_msb_address() - - # connect the banks to the vertical address bus - # connect the banks to the vertical control bus - for n in self.addr_bus_names + self.control_bus_names: - # Skip these from the horizontal bus - if n in ["vdd", "gnd"]: continue - # This will be the bank select, so skip it - if n in self.msb_bank_sel_addr: continue - - for bank_id in [0,2]: - pin0_pos = self.bank_inst[bank_id].get_pin(n).rc() - pin1_pos = self.bank_inst[bank_id+1].get_pin(n).lc() - rail_pos = vector(self.vert_control_bus_positions[n].x,pin0_pos.y) - self.add_path("metal3",[pin0_pos,pin1_pos]) - self.add_via_center(("metal2","via2","metal3"),rail_pos) - - - self.route_bank_supply_rails(left_banks=[0,2], bottom_banks=[2,3]) - - - def add_lvs_correspondence_points(self): - """ - This adds some points for easier debugging if LVS goes wrong. - These should probably be turned off by default though, since extraction - will show these as ports in the extracted netlist. - """ - - if self.num_banks==1: return - - for n in self.control_bus_names: - self.add_label(text=n, - layer="metal2", - offset=self.vert_control_bus_positions[n]) - for n in self.bank_sel_bus_names: - self.add_label(text=n, - layer="metal2", - offset=self.vert_control_bus_positions[n]) diff --git a/compiler/tests/20_sram_4bank_test.py b/compiler/tests/20_sram_4bank_test.py deleted file mode 100755 index 25649e8e..00000000 --- a/compiler/tests/20_sram_4bank_test.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 -""" -Run a regression test on a 4 bank SRAM -""" - -import unittest -from testutils import header,openram_test -import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) -import globals -from globals import OPTS -import debug - -@unittest.skip("Multibank is not working yet.") -class sram_4bank_test(openram_test): - - def runTest(self): - globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - from sram import sram - from sram_config import sram_config - c = sram_config(word_size=16, - num_words=64, - num_banks=4) - - debug.info(1, "Four bank, no column mux with control logic") - a = sram(c, "sram1") - self.local_check(a, final_verification=True) - - c.num_words=128 - c.words_per_row=2 - debug.info(1, "Four bank two way column mux with control logic") - a = sram(c, "sram2") - self.local_check(a, final_verification=True) - - c.num_words=256 - c.words_per_row=4 - debug.info(1, "Four bank, four way column mux with control logic") - a = sram(c, "sram3") - self.local_check(a, final_verification=True) - - c.word_size=2 - c.num_words=256 - c.words_per_row=8 - debug.info(1, "Four bank, eight way column mux with control logic") - a = sram.sram(c, "sram4") - 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()