mirror of https://github.com/VLSIDA/OpenRAM.git
Add bank_sel to bank_select module as input.
Remove reference to control in sram. Add dff_buf_array to options. Added inverted DFF Add variable height pinvbuf
This commit is contained in:
parent
5bf915a232
commit
696433b1ec
|
|
@ -56,8 +56,6 @@ class bank(design.design):
|
|||
self.add_modules()
|
||||
self.setup_layout_constraints()
|
||||
|
||||
self.add_power_ring(self.core_bbox)
|
||||
|
||||
# FIXME: Move this to the add modules function
|
||||
self.add_bank_select()
|
||||
|
||||
|
|
@ -451,6 +449,7 @@ class bank(design.design):
|
|||
|
||||
temp = []
|
||||
temp.extend(self.input_control_signals)
|
||||
temp.append("bank_sel")
|
||||
temp.extend(self.control_signals)
|
||||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
|
@ -488,39 +487,41 @@ class bank(design.design):
|
|||
#the column decoder (if there is one) or the tristate output
|
||||
#driver.
|
||||
# Leave room for the output below the tri gate.
|
||||
tri_gate_min_point = self.tri_gate_array_inst.by() - 3*self.m2_pitch
|
||||
row_decoder_min_point = self.row_decoder_inst.by()
|
||||
tri_gate_min_y_offset = self.tri_gate_array_inst.by() - 3*self.m2_pitch
|
||||
row_decoder_min_y_offset = self.row_decoder_inst.by()
|
||||
if self.col_addr_size > 0:
|
||||
col_decoder_min_point = self.col_decoder_inst.by()
|
||||
col_decoder_min_y_offset = self.col_decoder_inst.by()
|
||||
else:
|
||||
col_decoder_min_point = row_decoder_min_point
|
||||
col_decoder_min_y_offset = row_decoder_min_y_offset
|
||||
|
||||
if self.num_banks>1:
|
||||
# The control gating logic is below the decoder
|
||||
# Min of the control gating logic and tri gate.
|
||||
self.min_point = min(col_decoder_min_point - self.bank_select.height, tri_gate_min_point)
|
||||
self.min_y_offset = min(col_decoder_min_y_offset - self.bank_select.height, tri_gate_min_y_offset)
|
||||
else:
|
||||
# Just the min of the decoder logic logic and tri gate.
|
||||
self.min_point = min(col_decoder_min_point, tri_gate_min_point)
|
||||
self.min_y_offset = min(col_decoder_min_y_offset, tri_gate_min_y_offset)
|
||||
|
||||
# The max point is always the top of the precharge bitlines
|
||||
# Add a vdd and gnd power rail above the array
|
||||
self.max_point = self.precharge_array_inst.uy() + 3*self.m1_width
|
||||
self.max_y_offset = self.precharge_array_inst.uy() + 3*self.m1_width
|
||||
self.max_x_offset = self.bitcell_array_inst.ur().x + 3*self.m1_width
|
||||
self.min_x_offset = self.row_decoder_inst.lx()
|
||||
|
||||
# Create the core bbox for the power rings
|
||||
ur = vector(self.bitcell_array_inst.ur().x + 3*self.m1_width, self.max_point)
|
||||
ll = vector(self.row_decoder_inst.lx(), self.min_point)
|
||||
ur = vector(self.max_x_offset, self.max_y_offset)
|
||||
ll = vector(self.min_x_offset, self.min_y_offset)
|
||||
self.core_bbox = [ll, ur]
|
||||
|
||||
self.add_power_ring(self.core_bbox)
|
||||
|
||||
# Compute the vertical rail positions for later use
|
||||
self.right_gnd_x_offset = ur.x
|
||||
self.right_gnd_x_offset = self.right_gnd_x_center - 0.5*self.supply_rail_pitch
|
||||
self.right_vdd_x_offset = self.right_gnd_x_offset + self.supply_rail_pitch
|
||||
self.left_vdd_x_offset = ll.x - self.supply_rail_pitch
|
||||
self.left_vdd_x_offset = self.left_gnd_x_center - 0.5*self.supply_rail_pitch
|
||||
self.left_gnd_x_offset = self.left_vdd_x_offset - self.supply_rail_pitch
|
||||
|
||||
# Add a vdd and gnd power rail below the array
|
||||
self.min_point -= 2*self.supply_rail_pitch
|
||||
# Add a vdd and gnd power rail above the array
|
||||
self.max_point += self.supply_rail_pitch + self.supply_rail_width
|
||||
|
||||
# Have the pins go below the vdd and gnd power rail at the bottom
|
||||
self.min_y_offset -= 2*self.supply_rail_pitch
|
||||
|
||||
self.height = ur.y - ll.y + 4*self.supply_rail_pitch
|
||||
self.width = ur.x - ll.x + 4*self.supply_rail_pitch
|
||||
|
|
@ -547,9 +548,9 @@ class bank(design.design):
|
|||
self.bus_xoffset[self.control_signals[i]]=x_offset + 0.5*self.m2_width
|
||||
# Pins are added later if this is a single bank, so just add rectangle now
|
||||
self.add_rect(layer="metal2",
|
||||
offset=vector(x_offset, self.min_point),
|
||||
offset=vector(x_offset, self.min_y_offset),
|
||||
width=self.m2_width,
|
||||
height=self.height)
|
||||
height=self.max_y_offset-self.min_y_offset)
|
||||
|
||||
|
||||
|
||||
|
|
@ -606,12 +607,12 @@ class bank(design.design):
|
|||
""" Metal 3 routing of tri_gate output data """
|
||||
for i in range(self.word_size):
|
||||
tri_gate_out_position = self.tri_gate_array_inst.get_pin("out[{}]".format(i)).ul()
|
||||
data_line_position = vector(tri_gate_out_position.x, self.min_point)
|
||||
data_line_position = vector(tri_gate_out_position.x, self.min_y_offset)
|
||||
self.add_via(("metal2", "via2", "metal3"), data_line_position)
|
||||
self.add_rect(layer="metal3",
|
||||
offset=data_line_position,
|
||||
width=drc["minwidth_metal3"],
|
||||
height=tri_gate_out_position.y - self.min_point)
|
||||
height=tri_gate_out_position.y - self.min_y_offset)
|
||||
self.add_layout_pin(text="DATA[{}]".format(i),
|
||||
layer="metal2",
|
||||
offset=data_line_position,
|
||||
|
|
@ -620,12 +621,12 @@ class bank(design.design):
|
|||
def route_row_decoder(self):
|
||||
""" Routes the row decoder inputs and supplies """
|
||||
|
||||
# # Create inputs for the row address lines
|
||||
# for i in range(self.row_addr_size):
|
||||
# addr_idx = i + self.col_addr_size
|
||||
# decoder_name = "A[{}]".format(i)
|
||||
# addr_name = "A[{}]".format(addr_idx)
|
||||
# self.copy_layout_pin(self.row_decoder_inst, decoder_name, addr_name)
|
||||
# Create inputs for the row address lines
|
||||
for i in range(self.row_addr_size):
|
||||
addr_idx = i + self.col_addr_size
|
||||
decoder_name = "A[{}]".format(i)
|
||||
addr_name = "A[{}]".format(addr_idx)
|
||||
self.copy_layout_pin(self.row_decoder_inst, decoder_name, addr_name)
|
||||
|
||||
|
||||
# Route the power and ground, but only BELOW the y=0 since the
|
||||
|
|
@ -909,15 +910,15 @@ class bank(design.design):
|
|||
# it's not an input pin if we have multiple banks
|
||||
self.add_label_pin(text=ctrl,
|
||||
layer="metal2",
|
||||
offset=vector(x_offset, self.min_point),
|
||||
offset=vector(x_offset, self.min_y_offset),
|
||||
width=self.m2_width,
|
||||
height=self.height)
|
||||
height=self.max_y_offset-self.min_y_offset)
|
||||
else:
|
||||
self.add_layout_pin(text=ctrl,
|
||||
layer="metal2",
|
||||
offset=vector(x_offset, self.min_point),
|
||||
offset=vector(x_offset, self.min_y_offset),
|
||||
width=self.m2_width,
|
||||
height=self.height)
|
||||
height=self.max_y_offset-self.min_y_offset)
|
||||
|
||||
|
||||
def connect_rail_from_right(self,inst, pin, rail):
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ class bank_select(design.design):
|
|||
self.control_signals = ["gated_"+str for str in self.input_control_signals]
|
||||
|
||||
self.add_pin_list(self.input_control_signals, "INPUT")
|
||||
self.add_pin("bank_sel")
|
||||
self.add_pin_list(self.control_signals, "OUTPUT")
|
||||
self.add_pin("vdd","POWER")
|
||||
self.add_pin("gnd","GROUND")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,128 @@
|
|||
import debug
|
||||
import design
|
||||
from tech import drc
|
||||
from math import log
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
from pinv import pinv
|
||||
|
||||
class dff_inv(design.design):
|
||||
"""
|
||||
This is a simple DFF with an inverted output. Some DFFs
|
||||
do not have Qbar, so this will create it.
|
||||
"""
|
||||
|
||||
def __init__(self, inv_size=1, name=""):
|
||||
|
||||
if name=="":
|
||||
name = "dff_inv_{0}".format(inv_size)
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
c = reload(__import__(OPTS.dff))
|
||||
self.mod_dff = getattr(c, OPTS.dff)
|
||||
self.dff = self.mod_dff("dff")
|
||||
self.add_mod(self.dff)
|
||||
|
||||
self.inv1 = pinv(size=inv_size,height=self.dff.height)
|
||||
self.add_mod(self.inv1)
|
||||
|
||||
self.width = self.dff.width + self.inv1.width
|
||||
self.height = self.dff.height
|
||||
|
||||
self.create_layout()
|
||||
|
||||
def create_layout(self):
|
||||
self.add_pins()
|
||||
self.add_insts()
|
||||
self.add_wires()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
self.add_pin("D")
|
||||
self.add_pin("Q")
|
||||
self.add_pin("Qb")
|
||||
self.add_pin("clk")
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def add_insts(self):
|
||||
# Add the DFF
|
||||
self.dff_inst=self.add_inst(name="dff_inv_dff",
|
||||
mod=self.dff,
|
||||
offset=vector(0,0))
|
||||
self.connect_inst(["D", "Q", "clk", "vdd", "gnd"])
|
||||
|
||||
# Add INV1 to the right
|
||||
self.inv1_inst=self.add_inst(name="dff_inv_inv1",
|
||||
mod=self.inv1,
|
||||
offset=vector(self.dff_inst.rx(),0))
|
||||
self.connect_inst(["Q", "Qb", "vdd", "gnd"])
|
||||
|
||||
|
||||
def add_wires(self):
|
||||
# Route dff q to inv1 a
|
||||
q_pin = self.dff_inst.get_pin("Q")
|
||||
a1_pin = self.inv1_inst.get_pin("A")
|
||||
mid_point = vector(a1_pin.cx(), q_pin.cy())
|
||||
self.add_wire(("metal3","via2","metal2"),
|
||||
[q_pin.center(), mid_point, a1_pin.center()])
|
||||
self.add_via_center(("metal2","via2","metal3"),
|
||||
q_pin.center())
|
||||
self.add_via_center(("metal1","via1","metal2"),
|
||||
a1_pin.center())
|
||||
|
||||
|
||||
def add_layout_pins(self):
|
||||
|
||||
# Continous vdd rail along with label.
|
||||
vdd_pin=self.dff_inst.get_pin("vdd")
|
||||
self.add_layout_pin(text="vdd",
|
||||
layer="metal1",
|
||||
offset=vdd_pin.ll(),
|
||||
width=self.width,
|
||||
height=vdd_pin.height())
|
||||
|
||||
# Continous gnd rail along with label.
|
||||
gnd_pin=self.dff_inst.get_pin("gnd")
|
||||
self.add_layout_pin(text="gnd",
|
||||
layer="metal1",
|
||||
offset=gnd_pin.ll(),
|
||||
width=self.width,
|
||||
height=vdd_pin.height())
|
||||
|
||||
clk_pin = self.dff_inst.get_pin("clk")
|
||||
self.add_layout_pin(text="clk",
|
||||
layer=clk_pin.layer,
|
||||
offset=clk_pin.ll(),
|
||||
width=clk_pin.width(),
|
||||
height=clk_pin.height())
|
||||
|
||||
din_pin = self.dff_inst.get_pin("D")
|
||||
self.add_layout_pin(text="D",
|
||||
layer=din_pin.layer,
|
||||
offset=din_pin.ll(),
|
||||
width=din_pin.width(),
|
||||
height=din_pin.height())
|
||||
|
||||
dout_pin = self.dff_inst.get_pin("Q")
|
||||
self.add_layout_pin_center_rect(text="Q",
|
||||
layer=dout_pin.layer,
|
||||
offset=dout_pin.center())
|
||||
|
||||
dout_pin = self.inv1_inst.get_pin("Z")
|
||||
self.add_layout_pin_center_rect(text="Qb",
|
||||
layer="metal2",
|
||||
offset=dout_pin.center())
|
||||
self.add_via_center(layers=("metal1","via1","metal2"),
|
||||
offset=dout_pin.center())
|
||||
|
||||
|
||||
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
""" Calculate the analytical delay of DFF-> INV -> INV """
|
||||
dff_delay=self.dff.analytical_delay(slew=slew, load=self.inv1.input_load())
|
||||
inv1_delay = self.inv1.analytical_delay(slew=dff_delay.slew, load=load)
|
||||
return dff_delay + inv1_delay
|
||||
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
import debug
|
||||
import design
|
||||
from tech import drc
|
||||
from math import log
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
import dff_inv
|
||||
|
||||
class dff_inv_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, inv_size=2, 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 {}".format(self.name))
|
||||
|
||||
self.dff = dff_inv.dff_inv(inv_size)
|
||||
self.add_mod(self.dff)
|
||||
|
||||
self.width = self.columns * self.dff.width
|
||||
self.height = self.rows * self.dff.height
|
||||
|
||||
self.create_layout()
|
||||
|
||||
def create_layout(self):
|
||||
self.add_pins()
|
||||
self.create_dff_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
for y in range(self.rows):
|
||||
for x in range(self.columns):
|
||||
self.add_pin(self.get_din_name(y,x))
|
||||
for y in range(self.rows):
|
||||
for x in range(self.columns):
|
||||
self.add_pin(self.get_dout_name(y,x))
|
||||
self.add_pin(self.get_dout_bar_name(y,x))
|
||||
self.add_pin("clk")
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def create_dff_array(self):
|
||||
self.dff_insts={}
|
||||
for y in range(self.rows):
|
||||
for x in range(self.columns):
|
||||
name = "Xdff_r{0}_c{1}".format(y,x)
|
||||
if (y % 2 == 0):
|
||||
base = vector(x*self.dff.width,y*self.dff.height)
|
||||
mirror = "R0"
|
||||
else:
|
||||
base = vector(x*self.dff.width,(y+1)*self.dff.height)
|
||||
mirror = "MX"
|
||||
self.dff_insts[x,y]=self.add_inst(name=name,
|
||||
mod=self.dff,
|
||||
offset=base,
|
||||
mirror=mirror)
|
||||
self.connect_inst([self.get_din_name(y,x),
|
||||
self.get_dout_name(y,x),
|
||||
self.get_dout_bar_name(y,x),
|
||||
"clk",
|
||||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
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 get_dout_bar_name(self, row, col):
|
||||
if self.columns == 1:
|
||||
dout_bar_name = "dout_bar[{0}]".format(row)
|
||||
elif self.rows == 1:
|
||||
dout_bar_name = "dout_bar[{0}]".format(col)
|
||||
else:
|
||||
dout_bar_name = "dout_bar[{0}][{1}]".format(row,col)
|
||||
|
||||
return dout_bar_name
|
||||
|
||||
def add_layout_pins(self):
|
||||
|
||||
for y in range(self.rows):
|
||||
# Continous vdd rail along with label.
|
||||
vdd_pin=self.dff_insts[0,y].get_pin("vdd")
|
||||
self.add_layout_pin(text="vdd",
|
||||
layer="metal1",
|
||||
offset=vdd_pin.ll(),
|
||||
width=self.width,
|
||||
height=self.m1_width)
|
||||
|
||||
# Continous gnd rail along with label.
|
||||
gnd_pin=self.dff_insts[0,y].get_pin("gnd")
|
||||
self.add_layout_pin(text="gnd",
|
||||
layer="metal1",
|
||||
offset=gnd_pin.ll(),
|
||||
width=self.width,
|
||||
height=self.m1_width)
|
||||
|
||||
|
||||
for y in range(self.rows):
|
||||
for x in range(self.columns):
|
||||
din_pin = self.dff_insts[x,y].get_pin("D")
|
||||
debug.check(din_pin.layer=="metal2","DFF D pin not on metal2")
|
||||
self.add_layout_pin(text=self.get_din_name(y,x),
|
||||
layer=din_pin.layer,
|
||||
offset=din_pin.ll(),
|
||||
width=din_pin.width(),
|
||||
height=din_pin.height())
|
||||
|
||||
dout_pin = self.dff_insts[x,y].get_pin("Q")
|
||||
debug.check(dout_pin.layer=="metal2","DFF Q pin not on metal2")
|
||||
self.add_layout_pin(text=self.get_dout_name(y,x),
|
||||
layer=dout_pin.layer,
|
||||
offset=dout_pin.ll(),
|
||||
width=dout_pin.width(),
|
||||
height=dout_pin.height())
|
||||
|
||||
|
||||
dout_bar_pin = self.dff_insts[x,y].get_pin("Qb")
|
||||
debug.check(dout_bar_pin.layer=="metal2","DFF Qb pin not on metal2")
|
||||
self.add_layout_pin(text=self.get_dout_bar_name(y,x),
|
||||
layer=dout_bar_pin.layer,
|
||||
offset=dout_bar_pin.ll(),
|
||||
width=dout_bar_pin.width(),
|
||||
height=dout_bar_pin.height())
|
||||
|
||||
|
||||
# Create vertical spines to a single horizontal rail
|
||||
clk_pin = self.dff_insts[0,0].get_pin("clk")
|
||||
debug.check(clk_pin.layer=="metal2","DFF clk pin not on metal2")
|
||||
if self.columns==1:
|
||||
self.add_layout_pin(text="clk",
|
||||
layer="metal2",
|
||||
offset=clk_pin.ll().scale(1,0),
|
||||
width=self.m2_width,
|
||||
height=self.height)
|
||||
else:
|
||||
self.add_layout_pin(text="clk",
|
||||
layer="metal3",
|
||||
offset=vector(0,0),
|
||||
width=self.width,
|
||||
height=self.m3_width)
|
||||
for x in range(self.columns):
|
||||
clk_pin = self.dff_insts[x,0].get_pin("clk")
|
||||
# Make a vertical strip for each column
|
||||
self.add_layout_pin(text="clk",
|
||||
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=clk_pin.center().scale(1,0))
|
||||
|
||||
|
||||
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
return self.dff.analytical_delay(slew=slew, load=load)
|
||||
|
|
@ -59,7 +59,8 @@ class options(optparse.Values):
|
|||
ms_flop = "ms_flop"
|
||||
ms_flop_array = "ms_flop_array"
|
||||
dff = "dff"
|
||||
dff_array = "dff_buf_array"
|
||||
dff_array = "dff_array"
|
||||
dff_buf_array = "dff_buf_array"
|
||||
control_logic = "control_logic"
|
||||
bitcell_array = "bitcell_array"
|
||||
sense_amp = "sense_amp"
|
||||
|
|
|
|||
|
|
@ -11,21 +11,23 @@ class pinvbuf(design.design):
|
|||
This is a simple inverter/buffer used for driving loads. It is
|
||||
used in the column decoder for 1:2 decoding and as the clock buffer.
|
||||
"""
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
bitcell = getattr(c, OPTS.bitcell)
|
||||
|
||||
def __init__(self, inv1_size=2, inv2_size=4, name=""):
|
||||
def __init__(self, inv1_size=2, inv2_size=4, height=bitcell.height, name=""):
|
||||
|
||||
if name=="":
|
||||
name = "pinvbuf_{0}_{1}".format(inv1_size, inv2_size)
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
self.inv = pinv(size=1)
|
||||
self.inv = pinv(size=1, height=height)
|
||||
self.add_mod(self.inv)
|
||||
|
||||
self.inv1 = pinv(size=inv1_size)
|
||||
self.inv1 = pinv(size=inv1_size, height=height)
|
||||
self.add_mod(self.inv1)
|
||||
|
||||
self.inv2 = pinv(size=inv2_size)
|
||||
self.inv2 = pinv(size=inv2_size, height=height)
|
||||
self.add_mod(self.inv2)
|
||||
|
||||
self.width = 2*self.inv1.width + self.inv2.width
|
||||
|
|
|
|||
|
|
@ -219,18 +219,17 @@ class sram(design.design):
|
|||
# 3/5/18 MRG: Cannot reference positions inside submodules because boundaries
|
||||
# are not recomputed using instance placement. So, place the control logic such that it aligns
|
||||
# with the top of the SRAM.
|
||||
control_gap = 2*self.m3_width
|
||||
control_pos = vector(-self.control_logic.width-control_gap,
|
||||
self.bank.height-self.control_logic.height-3*self.supply_rail_width)
|
||||
control_pos = vector(-self.control_logic.width - self.m3_pitch,
|
||||
self.bank.height - self.control_logic.height - 3*self.supply_rail_width)
|
||||
self.add_control_logic(position=control_pos)
|
||||
|
||||
# Leave room for the control routes to the left of the flops
|
||||
addr_pos = vector(self.control_logic_inst.lx() + 4*self.m2_pitch,
|
||||
3*self.supply_rail_pitch)
|
||||
self.add_control_addr_dff(addr_pos)
|
||||
self.add_addr_dff(addr_pos)
|
||||
|
||||
self.width = self.bank.width + self.control_logic.height + control_gap
|
||||
self.height = self.bank.height
|
||||
self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
|
||||
self.height = self.bank.height + 2*self.supply_rail_pitch
|
||||
|
||||
|
||||
def route_shared_banks(self):
|
||||
|
|
@ -933,7 +932,7 @@ class sram(design.design):
|
|||
return line_positions
|
||||
|
||||
|
||||
def add_control_addr_dff(self, position):
|
||||
def add_addr_dff(self, position):
|
||||
""" Add and place address and control flops """
|
||||
self.addr_dff_inst = self.add_inst(name="address",
|
||||
mod=self.addr_dff,
|
||||
|
|
@ -945,7 +944,7 @@ class sram(design.design):
|
|||
inputs.append("ADDR[{}]".format(i))
|
||||
outputs.append("A[{}]".format(i))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk", "vdd", "gnd"])
|
||||
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
|
||||
|
||||
def add_control_logic(self, position):
|
||||
""" Add and place control logic """
|
||||
|
|
@ -989,9 +988,6 @@ class sram(design.design):
|
|||
for i in range(self.addr_size):
|
||||
self.copy_layout_pin(self.addr_dff_inst, "din[{}]".format(i),"ADDR[{}]".format(i))
|
||||
|
||||
self.copy_layout_pin(self.addr_dff_inst, "clk")
|
||||
|
||||
# Power ring contains the power pins
|
||||
|
||||
def add_two_banks(self):
|
||||
# Placement of bank 0 (left)
|
||||
|
|
@ -1083,10 +1079,8 @@ class sram(design.design):
|
|||
self.copy_layout_pin(self.control_logic_inst, n.lower(), n)
|
||||
|
||||
# Connect the clock between the flops and control module
|
||||
# FIXME: Buffered clock should drive the flops, but then
|
||||
# it would change the setup time...
|
||||
flop_pin = self.addr_dff_inst.get_pin("clk")
|
||||
ctrl_pin = self.control_logic_inst.get_pin("clk")
|
||||
ctrl_pin = self.control_logic_inst.get_pin("clk_buf")
|
||||
flop_pos = flop_pin.uc()
|
||||
ctrl_pos = ctrl_pin.bc()
|
||||
mid_ypos = 0.5*(ctrl_pos.y+flop_pos.y)
|
||||
|
|
@ -1109,7 +1103,7 @@ class sram(design.design):
|
|||
self.add_path("metal1", [left_rail_pos, vdd_pos])
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=left_rail_pos,
|
||||
size = (1,3),
|
||||
size = (1,self.supply_vias),
|
||||
rotate=90)
|
||||
|
||||
# Route the vdd rails to the TOP
|
||||
|
|
@ -1121,7 +1115,7 @@ class sram(design.design):
|
|||
self.add_path("metal2", [top_rail_pos, vdd_pos])
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=top_rail_pos,
|
||||
size = (1,3))
|
||||
size = (1,self.supply_vias))
|
||||
|
||||
|
||||
def route_single_bank_gnd(self):
|
||||
|
|
@ -1138,7 +1132,7 @@ class sram(design.design):
|
|||
self.add_path("metal1", [left_rail_pos, gnd_pos])
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=left_rail_pos,
|
||||
size = (1,3),
|
||||
size = (1,self.supply_vias),
|
||||
rotate=90)
|
||||
|
||||
# Route the vdd rails to the TOP
|
||||
|
|
@ -1150,7 +1144,7 @@ class sram(design.design):
|
|||
self.add_path("metal2", [top_rail_pos, gnd_pos])
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=top_rail_pos,
|
||||
size = (1,3))
|
||||
size = (1,self.supply_vias))
|
||||
|
||||
|
||||
def sp_write(self, sp_name):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env python2.7
|
||||
"""
|
||||
Run a regresion test on a dff_array.
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
class dff_inv_array_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import dff_inv_array
|
||||
|
||||
debug.info(2, "Testing dff_inv_array for 3x3")
|
||||
a = dff_inv_array.dff_inv_array(rows=3, columns=3)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(2, "Testing dff_inv_array for 1x3")
|
||||
a = dff_inv_array.dff_inv_array(rows=1, columns=3)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(2, "Testing dff_inv_array for 3x1")
|
||||
a = dff_inv_array.dff_inv_array(rows=3, columns=1)
|
||||
self.local_check(a)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
del sys.argv[1:]
|
||||
header(__file__, OPTS.tech_name)
|
||||
unittest.main()
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/env python2.7
|
||||
"""
|
||||
Run a regresion test on a dff_inv.
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
class dff_inv_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import dff_inv
|
||||
|
||||
debug.info(2, "Testing dff_inv 4x")
|
||||
a = dff_inv.dff_inv(4)
|
||||
self.local_check(a)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
del sys.argv[1:]
|
||||
header(__file__, OPTS.tech_name)
|
||||
unittest.main()
|
||||
|
|
@ -135,7 +135,6 @@ def write_netgen_script(cell_name, sp_name):
|
|||
# This circuit has symmetries and needs to be flattened to resolve them or the banks won't pass
|
||||
# Is there a more elegant way to add this when needed?
|
||||
f.write("flatten class {{{0}.spice precharge_array}}\n".format(cell_name))
|
||||
f.write("flatten class {{{0}.spice dff_array}}\n".format(cell_name))
|
||||
f.write("property {{nfet {0}.spice}} remove as ad ps pd\n".format(cell_name))
|
||||
f.write("property {{pfet {0}.spice}} remove as ad ps pd\n".format(cell_name))
|
||||
f.write("property {{n {0}}} remove as ad ps pd\n".format(sp_name))
|
||||
|
|
|
|||
Loading…
Reference in New Issue