Convert wordline driver to pand2 rather than pnand2+pdriver

This commit is contained in:
mrg 2020-04-22 13:27:50 -07:00
parent 8e243f1b3c
commit 32576fb62c
4 changed files with 54 additions and 71 deletions

View File

@ -90,7 +90,7 @@ class control_logic(design.design):
self.add_mod(self.ctrl_dff_array)
self.and2 = factory.create(module_type="pand2",
size=4,
size=12,
height=dff_height)
self.add_mod(self.and2)

View File

@ -32,7 +32,6 @@ class hierarchical_decoder(design.design):
self.cell_multiple = cell_properties.bitcell.decoder_bitcell_multiple
except AttributeError:
self.cell_multiple = 1
# For debugging
self.cell_height = self.cell_multiple * b.height
self.num_outputs = num_outputs

View File

@ -7,10 +7,12 @@
#
import debug
import design
import math
import contact
from vector import vector
from sram_factory import factory
from globals import OPTS
from tech import cell_properties
class wordline_driver(design.design):
@ -26,6 +28,13 @@ class wordline_driver(design.design):
self.rows = rows
self.cols = cols
b = factory.create(module_type="bitcell")
try:
self.cell_multiple = cell_properties.bitcell.decoder_bitcell_multiple
except AttributeError:
self.cell_multiple = 1
self.cell_height = self.cell_multiple * b.height
self.create_netlist()
if not OPTS.netlist_only:
@ -37,6 +46,7 @@ class wordline_driver(design.design):
self.create_drivers()
def create_layout(self):
self.setup_layout_constants()
self.place_drivers()
self.route_layout()
self.route_vdd_gnd()
@ -56,17 +66,10 @@ class wordline_driver(design.design):
self.add_pin("gnd", "GROUND")
def add_modules(self):
b = factory.create(module_type="bitcell")
self.inv = factory.create(module_type="pdriver",
fanout=self.cols,
neg_polarity=True,
height=b.height)
self.add_mod(self.inv)
self.nand2 = factory.create(module_type="pnand2",
height=b.height)
self.add_mod(self.nand2)
self.and2 = factory.create(module_type="pand2",
height=self.cell_height,
size=self.cols)
self.add_mod(self.and2)
def route_vdd_gnd(self):
"""
@ -75,68 +78,64 @@ class wordline_driver(design.design):
"""
# Find the x offsets for where the vias/pins should be placed
a_xoffset = self.nand_inst[0].lx()
xoffset_list = [self.and_inst[0].lx()]
for num in range(self.rows):
# this will result in duplicate polygons for rails, but who cares
# use the inverter offset even though it will be the nand's too
# use the inverter offset even though it will be the and's too
(gate_offset, y_dir) = self.get_gate_offset(0,
self.inv.height,
self.and2.height,
num)
# Route both supplies
for name in ["vdd", "gnd"]:
supply_pin = self.inv2_inst[num].get_pin(name)
supply_pin = self.and_inst[num].get_pin(name)
# Add pins in two locations
for xoffset in [a_xoffset]:
for xoffset in xoffset_list:
pin_pos = vector(xoffset, supply_pin.cy())
self.add_power_pin(name, pin_pos)
def create_drivers(self):
self.nand_inst = []
self.inv2_inst = []
self.and_inst = []
for row in range(self.rows):
name_nand = "wl_driver_nand{}".format(row)
name_inv2 = "wl_driver_inv{}".format(row)
name_and = "wl_driver_and{}".format(row)
# add nand 2
self.nand_inst.append(self.add_inst(name=name_nand,
mod=self.nand2))
# add and2
self.and_inst.append(self.add_inst(name=name_and,
mod=self.and2))
self.connect_inst(["en",
"in_{0}".format(row),
"wl_bar_{0}".format(row),
"vdd", "gnd"])
# add inv2
self.inv2_inst.append(self.add_inst(name=name_inv2,
mod=self.inv))
self.connect_inst(["wl_bar_{0}".format(row),
"wl_{0}".format(row),
"vdd", "gnd"])
def setup_layout_constants(self):
# We may have more than one bitcell per decoder row
self.num_rows = math.ceil(self.rows / self.cell_multiple)
# We will place this many final decoders per row
self.decoders_per_row = math.ceil(self.rows / self.num_rows)
def place_drivers(self):
nand2_xoffset = 2 * self.m1_width + 5 * self.m1_space
inv2_xoffset = nand2_xoffset + self.nand2.width
and2_xoffset = 2 * self.m1_width + 5 * self.m1_space
self.width = inv2_xoffset + self.inv.width
self.height = self.inv.height * self.rows
self.width = and2_xoffset + self.and2.width
self.height = self.and2.height * self.num_rows
for row in range(self.rows):
#row = math.floor(inst_index / self.decoders_per_row)
#dec = inst_index % self.decoders_per_row
if (row % 2):
y_offset = self.inv.height * (row + 1)
y_offset = self.and2.height * (row + 1)
inst_mirror = "MX"
else:
y_offset = self.inv.height * row
y_offset = self.and2.height * row
inst_mirror = "R0"
nand2_offset = [nand2_xoffset, y_offset]
inv2_offset = [inv2_xoffset, y_offset]
# x_off = self.internal_routing_width + dec * and_mod.width
and2_offset = [and2_xoffset, y_offset]
# add nand 2
self.nand_inst[row].place(offset=nand2_offset,
mirror=inst_mirror)
# add inv2
self.inv2_inst[row].place(offset=inv2_offset,
# add and2
self.and_inst[row].place(offset=and2_offset,
mirror=inst_mirror)
def route_layout(self):
@ -151,11 +150,10 @@ class wordline_driver(design.design):
height=self.height)
for row in range(self.rows):
nand_inst = self.nand_inst[row]
inv2_inst = self.inv2_inst[row]
and_inst = self.and_inst[row]
# en connection
a_pin = nand_inst.get_pin("A")
a_pin = and_inst.get_pin("A")
a_pos = a_pin.lc()
clk_offset = vector(en_pin.bc().x, a_pos.y)
self.add_segment_center(layer="m1",
@ -164,18 +162,10 @@ class wordline_driver(design.design):
self.add_via_center(layers=self.m1_stack,
offset=clk_offset)
# Nand2 out to 2nd inv
zr_pos = nand_inst.get_pin("Z").rc()
al_pos = inv2_inst.get_pin("A").lc()
# ensure the bend is in the middle
mid1_pos = vector(0.5 * (zr_pos.x + al_pos.x), zr_pos.y)
mid2_pos = vector(0.5 * (zr_pos.x + al_pos.x), al_pos.y)
self.add_path("m1", [zr_pos, mid1_pos, mid2_pos, al_pos])
# connect the decoder input pin to nand2 B
b_pin = nand_inst.get_pin("B")
# connect the decoder input pin to and2 B
b_pin = and_inst.get_pin("B")
b_pos = b_pin.lc()
# needs to move down since B nand input is
# needs to move down since B and input is
# nearly aligned with A inv input
up_or_down = self.m2_space if row % 2 else -self.m2_space
input_offset = vector(0, b_pos.y + up_or_down)
@ -192,7 +182,7 @@ class wordline_driver(design.design):
offset=mid_via_offset,
directions=("V", "V"))
# now connect to the nand2 B
# now connect to the and2 B
self.add_path("m2", [mid_via_offset, b_pos])
contact_offset = b_pos - vector(0.5 * contact.m1_via.height, 0)
self.add_via_center(layers=self.m1_stack,
@ -200,7 +190,7 @@ class wordline_driver(design.design):
directions=("H", "H"))
# output each WL on the right
wl_offset = inv2_inst.get_pin("Z").rc()
wl_offset = and_inst.get_pin("Z").rc()
self.add_layout_pin_segment_center(text="wl_{0}".format(row),
layer="m1",
start=wl_offset,
@ -213,13 +203,8 @@ class wordline_driver(design.design):
"""
stage_effort_list = []
stage1_cout = self.inv.get_cin()
stage1 = self.nand2.get_stage_effort(stage1_cout, inp_is_rise)
stage1 = self.and2.get_stage_effort(external_cout, inp_is_rise)
stage_effort_list.append(stage1)
last_stage_is_rise = stage1.is_rise
stage2 = self.inv.get_stage_efforts(external_cout, last_stage_is_rise)
stage_effort_list.extend(stage2)
return stage_effort_list
@ -228,6 +213,6 @@ class wordline_driver(design.design):
Get the relative capacitance of all
the enable connections in the bank
"""
# The enable is connected to a nand2 for every row.
total_cin = self.nand2.get_cin() * self.rows
# The enable is connected to a and2 for every row.
total_cin = self.and2.get_cin() * self.rows
return total_cin

View File

@ -30,13 +30,12 @@ class pand2(pgate.pgate):
self.create_insts()
def create_modules(self):
# Shield the cap, but have at least a stage effort of 4
self.nand = factory.create(module_type="pnand2", height=self.height)
self.add_mod(self.nand)
self.inv = factory.create(module_type="pdriver",
neg_polarity=True,
fanout=3*self.size,
fanout=self.size,
height=self.height)
self.add_mod(self.inv)