mirror of https://github.com/VLSIDA/OpenRAM.git
Convert wordline driver to pand2 rather than pnand2+pdriver
This commit is contained in:
parent
8e243f1b3c
commit
32576fb62c
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue