mirror of https://github.com/VLSIDA/OpenRAM.git
Change pbuf/pinv to pdriver in control logic.
This commit is contained in:
parent
23718b952f
commit
b58fd03083
|
|
@ -1253,20 +1253,22 @@ class bank(design.design):
|
||||||
def get_wl_en_cin(self):
|
def get_wl_en_cin(self):
|
||||||
"""Get the relative capacitance of all the clk connections in the bank"""
|
"""Get the relative capacitance of all the clk connections in the bank"""
|
||||||
#wl_en only used in the wordline driver.
|
#wl_en only used in the wordline driver.
|
||||||
total_clk_cin = self.wordline_driver.get_wl_en_cin()
|
return self.wordline_driver.get_wl_en_cin()
|
||||||
return total_clk_cin
|
|
||||||
|
def get_w_en_cin(self):
|
||||||
|
"""Get the relative capacitance of all the clk connections in the bank"""
|
||||||
|
#wl_en only used in the wordline driver.
|
||||||
|
return self.write_driver.get_w_en_cin()
|
||||||
|
|
||||||
def get_clk_bar_cin(self):
|
def get_clk_bar_cin(self):
|
||||||
"""Get the relative capacitance of all the clk_bar connections in the bank"""
|
"""Get the relative capacitance of all the clk_bar connections in the bank"""
|
||||||
#Current bank only uses clock bar (clk_buf_bar) as an enable for the precharge array.
|
#Current bank only uses clock bar (clk_buf_bar) as an enable for the precharge array.
|
||||||
|
|
||||||
#Precharges are the all the same in Mulitport, one is picked
|
#Precharges are the all the same in Mulitport, one is picked
|
||||||
port = self.read_ports[0]
|
port = self.read_ports[0]
|
||||||
total_clk_bar_cin = self.precharge_array[port].get_en_cin()
|
return self.precharge_array[port].get_en_cin()
|
||||||
return total_clk_bar_cin
|
|
||||||
|
|
||||||
def get_sen_cin(self):
|
def get_sen_cin(self):
|
||||||
"""Get the relative capacitance of all the sense amp enable connections in the bank"""
|
"""Get the relative capacitance of all the sense amp enable connections in the bank"""
|
||||||
#Current bank only uses sen as an enable for the sense amps.
|
#Current bank only uses sen as an enable for the sense amps.
|
||||||
total_sen_cin = self.sense_amp_array.get_en_cin()
|
return self.sense_amp_array.get_en_cin()
|
||||||
return total_sen_cin
|
|
||||||
|
|
|
||||||
|
|
@ -14,20 +14,22 @@ class control_logic(design.design):
|
||||||
Dynamically generated Control logic for the total SRAM circuit.
|
Dynamically generated Control logic for the total SRAM circuit.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, num_rows, words_per_row, sram=None, port_type="rw"):
|
def __init__(self, num_rows, words_per_row, word_size, sram=None, port_type="rw"):
|
||||||
""" Constructor """
|
""" Constructor """
|
||||||
name = "control_logic_" + port_type
|
name = "control_logic_" + port_type
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
debug.info(1, "Creating {}".format(name))
|
debug.info(1, "Creating {}".format(name))
|
||||||
|
|
||||||
|
self.sram=sram
|
||||||
self.num_rows = num_rows
|
self.num_rows = num_rows
|
||||||
self.words_per_row = words_per_row
|
self.words_per_row = words_per_row
|
||||||
|
self.word_size = word_size
|
||||||
self.port_type = port_type
|
self.port_type = port_type
|
||||||
|
|
||||||
|
self.num_words = num_rows * words_per_row
|
||||||
|
|
||||||
self.enable_delay_chain_resizing = False
|
self.enable_delay_chain_resizing = False
|
||||||
|
|
||||||
#This is needed to resize the delay chain. Likely to be changed at some point.
|
|
||||||
self.sram=sram
|
|
||||||
#self.sram=None #disable re-sizing for debugging, FIXME: resizing is not working, needs to be adjusted for new control logic.
|
#self.sram=None #disable re-sizing for debugging, FIXME: resizing is not working, needs to be adjusted for new control logic.
|
||||||
self.wl_timing_tolerance = 1 #Determines how much larger the sen delay should be. Accounts for possible error in model.
|
self.wl_timing_tolerance = 1 #Determines how much larger the sen delay should be. Accounts for possible error in model.
|
||||||
self.parasitic_inv_delay = parameter["min_inv_para_delay"] #Keeping 0 for now until further testing.
|
self.parasitic_inv_delay = parameter["min_inv_para_delay"] #Keeping 0 for now until further testing.
|
||||||
|
|
@ -82,33 +84,44 @@ class control_logic(design.design):
|
||||||
self.add_mod(self.and2)
|
self.add_mod(self.and2)
|
||||||
|
|
||||||
# Special gates: inverters for buffering
|
# Special gates: inverters for buffering
|
||||||
# Size the clock for the number of rows (fanout)
|
# clk_buf drives a flop for every address and control bit
|
||||||
clock_driver_size = max(1,int(self.num_rows/4))
|
clock_fanout = math.log(self.num_words,2) + math.log(self.words_per_row,2) + self.num_control_signals
|
||||||
self.clkbuf = factory.create(module_type="pbuf",
|
|
||||||
size=clock_driver_size,
|
self.clkbuf = factory.create(module_type="pdriver",
|
||||||
|
fanout=clock_fanout,
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
|
|
||||||
self.add_mod(self.clkbuf)
|
self.add_mod(self.clkbuf)
|
||||||
|
|
||||||
self.buf16 = factory.create(module_type="pbuf",
|
# wl_en drives every row in the bank
|
||||||
size=16,
|
self.wl_en_driver = factory.create(module_type="pdriver",
|
||||||
height=dff_height)
|
fanout=self.num_rows,
|
||||||
self.add_mod(self.buf16)
|
height=dff_height)
|
||||||
|
self.add_mod(self.wl_en_driver)
|
||||||
|
|
||||||
self.buf8 = factory.create(module_type="pbuf",
|
# w_en drives every write driver
|
||||||
size=8,
|
self.w_en_driver = factory.create(module_type="pbuf",
|
||||||
height=dff_height)
|
size=self.word_size,
|
||||||
self.add_mod(self.buf8)
|
height=dff_height)
|
||||||
|
self.add_mod(self.w_en_driver)
|
||||||
self.inv = self.inv1 = factory.create(module_type="pinv",
|
|
||||||
|
# s_en drives every sense amp
|
||||||
|
self.s_en_driver = factory.create(module_type="pbuf",
|
||||||
|
size=8,
|
||||||
|
height=dff_height)
|
||||||
|
self.add_mod(self.s_en_driver)
|
||||||
|
|
||||||
|
# used to generate inverted signals with low fanout
|
||||||
|
self.inv = factory.create(module_type="pinv",
|
||||||
size=1,
|
size=1,
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.inv1)
|
self.add_mod(self.inv)
|
||||||
|
|
||||||
self.inv8 = factory.create(module_type="pinv",
|
# p_en_bar drives every column in the bicell array
|
||||||
size=8,
|
self.p_en_bar_driver = factory.create(module_type="pdriver",
|
||||||
height=dff_height)
|
fanout=8,
|
||||||
self.add_mod(self.inv8)
|
height=dff_height)
|
||||||
|
self.add_mod(self.p_en_bar_driver)
|
||||||
|
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||||
delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
|
delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
|
||||||
|
|
@ -510,7 +523,7 @@ class control_logic(design.design):
|
||||||
def create_wlen_row(self):
|
def create_wlen_row(self):
|
||||||
# input pre_p_en, output: wl_en
|
# input pre_p_en, output: wl_en
|
||||||
self.wl_en_inst=self.add_inst(name="buf_wl_en",
|
self.wl_en_inst=self.add_inst(name="buf_wl_en",
|
||||||
mod=self.buf16)
|
mod=self.wl_en_driver)
|
||||||
self.connect_inst(["gated_clk_bar", "wl_en", "vdd", "gnd"])
|
self.connect_inst(["gated_clk_bar", "wl_en", "vdd", "gnd"])
|
||||||
|
|
||||||
def place_wlen_row(self, row):
|
def place_wlen_row(self, row):
|
||||||
|
|
@ -580,7 +593,7 @@ class control_logic(design.design):
|
||||||
|
|
||||||
# input: pre_p_en, 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.inv8)
|
mod=self.p_en_bar_driver)
|
||||||
self.connect_inst([input_name, "p_en_bar", "vdd", "gnd"])
|
self.connect_inst([input_name, "p_en_bar", "vdd", "gnd"])
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -620,7 +633,7 @@ class control_logic(design.design):
|
||||||
# BUFFER FOR S_EN
|
# BUFFER FOR S_EN
|
||||||
# input: pre_s_en, output: s_en
|
# input: pre_s_en, output: s_en
|
||||||
self.s_en_inst=self.add_inst(name="buf_s_en",
|
self.s_en_inst=self.add_inst(name="buf_s_en",
|
||||||
mod=self.buf8)
|
mod=self.s_en_driver)
|
||||||
self.connect_inst(["pre_s_en", "s_en", "vdd", "gnd"])
|
self.connect_inst(["pre_s_en", "s_en", "vdd", "gnd"])
|
||||||
|
|
||||||
def place_sen_row(self,row):
|
def place_sen_row(self,row):
|
||||||
|
|
@ -657,7 +670,7 @@ class control_logic(design.design):
|
||||||
|
|
||||||
# BUFFER FOR W_EN
|
# BUFFER FOR W_EN
|
||||||
self.w_en_inst = self.add_inst(name="buf_w_en_buf",
|
self.w_en_inst = self.add_inst(name="buf_w_en_buf",
|
||||||
mod=self.buf8)
|
mod=self.w_en_driver)
|
||||||
self.connect_inst([input_name, "w_en", "vdd", "gnd"])
|
self.connect_inst([input_name, "w_en", "vdd", "gnd"])
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -814,7 +827,7 @@ class control_logic(design.design):
|
||||||
#Calculate the load on wl_en within the module and add it to external load
|
#Calculate the load on wl_en within the module and add it to external load
|
||||||
external_cout = self.sram.get_wl_en_cin()
|
external_cout = self.sram.get_wl_en_cin()
|
||||||
#First stage is the clock buffer
|
#First stage is the clock buffer
|
||||||
stage_effort_list += self.clkbuf.get_output_stage_efforts(external_cout, is_clk_bar_rise)
|
stage_effort_list += self.clkbuf.get_stage_efforts(external_cout, is_clk_bar_rise)
|
||||||
last_stage_is_rise = stage_effort_list[-1].is_rise
|
last_stage_is_rise = stage_effort_list[-1].is_rise
|
||||||
|
|
||||||
#Then ask the sram for the other path delays (from the bank)
|
#Then ask the sram for the other path delays (from the bank)
|
||||||
|
|
@ -845,17 +858,17 @@ class control_logic(design.design):
|
||||||
#First stage, gated_clk_bar -(and2)-> rbl_in. Only for RW ports.
|
#First stage, gated_clk_bar -(and2)-> rbl_in. Only for RW ports.
|
||||||
if self.port_type == "rw":
|
if self.port_type == "rw":
|
||||||
stage1_cout = self.replica_bitline.get_en_cin()
|
stage1_cout = self.replica_bitline.get_en_cin()
|
||||||
stage_effort_list += self.and2.get_output_stage_efforts(stage1_cout, last_stage_rise)
|
stage_effort_list += self.and2.get_stage_efforts(stage1_cout, last_stage_rise)
|
||||||
last_stage_rise = stage_effort_list[-1].is_rise
|
last_stage_rise = stage_effort_list[-1].is_rise
|
||||||
|
|
||||||
#Replica bitline stage, rbl_in -(rbl)-> pre_s_en
|
#Replica bitline stage, rbl_in -(rbl)-> pre_s_en
|
||||||
stage2_cout = self.buf8.get_cin()
|
stage2_cout = self.s_en_driver.get_cin()
|
||||||
stage_effort_list += self.replica_bitline.determine_sen_stage_efforts(stage2_cout, last_stage_rise)
|
stage_effort_list += self.replica_bitline.determine_sen_stage_efforts(stage2_cout, last_stage_rise)
|
||||||
last_stage_rise = stage_effort_list[-1].is_rise
|
last_stage_rise = stage_effort_list[-1].is_rise
|
||||||
|
|
||||||
#buffer stage, pre_s_en -(buffer)-> s_en
|
#buffer stage, pre_s_en -(buffer)-> s_en
|
||||||
stage3_cout = self.sram.get_sen_cin()
|
stage3_cout = self.sram.get_sen_cin()
|
||||||
stage_effort_list += self.buf8.get_output_stage_efforts(stage3_cout, last_stage_rise)
|
stage_effort_list += self.s_en_driver.get_stage_efforts(stage3_cout, last_stage_rise)
|
||||||
last_stage_rise = stage_effort_list[-1].is_rise
|
last_stage_rise = stage_effort_list[-1].is_rise
|
||||||
|
|
||||||
return stage_effort_list
|
return stage_effort_list
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,7 @@ class delay_chain(design.design):
|
||||||
stage_cout = self.inv.get_cin()*(stage_fanout+1)
|
stage_cout = self.inv.get_cin()*(stage_fanout+1)
|
||||||
if len(stage_effort_list) == len(self.fanout_list)-1: #last stage
|
if len(stage_effort_list) == len(self.fanout_list)-1: #last stage
|
||||||
stage_cout+=ext_delayed_en_cout
|
stage_cout+=ext_delayed_en_cout
|
||||||
stage = self.inv.get_effort_stage(stage_cout, last_stage_is_rise)
|
stage = self.inv.get_stage_effort(stage_cout, last_stage_is_rise)
|
||||||
stage_effort_list.append(stage)
|
stage_effort_list.append(stage)
|
||||||
last_stage_is_rise = stage.is_rise
|
last_stage_is_rise = stage.is_rise
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -614,7 +614,7 @@ class replica_bitline(design.design):
|
||||||
|
|
||||||
#The delay chain triggers the enable on the replica bitline (rbl). This is used to track the bitline delay whereas this
|
#The delay chain triggers the enable on the replica bitline (rbl). This is used to track the bitline delay whereas this
|
||||||
#model is intended to track every but that. Therefore, the next stage is the inverter after the rbl.
|
#model is intended to track every but that. Therefore, the next stage is the inverter after the rbl.
|
||||||
stage2 = self.inv.get_effort_stage(ext_cout, last_stage_is_rise)
|
stage2 = self.inv.get_stage_effort(ext_cout, last_stage_is_rise)
|
||||||
stage_effort_list.append(stage2)
|
stage_effort_list.append(stage2)
|
||||||
|
|
||||||
return stage_effort_list
|
return stage_effort_list
|
||||||
|
|
|
||||||
|
|
@ -224,11 +224,11 @@ class wordline_driver(design.design):
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
|
|
||||||
stage1_cout = self.inv.get_cin()
|
stage1_cout = self.inv.get_cin()
|
||||||
stage1 = self.nand2.get_effort_stage(stage1_cout, inp_is_rise)
|
stage1 = self.nand2.get_stage_effort(stage1_cout, inp_is_rise)
|
||||||
stage_effort_list.append(stage1)
|
stage_effort_list.append(stage1)
|
||||||
last_stage_is_rise = stage1.is_rise
|
last_stage_is_rise = stage1.is_rise
|
||||||
|
|
||||||
stage2 = self.inv.get_effort_stage(external_cout, last_stage_is_rise)
|
stage2 = self.inv.get_stage_effort(external_cout, last_stage_is_rise)
|
||||||
stage_effort_list.append(stage2)
|
stage_effort_list.append(stage2)
|
||||||
|
|
||||||
return stage_effort_list
|
return stage_effort_list
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,8 @@ class write_driver(design.design):
|
||||||
self.height = write_driver.height
|
self.height = write_driver.height
|
||||||
self.pin_map = write_driver.pin_map
|
self.pin_map = write_driver.pin_map
|
||||||
|
|
||||||
|
|
||||||
|
def get_w_en_cin(self):
|
||||||
|
"""Get the relative capacitance of a single input"""
|
||||||
|
# This is approximated from SCMOS. It has roughly 5 3x transistor gates.
|
||||||
|
return 5*3
|
||||||
|
|
|
||||||
|
|
@ -130,3 +130,7 @@ class write_driver_array(design.design):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_w_en_cin(self):
|
||||||
|
"""Get the relative capacitance of all the enable connections in the bank"""
|
||||||
|
#The enable is connected to a nand2 for every row.
|
||||||
|
return self.driver.get_w_en_cin() * len(self.driver_insts)
|
||||||
|
|
|
||||||
|
|
@ -113,15 +113,15 @@ class pand2(pgate.pgate):
|
||||||
inv_delay = self.inv.analytical_delay(slew=nand_delay.slew, load=load)
|
inv_delay = self.inv.analytical_delay(slew=nand_delay.slew, load=load)
|
||||||
return nand_delay + inv_delay
|
return nand_delay + inv_delay
|
||||||
|
|
||||||
def get_output_stage_efforts(self, external_cout, inp_is_rise=False):
|
def get_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||||
"""Get the stage efforts of the A or B -> Z path"""
|
"""Get the stage efforts of the A or B -> Z path"""
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
stage1_cout = self.inv.get_cin()
|
stage1_cout = self.inv.get_cin()
|
||||||
stage1 = self.nand.get_effort_stage(stage1_cout, inp_is_rise)
|
stage1 = self.nand.get_stage_effort(stage1_cout, inp_is_rise)
|
||||||
stage_effort_list.append(stage1)
|
stage_effort_list.append(stage1)
|
||||||
last_stage_is_rise = stage1.is_rise
|
last_stage_is_rise = stage1.is_rise
|
||||||
|
|
||||||
stage2 = self.inv.get_effort_stage(external_cout, last_stage_is_rise)
|
stage2 = self.inv.get_stage_effort(external_cout, last_stage_is_rise)
|
||||||
stage_effort_list.append(stage2)
|
stage_effort_list.append(stage2)
|
||||||
|
|
||||||
return stage_effort_list
|
return stage_effort_list
|
||||||
|
|
|
||||||
|
|
@ -115,15 +115,15 @@ class pbuf(pgate.pgate):
|
||||||
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
|
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
|
||||||
return inv1_delay + inv2_delay
|
return inv1_delay + inv2_delay
|
||||||
|
|
||||||
def get_output_stage_efforts(self, external_cout, inp_is_rise=False):
|
def get_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||||
"""Get the stage efforts of the A -> Z path"""
|
"""Get the stage efforts of the A -> Z path"""
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
stage1_cout = self.inv2.get_cin()
|
stage1_cout = self.inv2.get_cin()
|
||||||
stage1 = self.inv1.get_effort_stage(stage1_cout, inp_is_rise)
|
stage1 = self.inv1.get_stage_effort(stage1_cout, inp_is_rise)
|
||||||
stage_effort_list.append(stage1)
|
stage_effort_list.append(stage1)
|
||||||
last_stage_is_rise = stage1.is_rise
|
last_stage_is_rise = stage1.is_rise
|
||||||
|
|
||||||
stage2 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise)
|
stage2 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise)
|
||||||
stage_effort_list.append(stage2)
|
stage_effort_list.append(stage2)
|
||||||
|
|
||||||
return stage_effort_list
|
return stage_effort_list
|
||||||
|
|
|
||||||
|
|
@ -11,16 +11,16 @@ class pdriver(pgate.pgate):
|
||||||
"""
|
"""
|
||||||
This instantiates an even or odd number of inverters sized for driving a load.
|
This instantiates an even or odd number of inverters sized for driving a load.
|
||||||
"""
|
"""
|
||||||
def __init__(self, name, neg_polarity=False, fanout_size=8, size_list = [], height=None):
|
def __init__(self, name, neg_polarity=False, fanout=0, size_list=None, height=None):
|
||||||
|
|
||||||
self.stage_effort = 4
|
self.stage_effort = 4
|
||||||
self.height = height
|
self.height = height
|
||||||
self.neg_polarity = neg_polarity
|
self.neg_polarity = neg_polarity
|
||||||
self.size_list = size_list
|
self.size_list = size_list
|
||||||
self.fanout_size = fanout_size
|
self.fanout = fanout
|
||||||
|
|
||||||
if len(self.size_list) > 0 and (self.fanout_size != 8 or self.neg_polarity):
|
if self.size_list and (self.fanout != 0 or self.neg_polarity):
|
||||||
debug.error("Cannot specify both size_list and neg_polarity or fanout_size.", -1)
|
debug.error("Cannot specify both size_list and neg_polarity or fanout.", -1)
|
||||||
|
|
||||||
pgate.pgate.__init__(self, name, height)
|
pgate.pgate.__init__(self, name, height)
|
||||||
debug.info(1, "Creating {}".format(self.name))
|
debug.info(1, "Creating {}".format(self.name))
|
||||||
|
|
@ -33,14 +33,14 @@ class pdriver(pgate.pgate):
|
||||||
|
|
||||||
def compute_sizes(self):
|
def compute_sizes(self):
|
||||||
# size_list specified
|
# size_list specified
|
||||||
if len(self.size_list) > 0:
|
if self.size_list:
|
||||||
if not len(self.size_list) % 2:
|
if not len(self.size_list) % 2:
|
||||||
neg_polarity = True
|
neg_polarity = True
|
||||||
self.num_inv = len(self.size_list)
|
self.num_inv = len(self.size_list)
|
||||||
else:
|
else:
|
||||||
# find the number of stages
|
# find the number of stages
|
||||||
#fanout_size is a unit inverter fanout, not a capacitance so c_in=1
|
#fanout is a unit inverter fanout, not a capacitance so c_in=1
|
||||||
num_stages = max(1,int(round(log(self.fanout_size)/log(4))))
|
num_stages = max(1,int(round(log(self.fanout)/log(4))))
|
||||||
|
|
||||||
# find inv_num and compute sizes
|
# find inv_num and compute sizes
|
||||||
if self.neg_polarity:
|
if self.neg_polarity:
|
||||||
|
|
@ -53,42 +53,42 @@ class pdriver(pgate.pgate):
|
||||||
self.same_polarity(num_stages=num_stages)
|
self.same_polarity(num_stages=num_stages)
|
||||||
else:
|
else:
|
||||||
self.diff_polarity(num_stages=num_stages)
|
self.diff_polarity(num_stages=num_stages)
|
||||||
|
|
||||||
|
|
||||||
def same_polarity(self, num_stages):
|
def same_polarity(self, num_stages):
|
||||||
self.calc_size_list = []
|
self.size_list = []
|
||||||
self.num_inv = num_stages
|
self.num_inv = num_stages
|
||||||
# compute sizes
|
# compute sizes
|
||||||
fanout_size_prev = self.fanout_size
|
fanout_prev = self.fanout
|
||||||
for x in range(self.num_inv-1,-1,-1):
|
for x in range(self.num_inv-1,-1,-1):
|
||||||
fanout_size_prev = int(round(fanout_size_prev/self.stage_effort))
|
fanout_prev = max(round(fanout_prev/self.stage_effort),1)
|
||||||
self.calc_size_list.append(fanout_size_prev)
|
self.size_list.append(fanout_prev)
|
||||||
|
self.size_list.reverse()
|
||||||
|
|
||||||
|
|
||||||
def diff_polarity(self, num_stages):
|
def diff_polarity(self, num_stages):
|
||||||
self.calc_size_list = []
|
self.size_list = []
|
||||||
# find which delay is smaller
|
# find which delay is smaller
|
||||||
if (num_stages > 1):
|
if (num_stages > 1):
|
||||||
delay_below = ((num_stages-1)*(self.fanout_size**(1/num_stages-1))) + num_stages-1
|
delay_below = ((num_stages-1)*(self.fanout**(1/num_stages-1))) + num_stages-1
|
||||||
delay_above = ((num_stages+1)*(self.fanout_size**(1/num_stages+1))) + num_stages+1
|
delay_above = ((num_stages+1)*(self.fanout**(1/num_stages+1))) + num_stages+1
|
||||||
if (delay_above < delay_below):
|
if (delay_above < delay_below):
|
||||||
# recompute stage_effort for this delay
|
# recompute stage_effort for this delay
|
||||||
self.num_inv = num_stages+1
|
self.num_inv = num_stages+1
|
||||||
polarity_stage_effort = self.fanout_size**(1/self.num_inv)
|
polarity_stage_effort = self.fanout**(1/self.num_inv)
|
||||||
else:
|
else:
|
||||||
self.num_inv = num_stages-1
|
self.num_inv = num_stages-1
|
||||||
polarity_stage_effort = self.fanout_size**(1/self.num_inv)
|
polarity_stage_effort = self.fanout**(1/self.num_inv)
|
||||||
else: # num_stages is 1, can't go to 0
|
else: # num_stages is 1, can't go to 0
|
||||||
self.num_inv = num_stages+1
|
self.num_inv = num_stages+1
|
||||||
polarity_stage_effort = self.fanout_size**(1/self.num_inv)
|
polarity_stage_effort = self.fanout**(1/self.num_inv)
|
||||||
|
|
||||||
|
|
||||||
# compute sizes
|
fanout_prev = self.fanout
|
||||||
fanout_size_prev = self.fanout_size
|
|
||||||
for x in range(self.num_inv-1,-1,-1):
|
for x in range(self.num_inv-1,-1,-1):
|
||||||
fanout_size_prev = int(round(fanout_size_prev/polarity_stage_effort))
|
fanout_prev = round(fanout_prev/polarity_stage_effort)
|
||||||
self.calc_size_list.append(fanout_size_prev)
|
self.size_list.append(fanout_prev)
|
||||||
|
self.size_list.reverse()
|
||||||
|
|
||||||
def create_netlist(self):
|
def create_netlist(self):
|
||||||
inv_list = []
|
inv_list = []
|
||||||
|
|
@ -115,16 +115,10 @@ class pdriver(pgate.pgate):
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.inv_list = []
|
self.inv_list = []
|
||||||
if len(self.size_list) > 0: # size list specified
|
for size in self.size_list:
|
||||||
for x in range(len(self.size_list)):
|
temp_inv = factory.create(module_type="pinv", size=size, height=self.height)
|
||||||
temp_inv = factory.create(module_type="pinv", size=self.size_list[x], height=self.height)
|
self.inv_list.append(temp_inv)
|
||||||
self.inv_list.append(temp_inv)
|
self.add_mod(temp_inv)
|
||||||
self.add_mod(self.inv_list[x])
|
|
||||||
else: # find inv sizes
|
|
||||||
for x in range(len(self.calc_size_list)):
|
|
||||||
temp_inv = factory.create(module_type="pinv", size=self.calc_size_list[x], height=self.height)
|
|
||||||
self.inv_list.append(temp_inv)
|
|
||||||
self.add_mod(self.inv_list[x])
|
|
||||||
|
|
||||||
|
|
||||||
def create_insts(self):
|
def create_insts(self):
|
||||||
|
|
@ -226,3 +220,24 @@ class pdriver(pgate.pgate):
|
||||||
return delay
|
return delay
|
||||||
|
|
||||||
|
|
||||||
|
def get_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||||
|
"""Get the stage efforts of the A -> Z path"""
|
||||||
|
|
||||||
|
cout_list = {}
|
||||||
|
for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]):
|
||||||
|
cout_list[prev_inv]=inv.get_cin()
|
||||||
|
|
||||||
|
cout_list[self.inv_list[-1]]=external_cout
|
||||||
|
|
||||||
|
stage_effort_list = []
|
||||||
|
last_inp_is_rise = inp_is_rise
|
||||||
|
for inv in self.inv_list:
|
||||||
|
stage = inv.get_stage_effort(cout_list[inv], last_inp_is_rise)
|
||||||
|
stage_effort_list.append(stage)
|
||||||
|
last_inp_is_rise = stage.is_rise
|
||||||
|
|
||||||
|
return stage_effort_list
|
||||||
|
|
||||||
|
def get_cin(self):
|
||||||
|
"""Returns the relative capacitance of the input"""
|
||||||
|
return self.inv_list[0].get_cin()
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@ class pinv(pgate.pgate):
|
||||||
"""Return the capacitance of the gate connection in generic capacitive units relative to the minimum width of a transistor"""
|
"""Return the capacitance of the gate connection in generic capacitive units relative to the minimum width of a transistor"""
|
||||||
return self.nmos_size + self.pmos_size
|
return self.nmos_size + self.pmos_size
|
||||||
|
|
||||||
def get_effort_stage(self, cout, inp_is_rise=True):
|
def get_stage_effort(self, cout, inp_is_rise=True):
|
||||||
"""Returns an object representing the parameters for delay in tau units.
|
"""Returns an object representing the parameters for delay in tau units.
|
||||||
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -186,11 +186,11 @@ class pinvbuf(design.design):
|
||||||
"""Get the stage efforts of the clk -> clk_buf path"""
|
"""Get the stage efforts of the clk -> clk_buf path"""
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
stage1_cout = self.inv1.get_cin() + self.inv2.get_cin()
|
stage1_cout = self.inv1.get_cin() + self.inv2.get_cin()
|
||||||
stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise)
|
stage1 = self.inv.get_stage_effort(stage1_cout, inp_is_rise)
|
||||||
stage_effort_list.append(stage1)
|
stage_effort_list.append(stage1)
|
||||||
last_stage_is_rise = stage1.is_rise
|
last_stage_is_rise = stage1.is_rise
|
||||||
|
|
||||||
stage2 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise)
|
stage2 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise)
|
||||||
stage_effort_list.append(stage2)
|
stage_effort_list.append(stage2)
|
||||||
|
|
||||||
return stage_effort_list
|
return stage_effort_list
|
||||||
|
|
@ -200,16 +200,16 @@ class pinvbuf(design.design):
|
||||||
#After (almost) every stage, the direction of the signal inverts.
|
#After (almost) every stage, the direction of the signal inverts.
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
stage1_cout = self.inv1.get_cin() + self.inv2.get_cin()
|
stage1_cout = self.inv1.get_cin() + self.inv2.get_cin()
|
||||||
stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise)
|
stage1 = self.inv.get_stage_effort(stage1_cout, inp_is_rise)
|
||||||
stage_effort_list.append(stage1)
|
stage_effort_list.append(stage1)
|
||||||
last_stage_is_rise = stage_effort_list[-1].is_rise
|
last_stage_is_rise = stage_effort_list[-1].is_rise
|
||||||
|
|
||||||
stage2_cout = self.inv2.get_cin()
|
stage2_cout = self.inv2.get_cin()
|
||||||
stage2 = self.inv1.get_effort_stage(stage2_cout, last_stage_is_rise)
|
stage2 = self.inv1.get_stage_effort(stage2_cout, last_stage_is_rise)
|
||||||
stage_effort_list.append(stage2)
|
stage_effort_list.append(stage2)
|
||||||
last_stage_is_rise = stage_effort_list[-1].is_rise
|
last_stage_is_rise = stage_effort_list[-1].is_rise
|
||||||
|
|
||||||
stage3 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise)
|
stage3 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise)
|
||||||
stage_effort_list.append(stage3)
|
stage_effort_list.append(stage3)
|
||||||
|
|
||||||
return stage_effort_list
|
return stage_effort_list
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,7 @@ class pnand2(pgate.pgate):
|
||||||
"""Return the relative input capacitance of a single input"""
|
"""Return the relative input capacitance of a single input"""
|
||||||
return self.nmos_size+self.pmos_size
|
return self.nmos_size+self.pmos_size
|
||||||
|
|
||||||
def get_effort_stage(self, cout, inp_is_rise=True):
|
def get_stage_effort(self, cout, inp_is_rise=True):
|
||||||
"""Returns an object representing the parameters for delay in tau units.
|
"""Returns an object representing the parameters for delay in tau units.
|
||||||
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ class pnand3(pgate.pgate):
|
||||||
"""Return the relative input capacitance of a single input"""
|
"""Return the relative input capacitance of a single input"""
|
||||||
return self.nmos_size+self.pmos_size
|
return self.nmos_size+self.pmos_size
|
||||||
|
|
||||||
def get_effort_stage(self, cout, inp_is_rise=True):
|
def get_stage_effort(self, cout, inp_is_rise=True):
|
||||||
"""Returns an object representing the parameters for delay in tau units.
|
"""Returns an object representing the parameters for delay in tau units.
|
||||||
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -279,20 +279,23 @@ class sram_base(design, verilog, lef):
|
||||||
|
|
||||||
# Create the control logic module for each port type
|
# Create the control logic module for each port type
|
||||||
if len(self.readwrite_ports)>0:
|
if len(self.readwrite_ports)>0:
|
||||||
self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
|
self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
|
||||||
words_per_row=self.words_per_row,
|
words_per_row=self.words_per_row,
|
||||||
|
word_size=self.word_size,
|
||||||
sram=self,
|
sram=self,
|
||||||
port_type="rw")
|
port_type="rw")
|
||||||
self.add_mod(self.control_logic_rw)
|
self.add_mod(self.control_logic_rw)
|
||||||
if len(self.writeonly_ports)>0:
|
if len(self.writeonly_ports)>0:
|
||||||
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
|
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
|
||||||
words_per_row=self.words_per_row,
|
words_per_row=self.words_per_row,
|
||||||
|
word_size=self.word_size,
|
||||||
sram=self,
|
sram=self,
|
||||||
port_type="w")
|
port_type="w")
|
||||||
self.add_mod(self.control_logic_w)
|
self.add_mod(self.control_logic_w)
|
||||||
if len(self.readonly_ports)>0:
|
if len(self.readonly_ports)>0:
|
||||||
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
|
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
|
||||||
words_per_row=self.words_per_row,
|
words_per_row=self.words_per_row,
|
||||||
|
word_size=self.word_size,
|
||||||
sram=self,
|
sram=self,
|
||||||
port_type="r")
|
port_type="r")
|
||||||
self.add_mod(self.control_logic_r)
|
self.add_mod(self.control_logic_r)
|
||||||
|
|
@ -512,25 +515,30 @@ class sram_base(design, verilog, lef):
|
||||||
|
|
||||||
def get_wl_en_cin(self):
|
def get_wl_en_cin(self):
|
||||||
"""Gets the capacitive load the of clock (clk_buf) for the sram"""
|
"""Gets the capacitive load the of clock (clk_buf) for the sram"""
|
||||||
#As clk_buf is an output of the control logic. The cap for that module is not determined here.
|
|
||||||
#Only the wordline drivers within the bank use this signal
|
#Only the wordline drivers within the bank use this signal
|
||||||
bank_clk_cin = self.bank.get_wl_en_cin()
|
return self.bank.get_wl_en_cin()
|
||||||
|
|
||||||
return bank_clk_cin
|
def get_w_en_cin(self):
|
||||||
|
"""Gets the capacitive load the of write enable (w_en) for the sram"""
|
||||||
|
#Only the write drivers within the bank use this signal
|
||||||
|
return self.bank.get_w_en_cin()
|
||||||
|
|
||||||
|
|
||||||
|
def get_p_en_bar_cin(self):
|
||||||
|
"""Gets the capacitive load the of precharge enable (p_en_bar) for the sram"""
|
||||||
|
#Only the precharges within the bank use this signal
|
||||||
|
return self.bank.get_p_en_bar_cin()
|
||||||
|
|
||||||
def get_clk_bar_cin(self):
|
def get_clk_bar_cin(self):
|
||||||
"""Gets the capacitive load the of clock (clk_buf_bar) for the sram"""
|
"""Gets the capacitive load the of clock (clk_buf_bar) for the sram"""
|
||||||
#As clk_buf_bar is an output of the control logic. The cap for that module is not determined here.
|
#As clk_buf_bar is an output of the control logic. The cap for that module is not determined here.
|
||||||
#Only the precharge cells use this signal (other than the control logic)
|
#Only the precharge cells use this signal (other than the control logic)
|
||||||
bank_clk_cin = self.bank.get_clk_bar_cin()
|
return self.bank.get_clk_bar_cin()
|
||||||
return bank_clk_cin
|
|
||||||
|
|
||||||
def get_sen_cin(self):
|
def get_sen_cin(self):
|
||||||
"""Gets the capacitive load the of sense amp enable for the sram"""
|
"""Gets the capacitive load the of sense amp enable for the sram"""
|
||||||
#As clk_buf_bar is an output of the control logic. The cap for that module is not determined here.
|
|
||||||
#Only the sense_amps use this signal (other than the control logic)
|
#Only the sense_amps use this signal (other than the control logic)
|
||||||
bank_sen_cin = self.bank.get_sen_cin()
|
return self.bank.get_sen_cin()
|
||||||
return bank_sen_cin
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,22 +22,22 @@ class pdriver_test(openram_test):
|
||||||
|
|
||||||
debug.info(2, "Testing inverter/buffer 4x 8x")
|
debug.info(2, "Testing inverter/buffer 4x 8x")
|
||||||
# a tests the error message for specifying conflicting conditions
|
# a tests the error message for specifying conflicting conditions
|
||||||
#a = pdriver.pdriver(fanout_size = 4,size_list = [1,2,4,8])
|
#a = pdriver.pdriver(fanout = 4,size_list = [1,2,4,8])
|
||||||
#self.local_check(a)
|
#self.local_check(a)
|
||||||
|
|
||||||
b = pdriver.pdriver(name="pdriver1", size_list = [1,2,4,8])
|
b = pdriver.pdriver(name="pdriver1", size_list = [1,2,4,8])
|
||||||
self.local_check(b)
|
self.local_check(b)
|
||||||
|
|
||||||
c = pdriver.pdriver(name="pdriver2", fanout_size = 50)
|
c = pdriver.pdriver(name="pdriver2", fanout = 50)
|
||||||
self.local_check(c)
|
self.local_check(c)
|
||||||
|
|
||||||
d = pdriver.pdriver(name="pdriver3", fanout_size = 50, neg_polarity = True)
|
d = pdriver.pdriver(name="pdriver3", fanout = 50, neg_polarity = True)
|
||||||
self.local_check(d)
|
self.local_check(d)
|
||||||
|
|
||||||
e = pdriver.pdriver(name="pdriver4", fanout_size = 64)
|
e = pdriver.pdriver(name="pdriver4", fanout = 64)
|
||||||
self.local_check(e)
|
self.local_check(e)
|
||||||
|
|
||||||
f = pdriver.pdriver(name="pdriver5", fanout_size = 64, neg_polarity = True)
|
f = pdriver.pdriver(name="pdriver5", fanout = 64, neg_polarity = True)
|
||||||
self.local_check(f)
|
self.local_check(f)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ class control_logic_test(openram_test):
|
||||||
|
|
||||||
# check control logic for single port
|
# check control logic for single port
|
||||||
debug.info(1, "Testing sample for control_logic")
|
debug.info(1, "Testing sample for control_logic")
|
||||||
a = control_logic.control_logic(num_rows=128, words_per_row=1)
|
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=32)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# check control logic for multi-port
|
# check control logic for multi-port
|
||||||
|
|
@ -31,7 +31,7 @@ class control_logic_test(openram_test):
|
||||||
OPTS.num_r_ports = 0
|
OPTS.num_r_ports = 0
|
||||||
|
|
||||||
debug.info(1, "Testing sample for control_logic for multiport")
|
debug.info(1, "Testing sample for control_logic for multiport")
|
||||||
a = control_logic.control_logic(num_rows=128, words_per_row=1)
|
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# Check port specific control logic
|
# Check port specific control logic
|
||||||
|
|
@ -40,15 +40,15 @@ class control_logic_test(openram_test):
|
||||||
OPTS.num_r_ports = 1
|
OPTS.num_r_ports = 1
|
||||||
|
|
||||||
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
||||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="rw")
|
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="rw")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
||||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="w")
|
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="w")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
|
debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
|
||||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="r")
|
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="r")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue