# 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 debug import design from tech import drc from math import log from vector import vector from sram_factory import factory from globals import OPTS class dff_array(design.design): """ This is a simple row (or multiple rows) of flops. Unlike the data flops, these are never spaced out. """ def __init__(self, rows, columns, name=""): self.rows = rows self.columns = columns if name=="": name = "dff_array_{0}x{1}".format(rows, columns) design.design.__init__(self, name) debug.info(1, "Creating {0} rows={1} cols={2}".format(self.name, self.rows, self.columns)) self.add_comment("rows: {0} cols: {1}".format(rows, columns)) self.create_netlist() if not OPTS.netlist_only: self.create_layout() def create_netlist(self): self.add_modules() self.add_pins() self.create_dff_array() def create_layout(self): self.width = self.columns * self.dff.width self.height = self.rows * self.dff.height self.place_dff_array() self.add_layout_pins() self.add_boundary() self.DRC_LVS() def add_modules(self): self.dff = factory.create(module_type="dff") self.add_mod(self.dff) def add_pins(self): for row in range(self.rows): for col in range(self.columns): self.add_pin(self.get_din_name(row,col)) for row in range(self.rows): for col in range(self.columns): self.add_pin(self.get_dout_name(row,col)) self.add_pin("clk") self.add_pin("vdd") self.add_pin("gnd") def create_dff_array(self): self.dff_insts={} for row in range(self.rows): for col in range(self.columns): name = "dff_r{0}_c{1}".format(row,col) self.dff_insts[row,col]=self.add_inst(name=name, mod=self.dff) self.connect_inst([self.get_din_name(row,col), self.get_dout_name(row,col), "clk", "vdd", "gnd"]) def place_dff_array(self): for row in range(self.rows): for col in range(self.columns): name = "dff_r{0}_c{1}".format(row,col) if (row % 2 == 0): base = vector(col*self.dff.width,row*self.dff.height) mirror = "R0" else: base = vector(col*self.dff.width,(row+1)*self.dff.height) mirror = "MX" self.dff_insts[row,col].place(offset=base, mirror=mirror) def get_din_name(self, row, col): if self.columns == 1: din_name = "din_{0}".format(row) elif self.rows == 1: din_name = "din_{0}".format(col) else: din_name = "din_{0}_{1}".format(row,col) return din_name def get_dout_name(self, row, col): if self.columns == 1: dout_name = "dout_{0}".format(row) elif self.rows == 1: dout_name = "dout_{0}".format(col) else: dout_name = "dout_{0}_{1}".format(row,col) return dout_name def add_layout_pins(self): for row in range(self.rows): for col in range(self.columns): # Continous vdd rail along with label. vdd_pin=self.dff_insts[row,col].get_pin("vdd") self.add_power_pin("vdd", vdd_pin.center()) # Continous gnd rail along with label. gnd_pin=self.dff_insts[row,col].get_pin("gnd") self.add_power_pin("gnd", gnd_pin.center()) for row in range(self.rows): for col in range(self.columns): din_pin = self.dff_insts[row,col].get_pin("D") debug.check(din_pin.layer=="metal2","DFF D pin not on metal2") self.add_layout_pin(text=self.get_din_name(row,col), layer=din_pin.layer, offset=din_pin.ll(), width=din_pin.width(), height=din_pin.height()) dout_pin = self.dff_insts[row,col].get_pin("Q") debug.check(dout_pin.layer=="metal2","DFF Q pin not on metal2") self.add_layout_pin(text=self.get_dout_name(row,col), layer=dout_pin.layer, offset=dout_pin.ll(), width=dout_pin.width(), height=dout_pin.height()) # Create vertical spines to a single horizontal rail clk_pin = self.dff_insts[0,0].get_pin("clk") clk_ypos = 2*self.m3_pitch+self.m3_width debug.check(clk_pin.layer=="metal2","DFF clk pin not on metal2") self.add_layout_pin_segment_center(text="clk", layer="metal3", start=vector(0,clk_ypos), end=vector(self.width,clk_ypos)) for col in range(self.columns): clk_pin = self.dff_insts[0,col].get_pin("clk") # Make a vertical strip for each column self.add_rect(layer="metal2", offset=clk_pin.ll().scale(1,0), width=self.m2_width, height=self.height) # Drop a via to the M3 pin self.add_via_center(layers=("metal2","via2","metal3"), offset=vector(clk_pin.cx(),clk_ypos)) def analytical_delay(self, corner, slew, load=0.0): return self.dff.analytical_delay(corner, slew=slew, load=load) def get_clk_cin(self): """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" dff_clk_cin = self.dff.get_clk_cin() total_cin = dff_clk_cin * self.rows * self.columns return total_cin