mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into analytical_cleanup
This commit is contained in:
commit
d273c0eef5
|
|
@ -84,8 +84,6 @@ class bank(design.design):
|
||||||
self.add_pin("dout{0}_{1}".format(port,bit),"OUTPUT")
|
self.add_pin("dout{0}_{1}".format(port,bit),"OUTPUT")
|
||||||
for port in self.read_ports:
|
for port in self.read_ports:
|
||||||
self.add_pin(self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]),"OUTPUT")
|
self.add_pin(self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]),"OUTPUT")
|
||||||
for port in self.read_ports:
|
|
||||||
self.add_pin(self.bitcell_array.get_rbl_wl_name(self.port_rbl_map[port]),"INPUT")
|
|
||||||
for port in self.write_ports:
|
for port in self.write_ports:
|
||||||
for bit in range(self.word_size):
|
for bit in range(self.word_size):
|
||||||
self.add_pin("din{0}_{1}".format(port,bit),"INPUT")
|
self.add_pin("din{0}_{1}".format(port,bit),"INPUT")
|
||||||
|
|
@ -306,13 +304,13 @@ class bank(design.design):
|
||||||
self.input_control_signals = []
|
self.input_control_signals = []
|
||||||
port_num = 0
|
port_num = 0
|
||||||
for port in range(OPTS.num_rw_ports):
|
for port in range(OPTS.num_rw_ports):
|
||||||
self.input_control_signals.append(["wl_en{}".format(port_num), "w_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num), "rbl_wl{}".format(port_num)])
|
self.input_control_signals.append(["w_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num), "wl_en{}".format(port_num)])
|
||||||
port_num += 1
|
port_num += 1
|
||||||
for port in range(OPTS.num_w_ports):
|
for port in range(OPTS.num_w_ports):
|
||||||
self.input_control_signals.append(["wl_en{}".format(port_num), "w_en{}".format(port_num), "p_en_bar{}".format(port_num)])
|
self.input_control_signals.append(["w_en{}".format(port_num), "p_en_bar{}".format(port_num), "wl_en{}".format(port_num)])
|
||||||
port_num += 1
|
port_num += 1
|
||||||
for port in range(OPTS.num_r_ports):
|
for port in range(OPTS.num_r_ports):
|
||||||
self.input_control_signals.append(["wl_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num), "rbl_wl{}".format(port_num)])
|
self.input_control_signals.append(["s_en{}".format(port_num), "p_en_bar{}".format(port_num), "wl_en{}".format(port_num)])
|
||||||
port_num += 1
|
port_num += 1
|
||||||
|
|
||||||
# Number of control lines in the bus for each port
|
# Number of control lines in the bus for each port
|
||||||
|
|
@ -422,9 +420,9 @@ class bank(design.design):
|
||||||
for row in range(self.num_rows):
|
for row in range(self.num_rows):
|
||||||
for wordline in self.wl_names:
|
for wordline in self.wl_names:
|
||||||
temp.append("{0}_{1}".format(wordline,row))
|
temp.append("{0}_{1}".format(wordline,row))
|
||||||
for rbl in range(self.num_rbl):
|
for port in self.all_ports:
|
||||||
rbl_wl_name=self.bitcell_array.get_rbl_wl_name(rbl)
|
if self.port_data[port].has_rbl():
|
||||||
temp.append(rbl_wl_name)
|
temp.append("wl_en{0}".format(port))
|
||||||
temp.append("vdd")
|
temp.append("vdd")
|
||||||
temp.append("gnd")
|
temp.append("gnd")
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
@ -947,7 +945,7 @@ class bank(design.design):
|
||||||
|
|
||||||
if port in self.read_ports:
|
if port in self.read_ports:
|
||||||
rbl_wl_name = self.bitcell_array.get_rbl_wl_name(self.port_rbl_map[port])
|
rbl_wl_name = self.bitcell_array.get_rbl_wl_name(self.port_rbl_map[port])
|
||||||
connection.append((self.prefix+"rbl_wl{}".format(port), self.bitcell_array_inst.get_pin(rbl_wl_name).lc()))
|
connection.append((self.prefix+"wl_en{}".format(port), self.bitcell_array_inst.get_pin(rbl_wl_name).lc()))
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
connection.append((self.prefix+"w_en{}".format(port), self.port_data_inst[port].get_pin("w_en").lc()))
|
connection.append((self.prefix+"w_en{}".format(port), self.port_data_inst[port].get_pin("w_en").lc()))
|
||||||
|
|
@ -967,10 +965,10 @@ class bank(design.design):
|
||||||
control_signal = self.prefix+"wl_en{}".format(port)
|
control_signal = self.prefix+"wl_en{}".format(port)
|
||||||
if port%2:
|
if port%2:
|
||||||
pin_pos = self.port_address_inst[port].get_pin("wl_en").uc()
|
pin_pos = self.port_address_inst[port].get_pin("wl_en").uc()
|
||||||
mid_pos = pin_pos + vector(0,self.m2_gap) # to route down to the top of the bus
|
mid_pos = pin_pos + vector(0,2*self.m2_gap) # to route down to the top of the bus
|
||||||
else:
|
else:
|
||||||
pin_pos = self.port_address_inst[port].get_pin("wl_en").bc()
|
pin_pos = self.port_address_inst[port].get_pin("wl_en").bc()
|
||||||
mid_pos = pin_pos - vector(0,self.m2_gap) # to route down to the top of the bus
|
mid_pos = pin_pos - vector(0,2*self.m2_gap) # to route down to the top of the bus
|
||||||
control_x_offset = self.bus_xoffset[port][control_signal].x
|
control_x_offset = self.bus_xoffset[port][control_signal].x
|
||||||
control_pos = vector(control_x_offset, mid_pos.y)
|
control_pos = vector(control_x_offset, mid_pos.y)
|
||||||
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
|
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
|
||||||
|
|
|
||||||
|
|
@ -101,17 +101,23 @@ class control_logic(design.design):
|
||||||
self.add_mod(self.rbl_driver)
|
self.add_mod(self.rbl_driver)
|
||||||
|
|
||||||
|
|
||||||
# clk_buf drives a flop for every address and control bit
|
# clk_buf drives a flop for every address
|
||||||
|
addr_flops = math.log(self.num_words,2) + math.log(self.words_per_row,2)
|
||||||
|
# plus data flops and control flops
|
||||||
|
num_flops = addr_flops + self.word_size + self.num_control_signals
|
||||||
|
# each flop internally has a FO 5 approximately
|
||||||
# plus about 5 fanouts for the control logic
|
# plus about 5 fanouts for the control logic
|
||||||
# each flop internally has a FO 4 approximately
|
clock_fanout = 5*num_flops + 5
|
||||||
clock_fanout = 4*(math.log(self.num_words,2) + math.log(self.words_per_row,2) \
|
|
||||||
+ self.num_control_signals) + 5
|
|
||||||
self.clk_buf_driver = factory.create(module_type="pdriver",
|
self.clk_buf_driver = factory.create(module_type="pdriver",
|
||||||
fanout=clock_fanout,
|
fanout=clock_fanout,
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
|
|
||||||
self.add_mod(self.clk_buf_driver)
|
self.add_mod(self.clk_buf_driver)
|
||||||
|
|
||||||
|
# We will use the maximum since this same value is used to size the wl_en
|
||||||
|
# and the p_en_bar drivers
|
||||||
|
max_fanout = max(self.num_rows,self.num_cols)
|
||||||
|
|
||||||
# wl_en drives every row in the bank
|
# wl_en drives every row in the bank
|
||||||
self.wl_en_driver = factory.create(module_type="pdriver",
|
self.wl_en_driver = factory.create(module_type="pdriver",
|
||||||
fanout=self.num_rows,
|
fanout=self.num_rows,
|
||||||
|
|
@ -132,14 +138,16 @@ class control_logic(design.design):
|
||||||
|
|
||||||
# used to generate inverted signals with low fanout
|
# used to generate inverted signals with low fanout
|
||||||
self.inv = factory.create(module_type="pinv",
|
self.inv = factory.create(module_type="pinv",
|
||||||
size=1,
|
size=1,
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.inv)
|
self.add_mod(self.inv)
|
||||||
|
|
||||||
# p_en_bar drives every column in the bitcell array
|
# p_en_bar drives every column in the bitcell array
|
||||||
|
# but it is sized the same as the wl_en driver with
|
||||||
|
# prepended 3 inverter stages to guarantee it is slower and odd polarity
|
||||||
self.p_en_bar_driver = factory.create(module_type="pdriver",
|
self.p_en_bar_driver = factory.create(module_type="pdriver",
|
||||||
neg_polarity=True,
|
|
||||||
fanout=self.num_cols,
|
fanout=self.num_cols,
|
||||||
|
neg_polarity=True,
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.p_en_bar_driver)
|
self.add_mod(self.p_en_bar_driver)
|
||||||
|
|
||||||
|
|
@ -346,9 +354,9 @@ class control_logic(design.design):
|
||||||
|
|
||||||
# Outputs to the bank
|
# Outputs to the bank
|
||||||
if self.port_type == "rw":
|
if self.port_type == "rw":
|
||||||
self.output_list = ["rbl_wl", "s_en", "w_en"]
|
self.output_list = ["s_en", "w_en"]
|
||||||
elif self.port_type == "r":
|
elif self.port_type == "r":
|
||||||
self.output_list = ["rbl_wl", "s_en"]
|
self.output_list = ["s_en"]
|
||||||
else:
|
else:
|
||||||
self.output_list = ["w_en"]
|
self.output_list = ["w_en"]
|
||||||
self.output_list.append("p_en_bar")
|
self.output_list.append("p_en_bar")
|
||||||
|
|
@ -376,7 +384,6 @@ class control_logic(design.design):
|
||||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||||
self.create_wen_row()
|
self.create_wen_row()
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||||
self.create_rbl_row()
|
|
||||||
self.create_sen_row()
|
self.create_sen_row()
|
||||||
self.create_delay()
|
self.create_delay()
|
||||||
self.create_pen_row()
|
self.create_pen_row()
|
||||||
|
|
@ -410,9 +417,6 @@ class control_logic(design.design):
|
||||||
height = self.w_en_gate_inst.uy()
|
height = self.w_en_gate_inst.uy()
|
||||||
control_center_y = self.w_en_gate_inst.uy()
|
control_center_y = self.w_en_gate_inst.uy()
|
||||||
row += 1
|
row += 1
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
|
||||||
self.place_rbl_row(row)
|
|
||||||
row += 1
|
|
||||||
self.place_pen_row(row)
|
self.place_pen_row(row)
|
||||||
row += 1
|
row += 1
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||||
|
|
@ -441,7 +445,6 @@ class control_logic(design.design):
|
||||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||||
self.route_wen()
|
self.route_wen()
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||||
self.route_rbl()
|
|
||||||
self.route_sen()
|
self.route_sen()
|
||||||
self.route_pen()
|
self.route_pen()
|
||||||
self.route_clk_buf()
|
self.route_clk_buf()
|
||||||
|
|
@ -596,42 +599,15 @@ class control_logic(design.design):
|
||||||
|
|
||||||
def route_wlen(self):
|
def route_wlen(self):
|
||||||
wlen_map = zip(["A"], ["gated_clk_bar"])
|
wlen_map = zip(["A"], ["gated_clk_bar"])
|
||||||
self.connect_vertical_bus(wlen_map, self.wl_en_inst, self.rail_offsets)
|
self.connect_vertical_bus(wlen_map, self.wl_en_inst, self.rail_offsets)
|
||||||
|
|
||||||
self.connect_output(self.wl_en_inst, "Z", "wl_en")
|
self.connect_output(self.wl_en_inst, "Z", "wl_en")
|
||||||
|
|
||||||
def create_rbl_row(self):
|
|
||||||
|
|
||||||
self.rbl_inst=self.add_inst(name="rbl_driver",
|
|
||||||
mod=self.rbl_driver)
|
|
||||||
# input: gated_clk_bar, output: rbl_wl
|
|
||||||
self.connect_inst(["gated_clk_bar", "rbl_wl", "vdd", "gnd"])
|
|
||||||
|
|
||||||
def place_rbl_row(self,row):
|
|
||||||
x_off = self.control_x_offset
|
|
||||||
(y_off,mirror)=self.get_offset(row)
|
|
||||||
|
|
||||||
offset = vector(x_off, y_off)
|
|
||||||
self.rbl_inst.place(offset, mirror)
|
|
||||||
|
|
||||||
self.row_end_inst.append(self.rbl_inst)
|
|
||||||
|
|
||||||
def route_rbl(self):
|
|
||||||
""" Connect the logic for the rbl_in generation """
|
|
||||||
|
|
||||||
rbl_in_map = zip(["A"], ["gated_clk_bar"])
|
|
||||||
self.connect_vertical_bus(rbl_in_map, self.rbl_inst, self.rail_offsets)
|
|
||||||
self.connect_output(self.rbl_inst, "Z", "rbl_wl")
|
|
||||||
|
|
||||||
# Input from RBL goes to the delay line for futher delay
|
|
||||||
self.copy_layout_pin(self.delay_inst, "in", "rbl_bl")
|
|
||||||
|
|
||||||
def create_pen_row(self):
|
def create_pen_row(self):
|
||||||
input_name = "gated_clk_buf"
|
# input: gated_clk_bar, output: p_en_bar
|
||||||
|
|
||||||
# input: pre_p_en, output: p_en_bar
|
|
||||||
self.p_en_bar_inst=self.add_inst(name="inv_p_en_bar",
|
self.p_en_bar_inst=self.add_inst(name="inv_p_en_bar",
|
||||||
mod=self.p_en_bar_driver)
|
mod=self.p_en_bar_driver)
|
||||||
self.connect_inst([input_name, "p_en_bar", "vdd", "gnd"])
|
self.connect_inst(["gated_clk_buf", "p_en_bar", "vdd", "gnd"])
|
||||||
|
|
||||||
|
|
||||||
def place_pen_row(self,row):
|
def place_pen_row(self,row):
|
||||||
|
|
@ -690,6 +666,10 @@ class control_logic(design.design):
|
||||||
self.add_wire(("metal1","via1","metal2"),[out_pos, mid1,in_pos])
|
self.add_wire(("metal1","via1","metal2"),[out_pos, mid1,in_pos])
|
||||||
|
|
||||||
self.connect_output(self.s_en_gate_inst, "Z", "s_en")
|
self.connect_output(self.s_en_gate_inst, "Z", "s_en")
|
||||||
|
|
||||||
|
# Input from RBL goes to the delay line for futher delay
|
||||||
|
self.copy_layout_pin(self.delay_inst, "in", "rbl_bl")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_wen_row(self):
|
def create_wen_row(self):
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
# 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
|
||||||
|
from tech import drc
|
||||||
|
from math import log
|
||||||
|
from vector import vector
|
||||||
|
from globals import OPTS
|
||||||
|
import pgate
|
||||||
|
from sram_factory import factory
|
||||||
|
|
||||||
|
class pand3(pgate.pgate):
|
||||||
|
"""
|
||||||
|
This is a simple buffer used for driving loads.
|
||||||
|
"""
|
||||||
|
def __init__(self, name, size=1, height=None):
|
||||||
|
debug.info(1, "Creating pand3 {}".format(name))
|
||||||
|
self.add_comment("size: {}".format(size))
|
||||||
|
|
||||||
|
self.size = size
|
||||||
|
|
||||||
|
# Creates the netlist and layout
|
||||||
|
pgate.pgate.__init__(self, name, height)
|
||||||
|
|
||||||
|
def create_netlist(self):
|
||||||
|
self.add_pins()
|
||||||
|
self.create_modules()
|
||||||
|
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="pnand3",height=self.height)
|
||||||
|
self.add_mod(self.nand)
|
||||||
|
|
||||||
|
self.inv = factory.create(module_type="pinv", size=self.size, height=self.height)
|
||||||
|
self.add_mod(self.inv)
|
||||||
|
|
||||||
|
def create_layout(self):
|
||||||
|
self.width = self.nand.width + self.inv.width
|
||||||
|
self.place_insts()
|
||||||
|
self.add_wires()
|
||||||
|
self.add_layout_pins()
|
||||||
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
def add_pins(self):
|
||||||
|
self.add_pin("A", "INPUT")
|
||||||
|
self.add_pin("B", "INPUT")
|
||||||
|
self.add_pin("C", "INPUT")
|
||||||
|
self.add_pin("Z", "OUTPUT")
|
||||||
|
self.add_pin("vdd", "POWER")
|
||||||
|
self.add_pin("gnd", "GROUND")
|
||||||
|
|
||||||
|
def create_insts(self):
|
||||||
|
self.nand_inst=self.add_inst(name="pand3_nand",
|
||||||
|
mod=self.nand)
|
||||||
|
self.connect_inst(["A", "B", "C", "zb_int", "vdd", "gnd"])
|
||||||
|
|
||||||
|
self.inv_inst=self.add_inst(name="pand3_inv",
|
||||||
|
mod=self.inv)
|
||||||
|
self.connect_inst(["zb_int", "Z", "vdd", "gnd"])
|
||||||
|
|
||||||
|
def place_insts(self):
|
||||||
|
# Add NAND to the right
|
||||||
|
self.nand_inst.place(offset=vector(0,0))
|
||||||
|
|
||||||
|
# Add INV to the right
|
||||||
|
self.inv_inst.place(offset=vector(self.nand_inst.rx(),0))
|
||||||
|
|
||||||
|
def add_wires(self):
|
||||||
|
# nand Z to inv A
|
||||||
|
z1_pin = self.nand_inst.get_pin("Z")
|
||||||
|
a2_pin = self.inv_inst.get_pin("A")
|
||||||
|
mid1_point = vector(0.5*(z1_pin.cx()+a2_pin.cx()), z1_pin.cy())
|
||||||
|
mid2_point = vector(mid1_point, a2_pin.cy())
|
||||||
|
self.add_path("metal1", [z1_pin.center(), mid1_point, mid2_point, a2_pin.center()])
|
||||||
|
|
||||||
|
|
||||||
|
def add_layout_pins(self):
|
||||||
|
# Continous vdd rail along with label.
|
||||||
|
vdd_pin=self.inv_inst.get_pin("vdd")
|
||||||
|
self.add_layout_pin(text="vdd",
|
||||||
|
layer="metal1",
|
||||||
|
offset=vdd_pin.ll().scale(0,1),
|
||||||
|
width=self.width,
|
||||||
|
height=vdd_pin.height())
|
||||||
|
|
||||||
|
# Continous gnd rail along with label.
|
||||||
|
gnd_pin=self.inv_inst.get_pin("gnd")
|
||||||
|
self.add_layout_pin(text="gnd",
|
||||||
|
layer="metal1",
|
||||||
|
offset=gnd_pin.ll().scale(0,1),
|
||||||
|
width=self.width,
|
||||||
|
height=vdd_pin.height())
|
||||||
|
|
||||||
|
pin = self.inv_inst.get_pin("Z")
|
||||||
|
self.add_layout_pin_rect_center(text="Z",
|
||||||
|
layer=pin.layer,
|
||||||
|
offset=pin.center(),
|
||||||
|
width=pin.width(),
|
||||||
|
height=pin.height())
|
||||||
|
|
||||||
|
for pin_name in ["A","B", "C"]:
|
||||||
|
pin = self.nand_inst.get_pin(pin_name)
|
||||||
|
self.add_layout_pin_rect_center(text=pin_name,
|
||||||
|
layer=pin.layer,
|
||||||
|
offset=pin.center(),
|
||||||
|
width=pin.width(),
|
||||||
|
height=pin.height())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
|
""" Calculate the analytical delay of DFF-> INV -> INV """
|
||||||
|
nand_delay = self.nand.analytical_delay(corner, slew=slew, load=self.inv.input_load())
|
||||||
|
inv_delay = self.inv.analytical_delay(corner, slew=nand_delay.slew, load=load)
|
||||||
|
return nand_delay + inv_delay
|
||||||
|
|
||||||
|
def get_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||||
|
"""Get the stage efforts of the A or B -> Z path"""
|
||||||
|
stage_effort_list = []
|
||||||
|
stage1_cout = self.inv.get_cin()
|
||||||
|
stage1 = self.nand.get_stage_effort(stage1_cout, inp_is_rise)
|
||||||
|
stage_effort_list.append(stage1)
|
||||||
|
last_stage_is_rise = stage1.is_rise
|
||||||
|
|
||||||
|
stage2 = self.inv.get_stage_effort(external_cout, last_stage_is_rise)
|
||||||
|
stage_effort_list.append(stage2)
|
||||||
|
|
||||||
|
return stage_effort_list
|
||||||
|
|
||||||
|
def get_cin(self):
|
||||||
|
"""Return the relative input capacitance of a single input"""
|
||||||
|
return self.nand.get_cin()
|
||||||
|
|
||||||
|
|
@ -5,12 +5,13 @@
|
||||||
# (acting for and on behalf of Oklahoma State University)
|
# (acting for and on behalf of Oklahoma State University)
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
|
import contact
|
||||||
import pgate
|
import pgate
|
||||||
import debug
|
import debug
|
||||||
from tech import drc, parameter, spice
|
from tech import drc, parameter, spice
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
import contact
|
import logical_effort
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
||||||
class pnor2(pgate.pgate):
|
class pnor2(pgate.pgate):
|
||||||
|
|
@ -38,28 +39,30 @@ class pnor2(pgate.pgate):
|
||||||
pgate.pgate.__init__(self, name, height)
|
pgate.pgate.__init__(self, name, height)
|
||||||
|
|
||||||
|
|
||||||
def add_pins(self):
|
|
||||||
""" Adds pins for spice netlist """
|
|
||||||
pin_list = ["A", "B", "Z", "vdd", "gnd"]
|
|
||||||
dir_list = ["INPUT", "INPUT", "OUTPUT", "INOUT", "INOUT"]
|
|
||||||
self.add_pin_list(pin_list, dir_list)
|
|
||||||
|
|
||||||
def create_netlist(self):
|
def create_netlist(self):
|
||||||
self.add_pins()
|
self.add_pins()
|
||||||
|
self.add_ptx()
|
||||||
self.create_ptx()
|
self.create_ptx()
|
||||||
self.setup_layout_constants()
|
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
""" Calls all functions related to the generation of the layout """
|
""" Calls all functions related to the generation of the layout """
|
||||||
self.add_supply_rails()
|
|
||||||
self.add_ptx()
|
self.setup_layout_constants()
|
||||||
|
self.route_supply_rails()
|
||||||
|
self.place_ptx()
|
||||||
self.connect_rails()
|
self.connect_rails()
|
||||||
self.add_well_contacts()
|
self.add_well_contacts()
|
||||||
self.extend_wells(self.well_pos)
|
self.extend_wells(self.well_pos)
|
||||||
self.route_inputs()
|
self.route_inputs()
|
||||||
self.route_output()
|
self.route_output()
|
||||||
|
|
||||||
def create_ptx(self):
|
def add_pins(self):
|
||||||
|
""" Adds pins for spice netlist """
|
||||||
|
pin_list = ["A", "B", "Z", "vdd", "gnd"]
|
||||||
|
dir_list = ["INPUT", "INPUT", "OUTPUT", "INOUT", "INOUT"]
|
||||||
|
self.add_pin_list(pin_list, dir_list)
|
||||||
|
|
||||||
|
def add_ptx(self):
|
||||||
""" Create the PMOS and NMOS transistors. """
|
""" Create the PMOS and NMOS transistors. """
|
||||||
self.nmos = factory.create(module_type="ptx",
|
self.nmos = factory.create(module_type="ptx",
|
||||||
width=self.nmos_width,
|
width=self.nmos_width,
|
||||||
|
|
@ -104,7 +107,7 @@ class pnor2(pgate.pgate):
|
||||||
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
|
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
|
||||||
drc("poly_extend_active"), self.poly_space)
|
drc("poly_extend_active"), self.poly_space)
|
||||||
|
|
||||||
def add_supply_rails(self):
|
def route_supply_rails(self):
|
||||||
""" Add vdd/gnd rails to the top and bottom. """
|
""" Add vdd/gnd rails to the top and bottom. """
|
||||||
self.add_layout_pin_rect_center(text="gnd",
|
self.add_layout_pin_rect_center(text="gnd",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
|
|
@ -116,7 +119,31 @@ class pnor2(pgate.pgate):
|
||||||
offset=vector(0.5*self.width,self.height),
|
offset=vector(0.5*self.width,self.height),
|
||||||
width=self.width)
|
width=self.width)
|
||||||
|
|
||||||
def add_ptx(self):
|
def create_ptx(self):
|
||||||
|
"""
|
||||||
|
Add PMOS and NMOS to the layout at the upper-most and lowest position
|
||||||
|
to provide maximum routing in channel
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.pmos1_inst=self.add_inst(name="pnor2_pmos1",
|
||||||
|
mod=self.pmos)
|
||||||
|
self.connect_inst(["vdd", "A", "net1", "vdd"])
|
||||||
|
|
||||||
|
self.pmos2_inst = self.add_inst(name="pnor2_pmos2",
|
||||||
|
mod=self.pmos)
|
||||||
|
self.connect_inst(["net1", "B", "Z", "vdd"])
|
||||||
|
|
||||||
|
|
||||||
|
self.nmos1_inst=self.add_inst(name="pnor2_nmos1",
|
||||||
|
mod=self.nmos)
|
||||||
|
self.connect_inst(["Z", "A", "gnd", "gnd"])
|
||||||
|
|
||||||
|
self.nmos2_inst=self.add_inst(name="pnor2_nmos2",
|
||||||
|
mod=self.nmos)
|
||||||
|
self.connect_inst(["Z", "B", "gnd", "gnd"])
|
||||||
|
|
||||||
|
|
||||||
|
def place_ptx(self):
|
||||||
"""
|
"""
|
||||||
Add PMOS and NMOS to the layout at the upper-most and lowest position
|
Add PMOS and NMOS to the layout at the upper-most and lowest position
|
||||||
to provide maximum routing in channel
|
to provide maximum routing in channel
|
||||||
|
|
@ -124,29 +151,16 @@ class pnor2(pgate.pgate):
|
||||||
|
|
||||||
pmos1_pos = vector(self.pmos.active_offset.x,
|
pmos1_pos = vector(self.pmos.active_offset.x,
|
||||||
self.height - self.pmos.active_height - self.top_bottom_space)
|
self.height - self.pmos.active_height - self.top_bottom_space)
|
||||||
self.pmos1_inst=self.add_inst(name="pnor2_pmos1",
|
self.pmos1_inst.place(pmos1_pos)
|
||||||
mod=self.pmos,
|
|
||||||
offset=pmos1_pos)
|
|
||||||
self.connect_inst(["vdd", "A", "net1", "vdd"])
|
|
||||||
|
|
||||||
self.pmos2_pos = pmos1_pos + self.overlap_offset
|
self.pmos2_pos = pmos1_pos + self.overlap_offset
|
||||||
self.pmos2_inst = self.add_inst(name="pnor2_pmos2",
|
self.pmos2_inst.place(self.pmos2_pos)
|
||||||
mod=self.pmos,
|
|
||||||
offset=self.pmos2_pos)
|
|
||||||
self.connect_inst(["net1", "B", "Z", "vdd"])
|
|
||||||
|
|
||||||
|
|
||||||
nmos1_pos = vector(self.pmos.active_offset.x, self.top_bottom_space)
|
nmos1_pos = vector(self.pmos.active_offset.x, self.top_bottom_space)
|
||||||
self.nmos1_inst=self.add_inst(name="pnor2_nmos1",
|
self.nmos1_inst.place(nmos1_pos)
|
||||||
mod=self.nmos,
|
|
||||||
offset=nmos1_pos)
|
|
||||||
self.connect_inst(["Z", "A", "gnd", "gnd"])
|
|
||||||
|
|
||||||
self.nmos2_pos = nmos1_pos + self.overlap_offset
|
self.nmos2_pos = nmos1_pos + self.overlap_offset
|
||||||
self.nmos2_inst=self.add_inst(name="pnor2_nmos2",
|
self.nmos2_inst.place(self.nmos2_pos)
|
||||||
mod=self.nmos,
|
|
||||||
offset=self.nmos2_pos)
|
|
||||||
self.connect_inst(["Z", "B", "gnd", "gnd"])
|
|
||||||
|
|
||||||
# Output position will be in between the PMOS and NMOS
|
# Output position will be in between the PMOS and NMOS
|
||||||
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
|
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
|
||||||
|
|
|
||||||
|
|
@ -341,8 +341,6 @@ class sram_base(design, verilog, lef):
|
||||||
temp.append("DOUT{0}[{1}]".format(port,bit))
|
temp.append("DOUT{0}[{1}]".format(port,bit))
|
||||||
for port in self.read_ports:
|
for port in self.read_ports:
|
||||||
temp.append("rbl_bl{0}".format(port))
|
temp.append("rbl_bl{0}".format(port))
|
||||||
for port in self.read_ports:
|
|
||||||
temp.append("rbl_wl{0}".format(port))
|
|
||||||
for port in self.write_ports:
|
for port in self.write_ports:
|
||||||
for bit in range(self.word_size):
|
for bit in range(self.word_size):
|
||||||
temp.append("BANK_DIN{0}[{1}]".format(port,bit))
|
temp.append("BANK_DIN{0}[{1}]".format(port,bit))
|
||||||
|
|
@ -506,9 +504,6 @@ class sram_base(design, verilog, lef):
|
||||||
temp.append("rbl_bl{}".format(port))
|
temp.append("rbl_bl{}".format(port))
|
||||||
|
|
||||||
# Ouputs
|
# Ouputs
|
||||||
if port in self.read_ports:
|
|
||||||
temp.append("rbl_wl{}".format(port))
|
|
||||||
|
|
||||||
if port in self.read_ports:
|
if port in self.read_ports:
|
||||||
temp.append("s_en{}".format(port))
|
temp.append("s_en{}".format(port))
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
|
|
@ -530,7 +525,10 @@ class sram_base(design, verilog, lef):
|
||||||
in_pos = src_pin.rc()
|
in_pos = src_pin.rc()
|
||||||
else:
|
else:
|
||||||
in_pos = src_pin.lc()
|
in_pos = src_pin.lc()
|
||||||
out_pos = dest_pin.center()
|
if src_pin.cy() < dest_pin.cy():
|
||||||
|
out_pos = dest_pin.bc()
|
||||||
|
else:
|
||||||
|
out_pos = dest_pin.uc()
|
||||||
|
|
||||||
# move horizontal first
|
# move horizontal first
|
||||||
self.add_wire(("metal3","via2","metal2"),[in_pos, vector(out_pos.x,in_pos.y),out_pos])
|
self.add_wire(("metal3","via2","metal2"),[in_pos, vector(out_pos.x,in_pos.y),out_pos])
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# 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 unittest
|
||||||
|
from testutils import *
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class pand3_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||||
|
global verify
|
||||||
|
import verify
|
||||||
|
|
||||||
|
import pand3
|
||||||
|
|
||||||
|
debug.info(2, "Testing pand3 gate 4x")
|
||||||
|
a = pand3.pand3(name="pand3x4", size=4)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
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(testRunner=debugTestRunner())
|
||||||
Loading…
Reference in New Issue