# 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 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_2bank(sram_base): """ Procedures specific to a two 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 two bank SRAM """ # In 2 bank SRAM, the height is determined by the control bus which is higher than the msb address self.vertical_bus_height = self.bank.height + 2*self.bank_to_bus_distance + self.data_bus_height + self.control_bus_height # 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.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) 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 = self.control_logic_inst.uy() def add_banks(self): # Placement of bank 0 (left) bank_position_0 = vector(self.bank.width, self.bank.height) self.bank_inst=[self.add_bank(0, bank_position_0, -1, -1)] # Placement of bank 1 (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)) def add_logic(self): """ Add the control and MSB logic """ 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(self.addr_size-1) self.connect_inst([self.msb_bank_sel_addr,"bank_sel[1]","bank_sel[0]","clk_buf", "vdd", "gnd"]) def route_shared_banks(self): """ Route the shared signals for two and four bank configurations. """ # create the input control pins for n in self.control_logic_inputs + ["clk"]: self.copy_layout_pin(self.control_logic_inst, n) # connect the control logic to the control bus for n in self.control_logic_outputs + ["vdd", "gnd"]: pins = self.control_logic_inst.get_pins(n) for pin in pins: if pin.layer=="m2": pin_pos = pin.bc() break rail_pos = vector(pin_pos.x,self.horz_control_bus_positions[n].y) self.add_path("m2",[pin_pos,rail_pos]) self.add_via_center(self.m1_stack,rail_pos) # connect the control logic cross bar for n in self.control_logic_outputs: cross_pos = vector(self.vert_control_bus_positions[n].x,self.horz_control_bus_positions[n].y) self.add_via_center(self.m1_stack,cross_pos) # connect the bank select signals to the vertical bus for i in range(self.num_banks): pin = self.bank_inst[i].get_pin("bank_sel") pin_pos = pin.rc() if i==0 else pin.lc() rail_pos = vector(self.vert_control_bus_positions["bank_sel[{}]".format(i)].x,pin_pos.y) self.add_path("m3",[pin_pos,rail_pos]) self.add_via_center(self.m2_stack,rail_pos) def route_single_msb_address(self): """ Route one MSB address bit for 2-bank SRAM """ # connect the bank MSB flop supplies vdd_pins = self.msb_address_inst.get_pins("vdd") for vdd_pin in vdd_pins: if vdd_pin.layer != "m1": 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("m1",[vdd_pos,down_pos]) self.add_via_center(self.m1_stack,down_pos,rotate=90) self.add_path("m2",[down_pos,rail_pos]) self.add_via_center(self.m1_stack,rail_pos) gnd_pins = self.msb_address_inst.get_pins("gnd") # Only add the ground connection to the lowest metal2 rail in the flop array # FIXME: SCMOS doesn't have a vertical rail in the cell, or we could use those lowest_y = None for gnd_pin in gnd_pins: if gnd_pin.layer != "m2": continue if lowest_y==None or gnd_pin.by()