mirror of https://github.com/VLSIDA/OpenRAM.git
Removed line to skip pdriver_test
This commit is contained in:
commit
4a5c18b6cc
|
|
@ -10,6 +10,7 @@ omit =
|
|||
debug.py
|
||||
[paths]
|
||||
source =
|
||||
../..
|
||||
/home/gitlab-runner/builds/2fd64746/0
|
||||
/home/gitlab-runner/builds/2fd64746/1
|
||||
/home/gitlab-runner/builds/2fd64746/2
|
||||
|
|
@ -25,4 +26,4 @@ exclude_lines =
|
|||
raise NotImplementedError
|
||||
if 0:
|
||||
if __name__ == "__main__":
|
||||
if not OPTS.is_unit_test
|
||||
if not OPTS.is_unit_test
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import debug
|
|||
import os
|
||||
from globals import OPTS
|
||||
|
||||
total_drc_errors = 0
|
||||
total_lvs_errors = 0
|
||||
|
||||
class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||
"""
|
||||
|
|
@ -13,7 +15,6 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
Class consisting of a set of modules and instances of these modules
|
||||
"""
|
||||
name_map = []
|
||||
|
||||
|
||||
def __init__(self, name):
|
||||
try:
|
||||
|
|
@ -28,8 +29,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
self.name = name
|
||||
hierarchy_layout.layout.__init__(self, name)
|
||||
hierarchy_spice.spice.__init__(self, name)
|
||||
|
||||
|
||||
|
||||
# Check if the name already exists, if so, give an error
|
||||
# because each reference must be a unique name.
|
||||
# These modules ensure unique names or have no changes if they
|
||||
|
|
@ -73,13 +74,23 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
"""Checks both DRC and LVS for a module"""
|
||||
# Unit tests will check themselves.
|
||||
# Do not run if disabled in options.
|
||||
|
||||
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
||||
|
||||
global total_drc_errors
|
||||
global total_lvs_errors
|
||||
tempspice = OPTS.openram_temp + "/temp.sp"
|
||||
tempgds = OPTS.openram_temp + "/temp.gds"
|
||||
self.sp_write(tempspice)
|
||||
self.gds_write(tempgds)
|
||||
debug.check(verify.run_drc(self.name, tempgds, final_verification) == 0,"DRC failed for {0}".format(self.name))
|
||||
debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name))
|
||||
|
||||
num_drc_errors = verify.run_drc(self.name, tempgds, final_verification)
|
||||
num_lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification)
|
||||
debug.check(num_drc_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_drc_errors))
|
||||
debug.check(num_lvs_errors == 0,"LVS failed for {0} with {1} errors(s)".format(self.name,num_lvs_errors))
|
||||
total_drc_errors += num_drc_errors
|
||||
total_lvs_errors += num_lvs_errors
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
|
|
@ -87,22 +98,31 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
"""Checks DRC for a module"""
|
||||
# Unit tests will check themselves.
|
||||
# Do not run if disabled in options.
|
||||
|
||||
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
||||
global total_drc_errors
|
||||
tempgds = OPTS.openram_temp + "/temp.gds"
|
||||
self.gds_write(tempgds)
|
||||
debug.check(verify.run_drc(self.name, tempgds, final_verification) == 0,"DRC failed for {0}".format(self.name))
|
||||
num_errors = verify.run_drc(self.name, tempgds, final_verification)
|
||||
total_drc_errors += num_errors
|
||||
debug.check(num_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_error))
|
||||
|
||||
os.remove(tempgds)
|
||||
|
||||
def LVS(self, final_verification=False):
|
||||
"""Checks LVS for a module"""
|
||||
# Unit tests will check themselves.
|
||||
# Do not run if disabled in options.
|
||||
|
||||
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
||||
global total_lvs_errors
|
||||
tempspice = OPTS.openram_temp + "/temp.sp"
|
||||
tempgds = OPTS.openram_temp + "/temp.gds"
|
||||
self.sp_write(tempspice)
|
||||
self.gds_write(tempgds)
|
||||
debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name))
|
||||
num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification)
|
||||
total_lvs_errors += num_errors
|
||||
debug.check(num_errors == 0,"LVS failed for {0} with {1} error(s)".format(self.name,num_errors))
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import design
|
||||
import debug
|
||||
import utils
|
||||
from tech import GDS,layer
|
||||
from tech import GDS,layer,parameter,drc
|
||||
|
||||
class bitcell(design.design):
|
||||
"""
|
||||
|
|
@ -73,3 +73,9 @@ class bitcell(design.design):
|
|||
total_power = self.return_power(dynamic, leakage)
|
||||
return total_power
|
||||
|
||||
def get_wl_cin(self):
|
||||
"""Return the relative capacitance of the access transistor gates"""
|
||||
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
|
||||
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
|
||||
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
|
||||
return 2*access_tx_cin
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import design
|
||||
import debug
|
||||
import utils
|
||||
from tech import GDS,layer
|
||||
from tech import GDS,layer,parameter,drc
|
||||
|
||||
class bitcell_1rw_1r(design.design):
|
||||
"""
|
||||
|
|
@ -96,3 +96,10 @@ class bitcell_1rw_1r(design.design):
|
|||
total_power = self.return_power(dynamic, leakage)
|
||||
return total_power
|
||||
|
||||
def get_wl_cin(self):
|
||||
"""Return the relative capacitance of the access transistor gates"""
|
||||
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
|
||||
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
|
||||
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
|
||||
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
|
||||
return 2*access_tx_cin
|
||||
|
|
@ -887,3 +887,10 @@ class pbitcell(design.design):
|
|||
dynamic = 0 #temporary
|
||||
total_power = self.return_power(dynamic, leakage)
|
||||
return total_power
|
||||
|
||||
def get_wl_cin(self):
|
||||
"""Return the relative capacitance of the access transistor gates"""
|
||||
#pbitcell uses the different sizing for the port access tx's. Not accounted for in this model.
|
||||
access_tx_cin = self.readwrite_nmos.get_cin()
|
||||
return 2*access_tx_cin
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import design
|
||||
import debug
|
||||
import utils
|
||||
from tech import GDS,layer
|
||||
from tech import GDS,layer,drc,parameter
|
||||
|
||||
class replica_bitcell(design.design):
|
||||
"""
|
||||
|
|
@ -21,3 +21,10 @@ class replica_bitcell(design.design):
|
|||
self.width = replica_bitcell.width
|
||||
self.height = replica_bitcell.height
|
||||
self.pin_map = replica_bitcell.pin_map
|
||||
|
||||
def get_wl_cin(self):
|
||||
"""Return the relative capacitance of the access transistor gates"""
|
||||
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
|
||||
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
|
||||
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
|
||||
return 2*access_tx_cin
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import design
|
||||
import debug
|
||||
import utils
|
||||
from tech import GDS,layer
|
||||
from tech import GDS,layer,drc,parameter
|
||||
|
||||
class replica_bitcell_1rw_1r(design.design):
|
||||
"""
|
||||
|
|
@ -21,3 +21,11 @@ class replica_bitcell_1rw_1r(design.design):
|
|||
self.width = replica_bitcell_1rw_1r.width
|
||||
self.height = replica_bitcell_1rw_1r.height
|
||||
self.pin_map = replica_bitcell_1rw_1r.pin_map
|
||||
|
||||
def get_wl_cin(self):
|
||||
"""Return the relative capacitance of the access transistor gates"""
|
||||
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
|
||||
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
|
||||
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
|
||||
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
|
||||
return 2*access_tx_cin
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import debug
|
||||
import design
|
||||
from tech import drc, spice
|
||||
from tech import drc, spice,parameter
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
from pbitcell import pbitcell
|
||||
|
|
@ -79,4 +79,8 @@ class replica_pbitcell(design.design):
|
|||
self.copy_layout_pin(self.prbc_inst, "wl{}".format(port))
|
||||
self.copy_layout_pin(self.prbc_inst, "vdd")
|
||||
self.copy_layout_pin(self.prbc_inst, "gnd")
|
||||
|
||||
|
||||
def get_wl_cin(self):
|
||||
"""Return the relative capacitance of the access transistor gates"""
|
||||
#This module is made using a pbitcell. Get the cin from that module
|
||||
return self.prbc.get_wl_cin()
|
||||
|
|
@ -8,7 +8,7 @@ from .setup_hold import *
|
|||
from .functional import *
|
||||
from .worst_case import *
|
||||
from .simulation import *
|
||||
|
||||
from .bitline_delay import *
|
||||
|
||||
debug.info(1,"Initializing characterizer...")
|
||||
OPTS.spice_exe = ""
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
import sys,re,shutil
|
||||
import debug
|
||||
import tech
|
||||
import math
|
||||
from .stimuli import *
|
||||
from .trim_spice import *
|
||||
from .charutils import *
|
||||
import utils
|
||||
from globals import OPTS
|
||||
from .delay import delay
|
||||
|
||||
class bitline_delay(delay):
|
||||
"""Functions to test for the worst case delay in a target SRAM
|
||||
|
||||
The current worst case determines a feasible period for the SRAM then tests
|
||||
several bits and record the delay and differences between the bits.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, sram, spfile, corner):
|
||||
delay.__init__(self,sram,spfile,corner)
|
||||
self.period = tech.spice["feasible_period"]
|
||||
self.is_bitline_measure = True
|
||||
|
||||
def create_measurement_names(self):
|
||||
"""Create measurement names. The names themselves currently define the type of measurement"""
|
||||
#Altering the names will crash the characterizer. TODO: object orientated approach to the measurements.
|
||||
self.bitline_meas_names = ["bl_volt", "br_volt"]
|
||||
|
||||
def write_delay_measures(self):
|
||||
"""
|
||||
Write the measure statements to quantify the bitline voltage at sense amp enable 50%.
|
||||
"""
|
||||
self.sf.write("\n* Measure statements for delay and power\n")
|
||||
|
||||
# Output some comments to aid where cycles start and
|
||||
for comment in self.cycle_comments:
|
||||
self.sf.write("* {}\n".format(comment))
|
||||
|
||||
for read_port in self.targ_read_ports:
|
||||
self.write_bitline_measures_read_port(read_port)
|
||||
|
||||
def write_bitline_measures_read_port(self, port):
|
||||
"""
|
||||
Write the measure statements to quantify the delay and power results for a read port.
|
||||
"""
|
||||
# add measure statements for delays/slews
|
||||
measure_bitline = self.get_data_bit_column_number(self.probe_address, self.probe_data)
|
||||
debug.info(2, "Measuring bitline column={}".format(measure_bitline))
|
||||
for port in self.targ_read_ports:
|
||||
if len(self.all_ports) == 1: #special naming case for single port sram bitlines
|
||||
bitline_port = ""
|
||||
else:
|
||||
bitline_port = str(port)
|
||||
|
||||
sen_name = "Xsram.s_en{}".format(port)
|
||||
bl_name = "Xsram.Xbank0.bl{}_{}".format(bitline_port, measure_bitline)
|
||||
br_name = "Xsram.Xbank0.br{}_{}".format(bitline_port, measure_bitline)
|
||||
self.stim.gen_meas_find_voltage("bl_volt", sen_name, bl_name, .5, "RISE", self.cycle_times[self.measure_cycles[port]["read0"]])
|
||||
self.stim.gen_meas_find_voltage("br_volt", sen_name, br_name, .5, "RISE", self.cycle_times[self.measure_cycles[port]["read0"]])
|
||||
|
||||
def gen_test_cycles_one_port(self, read_port, write_port):
|
||||
"""Sets a list of key time-points [ns] of the waveform (each rising edge)
|
||||
of the cycles to do a timing evaluation of a single port """
|
||||
|
||||
# Create the inverse address for a scratch address
|
||||
inverse_address = self.calculate_inverse_address()
|
||||
|
||||
# For now, ignore data patterns and write ones or zeros
|
||||
data_ones = "1"*self.word_size
|
||||
data_zeros = "0"*self.word_size
|
||||
|
||||
if self.t_current == 0:
|
||||
self.add_noop_all_ports("Idle cycle (no positive clock edge)",
|
||||
inverse_address, data_zeros)
|
||||
|
||||
self.add_write("W data 1 address {}".format(inverse_address),
|
||||
inverse_address,data_ones,write_port)
|
||||
|
||||
self.add_write("W data 0 address {} to write value".format(self.probe_address),
|
||||
self.probe_address,data_zeros,write_port)
|
||||
self.measure_cycles[write_port]["write0"] = len(self.cycle_times)-1
|
||||
|
||||
# This also ensures we will have a H->L transition on the next read
|
||||
self.add_read("R data 1 address {} to set DOUT caps".format(inverse_address),
|
||||
inverse_address,data_zeros,read_port)
|
||||
self.measure_cycles[read_port]["read1"] = len(self.cycle_times)-1
|
||||
|
||||
self.add_read("R data 0 address {} to check W0 worked".format(self.probe_address),
|
||||
self.probe_address,data_zeros,read_port)
|
||||
self.measure_cycles[read_port]["read0"] = len(self.cycle_times)-1
|
||||
def get_data_bit_column_number(self, probe_address, probe_data):
|
||||
"""Calculates bitline column number of data bit under test using bit position and mux size"""
|
||||
if self.sram.col_addr_size>0:
|
||||
col_address = int(probe_address[0:self.sram.col_addr_size],2)
|
||||
else:
|
||||
col_address = 0
|
||||
bl_column = int(self.sram.words_per_row*probe_data + col_address)
|
||||
return bl_column
|
||||
|
||||
def run_delay_simulation(self):
|
||||
"""
|
||||
This tries to simulate a period and checks if the result works. If
|
||||
so, it returns True and the delays, slews, and powers. It
|
||||
works on the trimmed netlist by default, so powers do not
|
||||
include leakage of all cells.
|
||||
"""
|
||||
#Sanity Check
|
||||
debug.check(self.period > 0, "Target simulation period non-positive")
|
||||
|
||||
result = [{} for i in self.all_ports]
|
||||
# Checking from not data_value to data_value
|
||||
self.write_delay_stimulus()
|
||||
|
||||
self.stim.run_sim() #running sim prodoces spice output file.
|
||||
|
||||
for port in self.targ_read_ports:
|
||||
bitlines_meas_vals = {}
|
||||
for mname in self.bitline_meas_names:
|
||||
bitlines_meas_vals[mname] = parse_spice_list("timing", mname)
|
||||
#Check that power parsing worked.
|
||||
for name, val in bitlines_meas_vals.items():
|
||||
if type(val)!=float:
|
||||
debug.error("Failed to Parse Bitline Values:\n\t\t{0}".format(bitlines_meas_vals),1) #Printing the entire dict looks bad.
|
||||
result[port].update(bitlines_meas_vals)
|
||||
|
||||
|
||||
# The delay is from the negative edge for our SRAM
|
||||
return (True,result)
|
||||
|
||||
def analyze(self, probe_address, probe_data, slews, loads):
|
||||
"""Measures the bitline swing of the differential bitlines (bl/br) at 50% s_en """
|
||||
self.set_probe(probe_address, probe_data)
|
||||
self.load=max(loads)
|
||||
self.slew=max(slews)
|
||||
|
||||
read_port = self.read_ports[0] #only test the first read port
|
||||
bitline_swings = {}
|
||||
self.targ_read_ports = [read_port]
|
||||
self.targ_write_ports = [self.write_ports[0]]
|
||||
debug.info(1,"Bitline swing test: corner {}".format(self.corner))
|
||||
(success, results)=self.run_delay_simulation()
|
||||
debug.check(success, "Bitline Failed: period {}".format(self.period))
|
||||
for mname in self.bitline_meas_names:
|
||||
bitline_swings[mname] = results[read_port][mname]
|
||||
debug.info(1,"Bitline values (bl/br): {}".format(bitline_swings))
|
||||
return bitline_swings
|
||||
|
||||
|
||||
|
||||
|
|
@ -5,7 +5,7 @@ from globals import OPTS
|
|||
|
||||
def relative_compare(value1,value2,error_tolerance=0.001):
|
||||
""" This is used to compare relative values for convergence. """
|
||||
return (abs(value1 - value2) / max(value1,value2) <= error_tolerance)
|
||||
return (abs(value1 - value2) / abs(max(value1,value2)) <= error_tolerance)
|
||||
|
||||
|
||||
def parse_spice_list(filename, key):
|
||||
|
|
|
|||
|
|
@ -208,14 +208,15 @@ class delay(simulation):
|
|||
trig_slew_low = 0.1 * self.vdd_voltage
|
||||
targ_slew_high = 0.9 * self.vdd_voltage
|
||||
if 'delay' in delay_name:
|
||||
trig_dir="RISE"
|
||||
trig_val = half_vdd
|
||||
targ_val = half_vdd
|
||||
trig_name = trig_clk_name
|
||||
if 'lh' in delay_name:
|
||||
trig_dir="RISE"
|
||||
targ_dir="RISE"
|
||||
trig_td = targ_td = self.cycle_times[self.measure_cycles[port]["read1"]]
|
||||
else:
|
||||
trig_dir="FALL"
|
||||
targ_dir="FALL"
|
||||
trig_td = targ_td = self.cycle_times[self.measure_cycles[port]["read0"]]
|
||||
|
||||
|
|
@ -426,10 +427,9 @@ class delay(simulation):
|
|||
#Too much duplicate code here. Try reducing
|
||||
for port in self.targ_read_ports:
|
||||
debug.info(2, "Check delay values for port {}".format(port))
|
||||
delay_names = ["{0}{1}".format(mname,port) for mname in self.delay_meas_names]
|
||||
delay_names = [mname for mname in self.delay_meas_names]
|
||||
delays = self.parse_values(delay_names, port, 1e9) # scale delays to ns
|
||||
if not self.check_valid_delays(tuple(delays.values())):
|
||||
if not self.check_valid_delays(delays):
|
||||
return (False,{})
|
||||
result[port].update(delays)
|
||||
|
||||
|
|
@ -478,10 +478,13 @@ class delay(simulation):
|
|||
#key=raw_input("press return to continue")
|
||||
return (leakage_power*1e3, trim_leakage_power*1e3)
|
||||
|
||||
def check_valid_delays(self, delay_tuple):
|
||||
def check_valid_delays(self, delay_dict):
|
||||
""" Check if the measurements are defined and if they are valid. """
|
||||
|
||||
(delay_hl, delay_lh, slew_hl, slew_lh) = delay_tuple
|
||||
#Hard coded names currently
|
||||
delay_hl = delay_dict["delay_hl"]
|
||||
delay_lh = delay_dict["delay_lh"]
|
||||
slew_hl = delay_dict["slew_hl"]
|
||||
slew_lh = delay_dict["slew_lh"]
|
||||
period_load_slew_str = "period {0} load {1} slew {2}".format(self.period,self.load, self.slew)
|
||||
|
||||
# if it failed or the read was longer than a period
|
||||
|
|
@ -495,7 +498,8 @@ class delay(simulation):
|
|||
|
||||
delays_str = "delay_hl={0} delay_lh={1}".format(delay_hl, delay_lh)
|
||||
slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl,slew_lh)
|
||||
if delay_hl>self.period or delay_lh>self.period or slew_hl>self.period or slew_lh>self.period:
|
||||
half_period = self.period/2 #high-to-low delays start at neg. clk edge, so they need to be less than half_period
|
||||
if abs(delay_hl)>half_period or abs(delay_lh)>self.period or abs(slew_hl)>half_period or abs(slew_lh)>self.period:
|
||||
debug.info(2,"UNsuccessful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str,
|
||||
delays_str,
|
||||
slews_str))
|
||||
|
|
@ -565,6 +569,7 @@ class delay(simulation):
|
|||
|
||||
#Update target
|
||||
target_period = 0.5 * (ub_period + lb_period)
|
||||
#key=input("press return to continue")
|
||||
|
||||
|
||||
def try_period(self, feasible_delays):
|
||||
|
|
@ -579,8 +584,14 @@ class delay(simulation):
|
|||
|
||||
#Check the values of target readwrite and read ports. Write ports do not produce delays in this current version
|
||||
for port in self.targ_read_ports:
|
||||
delay_port_names = [mname for mname in self.delay_meas_names if "delay" in mname]
|
||||
for dname in delay_port_names:
|
||||
for dname in self.delay_meas_names: #check that the delays and slews do not degrade with tested period.
|
||||
|
||||
#FIXME: This is a hack solution to fix the min period search. The slew will always be based on the period when there
|
||||
#is a column mux. Therefore, the checks are skipped for this condition. This is hard to solve without changing the netlist.
|
||||
#Delays/slews based on the period will cause the min_period search to come to the wrong period.
|
||||
if self.sram.col_addr_size>0 and "slew" in dname:
|
||||
continue
|
||||
|
||||
if not relative_compare(results[port][dname],feasible_delays[port][dname],error_tolerance=0.05):
|
||||
debug.info(2,"Delay too big {0} vs {1}".format(results[port][dname],feasible_delays[port][dname]))
|
||||
return False
|
||||
|
|
@ -646,18 +657,6 @@ class delay(simulation):
|
|||
# slew=0.04
|
||||
# self.try_period(target_period, feasible_delay_lh, feasible_delay_hl)
|
||||
# sys.exit(1)
|
||||
|
||||
#For debugging, skips characterization and returns dummy values.
|
||||
# char_data = self.get_empty_measure_data_dict()
|
||||
# i = 1.0
|
||||
# for slew in slews:
|
||||
# for load in loads:
|
||||
# for k,v in char_data.items():
|
||||
# char_data[k].append(i)
|
||||
# i+=1.0
|
||||
# char_data["min_period"] = i
|
||||
# char_data["leakage_power"] = i+1.0
|
||||
# return char_data
|
||||
|
||||
# 1) Find a feasible period and it's corresponding delays using the trimmed array.
|
||||
feasible_delays = self.find_feasible_period()
|
||||
|
|
@ -677,8 +676,18 @@ class delay(simulation):
|
|||
self.period = min_period
|
||||
char_port_data = self.simulate_loads_and_slews(slews, loads, leakage_offset)
|
||||
|
||||
#FIXME: low-to-high delays are altered to be independent of the period. This makes the lib results less accurate.
|
||||
self.alter_lh_char_data(char_port_data)
|
||||
|
||||
return (char_sram_data, char_port_data)
|
||||
|
||||
def alter_lh_char_data(self, char_port_data):
|
||||
"""Copies high-to-low data to low-to-high data to make them consistent on the same clock edge."""
|
||||
#This is basically a hack solution which should be removed/fixed later.
|
||||
for port in self.all_ports:
|
||||
char_port_data[port]['delay_lh'] = char_port_data[port]['delay_hl']
|
||||
char_port_data[port]['slew_lh'] = char_port_data[port]['slew_hl']
|
||||
|
||||
def simulate_loads_and_slews(self, slews, loads, leakage_offset):
|
||||
"""Simulate all specified output loads and input slews pairs of all ports"""
|
||||
measure_data = self.get_empty_measure_data_dict()
|
||||
|
|
@ -702,20 +711,27 @@ class delay(simulation):
|
|||
measure_data[port][mname].append(value)
|
||||
return measure_data
|
||||
|
||||
|
||||
def gen_test_cycles_one_port(self, read_port, write_port):
|
||||
"""Intended but not implemented: Returns a list of key time-points [ns] of the waveform (each rising edge)
|
||||
of the cycles to do a timing evaluation of a single port. Current: Values overwritten for multiple calls"""
|
||||
|
||||
# Create the inverse address for a scratch address
|
||||
def calculate_inverse_address(self):
|
||||
"""Determine dummy test address based on probe address and column mux size."""
|
||||
#The inverse address needs to share the same bitlines as the probe address as the trimming will remove all other bitlines
|
||||
#This is only an issue when there is a column mux and the address maps to different bitlines.
|
||||
column_addr = self.probe_address[:self.sram.col_addr_size] #do not invert this part
|
||||
inverse_address = ""
|
||||
for c in self.probe_address:
|
||||
for c in self.probe_address[self.sram.col_addr_size:]: #invert everything else
|
||||
if c=="0":
|
||||
inverse_address += "1"
|
||||
elif c=="1":
|
||||
inverse_address += "0"
|
||||
else:
|
||||
debug.error("Non-binary address string",1)
|
||||
return inverse_address+column_addr
|
||||
|
||||
def gen_test_cycles_one_port(self, read_port, write_port):
|
||||
"""Sets a list of key time-points [ns] of the waveform (each rising edge)
|
||||
of the cycles to do a timing evaluation of a single port """
|
||||
|
||||
# Create the inverse address for a scratch address
|
||||
inverse_address = self.calculate_inverse_address()
|
||||
|
||||
# For now, ignore data patterns and write ones or zeros
|
||||
data_ones = "1"*self.word_size
|
||||
|
|
@ -725,36 +741,36 @@ class delay(simulation):
|
|||
self.add_noop_all_ports("Idle cycle (no positive clock edge)",
|
||||
inverse_address, data_zeros)
|
||||
|
||||
self.add_write("W data 1 address 0..00",
|
||||
self.add_write("W data 1 address {}".format(inverse_address),
|
||||
inverse_address,data_ones,write_port)
|
||||
|
||||
self.add_write("W data 0 address 11..11 to write value",
|
||||
self.add_write("W data 0 address {} to write value".format(self.probe_address),
|
||||
self.probe_address,data_zeros,write_port)
|
||||
self.measure_cycles[write_port]["write0"] = len(self.cycle_times)-1
|
||||
|
||||
# This also ensures we will have a H->L transition on the next read
|
||||
self.add_read("R data 1 address 00..00 to set DOUT caps",
|
||||
self.add_read("R data 1 address {} to set DOUT caps".format(inverse_address),
|
||||
inverse_address,data_zeros,read_port)
|
||||
|
||||
self.add_read("R data 0 address 11..11 to check W0 worked",
|
||||
self.add_read("R data 0 address {} to check W0 worked".format(self.probe_address),
|
||||
self.probe_address,data_zeros,read_port)
|
||||
self.measure_cycles[read_port]["read0"] = len(self.cycle_times)-1
|
||||
|
||||
self.add_noop_all_ports("Idle cycle (if read takes >1 cycle)",
|
||||
inverse_address,data_zeros)
|
||||
|
||||
self.add_write("W data 1 address 11..11 to write value",
|
||||
self.add_write("W data 1 address {} to write value".format(self.probe_address),
|
||||
self.probe_address,data_ones,write_port)
|
||||
self.measure_cycles[write_port]["write1"] = len(self.cycle_times)-1
|
||||
|
||||
self.add_write("W data 0 address 00..00 to clear DIN caps",
|
||||
self.add_write("W data 0 address {} to clear DIN caps".format(inverse_address),
|
||||
inverse_address,data_zeros,write_port)
|
||||
|
||||
# This also ensures we will have a L->H transition on the next read
|
||||
self.add_read("R data 0 address 00..00 to clear DOUT caps",
|
||||
self.add_read("R data 0 address {} to clear DOUT caps".format(inverse_address),
|
||||
inverse_address,data_zeros,read_port)
|
||||
|
||||
self.add_read("R data 1 address 11..11 to check W1 worked",
|
||||
self.add_read("R data 1 address {} to check W1 worked".format(self.probe_address),
|
||||
self.probe_address,data_zeros,read_port)
|
||||
self.measure_cycles[read_port]["read1"] = len(self.cycle_times)-1
|
||||
|
||||
|
|
@ -834,34 +850,6 @@ class delay(simulation):
|
|||
|
||||
return (sram_data,port_data)
|
||||
|
||||
# delay_lh = []
|
||||
# delay_hl = []
|
||||
# slew_lh = []
|
||||
# slew_hl = []
|
||||
# for slew in slews:
|
||||
# for load in loads:
|
||||
# self.set_load_slew(load,slew)
|
||||
# bank_delay = sram.analytical_delay(self.vdd_voltage, self.slew,self.load)
|
||||
# # Convert from ps to ns
|
||||
# delay_lh.append(bank_delay.delay/1e3)
|
||||
# delay_hl.append(bank_delay.delay/1e3)
|
||||
# slew_lh.append(bank_delay.slew/1e3)
|
||||
# slew_hl.append(bank_delay.slew/1e3)
|
||||
|
||||
# power = self.analytical_power()
|
||||
|
||||
# sram_data = { "min_period": 0,
|
||||
# "leakage_power": power.leakage}
|
||||
# port_data = [{"delay_lh": delay_lh,
|
||||
# "delay_hl": delay_hl,
|
||||
# "slew_lh": slew_lh,
|
||||
# "slew_hl": slew_hl,
|
||||
# "read0_power": power.dynamic,
|
||||
# "read1_power": power.dynamic,
|
||||
# "write0_power": power.dynamic,
|
||||
# "write1_power": power.dynamic,
|
||||
# }]
|
||||
# return (sram_data,port_data)
|
||||
|
||||
def analytical_power(self, slews, loads):
|
||||
"""Get the dynamic and leakage power from the SRAM"""
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import utils
|
|||
from globals import OPTS
|
||||
|
||||
from .simulation import simulation
|
||||
|
||||
from .delay import delay
|
||||
|
||||
class functional(simulation):
|
||||
"""
|
||||
|
|
@ -27,6 +27,7 @@ class functional(simulation):
|
|||
|
||||
self.set_corner(corner)
|
||||
self.set_spice_constants()
|
||||
#self.set_feasible_period(sram, spfile, corner)
|
||||
self.set_stimulus_variables()
|
||||
self.create_signal_names()
|
||||
|
||||
|
|
@ -37,15 +38,9 @@ class functional(simulation):
|
|||
self.write_check = []
|
||||
self.read_check = []
|
||||
|
||||
def set_spice_constants(self):
|
||||
"""Spice constants for functional test"""
|
||||
simulation.set_spice_constants(self)
|
||||
#Heuristic increase for functional period. Base feasible period typically does not pass the functional test
|
||||
#for column mux of this size. Increase the feasible period by 20% for this case.
|
||||
if self.sram.words_per_row >= 4:
|
||||
self.period = self.period*1.2
|
||||
|
||||
def run(self):
|
||||
def run(self, feasible_period=None):
|
||||
if feasible_period: #period defaults to tech.py feasible period otherwise.
|
||||
self.period = feasible_period
|
||||
# Generate a random sequence of reads and writes
|
||||
self.write_random_memory_sequence()
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class lib:
|
|||
debug.info(1,"Writing to {0}".format(lib_name))
|
||||
self.characterize()
|
||||
self.lib.close()
|
||||
self.parse_info()
|
||||
self.parse_info(self.corner,lib_name)
|
||||
def characterize(self):
|
||||
""" Characterize the current corner. """
|
||||
|
||||
|
|
@ -503,36 +503,132 @@ class lib:
|
|||
self.times = self.sh.analyze(self.slews,self.slews)
|
||||
|
||||
|
||||
def parse_info(self):
|
||||
def parse_info(self,corner,lib_name):
|
||||
""" Copies important characterization data to datasheet.info to be added to datasheet """
|
||||
if OPTS.is_unit_test:
|
||||
return
|
||||
datasheet = open(OPTS.openram_temp +'/datasheet.info', 'a+')
|
||||
|
||||
for (corner, lib_name) in zip(self.corners, self.lib_files):
|
||||
|
||||
# ports = ""
|
||||
# if OPTS.num_rw_ports>0:
|
||||
# ports += "{}_".format(OPTS.num_rw_ports)
|
||||
# if OPTS.num_w_ports>0:
|
||||
# ports += "{}_".format(OPTS.num_w_ports)
|
||||
# if OPTS.num_r_ports>0:
|
||||
# ports += "{}_".format(OPTS.num_r_ports)
|
||||
git_id = 'AAAAAAAAAAAAAAAAAAAA'
|
||||
else:
|
||||
with open(os.devnull, 'wb') as devnull:
|
||||
proc = subprocess.Popen(['git','rev-parse','HEAD'], stdout=subprocess.PIPE)
|
||||
git_id = str(proc.stdout.read())
|
||||
git_id = git_id[2:-3]
|
||||
|
||||
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13}".format("sram_{0}_{1}_{2}".format(OPTS.word_size, OPTS.num_words, OPTS.tech_name),
|
||||
OPTS.num_words,
|
||||
OPTS.num_banks,
|
||||
OPTS.num_rw_ports,
|
||||
OPTS.num_w_ports,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.tech_name,
|
||||
self.corner[1],
|
||||
self.corner[2],
|
||||
self.corner[0],
|
||||
round_time(self.char_sram_results["min_period"]),
|
||||
self.out_dir,
|
||||
lib_name,
|
||||
OPTS.word_size))
|
||||
datasheet = open(OPTS.openram_temp +'/datasheet.info', 'a+')
|
||||
|
||||
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},".format(
|
||||
"sram_{0}_{1}_{2}".format(OPTS.word_size, OPTS.num_words, OPTS.tech_name),
|
||||
OPTS.num_words,
|
||||
OPTS.num_banks,
|
||||
OPTS.num_rw_ports,
|
||||
OPTS.num_w_ports,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.tech_name,
|
||||
corner[2],
|
||||
corner[1],
|
||||
corner[0],
|
||||
round_time(self.char_sram_results["min_period"]),
|
||||
self.out_dir,
|
||||
lib_name,
|
||||
OPTS.word_size,
|
||||
git_id
|
||||
))
|
||||
|
||||
for port in self.all_ports:
|
||||
#DIN timings
|
||||
if port in self.write_ports:
|
||||
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format(
|
||||
"DIN{1}[{0}:0]".format(self.sram.word_size - 1, port),
|
||||
min(list(map(round_time,self.times["setup_times_LH"]))),
|
||||
max(list(map(round_time,self.times["setup_times_LH"]))),
|
||||
|
||||
min(list(map(round_time,self.times["setup_times_HL"]))),
|
||||
max(list(map(round_time,self.times["setup_times_HL"]))),
|
||||
|
||||
min(list(map(round_time,self.times["hold_times_LH"]))),
|
||||
max(list(map(round_time,self.times["hold_times_LH"]))),
|
||||
|
||||
min(list(map(round_time,self.times["hold_times_HL"]))),
|
||||
max(list(map(round_time,self.times["hold_times_HL"])))
|
||||
|
||||
))
|
||||
|
||||
for port in self.all_ports:
|
||||
#DOUT timing
|
||||
if port in self.read_ports:
|
||||
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format(
|
||||
"DOUT{1}[{0}:0]".format(self.sram.word_size - 1, port),
|
||||
min(list(map(round_time,self.char_port_results[port]["delay_lh"]))),
|
||||
max(list(map(round_time,self.char_port_results[port]["delay_lh"]))),
|
||||
|
||||
min(list(map(round_time,self.char_port_results[port]["delay_hl"]))),
|
||||
max(list(map(round_time,self.char_port_results[port]["delay_hl"]))),
|
||||
|
||||
min(list(map(round_time,self.char_port_results[port]["slew_lh"]))),
|
||||
max(list(map(round_time,self.char_port_results[port]["slew_lh"]))),
|
||||
|
||||
min(list(map(round_time,self.char_port_results[port]["slew_hl"]))),
|
||||
max(list(map(round_time,self.char_port_results[port]["slew_hl"])))
|
||||
|
||||
|
||||
))
|
||||
|
||||
for port in self.all_ports:
|
||||
#CSb timings
|
||||
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format(
|
||||
"CSb{0}".format(port),
|
||||
min(list(map(round_time,self.times["setup_times_LH"]))),
|
||||
max(list(map(round_time,self.times["setup_times_LH"]))),
|
||||
|
||||
min(list(map(round_time,self.times["setup_times_HL"]))),
|
||||
max(list(map(round_time,self.times["setup_times_HL"]))),
|
||||
|
||||
min(list(map(round_time,self.times["hold_times_LH"]))),
|
||||
max(list(map(round_time,self.times["hold_times_LH"]))),
|
||||
|
||||
min(list(map(round_time,self.times["hold_times_HL"]))),
|
||||
max(list(map(round_time,self.times["hold_times_HL"])))
|
||||
|
||||
))
|
||||
|
||||
for port in self.all_ports:
|
||||
#ADDR timings
|
||||
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format(
|
||||
"ADDR{1}[{0}:0]".format(self.sram.addr_size - 1, port),
|
||||
min(list(map(round_time,self.times["setup_times_LH"]))),
|
||||
max(list(map(round_time,self.times["setup_times_LH"]))),
|
||||
|
||||
min(list(map(round_time,self.times["setup_times_HL"]))),
|
||||
max(list(map(round_time,self.times["setup_times_HL"]))),
|
||||
|
||||
min(list(map(round_time,self.times["hold_times_LH"]))),
|
||||
max(list(map(round_time,self.times["hold_times_LH"]))),
|
||||
|
||||
min(list(map(round_time,self.times["hold_times_HL"]))),
|
||||
max(list(map(round_time,self.times["hold_times_HL"])))
|
||||
|
||||
))
|
||||
|
||||
|
||||
for port in self.all_ports:
|
||||
if port in self.readwrite_ports:
|
||||
|
||||
#WEb timings
|
||||
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format(
|
||||
"WEb{0}".format(port),
|
||||
min(list(map(round_time,self.times["setup_times_LH"]))),
|
||||
max(list(map(round_time,self.times["setup_times_LH"]))),
|
||||
|
||||
min(list(map(round_time,self.times["setup_times_HL"]))),
|
||||
max(list(map(round_time,self.times["setup_times_HL"]))),
|
||||
|
||||
min(list(map(round_time,self.times["hold_times_LH"]))),
|
||||
max(list(map(round_time,self.times["hold_times_LH"]))),
|
||||
|
||||
min(list(map(round_time,self.times["hold_times_HL"]))),
|
||||
max(list(map(round_time,self.times["hold_times_HL"])))
|
||||
|
||||
))
|
||||
|
||||
|
||||
datasheet.write("END\n")
|
||||
datasheet.close()
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
import debug
|
||||
from tech import drc, parameter, spice
|
||||
|
||||
class logical_effort():
|
||||
"""
|
||||
Class to support the values behind logical effort. Useful for storing the different components
|
||||
such as logical effort, electrical effort, and parasitic delay.
|
||||
"""
|
||||
beta = parameter["beta"]
|
||||
min_inv_cin = 1+beta
|
||||
pinv=parameter["min_inv_para_delay"]
|
||||
|
||||
def __init__(self, size, cin, cout, parasitic, out_is_rise=True):
|
||||
self.cin = cin
|
||||
self.cout = cout
|
||||
self.logical_effort = (self.cin/size)/logical_effort.min_inv_cin
|
||||
self.eletrical_effort = self.cout/self.cin
|
||||
self.parasitic_scale = parasitic
|
||||
self.is_rise = out_is_rise
|
||||
|
||||
def __str__(self):
|
||||
return "g=" + str(self.logical_effort) + ", h=" + str(self.eletrical_effort) + ", p=" + str(self.parasitic_scale)+"*pinv, rise_delay="+str(self.is_rise)
|
||||
|
||||
def get_stage_effort(self):
|
||||
return self.logical_effort*self.eletrical_effort
|
||||
|
||||
def get_parasitic_delay(self, pinv):
|
||||
return pinv * self.parasitic_scale
|
||||
|
||||
def get_stage_delay(self, pinv):
|
||||
return self.get_stage_effort()+self.get_parasitic_delay(pinv)
|
||||
|
||||
def calculate_relative_delay(stage_effort_list, pinv=parameter["min_inv_para_delay"]):
|
||||
"""Calculates the total delay of a given delay path made of a list of logical effort objects."""
|
||||
total_rise_delay, total_fall_delay = calculate_relative_rise_fall_delays(stage_effort_list, pinv)
|
||||
return total_rise_delay + total_fall_delay
|
||||
|
||||
def calculate_relative_rise_fall_delays(stage_effort_list, pinv=parameter["min_inv_para_delay"]):
|
||||
"""Calculates the rise/fall delays of a given delay path made of a list of logical effort objects."""
|
||||
debug.info(2, "Calculating rise/fall relative delays")
|
||||
total_rise_delay, total_fall_delay = 0,0
|
||||
for stage in stage_effort_list:
|
||||
debug.info(3, stage)
|
||||
if stage.is_rise:
|
||||
total_rise_delay += stage.get_stage_delay(pinv)
|
||||
else:
|
||||
total_fall_delay += stage.get_stage_delay(pinv)
|
||||
return total_rise_delay, total_fall_delay
|
||||
|
||||
|
|
@ -216,6 +216,16 @@ class stimuli():
|
|||
targ_dir,
|
||||
targ_td))
|
||||
|
||||
def gen_meas_find_voltage(self, meas_name, trig_name, targ_name, trig_val, trig_dir, trig_td):
|
||||
""" Creates the .meas statement for the measurement of delay """
|
||||
measure_string=".meas tran {0} FIND v({1}) WHEN v({2})={3}v {4}=1 TD={5}n \n\n"
|
||||
self.sf.write(measure_string.format(meas_name,
|
||||
targ_name,
|
||||
trig_name,
|
||||
trig_val,
|
||||
trig_dir,
|
||||
trig_td))
|
||||
|
||||
def gen_meas_power(self, meas_name, t_initial, t_final):
|
||||
""" Creates the .meas statement for the measurement of avg power """
|
||||
# power mea cmd is different in different spice:
|
||||
|
|
@ -244,9 +254,10 @@ class stimuli():
|
|||
reltol = 0.005 # 0.5%
|
||||
else:
|
||||
reltol = 0.001 # 0.1%
|
||||
|
||||
timestep = 10 #ps, was 5ps but ngspice was complaining the timestep was too small in certain tests.
|
||||
|
||||
# UIC is needed for ngspice to converge
|
||||
self.sf.write(".TRAN 5p {0}n UIC\n".format(end_time))
|
||||
self.sf.write(".TRAN {0}p {1}n UIC\n".format(timestep,end_time))
|
||||
if OPTS.spice_name == "ngspice":
|
||||
# ngspice sometimes has convergence problems if not using gear method
|
||||
# which is more accurate, but slower than the default trapezoid method
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class trim_spice():
|
|||
|
||||
# Split up the address and convert to an int
|
||||
wl_address = int(address[self.col_addr_size:],2)
|
||||
if self.col_addr_size>1:
|
||||
if self.col_addr_size>0:
|
||||
col_address = int(address[0:self.col_addr_size],2)
|
||||
else:
|
||||
col_address = 0
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
<style>
|
||||
#data {
|
||||
font-family: Trebuchet MS, Arial, Helvetica, sans-serif;
|
||||
border-collapse: collapse;
|
||||
width: 99%;
|
||||
max-width: 799px
|
||||
}
|
||||
|
||||
#data td, #data th {
|
||||
border: 0px solid #ddd;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
#data tr:nth-child(even){background-color: #f1f2f2;}
|
||||
|
||||
#data tr:hover {background-color: #ddd;}
|
||||
|
||||
#data th {
|
||||
padding-top: 11px;
|
||||
padding-bottom: 11px;
|
||||
text-align: left;
|
||||
background-color: #004184;
|
||||
color: #F1B521;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
|
|
@ -1,6 +1,9 @@
|
|||
from flask_table import *
|
||||
|
||||
class characterization_corners(Table):
|
||||
"""
|
||||
Set up characterization corners table columns and title information
|
||||
"""
|
||||
corner_name = Col('Corner Name')
|
||||
process = Col('Process')
|
||||
power_supply = Col('Power Supply')
|
||||
|
|
@ -8,6 +11,9 @@ class characterization_corners(Table):
|
|||
library_name_suffix = Col('Library Name Suffix')
|
||||
|
||||
class characterization_corners_item(object):
|
||||
"""
|
||||
Defines the contents of a charcaterization corner table row
|
||||
"""
|
||||
def __init__(self, corner_name, process, power_supply, temperature, library_name_suffix):
|
||||
self.corner_name = corner_name
|
||||
self.process = process
|
||||
|
|
|
|||
|
|
@ -4,11 +4,17 @@ from characterization_corners import *
|
|||
from deliverables import *
|
||||
from timing_and_current_data import *
|
||||
from in_out import *
|
||||
from hierarchy_design import total_drc_errors
|
||||
from hierarchy_design import total_lvs_errors
|
||||
import os
|
||||
import csv
|
||||
import base64
|
||||
from globals import OPTS
|
||||
|
||||
class datasheet():
|
||||
|
||||
"""
|
||||
Defines the layout,but not the data, of the html datasheet
|
||||
"""
|
||||
def __init__(self,identifier):
|
||||
self.io = []
|
||||
self.corners = []
|
||||
|
|
@ -20,50 +26,63 @@ class datasheet():
|
|||
|
||||
|
||||
def generate_html(self):
|
||||
self.html = """<style>
|
||||
#data {
|
||||
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
max-width: 800px
|
||||
}
|
||||
"""
|
||||
Generates html tables using flask-table
|
||||
"""
|
||||
with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/datasheet.css', 'r') as datasheet_css:
|
||||
#css styling is kept in a seperate file
|
||||
self.html += datasheet_css.read()
|
||||
|
||||
#data td, #data th {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
}
|
||||
if OPTS.check_lvsdrc:
|
||||
|
||||
DRC = str(total_drc_errors) + ' errors'
|
||||
LVS = str(total_lvs_errors) + ' errors'
|
||||
PEX = 'n/a'
|
||||
else:
|
||||
DRC = 'skipped'
|
||||
LVS = 'skipped'
|
||||
PEX = 'skipped'
|
||||
|
||||
with open(OPTS.openram_temp + "/datasheet.info") as info:
|
||||
self.html += '<!--'
|
||||
for row in info:
|
||||
self.html += row
|
||||
self.html +='-->'
|
||||
|
||||
vlsi_logo = 0
|
||||
with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/vlsi_logo.png' , "rb") as image_file:
|
||||
vlsi_logo = base64.b64encode(image_file.read())
|
||||
|
||||
#data tr:nth-child(even){background-color: #f2f2f2;}
|
||||
openram_logo = 0
|
||||
with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/openram_logo_placeholder.png' , "rb") as image_file:
|
||||
openram_logo = base64.b64encode(image_file.read())
|
||||
|
||||
#data tr:hover {background-color: #ddd;}
|
||||
|
||||
#data th {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
text-align: left;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
}
|
||||
</style>"""
|
||||
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>'+ self.name + '.html' + '</p>'
|
||||
# self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>{0}</p>'
|
||||
# self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>{0}</p>'
|
||||
self.html += '<a href="https://vlsida.soe.ucsc.edu/"><img src="data:image/png;base64,{0}" alt="VLSIDA"></a><a href="https://vlsida.github.io/OpenRAM"><img src="data:image/png;base64,{1}"="OpenRAM"></a>'.format(str(vlsi_logo)[2:-1],str(openram_logo)[2:-1])
|
||||
|
||||
|
||||
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>Ports and Configuration (DEBUG)</p>'
|
||||
|
||||
|
||||
|
||||
self.html +='<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">'+ self.name + '.html' + '</p>'
|
||||
self.html +='<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">'+ 'DRC: ' + str(DRC) + '</p>'
|
||||
self.html +='<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">'+ 'LVS: ' + str(LVS) + '</p>'
|
||||
self.html += '<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">'+ 'Git commit id: ' + str(self.git_id) + '</p>'
|
||||
|
||||
self.html +='<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Ports and Configuration (DEBUG)</p>'
|
||||
self.html += in_out(self.io,table_id='data').__html__().replace('<','<').replace('"','"').replace('>',">")
|
||||
|
||||
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>Operating Conditions</p>'
|
||||
self.html +='<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Operating Conditions</p>'
|
||||
self.html += operating_conditions(self.operating,table_id='data').__html__()
|
||||
|
||||
self.html += '<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>Timing and Current Data</p>'
|
||||
self.html += '<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Timing and Current Data</p>'
|
||||
self.html += timing_and_current_data(self.timing,table_id='data').__html__()
|
||||
|
||||
self.html += '<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>Characterization Corners</p>'
|
||||
self.html += '<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Characterization Corners</p>'
|
||||
self.html += characterization_corners(self.corners,table_id='data').__html__()
|
||||
|
||||
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>Deliverables</p>'
|
||||
self.html +='<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Deliverables</p>'
|
||||
self.html += deliverables(self.dlv,table_id='data').__html__().replace('<','<').replace('"','"').replace('>',">")
|
||||
|
||||
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>*Feature only supported with characterizer</p>'
|
||||
|
||||
self.html +='<img src=' + os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/vlsi_logo.png alt="VLSIDA" />'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Datasheet Generator
|
||||
|
||||
TODO:
|
||||
locate all port elements in .lib
|
||||
Locate all timing elements in .lib
|
||||
Diagram generation
|
||||
Improve css
|
||||
This is a script to load data from the characterization and layout processes into
|
||||
a web friendly html datasheet. This script requres the python-flask and flask-table
|
||||
packages to be installed.
|
||||
"""
|
||||
#TODO:
|
||||
#locate all port elements in .lib
|
||||
#Locate all timing elements in .lib
|
||||
#Diagram generation
|
||||
#Improve css
|
||||
|
||||
|
||||
import debug
|
||||
from globals import OPTS
|
||||
|
||||
|
|
@ -24,10 +27,13 @@ if OPTS.datasheet_gen:
|
|||
from in_out import *
|
||||
else:
|
||||
debug.warning("Python library flask_table not found. Skipping html datasheet generation. This can be installed with pip install flask-table.")
|
||||
|
||||
#make sure appropriate python libraries are installed
|
||||
|
||||
|
||||
def process_name(corner):
|
||||
"""
|
||||
Expands the names of the characterization corner types into something human friendly
|
||||
"""
|
||||
if corner == "TT":
|
||||
return "Typical - Typical"
|
||||
if corner == "SS":
|
||||
|
|
@ -37,34 +43,76 @@ def process_name(corner):
|
|||
else:
|
||||
return "custom"
|
||||
|
||||
def parse_file(f,pages):
|
||||
def parse_characterizer_csv(sram,f,pages):
|
||||
"""
|
||||
Parses output data of the Liberty file generator in order to construct the timing and
|
||||
current table
|
||||
"""
|
||||
with open(f) as csv_file:
|
||||
csv_reader = csv.reader(csv_file, delimiter=',')
|
||||
line_count = 0
|
||||
for row in csv_reader:
|
||||
|
||||
found = 0
|
||||
NAME = row[0]
|
||||
NUM_WORDS = row[1]
|
||||
NUM_BANKS = row[2]
|
||||
NUM_RW_PORTS = row[3]
|
||||
NUM_W_PORTS = row[4]
|
||||
NUM_R_PORTS = row[5]
|
||||
TECH_NAME = row[6]
|
||||
TEMP = row[8]
|
||||
VOLT = row[7]
|
||||
PROC = row[9]
|
||||
MIN_PERIOD = row[10]
|
||||
OUT_DIR = row[11]
|
||||
LIB_NAME = row[12]
|
||||
WORD_SIZE = row[13]
|
||||
col = 0
|
||||
|
||||
#defines layout of csv file
|
||||
NAME = row[col]
|
||||
col += 1
|
||||
|
||||
NUM_WORDS = row[col]
|
||||
col += 1
|
||||
|
||||
NUM_BANKS = row[col]
|
||||
col += 1
|
||||
|
||||
NUM_RW_PORTS = row[col]
|
||||
col += 1
|
||||
|
||||
NUM_W_PORTS = row[col]
|
||||
col += 1
|
||||
|
||||
NUM_R_PORTS = row[col]
|
||||
col += 1
|
||||
|
||||
TECH_NAME = row[col]
|
||||
col += 1
|
||||
|
||||
TEMP = row[col]
|
||||
col += 1
|
||||
|
||||
VOLT = row[col]
|
||||
col += 1
|
||||
|
||||
PROC = row[col]
|
||||
col += 1
|
||||
|
||||
MIN_PERIOD = row[col]
|
||||
col += 1
|
||||
|
||||
OUT_DIR = row[col]
|
||||
col += 1
|
||||
|
||||
LIB_NAME = row[col]
|
||||
col += 1
|
||||
|
||||
WORD_SIZE = row[col]
|
||||
col += 1
|
||||
|
||||
ORIGIN_ID = row[col]
|
||||
col += 1
|
||||
|
||||
|
||||
for sheet in pages:
|
||||
|
||||
|
||||
if sheet.name == row[0]:
|
||||
if sheet.name == NAME:
|
||||
|
||||
found = 1
|
||||
#if the .lib information is for an existing datasheet compare timing data
|
||||
|
||||
for item in sheet.operating:
|
||||
#check if the new corner data is worse than the previous worse corner data
|
||||
|
||||
if item.parameter == 'Operating Temperature':
|
||||
if float(TEMP) > float(item.max):
|
||||
|
|
@ -91,52 +139,345 @@ def parse_file(f,pages):
|
|||
|
||||
|
||||
|
||||
while(True):
|
||||
if(row[col].startswith('DIN')):
|
||||
start = col
|
||||
for item in sheet.timing:
|
||||
if item.parameter.startswith(row[col]):
|
||||
|
||||
if item.parameter.endswith('setup rising'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('setup falling'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('hold rising'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('hold falling'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
col += 1
|
||||
|
||||
elif(row[col].startswith('DOUT')):
|
||||
start = col
|
||||
for item in sheet.timing:
|
||||
if item.parameter.startswith(row[col]):
|
||||
|
||||
if item.parameter.endswith('cell rise'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('cell fall'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('rise transition'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('fall transition'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
col += 1
|
||||
|
||||
elif(row[col].startswith('CSb')):
|
||||
start = col
|
||||
for item in sheet.timing:
|
||||
if item.parameter.startswith(row[col]):
|
||||
|
||||
if item.parameter.endswith('setup rising'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('setup falling'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('hold rising'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('hold falling'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
col += 1
|
||||
|
||||
|
||||
elif(row[col].startswith('WEb')):
|
||||
start = col
|
||||
for item in sheet.timing:
|
||||
if item.parameter.startswith(row[col]):
|
||||
|
||||
if item.parameter.endswith('setup rising'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('setup falling'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('hold rising'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('hold falling'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
col += 1
|
||||
|
||||
|
||||
elif(row[col].startswith('ADDR')):
|
||||
start = col
|
||||
for item in sheet.timing:
|
||||
if item.parameter.startswith(row[col]):
|
||||
|
||||
if item.parameter.endswith('setup rising'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('setup falling'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('hold rising'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
elif item.parameter.endswith('hold falling'):
|
||||
if float(row[col+1]) < float(item.min):
|
||||
item.min = row[col+1]
|
||||
if float(row[col+2]) > float(item.max):
|
||||
item.max = row[col+2]
|
||||
|
||||
col += 2
|
||||
|
||||
col += 1
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
#regardless of if there is already a corner for the current sram, append the new corner to the datasheet
|
||||
new_sheet.corners.append(characterization_corners_item(PROC,process_name(PROC),VOLT,TEMP,LIB_NAME.replace(OUT_DIR,'').replace(NAME,'')))
|
||||
new_sheet.dlv.append(deliverables_item('.lib','Synthesis models','<a href="file://{0}">{1}</a>'.format(LIB_NAME,LIB_NAME.replace(OUT_DIR,''))))
|
||||
|
||||
if found == 0:
|
||||
|
||||
#if this is the first corner for this sram, run first time configuration and set up tables
|
||||
new_sheet = datasheet(NAME)
|
||||
pages.append(new_sheet)
|
||||
|
||||
new_sheet.git_id = ORIGIN_ID
|
||||
|
||||
new_sheet.corners.append(characterization_corners_item(PROC,process_name(PROC),VOLT,TEMP,LIB_NAME.replace(OUT_DIR,'').replace(NAME,'')))
|
||||
|
||||
new_sheet.operating.append(operating_conditions_item('Power supply (VDD) range',VOLT,VOLT,VOLT,'Volts'))
|
||||
new_sheet.operating.append(operating_conditions_item('Operating Temperature',TEMP,TEMP,TEMP,'Celsius'))
|
||||
try:
|
||||
new_sheet.operating.append(operating_conditions_item('Operating Frequency (F)*','','',str(math.floor(1000/float(MIN_PERIOD))),'MHz'))
|
||||
new_sheet.operating.append(operating_conditions_item('Operating Frequency (F)','','',str(math.floor(1000/float(MIN_PERIOD))),'MHz'))
|
||||
except Exception:
|
||||
new_sheet.operating.append(operating_conditions_item('Operating Frequency (F)*','','',"unknown",'MHz')) #analytical model fails to provide MIN_PERIOD
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('Cycle time','2','3','4'))
|
||||
new_sheet.timing.append(timing_and_current_data_item('Access time','2','3','4'))
|
||||
new_sheet.timing.append(timing_and_current_data_item('Positive clk setup','2','3','4'))
|
||||
new_sheet.timing.append(timing_and_current_data_item('Positive clk hold','2','3','4'))
|
||||
new_sheet.timing.append(timing_and_current_data_item('RW setup','2','3','4'))
|
||||
new_sheet.timing.append(timing_and_current_data_item('RW hold','2','3','4'))
|
||||
new_sheet.timing.append(timing_and_current_data_item('AC current','2','3','4'))
|
||||
new_sheet.timing.append(timing_and_current_data_item('Standby current','2','3','4'))
|
||||
new_sheet.timing.append(timing_and_current_data_item('Area','2','3','4'))
|
||||
|
||||
|
||||
new_sheet.dlv.append(deliverables_item('.sp','SPICE netlists','<a href="file://{0}{1}.{2}">{1}.{2}</a>'.format(OUT_DIR,NAME,'sp')))
|
||||
new_sheet.dlv.append(deliverables_item('.v','Verilog simulation models','<a href="file://{0}{1}.{2}">{1}.{2}</a>'.format(OUT_DIR,NAME,'v')))
|
||||
new_sheet.dlv.append(deliverables_item('.gds','GDSII layout views','<a href="file://{0}{1}.{2}">{1}.{2}</a>'.format(OUT_DIR,NAME,'gds')))
|
||||
new_sheet.dlv.append(deliverables_item('.lef','LEF files','<a href="file://{0}{1}.{2}">{1}.{2}</a>'.format(OUT_DIR,NAME,'lef')))
|
||||
new_sheet.dlv.append(deliverables_item('.lib','Synthesis models','<a href="file://{0}">{1}</a>'.format(LIB_NAME,LIB_NAME.replace(OUT_DIR,''))))
|
||||
new_sheet.operating.append(operating_conditions_item('Operating Frequency (F)','','',"not available in netlist only",'MHz')) #failed to provide non-zero MIN_PERIOD
|
||||
|
||||
|
||||
while(True):
|
||||
if(row[col].startswith('DIN')):
|
||||
start = col
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
col +=1
|
||||
|
||||
elif(row[col].startswith('DOUT')):
|
||||
start = col
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} cell rise'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} cell fall'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} rise transition'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} fall transition'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
col +=1
|
||||
|
||||
elif(row[col].startswith('CSb')):
|
||||
start = col
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
col +=1
|
||||
|
||||
elif(row[col].startswith('WEb')):
|
||||
start = col
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
col +=1
|
||||
|
||||
elif(row[col].startswith('ADDR')):
|
||||
start = col
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
new_sheet.timing.append(timing_and_current_data_item('{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns'))
|
||||
col += 2
|
||||
|
||||
col +=1
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
|
||||
|
||||
if not OPTS.netlist_only:
|
||||
#physical layout files should not be generated in netlist only mode
|
||||
new_sheet.dlv.append(deliverables_item('.gds','GDSII layout views','<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name,'gds')))
|
||||
new_sheet.dlv.append(deliverables_item('.lef','LEF files','<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name,'lef')))
|
||||
|
||||
|
||||
new_sheet.dlv.append(deliverables_item('.sp','SPICE netlists','<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name,'sp')))
|
||||
new_sheet.dlv.append(deliverables_item('.v','Verilog simulation models','<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name,'v')))
|
||||
new_sheet.dlv.append(deliverables_item('.html','This datasheet','<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name,'html')))
|
||||
new_sheet.dlv.append(deliverables_item('.lib','Synthesis models','<a href="{1}">{1}</a>'.format(LIB_NAME,LIB_NAME.replace(OUT_DIR,''))))
|
||||
new_sheet.dlv.append(deliverables_item('.py','OpenRAM configuration file','<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name,'py')))
|
||||
|
||||
|
||||
|
||||
#debug table for multiport information
|
||||
new_sheet.io.append(in_out_item('WORD_SIZE',WORD_SIZE))
|
||||
new_sheet.io.append(in_out_item('NUM_WORDS',NUM_WORDS))
|
||||
new_sheet.io.append(in_out_item('NUM_BANKS',NUM_BANKS))
|
||||
new_sheet.io.append(in_out_item('NUM_RW_PORTS',NUM_RW_PORTS))
|
||||
new_sheet.io.append(in_out_item('NUM_R_PORTS',NUM_R_PORTS))
|
||||
new_sheet.io.append(in_out_item('NUM_W_PORTS',NUM_W_PORTS))
|
||||
new_sheet.io.append(in_out_item('Area',sram.width * sram.height))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class datasheet_gen():
|
||||
def datasheet_write(name):
|
||||
def datasheet_write(sram,name):
|
||||
|
||||
if OPTS.datasheet_gen:
|
||||
in_dir = OPTS.openram_temp
|
||||
|
|
@ -144,11 +485,9 @@ class datasheet_gen():
|
|||
if not (os.path.isdir(in_dir)):
|
||||
os.mkdir(in_dir)
|
||||
|
||||
#if not (os.path.isdir(out_dir)):
|
||||
# os.mkdir(out_dir)
|
||||
|
||||
datasheets = []
|
||||
parse_file(in_dir + "/datasheet.info", datasheets)
|
||||
parse_characterizer_csv(sram, in_dir + "/datasheet.info", datasheets)
|
||||
|
||||
|
||||
for sheets in datasheets:
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
from flask_table import *
|
||||
|
||||
class deliverables(Table):
|
||||
"""
|
||||
Set up delivarables table columns and title information
|
||||
"""
|
||||
typ = Col('Type')
|
||||
description = Col('Description')
|
||||
link = Col('Link')
|
||||
|
||||
|
||||
class deliverables_item(object):
|
||||
"""
|
||||
Define deliverables table row elemenent information
|
||||
"""
|
||||
def __init__(self, typ, description,link):
|
||||
self.typ = typ
|
||||
self.description = description
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
from flask_table import *
|
||||
|
||||
class in_out(Table):
|
||||
"""
|
||||
Set up I/O table columns and title information for multiport debugging
|
||||
"""
|
||||
typ = Col('Type')
|
||||
description = Col('Description')
|
||||
|
||||
|
||||
class in_out_item(object):
|
||||
"""
|
||||
Define table row element for I/O table
|
||||
"""
|
||||
def __init__(self, typ, description):
|
||||
self.typ = typ
|
||||
self.description = description
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
from flask_table import *
|
||||
|
||||
class operating_conditions(Table):
|
||||
"""
|
||||
Set up operating conditions columns and title information
|
||||
"""
|
||||
parameter = Col('Parameter')
|
||||
min = Col('Min')
|
||||
typ = Col('Typ')
|
||||
|
|
@ -8,6 +11,9 @@ class operating_conditions(Table):
|
|||
units = Col('Units')
|
||||
|
||||
class operating_conditions_item(object):
|
||||
"""
|
||||
Define operating conditions table row element
|
||||
"""
|
||||
def __init__(self, parameter, min, typ, max, units):
|
||||
self.parameter = parameter
|
||||
self.min = min
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import os
|
||||
import jinja2
|
||||
from flask import Flask, render_template
|
||||
from filelist import *
|
||||
|
||||
|
||||
filedir = './files'
|
||||
file_data = './filelist.info'
|
||||
|
||||
|
||||
app = Flask('server_scripts')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
files = filelist()
|
||||
|
||||
files.update_filelist(filedir,file_data)
|
||||
|
||||
f = open('./index.html','w')
|
||||
with app.app_context():
|
||||
f.write(render_template('index.html', filedir = filedir , os = os))
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
class deliverable:
|
||||
def __init__(self, name, file_type, path, size):
|
||||
self.name = name
|
||||
self.file_type = file_type
|
||||
self.path = path
|
||||
self.size = size
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import os
|
||||
from deliverable import *
|
||||
class filelist:
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.list = []
|
||||
|
||||
def update_filelist(self,path,outdir):
|
||||
out_file = open(outdir,'w')
|
||||
for root, dirs, files in os.walk(path):
|
||||
for file in files:
|
||||
self.list.append(root + '/' + file)
|
||||
out_file.write('{}/{}\n'.format(root,file))
|
||||
#print('{}/{}'.format(root,file))
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,116 @@
|
|||
<style>
|
||||
#data {
|
||||
font-family: Trebuchet MS, Arial, Helvetica, sans-serif;
|
||||
border-collapse: collapse;
|
||||
width: 99%;
|
||||
max-width: 799px
|
||||
}
|
||||
|
||||
#data td, #data th {
|
||||
border: 0px solid #ddd;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
#data tr:nth-child(even){background-color: #f1f2f2;}
|
||||
|
||||
#data tr:hover {background-color: #ddd;}
|
||||
|
||||
#data th {
|
||||
padding-top: 11px;
|
||||
padding-bottom: 11px;
|
||||
text-align: left;
|
||||
background-color: #004184;
|
||||
color: #F1B521;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<!--sram_2_16_scn4m_subm,16,1,1,1,1,scn4m_subm,25,5.0,TT,0,/home/jesse/clones/PrivateRAM/compiler/temp/,/home/jesse/clones/PrivateRAM/compiler/temp/sram_2_16_scn4m_subm_TT_5p0V_25C.lib,2,DIN0[1:0],0.009,0.009,0.009,0.009,0.001,0.001,0.001,0.001,DIN1[1:0],0.009,0.009,0.009,0.009,0.001,0.001,0.001,0.001,DOUT0[1:0],0.079,0.079,0.079,0.079,0.001,0.001,0.001,0.001,DOUT2[1:0],0.079,0.079,0.079,0.079,0.001,0.001,0.001,0.001,CSb0,0.009,0.009,0.009,0.009,0.001,0.001,0.001,0.001,CSb1,0.009,0.009,0.009,0.009,0.001,0.001,0.001,0.001,CSb2,0.009,0.009,0.009,0.009,0.001,0.001,0.001,0.001,ADDR0[3:0],0.009,0.009,0.009,0.009,0.001,0.001,0.001,0.001,ADDR1[3:0],0.009,0.009,0.009,0.009,0.001,0.001,0.001,0.001,ADDR2[3:0],0.009,0.009,0.009,0.009,0.001,0.001,0.001,0.001,WEb0,0.009,0.009,0.009,0.009,0.001,0.001,0.001,0.001,END
|
||||
--><a href="https://vlsida.soe.ucsc.edu/"><img src=/home/jesse/clones/PrivateRAM/compiler/datasheet/assets/vlsi_logo.png alt="VLSIDA"></a><a href="https://vlsida.github.io/OpenRAM"><img src=/home/jesse/clones/PrivateRAM/compiler/datasheet/assets/openram_logo_placeholder.png alt="OpenRAM"></a><p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">sram_2_16_scn4m_subm.html</p><p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">DRC: skipped</p><p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">LVS: skipped</p><p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Ports and Configuration (DEBUG)</p><table id="data">
|
||||
<thead><tr><th>Type</th><th>Description</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>WORD_SIZE</td><td>2</td></tr>
|
||||
<tr><td>NUM_WORDS</td><td>16</td></tr>
|
||||
<tr><td>NUM_BANKS</td><td>1</td></tr>
|
||||
<tr><td>NUM_RW_PORTS</td><td>1</td></tr>
|
||||
<tr><td>NUM_R_PORTS</td><td>1</td></tr>
|
||||
<tr><td>NUM_W_PORTS</td><td>1</td></tr>
|
||||
<tr><td>Area</td><td>0</td></tr>
|
||||
</tbody>
|
||||
</table><p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Operating Conditions</p><table id="data">
|
||||
<thead><tr><th>Parameter</th><th>Min</th><th>Typ</th><th>Max</th><th>Units</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Power supply (VDD) range</td><td>5.0</td><td>5.0</td><td>5.0</td><td>Volts</td></tr>
|
||||
<tr><td>Operating Temperature</td><td>25</td><td>25</td><td>25</td><td>Celsius</td></tr>
|
||||
<tr><td>Operating Frequency (F)*</td><td></td><td></td><td>unknown</td><td>MHz</td></tr>
|
||||
</tbody>
|
||||
</table><p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Timing and Current Data</p><table id="data">
|
||||
<thead><tr><th>Parameter</th><th>Min</th><th>Max</th><th>Units</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Cycle time</td><td>2</td><td>3</td><td>4</td></tr>
|
||||
<tr><td>Access time</td><td>2</td><td>3</td><td>4</td></tr>
|
||||
<tr><td>Positive clk setup</td><td>2</td><td>3</td><td>4</td></tr>
|
||||
<tr><td>Positive clk hold</td><td>2</td><td>3</td><td>4</td></tr>
|
||||
<tr><td>DIN0[1:0] setup rising</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>DIN0[1:0] setup falling</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>DIN0[1:0] hold rising</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>DIN0[1:0] hold falling</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>DIN1[1:0] setup rising</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>DIN1[1:0] setup falling</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>DIN1[1:0] hold rising</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>DIN1[1:0] hold falling</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>DOUT0[1:0] cell rise</td><td>0.079</td><td>0.079</td><td>ns</td></tr>
|
||||
<tr><td>DOUT0[1:0] cell fall</td><td>0.079</td><td>0.079</td><td>ns</td></tr>
|
||||
<tr><td>DOUT0[1:0] rise transition</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>DOUT0[1:0] fall transition</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>DOUT2[1:0] cell rise</td><td>0.079</td><td>0.079</td><td>ns</td></tr>
|
||||
<tr><td>DOUT2[1:0] cell fall</td><td>0.079</td><td>0.079</td><td>ns</td></tr>
|
||||
<tr><td>DOUT2[1:0] rise transition</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>DOUT2[1:0] fall transition</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>CSb0 setup rising</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>CSb0 setup falling</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>CSb0 hold rising</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>CSb0 hold falling</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>CSb1 setup rising</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>CSb1 setup falling</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>CSb1 hold rising</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>CSb1 hold falling</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>CSb2 setup rising</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>CSb2 setup falling</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>CSb2 hold rising</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>CSb2 hold falling</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>ADDR0[3:0] setup rising</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>ADDR0[3:0] setup falling</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>ADDR0[3:0] hold rising</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>ADDR0[3:0] hold falling</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>ADDR1[3:0] setup rising</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>ADDR1[3:0] setup falling</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>ADDR1[3:0] hold rising</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>ADDR1[3:0] hold falling</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>ADDR2[3:0] setup rising</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>ADDR2[3:0] setup falling</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>ADDR2[3:0] hold rising</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>ADDR2[3:0] hold falling</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>WEb0 setup rising</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>WEb0 setup falling</td><td>0.009</td><td>0.009</td><td>ns</td></tr>
|
||||
<tr><td>WEb0 hold rising</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>WEb0 hold falling</td><td>0.001</td><td>0.001</td><td>ns</td></tr>
|
||||
<tr><td>AC current</td><td>2</td><td>3</td><td>4</td></tr>
|
||||
<tr><td>Standby current</td><td>2</td><td>3</td><td>4</td></tr>
|
||||
</tbody>
|
||||
</table><p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Characterization Corners</p><table id="data">
|
||||
<thead><tr><th>Corner Name</th><th>Process</th><th>Power Supply</th><th>Temperature</th><th>Library Name Suffix</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>TT</td><td>Typical - Typical</td><td>5.0</td><td>25</td><td>_TT_5p0V_25C.lib</td></tr>
|
||||
</tbody>
|
||||
</table><p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Deliverables</p><table id="data">
|
||||
<thead><tr><th>Type</th><th>Description</th><th>Link</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>.sp</td><td>SPICE netlists</td><td><a href="sram_2_16_scn4m_subm.sp">sram_2_16_scn4m_subm.sp</a></td></tr>
|
||||
<tr><td>.v</td><td>Verilog simulation models</td><td><a href="sram_2_16_scn4m_subm.v">sram_2_16_scn4m_subm.v</a></td></tr>
|
||||
<tr><td>.html</td><td>This datasheet</td><td><a href="sram_2_16_scn4m_subm.html">sram_2_16_scn4m_subm.html</a></td></tr>
|
||||
<tr><td>.lib</td><td>Synthesis models</td><td><a href="sram_2_16_scn4m_subm_TT_5p0V_25C.lib">sram_2_16_scn4m_subm_TT_5p0V_25C.lib</a></td></tr>
|
||||
<tr><td>.py</td><td>OpenRAM configuration file</td><td><a href="sram_2_16_scn4m_subm.py">sram_2_16_scn4m_subm.py</a></td></tr>
|
||||
</tbody>
|
||||
</table><p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">*Feature only supported with characterizer</p>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,18 @@
|
|||
word_size = 2
|
||||
num_words = 16
|
||||
|
||||
tech_name = "scn4m_subm"
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [ 5.0 ]
|
||||
temperatures = [ 25 ]
|
||||
|
||||
output_path = "temp"
|
||||
output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name)
|
||||
|
||||
#Setting for multiport
|
||||
netlist_only = True
|
||||
bitcell = "pbitcell"
|
||||
replica_bitcell="replica_pbitcell"
|
||||
num_rw_ports = 1
|
||||
num_r_ports = 1
|
||||
num_w_ports = 1
|
||||
|
|
@ -0,0 +1,767 @@
|
|||
**************************************************
|
||||
* OpenRAM generated memory.
|
||||
* Words: 16
|
||||
* Data bits: 2
|
||||
* Banks: 1
|
||||
* Column mux: 1:1
|
||||
**************************************************
|
||||
*********************** "dff" ******************************
|
||||
* Positive edge-triggered FF
|
||||
.SUBCKT dff D Q clk vdd gnd
|
||||
|
||||
* SPICE3 file created from dff.ext - technology: scmos
|
||||
|
||||
M1000 vdd clk a_24_24# vdd p w=8u l=0.4u
|
||||
M1001 a_84_296# D vdd vdd p w=4u l=0.4u
|
||||
M1002 a_104_24# clk a_84_296# vdd p w=4u l=0.4u
|
||||
M1003 a_140_296# a_24_24# a_104_24# vdd p w=4u l=0.4u
|
||||
M1004 vdd a_152_16# a_140_296# vdd p w=4u l=0.4u
|
||||
M1005 a_152_16# a_104_24# vdd vdd p w=4u l=0.4u
|
||||
M1006 a_260_296# a_152_16# vdd vdd p w=4u l=0.4u
|
||||
M1007 a_280_24# a_24_24# a_260_296# vdd p w=4u l=0.4u
|
||||
M1008 a_320_336# clk a_280_24# vdd p w=2u l=0.4u
|
||||
M1009 vdd Q a_320_336# vdd p w=2u l=0.4u
|
||||
M1010 gnd clk a_24_24# gnd n w=4u l=0.4u
|
||||
M1011 Q a_280_24# vdd vdd p w=8u l=0.4u
|
||||
M1012 a_84_24# D gnd gnd n w=2u l=0.4u
|
||||
M1013 a_104_24# a_24_24# a_84_24# gnd n w=2u l=0.4u
|
||||
M1014 a_140_24# clk a_104_24# gnd n w=2u l=0.4u
|
||||
M1015 gnd a_152_16# a_140_24# gnd n w=2u l=0.4u
|
||||
M1016 a_152_16# a_104_24# gnd gnd n w=2u l=0.4u
|
||||
M1017 a_260_24# a_152_16# gnd gnd n w=2u l=0.4u
|
||||
M1018 a_280_24# clk a_260_24# gnd n w=2u l=0.4u
|
||||
M1019 a_320_24# a_24_24# a_280_24# gnd n w=2u l=0.4u
|
||||
M1020 gnd Q a_320_24# gnd n w=2u l=0.4u
|
||||
M1021 Q a_280_24# gnd gnd n w=4u l=0.4u
|
||||
|
||||
.ENDS
|
||||
|
||||
* ptx M{0} {1} n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
|
||||
* ptx M{0} {1} p m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
|
||||
.SUBCKT pinv_2 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pinv_2
|
||||
|
||||
.SUBCKT dff_inv_2 D Q Qb clk vdd gnd
|
||||
Xdff_inv_dff D Q clk vdd gnd dff
|
||||
Xdff_inv_inv1 Q Qb vdd gnd pinv_2
|
||||
.ENDS dff_inv_2
|
||||
|
||||
.SUBCKT dff_inv_array_2x1_1 din_0 din_1 dout_0 dout_bar_0 dout_1 dout_bar_1 clk vdd gnd
|
||||
XXdff_r0_c0 din_0 dout_0 dout_bar_0 clk vdd gnd dff_inv_2
|
||||
XXdff_r1_c0 din_1 dout_1 dout_bar_1 clk vdd gnd dff_inv_2
|
||||
.ENDS dff_inv_array_2x1_1
|
||||
|
||||
* ptx M{0} {1} p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
|
||||
.SUBCKT pnand2_1 A B Z vdd gnd
|
||||
Mpnand2_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_nmos1 Z B net1 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_nmos2 net1 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pnand2_1
|
||||
|
||||
.SUBCKT pnand3_1 A B C Z vdd gnd
|
||||
Mpnand3_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_pmos3 Z C vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos1 Z C net1 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos2 net1 B net2 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos3 net2 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pnand3_1
|
||||
|
||||
* ptx M{0} {1} n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
|
||||
.SUBCKT pinv_3 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_3
|
||||
|
||||
.SUBCKT pinv_4 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pinv_4
|
||||
|
||||
* ptx M{0} {1} n m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
|
||||
* ptx M{0} {1} p m=1 w=6.4u l=0.4u pd=13.600000000000001u ps=13.600000000000001u as=6.4p ad=6.4p
|
||||
|
||||
.SUBCKT pinv_5 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=6.4u l=0.4u pd=13.600000000000001u ps=13.600000000000001u as=6.4p ad=6.4p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
.ENDS pinv_5
|
||||
|
||||
.SUBCKT pinvbuf_2_4_1 A Zb Z vdd gnd
|
||||
Xbuf_inv1 A zb_int vdd gnd pinv_3
|
||||
Xbuf_inv2 zb_int z_int vdd gnd pinv_4
|
||||
Xbuf_inv3 z_int Zb vdd gnd pinv_5
|
||||
Xbuf_inv4 zb_int Z vdd gnd pinv_5
|
||||
.ENDS pinvbuf_2_4_1
|
||||
|
||||
.SUBCKT pinv_6 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_6
|
||||
|
||||
.SUBCKT pinv_7 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=6.4u l=0.4u pd=13.600000000000001u ps=13.600000000000001u as=6.4p ad=6.4p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
.ENDS pinv_7
|
||||
|
||||
* ptx M{0} {1} n m=1 w=12.8u l=0.4u pd=26.400000000000002u ps=26.400000000000002u as=12.8p ad=12.8p
|
||||
|
||||
* ptx M{0} {1} p m=1 w=25.6u l=0.4u pd=52.0u ps=52.0u as=25.6p ad=25.6p
|
||||
|
||||
.SUBCKT pinv_8 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=25.6u l=0.4u pd=52.0u ps=52.0u as=25.6p ad=25.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=12.8u l=0.4u pd=26.400000000000002u ps=26.400000000000002u as=12.8p ad=12.8p
|
||||
.ENDS pinv_8
|
||||
|
||||
* ptx M{0} {1} n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
|
||||
* ptx M{0} {1} p m=1 w=0.6000000000000001u l=0.4u pd=2.0u ps=2.0u as=0.6000000000000001p ad=0.6000000000000001p
|
||||
|
||||
* ptx M{0} {1} n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
|
||||
* ptx M{0} {1} n m=1 w=1.2000000000000002u l=0.4u pd=3.2u ps=3.2u as=1.2000000000000002p ad=1.2000000000000002p
|
||||
|
||||
.SUBCKT replica_pbitcell_1RW_1W_1R bl0 br0 bl1 br1 bl2 br2 wl0 wl1 wl2 vdd gnd
|
||||
Minverter_nmos_left Q vdd gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Minverter_nmos_right gnd Q vdd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Minverter_pmos_left Q vdd vdd vdd p m=1 w=0.6000000000000001u l=0.4u pd=2.0u ps=2.0u as=0.6000000000000001p ad=0.6000000000000001p
|
||||
Minverter_pmos_right vdd Q vdd vdd p m=1 w=0.6000000000000001u l=0.4u pd=2.0u ps=2.0u as=0.6000000000000001p ad=0.6000000000000001p
|
||||
Mreadwrite_nmos_left0 bl0 wl0 Q gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
Mreadwrite_nmos_right0 vdd wl0 br0 gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
Mwrite_nmos_left0 bl1 wl1 Q gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
Mwrite_nmos_right0 vdd wl1 br1 gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
Mread_access_nmos_left0 RA_to_R_left0 vdd gnd gnd n m=1 w=1.2000000000000002u l=0.4u pd=3.2u ps=3.2u as=1.2000000000000002p ad=1.2000000000000002p
|
||||
Mread_access_nmos_right0 gnd Q RA_to_R_right0 gnd n m=1 w=1.2000000000000002u l=0.4u pd=3.2u ps=3.2u as=1.2000000000000002p ad=1.2000000000000002p
|
||||
Mread_nmos_left0 bl2 wl2 RA_to_R_left0 gnd n m=1 w=1.2000000000000002u l=0.4u pd=3.2u ps=3.2u as=1.2000000000000002p ad=1.2000000000000002p
|
||||
Mread_nmos_right0 RA_to_R_right0 wl2 br2 gnd n m=1 w=1.2000000000000002u l=0.4u pd=3.2u ps=3.2u as=1.2000000000000002p ad=1.2000000000000002p
|
||||
.ENDS replica_pbitcell_1RW_1W_1R
|
||||
|
||||
.SUBCKT replica_pbitcell bl0 br0 bl1 br1 bl2 br2 wl0 wl1 wl2 vdd gnd
|
||||
Xpbitcell bl0 br0 bl1 br1 bl2 br2 wl0 wl1 wl2 vdd gnd replica_pbitcell_1RW_1W_1R
|
||||
.ENDS replica_pbitcell
|
||||
|
||||
.SUBCKT pbitcell_1RW_1W_1R bl0 br0 bl1 br1 bl2 br2 wl0 wl1 wl2 vdd gnd
|
||||
Minverter_nmos_left Q Q_bar gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Minverter_nmos_right gnd Q Q_bar gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Minverter_pmos_left Q Q_bar vdd vdd p m=1 w=0.6000000000000001u l=0.4u pd=2.0u ps=2.0u as=0.6000000000000001p ad=0.6000000000000001p
|
||||
Minverter_pmos_right vdd Q Q_bar vdd p m=1 w=0.6000000000000001u l=0.4u pd=2.0u ps=2.0u as=0.6000000000000001p ad=0.6000000000000001p
|
||||
Mreadwrite_nmos_left0 bl0 wl0 Q gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
Mreadwrite_nmos_right0 Q_bar wl0 br0 gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
Mwrite_nmos_left0 bl1 wl1 Q gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
Mwrite_nmos_right0 Q_bar wl1 br1 gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
Mread_access_nmos_left0 RA_to_R_left0 Q_bar gnd gnd n m=1 w=1.2000000000000002u l=0.4u pd=3.2u ps=3.2u as=1.2000000000000002p ad=1.2000000000000002p
|
||||
Mread_access_nmos_right0 gnd Q RA_to_R_right0 gnd n m=1 w=1.2000000000000002u l=0.4u pd=3.2u ps=3.2u as=1.2000000000000002p ad=1.2000000000000002p
|
||||
Mread_nmos_left0 bl2 wl2 RA_to_R_left0 gnd n m=1 w=1.2000000000000002u l=0.4u pd=3.2u ps=3.2u as=1.2000000000000002p ad=1.2000000000000002p
|
||||
Mread_nmos_right0 RA_to_R_right0 wl2 br2 gnd n m=1 w=1.2000000000000002u l=0.4u pd=3.2u ps=3.2u as=1.2000000000000002p ad=1.2000000000000002p
|
||||
.ENDS pbitcell_1RW_1W_1R
|
||||
|
||||
.SUBCKT bitcell_array_8x1_1 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_0 wl1_0 wl2_0 wl0_1 wl1_1 wl2_1 wl0_2 wl1_2 wl2_2 wl0_3 wl1_3 wl2_3 wl0_4 wl1_4 wl2_4 wl0_5 wl1_5 wl2_5 wl0_6 wl1_6 wl2_6 wl0_7 wl1_7 wl2_7 vdd gnd
|
||||
Xbit_r0_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_0 wl1_0 wl2_0 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r1_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_1 wl1_1 wl2_1 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r2_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_2 wl1_2 wl2_2 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r3_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_3 wl1_3 wl2_3 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r4_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_4 wl1_4 wl2_4 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r5_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_5 wl1_5 wl2_5 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r6_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_6 wl1_6 wl2_6 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r7_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_7 wl1_7 wl2_7 vdd gnd pbitcell_1RW_1W_1R
|
||||
.ENDS bitcell_array_8x1_1
|
||||
|
||||
.SUBCKT pinv_9 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_9
|
||||
|
||||
.SUBCKT delay_chain_1 in out vdd gnd
|
||||
Xdinv0 in dout_1 vdd gnd pinv_9
|
||||
Xdload_0_0 dout_1 n_0_0 vdd gnd pinv_9
|
||||
Xdload_0_1 dout_1 n_0_1 vdd gnd pinv_9
|
||||
Xdload_0_2 dout_1 n_0_2 vdd gnd pinv_9
|
||||
Xdinv1 dout_1 dout_2 vdd gnd pinv_9
|
||||
Xdload_1_0 dout_2 n_1_0 vdd gnd pinv_9
|
||||
Xdload_1_1 dout_2 n_1_1 vdd gnd pinv_9
|
||||
Xdload_1_2 dout_2 n_1_2 vdd gnd pinv_9
|
||||
Xdinv2 dout_2 dout_3 vdd gnd pinv_9
|
||||
Xdload_2_0 dout_3 n_2_0 vdd gnd pinv_9
|
||||
Xdload_2_1 dout_3 n_2_1 vdd gnd pinv_9
|
||||
Xdload_2_2 dout_3 n_2_2 vdd gnd pinv_9
|
||||
Xdinv3 dout_3 out vdd gnd pinv_9
|
||||
Xdload_3_0 out n_3_0 vdd gnd pinv_9
|
||||
Xdload_3_1 out n_3_1 vdd gnd pinv_9
|
||||
Xdload_3_2 out n_3_2 vdd gnd pinv_9
|
||||
.ENDS delay_chain_1
|
||||
|
||||
.SUBCKT pinv_10 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_10
|
||||
|
||||
* ptx M{0} {1} p m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
|
||||
.SUBCKT replica_bitline_rw en out vdd gnd
|
||||
Xrbl_inv bl0_0 out vdd gnd pinv_10
|
||||
Mrbl_access_tx vdd delayed_en bl0_0 vdd p m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
Xdelay_chain en delayed_en vdd gnd delay_chain_1
|
||||
Xbitcell bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 delayed_en delayed_en delayed_en vdd gnd replica_pbitcell
|
||||
Xload bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd vdd gnd bitcell_array_8x1_1
|
||||
.ENDS replica_bitline_rw
|
||||
|
||||
.SUBCKT control_logic_rw csb web clk s_en w_en clk_buf_bar clk_buf vdd gnd
|
||||
Xctrl_dffs csb web cs_bar cs we_bar we clk_buf vdd gnd dff_inv_array_2x1_1
|
||||
Xclkbuf clk clk_buf_bar clk_buf vdd gnd pinvbuf_2_4_1
|
||||
Xnand3_w_en_bar clk_buf_bar cs we w_en_bar vdd gnd pnand3_1
|
||||
Xinv_pre_w_en w_en_bar pre_w_en vdd gnd pinv_6
|
||||
Xinv_pre_w_en_bar pre_w_en pre_w_en_bar vdd gnd pinv_7
|
||||
Xinv_w_en2 pre_w_en_bar w_en vdd gnd pinv_8
|
||||
Xnand2_rbl_in_bar clk_buf_bar cs rbl_in_bar vdd gnd pnand2_1
|
||||
Xinv_rbl_in rbl_in_bar rbl_in vdd gnd pinv_6
|
||||
Xinv_pre_s_en_bar pre_s_en pre_s_en_bar vdd gnd pinv_7
|
||||
Xinv_s_en pre_s_en_bar s_en vdd gnd pinv_8
|
||||
Xreplica_bitline rbl_in pre_s_en vdd gnd replica_bitline_rw
|
||||
.ENDS control_logic_rw
|
||||
|
||||
.SUBCKT pinv_12 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pinv_12
|
||||
|
||||
.SUBCKT dff_inv_4 D Q Qb clk vdd gnd
|
||||
Xdff_inv_dff D Q clk vdd gnd dff
|
||||
Xdff_inv_inv1 Q Qb vdd gnd pinv_12
|
||||
.ENDS dff_inv_4
|
||||
|
||||
.SUBCKT dff_inv_array_1x1_2 din_0 dout_0 dout_bar_0 clk vdd gnd
|
||||
XXdff_r0_c0 din_0 dout_0 dout_bar_0 clk vdd gnd dff_inv_4
|
||||
.ENDS dff_inv_array_1x1_2
|
||||
|
||||
.SUBCKT pnand2_2 A B Z vdd gnd
|
||||
Mpnand2_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_nmos1 Z B net1 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_nmos2 net1 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pnand2_2
|
||||
|
||||
.SUBCKT pnand3_2 A B C Z vdd gnd
|
||||
Mpnand3_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_pmos3 Z C vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos1 Z C net1 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos2 net1 B net2 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos3 net2 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pnand3_2
|
||||
|
||||
.SUBCKT pinv_13 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_13
|
||||
|
||||
.SUBCKT pinv_14 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pinv_14
|
||||
|
||||
.SUBCKT pinv_15 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=6.4u l=0.4u pd=13.600000000000001u ps=13.600000000000001u as=6.4p ad=6.4p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
.ENDS pinv_15
|
||||
|
||||
.SUBCKT pinvbuf_2_4_2 A Zb Z vdd gnd
|
||||
Xbuf_inv1 A zb_int vdd gnd pinv_13
|
||||
Xbuf_inv2 zb_int z_int vdd gnd pinv_14
|
||||
Xbuf_inv3 z_int Zb vdd gnd pinv_15
|
||||
Xbuf_inv4 zb_int Z vdd gnd pinv_15
|
||||
.ENDS pinvbuf_2_4_2
|
||||
|
||||
.SUBCKT pinv_16 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_16
|
||||
|
||||
.SUBCKT pinv_17 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=6.4u l=0.4u pd=13.600000000000001u ps=13.600000000000001u as=6.4p ad=6.4p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
.ENDS pinv_17
|
||||
|
||||
.SUBCKT pinv_18 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=25.6u l=0.4u pd=52.0u ps=52.0u as=25.6p ad=25.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=12.8u l=0.4u pd=26.400000000000002u ps=26.400000000000002u as=12.8p ad=12.8p
|
||||
.ENDS pinv_18
|
||||
|
||||
.SUBCKT control_logic_w csb clk w_en clk_buf_bar clk_buf vdd gnd
|
||||
Xctrl_dffs csb cs_bar cs clk_buf vdd gnd dff_inv_array_1x1_2
|
||||
Xclkbuf clk clk_buf_bar clk_buf vdd gnd pinvbuf_2_4_2
|
||||
Xnand3_w_en_bar clk_buf_bar cs w_en_bar vdd gnd pnand2_2
|
||||
Xinv_pre_w_en w_en_bar pre_w_en vdd gnd pinv_16
|
||||
Xinv_pre_w_en_bar pre_w_en pre_w_en_bar vdd gnd pinv_17
|
||||
Xinv_w_en2 pre_w_en_bar w_en vdd gnd pinv_18
|
||||
.ENDS control_logic_w
|
||||
|
||||
.SUBCKT pinv_20 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pinv_20
|
||||
|
||||
.SUBCKT dff_inv_6 D Q Qb clk vdd gnd
|
||||
Xdff_inv_dff D Q clk vdd gnd dff
|
||||
Xdff_inv_inv1 Q Qb vdd gnd pinv_20
|
||||
.ENDS dff_inv_6
|
||||
|
||||
.SUBCKT dff_inv_array_1x1_3 din_0 dout_0 dout_bar_0 clk vdd gnd
|
||||
XXdff_r0_c0 din_0 dout_0 dout_bar_0 clk vdd gnd dff_inv_6
|
||||
.ENDS dff_inv_array_1x1_3
|
||||
|
||||
.SUBCKT pnand2_3 A B Z vdd gnd
|
||||
Mpnand2_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_nmos1 Z B net1 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_nmos2 net1 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pnand2_3
|
||||
|
||||
.SUBCKT pnand3_3 A B C Z vdd gnd
|
||||
Mpnand3_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_pmos3 Z C vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos1 Z C net1 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos2 net1 B net2 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos3 net2 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pnand3_3
|
||||
|
||||
.SUBCKT pinv_21 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_21
|
||||
|
||||
.SUBCKT pinv_22 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pinv_22
|
||||
|
||||
.SUBCKT pinv_23 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=6.4u l=0.4u pd=13.600000000000001u ps=13.600000000000001u as=6.4p ad=6.4p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
.ENDS pinv_23
|
||||
|
||||
.SUBCKT pinvbuf_2_4_3 A Zb Z vdd gnd
|
||||
Xbuf_inv1 A zb_int vdd gnd pinv_21
|
||||
Xbuf_inv2 zb_int z_int vdd gnd pinv_22
|
||||
Xbuf_inv3 z_int Zb vdd gnd pinv_23
|
||||
Xbuf_inv4 zb_int Z vdd gnd pinv_23
|
||||
.ENDS pinvbuf_2_4_3
|
||||
|
||||
.SUBCKT pinv_24 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_24
|
||||
|
||||
.SUBCKT pinv_25 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=6.4u l=0.4u pd=13.600000000000001u ps=13.600000000000001u as=6.4p ad=6.4p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=3.2u l=0.4u pd=7.2u ps=7.2u as=3.2p ad=3.2p
|
||||
.ENDS pinv_25
|
||||
|
||||
.SUBCKT pinv_26 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=25.6u l=0.4u pd=52.0u ps=52.0u as=25.6p ad=25.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=12.8u l=0.4u pd=26.400000000000002u ps=26.400000000000002u as=12.8p ad=12.8p
|
||||
.ENDS pinv_26
|
||||
|
||||
.SUBCKT bitcell_array_8x1_2 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_0 wl1_0 wl2_0 wl0_1 wl1_1 wl2_1 wl0_2 wl1_2 wl2_2 wl0_3 wl1_3 wl2_3 wl0_4 wl1_4 wl2_4 wl0_5 wl1_5 wl2_5 wl0_6 wl1_6 wl2_6 wl0_7 wl1_7 wl2_7 vdd gnd
|
||||
Xbit_r0_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_0 wl1_0 wl2_0 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r1_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_1 wl1_1 wl2_1 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r2_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_2 wl1_2 wl2_2 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r3_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_3 wl1_3 wl2_3 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r4_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_4 wl1_4 wl2_4 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r5_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_5 wl1_5 wl2_5 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r6_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_6 wl1_6 wl2_6 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r7_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_7 wl1_7 wl2_7 vdd gnd pbitcell_1RW_1W_1R
|
||||
.ENDS bitcell_array_8x1_2
|
||||
|
||||
.SUBCKT pinv_27 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_27
|
||||
|
||||
.SUBCKT delay_chain_2 in out vdd gnd
|
||||
Xdinv0 in dout_1 vdd gnd pinv_27
|
||||
Xdload_0_0 dout_1 n_0_0 vdd gnd pinv_27
|
||||
Xdload_0_1 dout_1 n_0_1 vdd gnd pinv_27
|
||||
Xdload_0_2 dout_1 n_0_2 vdd gnd pinv_27
|
||||
Xdinv1 dout_1 dout_2 vdd gnd pinv_27
|
||||
Xdload_1_0 dout_2 n_1_0 vdd gnd pinv_27
|
||||
Xdload_1_1 dout_2 n_1_1 vdd gnd pinv_27
|
||||
Xdload_1_2 dout_2 n_1_2 vdd gnd pinv_27
|
||||
Xdinv2 dout_2 dout_3 vdd gnd pinv_27
|
||||
Xdload_2_0 dout_3 n_2_0 vdd gnd pinv_27
|
||||
Xdload_2_1 dout_3 n_2_1 vdd gnd pinv_27
|
||||
Xdload_2_2 dout_3 n_2_2 vdd gnd pinv_27
|
||||
Xdinv3 dout_3 out vdd gnd pinv_27
|
||||
Xdload_3_0 out n_3_0 vdd gnd pinv_27
|
||||
Xdload_3_1 out n_3_1 vdd gnd pinv_27
|
||||
Xdload_3_2 out n_3_2 vdd gnd pinv_27
|
||||
.ENDS delay_chain_2
|
||||
|
||||
.SUBCKT pinv_28 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_28
|
||||
|
||||
.SUBCKT replica_bitline_r en out vdd gnd
|
||||
Xrbl_inv bl0_0 out vdd gnd pinv_28
|
||||
Mrbl_access_tx vdd delayed_en bl0_0 vdd p m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
Xdelay_chain en delayed_en vdd gnd delay_chain_2
|
||||
Xbitcell bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 delayed_en delayed_en delayed_en vdd gnd replica_pbitcell
|
||||
Xload bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd gnd vdd gnd bitcell_array_8x1_2
|
||||
.ENDS replica_bitline_r
|
||||
|
||||
.SUBCKT control_logic_r csb clk s_en clk_buf_bar clk_buf vdd gnd
|
||||
Xctrl_dffs csb cs_bar cs clk_buf vdd gnd dff_inv_array_1x1_3
|
||||
Xclkbuf clk clk_buf_bar clk_buf vdd gnd pinvbuf_2_4_3
|
||||
Xnand2_rbl_in_bar clk_buf_bar cs rbl_in_bar vdd gnd pnand2_3
|
||||
Xinv_rbl_in rbl_in_bar rbl_in vdd gnd pinv_24
|
||||
Xinv_pre_s_en_bar pre_s_en pre_s_en_bar vdd gnd pinv_25
|
||||
Xinv_s_en pre_s_en_bar s_en vdd gnd pinv_26
|
||||
Xreplica_bitline rbl_in pre_s_en vdd gnd replica_bitline_r
|
||||
.ENDS control_logic_r
|
||||
|
||||
.SUBCKT row_addr_dff din_0 din_1 din_2 din_3 dout_0 dout_1 dout_2 dout_3 clk vdd gnd
|
||||
XXdff_r0_c0 din_0 dout_0 clk vdd gnd dff
|
||||
XXdff_r1_c0 din_1 dout_1 clk vdd gnd dff
|
||||
XXdff_r2_c0 din_2 dout_2 clk vdd gnd dff
|
||||
XXdff_r3_c0 din_3 dout_3 clk vdd gnd dff
|
||||
.ENDS row_addr_dff
|
||||
|
||||
.SUBCKT data_dff din_0 din_1 dout_0 dout_1 clk vdd gnd
|
||||
XXdff_r0_c0 din_0 dout_0 clk vdd gnd dff
|
||||
XXdff_r0_c1 din_1 dout_1 clk vdd gnd dff
|
||||
.ENDS data_dff
|
||||
|
||||
.SUBCKT bitcell_array_16x2_1 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_0 wl1_0 wl2_0 wl0_1 wl1_1 wl2_1 wl0_2 wl1_2 wl2_2 wl0_3 wl1_3 wl2_3 wl0_4 wl1_4 wl2_4 wl0_5 wl1_5 wl2_5 wl0_6 wl1_6 wl2_6 wl0_7 wl1_7 wl2_7 wl0_8 wl1_8 wl2_8 wl0_9 wl1_9 wl2_9 wl0_10 wl1_10 wl2_10 wl0_11 wl1_11 wl2_11 wl0_12 wl1_12 wl2_12 wl0_13 wl1_13 wl2_13 wl0_14 wl1_14 wl2_14 wl0_15 wl1_15 wl2_15 vdd gnd
|
||||
Xbit_r0_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_0 wl1_0 wl2_0 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r1_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_1 wl1_1 wl2_1 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r2_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_2 wl1_2 wl2_2 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r3_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_3 wl1_3 wl2_3 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r4_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_4 wl1_4 wl2_4 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r5_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_5 wl1_5 wl2_5 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r6_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_6 wl1_6 wl2_6 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r7_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_7 wl1_7 wl2_7 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r8_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_8 wl1_8 wl2_8 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r9_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_9 wl1_9 wl2_9 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r10_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_10 wl1_10 wl2_10 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r11_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_11 wl1_11 wl2_11 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r12_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_12 wl1_12 wl2_12 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r13_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_13 wl1_13 wl2_13 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r14_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_14 wl1_14 wl2_14 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r15_c0 bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 wl0_15 wl1_15 wl2_15 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r0_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_0 wl1_0 wl2_0 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r1_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_1 wl1_1 wl2_1 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r2_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_2 wl1_2 wl2_2 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r3_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_3 wl1_3 wl2_3 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r4_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_4 wl1_4 wl2_4 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r5_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_5 wl1_5 wl2_5 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r6_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_6 wl1_6 wl2_6 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r7_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_7 wl1_7 wl2_7 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r8_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_8 wl1_8 wl2_8 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r9_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_9 wl1_9 wl2_9 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r10_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_10 wl1_10 wl2_10 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r11_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_11 wl1_11 wl2_11 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r12_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_12 wl1_12 wl2_12 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r13_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_13 wl1_13 wl2_13 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r14_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_14 wl1_14 wl2_14 vdd gnd pbitcell_1RW_1W_1R
|
||||
Xbit_r15_c1 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_15 wl1_15 wl2_15 vdd gnd pbitcell_1RW_1W_1R
|
||||
.ENDS bitcell_array_16x2_1
|
||||
|
||||
* ptx M{0} {1} p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
|
||||
.SUBCKT precharge_1 bl br en vdd
|
||||
Mlower_pmos bl en br vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mupper_pmos1 bl en vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mupper_pmos2 br en vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS precharge_1
|
||||
|
||||
.SUBCKT precharge_array_1 bl_0 br_0 bl_1 br_1 en vdd
|
||||
Xpre_column_0 bl_0 br_0 en vdd precharge_1
|
||||
Xpre_column_1 bl_1 br_1 en vdd precharge_1
|
||||
.ENDS precharge_array_1
|
||||
|
||||
.SUBCKT precharge_2 bl br en vdd
|
||||
Mlower_pmos bl en br vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mupper_pmos1 bl en vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mupper_pmos2 br en vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS precharge_2
|
||||
|
||||
.SUBCKT precharge_array_2 bl_0 br_0 bl_1 br_1 en vdd
|
||||
Xpre_column_0 bl_0 br_0 en vdd precharge_2
|
||||
Xpre_column_1 bl_1 br_1 en vdd precharge_2
|
||||
.ENDS precharge_array_2
|
||||
*********************** "sense_amp" ******************************
|
||||
|
||||
.SUBCKT sense_amp bl br dout en vdd gnd
|
||||
|
||||
* SPICE3 file created from sense_amp.ext - technology: scmos
|
||||
|
||||
M1000 gnd en a_56_432# gnd n w=1.8u l=0.4u
|
||||
M1001 a_56_432# a_48_304# dout gnd n w=1.8u l=0.4u
|
||||
M1002 a_48_304# dout a_56_432# gnd n w=1.8u l=0.4u
|
||||
M1003 vdd a_48_304# dout vdd p w=3.6u l=0.4u
|
||||
M1004 a_48_304# dout vdd vdd p w=3.6u l=0.4u
|
||||
M1005 bl en dout vdd p w=4.8u l=0.4u
|
||||
M1006 a_48_304# en br vdd p w=4.8u l=0.4u
|
||||
|
||||
.ENDS
|
||||
|
||||
.SUBCKT sense_amp_array data_0 bl_0 br_0 data_1 bl_1 br_1 en vdd gnd
|
||||
Xsa_d0 bl_0 br_0 data_0 en vdd gnd sense_amp
|
||||
Xsa_d1 bl_1 br_1 data_1 en vdd gnd sense_amp
|
||||
.ENDS sense_amp_array
|
||||
*********************** Write_Driver ******************************
|
||||
.SUBCKT write_driver din bl br en vdd gnd
|
||||
* SPICE3 file created from write_driver.ext - technology: scmos
|
||||
|
||||
M1000 a_44_708# a_36_700# bl gnd n w=2.4u l=0.4u
|
||||
M1001 br a_16_500# a_44_708# gnd n w=2.4u l=0.4u
|
||||
M1002 a_44_708# en gnd gnd n w=2.4u l=0.4u
|
||||
M1003 gnd a_8_284# a_16_500# gnd n w=0.8u l=0.4u
|
||||
M1004 a_36_700# a_20_328# gnd gnd n w=0.8u l=0.4u
|
||||
M1005 vdd a_8_284# a_16_500# vdd p w=1.4u l=0.4u
|
||||
M1006 a_36_700# a_20_328# vdd vdd p w=1.4u l=0.4u
|
||||
M1007 vdd en a_20_328# vdd p w=1.4u l=0.4u
|
||||
M1008 a_20_328# a_64_360# vdd vdd p w=1.4u l=0.4u
|
||||
M1009 a_48_328# en a_20_328# gnd n w=1.4u l=0.4u
|
||||
M1010 gnd a_64_360# a_48_328# gnd n w=1.4u l=0.4u
|
||||
M1011 a_40_228# en a_8_284# gnd n w=1.4u l=0.4u
|
||||
M1012 gnd din a_40_228# gnd n w=1.4u l=0.4u
|
||||
M1013 a_64_360# din gnd gnd n w=0.8u l=0.4u
|
||||
M1014 a_8_284# en vdd vdd p w=1.4u l=0.4u
|
||||
M1015 vdd din a_8_284# vdd p w=1.4u l=0.4u
|
||||
M1016 a_64_360# din vdd vdd p w=1.4u l=0.4u
|
||||
|
||||
.ENDS
|
||||
|
||||
.SUBCKT write_driver_array data_0 data_1 bl_0 br_0 bl_1 br_1 en vdd gnd
|
||||
XXwrite_driver0 data_0 bl_0 br_0 en vdd gnd write_driver
|
||||
XXwrite_driver1 data_1 bl_1 br_1 en vdd gnd write_driver
|
||||
.ENDS write_driver_array
|
||||
|
||||
.SUBCKT pinv_29 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_29
|
||||
|
||||
.SUBCKT pnand2_4 A B Z vdd gnd
|
||||
Mpnand2_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_nmos1 Z B net1 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_nmos2 net1 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pnand2_4
|
||||
|
||||
.SUBCKT pnand3_4 A B C Z vdd gnd
|
||||
Mpnand3_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_pmos3 Z C vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos1 Z C net1 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos2 net1 B net2 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos3 net2 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pnand3_4
|
||||
|
||||
.SUBCKT pinv_30 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_30
|
||||
|
||||
.SUBCKT pnand2_5 A B Z vdd gnd
|
||||
Mpnand2_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_nmos1 Z B net1 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_nmos2 net1 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pnand2_5
|
||||
|
||||
.SUBCKT pre2x4 in_0 in_1 out_0 out_1 out_2 out_3 vdd gnd
|
||||
XXpre_inv_0 in_0 inbar_0 vdd gnd pinv_30
|
||||
XXpre_inv_1 in_1 inbar_1 vdd gnd pinv_30
|
||||
XXpre_nand_inv_0 Z_0 out_0 vdd gnd pinv_30
|
||||
XXpre_nand_inv_1 Z_1 out_1 vdd gnd pinv_30
|
||||
XXpre_nand_inv_2 Z_2 out_2 vdd gnd pinv_30
|
||||
XXpre_nand_inv_3 Z_3 out_3 vdd gnd pinv_30
|
||||
XXpre2x4_nand_0 inbar_0 inbar_1 Z_0 vdd gnd pnand2_5
|
||||
XXpre2x4_nand_1 in_0 inbar_1 Z_1 vdd gnd pnand2_5
|
||||
XXpre2x4_nand_2 inbar_0 in_1 Z_2 vdd gnd pnand2_5
|
||||
XXpre2x4_nand_3 in_0 in_1 Z_3 vdd gnd pnand2_5
|
||||
.ENDS pre2x4
|
||||
|
||||
.SUBCKT pinv_31 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_31
|
||||
|
||||
.SUBCKT pnand3_5 A B C Z vdd gnd
|
||||
Mpnand3_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_pmos3 Z C vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos1 Z C net1 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos2 net1 B net2 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand3_nmos3 net2 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pnand3_5
|
||||
|
||||
.SUBCKT pre3x8 in_0 in_1 in_2 out_0 out_1 out_2 out_3 out_4 out_5 out_6 out_7 vdd gnd
|
||||
XXpre_inv_0 in_0 inbar_0 vdd gnd pinv_31
|
||||
XXpre_inv_1 in_1 inbar_1 vdd gnd pinv_31
|
||||
XXpre_inv_2 in_2 inbar_2 vdd gnd pinv_31
|
||||
XXpre_nand_inv_0 Z_0 out_0 vdd gnd pinv_31
|
||||
XXpre_nand_inv_1 Z_1 out_1 vdd gnd pinv_31
|
||||
XXpre_nand_inv_2 Z_2 out_2 vdd gnd pinv_31
|
||||
XXpre_nand_inv_3 Z_3 out_3 vdd gnd pinv_31
|
||||
XXpre_nand_inv_4 Z_4 out_4 vdd gnd pinv_31
|
||||
XXpre_nand_inv_5 Z_5 out_5 vdd gnd pinv_31
|
||||
XXpre_nand_inv_6 Z_6 out_6 vdd gnd pinv_31
|
||||
XXpre_nand_inv_7 Z_7 out_7 vdd gnd pinv_31
|
||||
XXpre3x8_nand_0 inbar_0 inbar_1 inbar_2 Z_0 vdd gnd pnand3_5
|
||||
XXpre3x8_nand_1 in_0 inbar_1 inbar_2 Z_1 vdd gnd pnand3_5
|
||||
XXpre3x8_nand_2 inbar_0 in_1 inbar_2 Z_2 vdd gnd pnand3_5
|
||||
XXpre3x8_nand_3 in_0 in_1 inbar_2 Z_3 vdd gnd pnand3_5
|
||||
XXpre3x8_nand_4 inbar_0 inbar_1 in_2 Z_4 vdd gnd pnand3_5
|
||||
XXpre3x8_nand_5 in_0 inbar_1 in_2 Z_5 vdd gnd pnand3_5
|
||||
XXpre3x8_nand_6 inbar_0 in_1 in_2 Z_6 vdd gnd pnand3_5
|
||||
XXpre3x8_nand_7 in_0 in_1 in_2 Z_7 vdd gnd pnand3_5
|
||||
.ENDS pre3x8
|
||||
|
||||
.SUBCKT hierarchical_decoder_16rows addr_0 addr_1 addr_2 addr_3 decode_0 decode_1 decode_2 decode_3 decode_4 decode_5 decode_6 decode_7 decode_8 decode_9 decode_10 decode_11 decode_12 decode_13 decode_14 decode_15 vdd gnd
|
||||
Xpre_0 addr_0 addr_1 out_0 out_1 out_2 out_3 vdd gnd pre2x4
|
||||
Xpre_1 addr_2 addr_3 out_4 out_5 out_6 out_7 vdd gnd pre2x4
|
||||
XDEC_NAND_0 out_0 out_4 Z_0 vdd gnd pnand2_4
|
||||
XDEC_NAND_1 out_0 out_5 Z_1 vdd gnd pnand2_4
|
||||
XDEC_NAND_2 out_0 out_6 Z_2 vdd gnd pnand2_4
|
||||
XDEC_NAND_3 out_0 out_7 Z_3 vdd gnd pnand2_4
|
||||
XDEC_NAND_4 out_1 out_4 Z_4 vdd gnd pnand2_4
|
||||
XDEC_NAND_5 out_1 out_5 Z_5 vdd gnd pnand2_4
|
||||
XDEC_NAND_6 out_1 out_6 Z_6 vdd gnd pnand2_4
|
||||
XDEC_NAND_7 out_1 out_7 Z_7 vdd gnd pnand2_4
|
||||
XDEC_NAND_8 out_2 out_4 Z_8 vdd gnd pnand2_4
|
||||
XDEC_NAND_9 out_2 out_5 Z_9 vdd gnd pnand2_4
|
||||
XDEC_NAND_10 out_2 out_6 Z_10 vdd gnd pnand2_4
|
||||
XDEC_NAND_11 out_2 out_7 Z_11 vdd gnd pnand2_4
|
||||
XDEC_NAND_12 out_3 out_4 Z_12 vdd gnd pnand2_4
|
||||
XDEC_NAND_13 out_3 out_5 Z_13 vdd gnd pnand2_4
|
||||
XDEC_NAND_14 out_3 out_6 Z_14 vdd gnd pnand2_4
|
||||
XDEC_NAND_15 out_3 out_7 Z_15 vdd gnd pnand2_4
|
||||
XDEC_INV_0 Z_0 decode_0 vdd gnd pinv_29
|
||||
XDEC_INV_1 Z_1 decode_1 vdd gnd pinv_29
|
||||
XDEC_INV_2 Z_2 decode_2 vdd gnd pinv_29
|
||||
XDEC_INV_3 Z_3 decode_3 vdd gnd pinv_29
|
||||
XDEC_INV_4 Z_4 decode_4 vdd gnd pinv_29
|
||||
XDEC_INV_5 Z_5 decode_5 vdd gnd pinv_29
|
||||
XDEC_INV_6 Z_6 decode_6 vdd gnd pinv_29
|
||||
XDEC_INV_7 Z_7 decode_7 vdd gnd pinv_29
|
||||
XDEC_INV_8 Z_8 decode_8 vdd gnd pinv_29
|
||||
XDEC_INV_9 Z_9 decode_9 vdd gnd pinv_29
|
||||
XDEC_INV_10 Z_10 decode_10 vdd gnd pinv_29
|
||||
XDEC_INV_11 Z_11 decode_11 vdd gnd pinv_29
|
||||
XDEC_INV_12 Z_12 decode_12 vdd gnd pinv_29
|
||||
XDEC_INV_13 Z_13 decode_13 vdd gnd pinv_29
|
||||
XDEC_INV_14 Z_14 decode_14 vdd gnd pinv_29
|
||||
XDEC_INV_15 Z_15 decode_15 vdd gnd pinv_29
|
||||
.ENDS hierarchical_decoder_16rows
|
||||
|
||||
.SUBCKT pinv_32 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_32
|
||||
|
||||
.SUBCKT pinv_33 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_33
|
||||
|
||||
.SUBCKT pnand2_6 A B Z vdd gnd
|
||||
Mpnand2_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_nmos1 Z B net1 gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpnand2_nmos2 net1 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
.ENDS pnand2_6
|
||||
|
||||
.SUBCKT wordline_driver in_0 in_1 in_2 in_3 in_4 in_5 in_6 in_7 in_8 in_9 in_10 in_11 in_12 in_13 in_14 in_15 wl_0 wl_1 wl_2 wl_3 wl_4 wl_5 wl_6 wl_7 wl_8 wl_9 wl_10 wl_11 wl_12 wl_13 wl_14 wl_15 en vdd gnd
|
||||
Xwl_driver_inv_en0 en en_bar_0 vdd gnd pinv_33
|
||||
Xwl_driver_nand0 en_bar_0 in_0 wl_bar_0 vdd gnd pnand2_6
|
||||
Xwl_driver_inv0 wl_bar_0 wl_0 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en1 en en_bar_1 vdd gnd pinv_33
|
||||
Xwl_driver_nand1 en_bar_1 in_1 wl_bar_1 vdd gnd pnand2_6
|
||||
Xwl_driver_inv1 wl_bar_1 wl_1 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en2 en en_bar_2 vdd gnd pinv_33
|
||||
Xwl_driver_nand2 en_bar_2 in_2 wl_bar_2 vdd gnd pnand2_6
|
||||
Xwl_driver_inv2 wl_bar_2 wl_2 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en3 en en_bar_3 vdd gnd pinv_33
|
||||
Xwl_driver_nand3 en_bar_3 in_3 wl_bar_3 vdd gnd pnand2_6
|
||||
Xwl_driver_inv3 wl_bar_3 wl_3 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en4 en en_bar_4 vdd gnd pinv_33
|
||||
Xwl_driver_nand4 en_bar_4 in_4 wl_bar_4 vdd gnd pnand2_6
|
||||
Xwl_driver_inv4 wl_bar_4 wl_4 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en5 en en_bar_5 vdd gnd pinv_33
|
||||
Xwl_driver_nand5 en_bar_5 in_5 wl_bar_5 vdd gnd pnand2_6
|
||||
Xwl_driver_inv5 wl_bar_5 wl_5 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en6 en en_bar_6 vdd gnd pinv_33
|
||||
Xwl_driver_nand6 en_bar_6 in_6 wl_bar_6 vdd gnd pnand2_6
|
||||
Xwl_driver_inv6 wl_bar_6 wl_6 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en7 en en_bar_7 vdd gnd pinv_33
|
||||
Xwl_driver_nand7 en_bar_7 in_7 wl_bar_7 vdd gnd pnand2_6
|
||||
Xwl_driver_inv7 wl_bar_7 wl_7 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en8 en en_bar_8 vdd gnd pinv_33
|
||||
Xwl_driver_nand8 en_bar_8 in_8 wl_bar_8 vdd gnd pnand2_6
|
||||
Xwl_driver_inv8 wl_bar_8 wl_8 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en9 en en_bar_9 vdd gnd pinv_33
|
||||
Xwl_driver_nand9 en_bar_9 in_9 wl_bar_9 vdd gnd pnand2_6
|
||||
Xwl_driver_inv9 wl_bar_9 wl_9 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en10 en en_bar_10 vdd gnd pinv_33
|
||||
Xwl_driver_nand10 en_bar_10 in_10 wl_bar_10 vdd gnd pnand2_6
|
||||
Xwl_driver_inv10 wl_bar_10 wl_10 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en11 en en_bar_11 vdd gnd pinv_33
|
||||
Xwl_driver_nand11 en_bar_11 in_11 wl_bar_11 vdd gnd pnand2_6
|
||||
Xwl_driver_inv11 wl_bar_11 wl_11 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en12 en en_bar_12 vdd gnd pinv_33
|
||||
Xwl_driver_nand12 en_bar_12 in_12 wl_bar_12 vdd gnd pnand2_6
|
||||
Xwl_driver_inv12 wl_bar_12 wl_12 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en13 en en_bar_13 vdd gnd pinv_33
|
||||
Xwl_driver_nand13 en_bar_13 in_13 wl_bar_13 vdd gnd pnand2_6
|
||||
Xwl_driver_inv13 wl_bar_13 wl_13 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en14 en en_bar_14 vdd gnd pinv_33
|
||||
Xwl_driver_nand14 en_bar_14 in_14 wl_bar_14 vdd gnd pnand2_6
|
||||
Xwl_driver_inv14 wl_bar_14 wl_14 vdd gnd pinv_32
|
||||
Xwl_driver_inv_en15 en en_bar_15 vdd gnd pinv_33
|
||||
Xwl_driver_nand15 en_bar_15 in_15 wl_bar_15 vdd gnd pnand2_6
|
||||
Xwl_driver_inv15 wl_bar_15 wl_15 vdd gnd pinv_32
|
||||
.ENDS wordline_driver
|
||||
|
||||
.SUBCKT pinv_34 A Z vdd gnd
|
||||
Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.0u ps=4.0u as=1.6p ad=1.6p
|
||||
Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.4000000000000004u ps=2.4000000000000004u as=0.8p ad=0.8p
|
||||
.ENDS pinv_34
|
||||
|
||||
.SUBCKT bank dout0_0 dout0_1 dout2_0 dout2_1 din0_0 din0_1 din1_0 din1_1 addr0_0 addr0_1 addr0_2 addr0_3 addr1_0 addr1_1 addr1_2 addr1_3 addr2_0 addr2_1 addr2_2 addr2_3 s_en0 s_en2 w_en0 w_en1 clk_buf_bar0 clk_buf0 clk_buf_bar1 clk_buf1 clk_buf_bar2 clk_buf2 vdd gnd
|
||||
Xbitcell_array bl0_0 br0_0 bl1_0 br1_0 bl2_0 br2_0 bl0_1 br0_1 bl1_1 br1_1 bl2_1 br2_1 wl0_0 wl1_0 wl2_0 wl0_1 wl1_1 wl2_1 wl0_2 wl1_2 wl2_2 wl0_3 wl1_3 wl2_3 wl0_4 wl1_4 wl2_4 wl0_5 wl1_5 wl2_5 wl0_6 wl1_6 wl2_6 wl0_7 wl1_7 wl2_7 wl0_8 wl1_8 wl2_8 wl0_9 wl1_9 wl2_9 wl0_10 wl1_10 wl2_10 wl0_11 wl1_11 wl2_11 wl0_12 wl1_12 wl2_12 wl0_13 wl1_13 wl2_13 wl0_14 wl1_14 wl2_14 wl0_15 wl1_15 wl2_15 vdd gnd bitcell_array_16x2_1
|
||||
Xprecharge_array0 bl0_0 br0_0 bl0_1 br0_1 clk_buf_bar0 vdd precharge_array_1
|
||||
Xprecharge_array2 bl2_0 br2_0 bl2_1 br2_1 clk_buf_bar2 vdd precharge_array_2
|
||||
Xsense_amp_array0 dout0_0 bl0_0 br0_0 dout0_1 bl0_1 br0_1 s_en0 vdd gnd sense_amp_array
|
||||
Xsense_amp_array2 dout2_0 bl2_0 br2_0 dout2_1 bl2_1 br2_1 s_en2 vdd gnd sense_amp_array
|
||||
Xwrite_driver_array0 din0_0 din0_1 bl0_0 br0_0 bl0_1 br0_1 w_en0 vdd gnd write_driver_array
|
||||
Xwrite_driver_array1 din1_0 din1_1 bl1_0 br1_0 bl1_1 br1_1 w_en1 vdd gnd write_driver_array
|
||||
Xrow_decoder0 addr0_0 addr0_1 addr0_2 addr0_3 dec_out0_0 dec_out0_1 dec_out0_2 dec_out0_3 dec_out0_4 dec_out0_5 dec_out0_6 dec_out0_7 dec_out0_8 dec_out0_9 dec_out0_10 dec_out0_11 dec_out0_12 dec_out0_13 dec_out0_14 dec_out0_15 vdd gnd hierarchical_decoder_16rows
|
||||
Xrow_decoder1 addr1_0 addr1_1 addr1_2 addr1_3 dec_out1_0 dec_out1_1 dec_out1_2 dec_out1_3 dec_out1_4 dec_out1_5 dec_out1_6 dec_out1_7 dec_out1_8 dec_out1_9 dec_out1_10 dec_out1_11 dec_out1_12 dec_out1_13 dec_out1_14 dec_out1_15 vdd gnd hierarchical_decoder_16rows
|
||||
Xrow_decoder2 addr2_0 addr2_1 addr2_2 addr2_3 dec_out2_0 dec_out2_1 dec_out2_2 dec_out2_3 dec_out2_4 dec_out2_5 dec_out2_6 dec_out2_7 dec_out2_8 dec_out2_9 dec_out2_10 dec_out2_11 dec_out2_12 dec_out2_13 dec_out2_14 dec_out2_15 vdd gnd hierarchical_decoder_16rows
|
||||
Xwordline_driver0 dec_out0_0 dec_out0_1 dec_out0_2 dec_out0_3 dec_out0_4 dec_out0_5 dec_out0_6 dec_out0_7 dec_out0_8 dec_out0_9 dec_out0_10 dec_out0_11 dec_out0_12 dec_out0_13 dec_out0_14 dec_out0_15 wl0_0 wl0_1 wl0_2 wl0_3 wl0_4 wl0_5 wl0_6 wl0_7 wl0_8 wl0_9 wl0_10 wl0_11 wl0_12 wl0_13 wl0_14 wl0_15 clk_buf0 vdd gnd wordline_driver
|
||||
Xwordline_driver1 dec_out1_0 dec_out1_1 dec_out1_2 dec_out1_3 dec_out1_4 dec_out1_5 dec_out1_6 dec_out1_7 dec_out1_8 dec_out1_9 dec_out1_10 dec_out1_11 dec_out1_12 dec_out1_13 dec_out1_14 dec_out1_15 wl1_0 wl1_1 wl1_2 wl1_3 wl1_4 wl1_5 wl1_6 wl1_7 wl1_8 wl1_9 wl1_10 wl1_11 wl1_12 wl1_13 wl1_14 wl1_15 clk_buf1 vdd gnd wordline_driver
|
||||
Xwordline_driver2 dec_out2_0 dec_out2_1 dec_out2_2 dec_out2_3 dec_out2_4 dec_out2_5 dec_out2_6 dec_out2_7 dec_out2_8 dec_out2_9 dec_out2_10 dec_out2_11 dec_out2_12 dec_out2_13 dec_out2_14 dec_out2_15 wl2_0 wl2_1 wl2_2 wl2_3 wl2_4 wl2_5 wl2_6 wl2_7 wl2_8 wl2_9 wl2_10 wl2_11 wl2_12 wl2_13 wl2_14 wl2_15 clk_buf2 vdd gnd wordline_driver
|
||||
.ENDS bank
|
||||
|
||||
.SUBCKT sram_2_16_scn4m_subm DIN0[0] DIN0[1] DIN1[0] DIN1[1] ADDR0[0] ADDR0[1] ADDR0[2] ADDR0[3] ADDR1[0] ADDR1[1] ADDR1[2] ADDR1[3] ADDR2[0] ADDR2[1] ADDR2[2] ADDR2[3] csb0 csb1 csb2 web0 clk0 clk1 clk2 DOUT0[0] DOUT0[1] DOUT2[0] DOUT2[1] vdd gnd
|
||||
Xbank0 DOUT0[0] DOUT0[1] DOUT2[0] DOUT2[1] BANK_DIN0[0] BANK_DIN0[1] BANK_DIN1[0] BANK_DIN1[1] A0[0] A0[1] A0[2] A0[3] A1[0] A1[1] A1[2] A1[3] A2[0] A2[1] A2[2] A2[3] s_en0 s_en2 w_en0 w_en1 clk_buf_bar0 clk_buf0 clk_buf_bar1 clk_buf1 clk_buf_bar2 clk_buf2 vdd gnd bank
|
||||
Xcontrol0 csb0 web0 clk0 s_en0 w_en0 clk_buf_bar0 clk_buf0 vdd gnd control_logic_rw
|
||||
Xcontrol1 csb1 clk1 w_en1 clk_buf_bar1 clk_buf1 vdd gnd control_logic_w
|
||||
Xcontrol2 csb2 clk2 s_en2 clk_buf_bar2 clk_buf2 vdd gnd control_logic_r
|
||||
Xrow_address0 ADDR0[0] ADDR0[1] ADDR0[2] ADDR0[3] A0[0] A0[1] A0[2] A0[3] clk_buf0 vdd gnd row_addr_dff
|
||||
Xrow_address1 ADDR1[0] ADDR1[1] ADDR1[2] ADDR1[3] A1[0] A1[1] A1[2] A1[3] clk_buf1 vdd gnd row_addr_dff
|
||||
Xrow_address2 ADDR2[0] ADDR2[1] ADDR2[2] ADDR2[3] A2[0] A2[1] A2[2] A2[3] clk_buf2 vdd gnd row_addr_dff
|
||||
Xdata_dff0 DIN0[0] DIN0[1] BANK_DIN0[0] BANK_DIN0[1] clk_buf0 vdd gnd data_dff
|
||||
Xdata_dff1 DIN1[0] DIN1[1] BANK_DIN1[0] BANK_DIN1[1] clk_buf1 vdd gnd data_dff
|
||||
.ENDS sram_2_16_scn4m_subm
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// OpenRAM SRAM model
|
||||
// Words: 16
|
||||
// Word size: 2
|
||||
|
||||
module sram_2_16_scn4m_subm(DATA,ADDR,CSb,WEb,OEb,clk);
|
||||
|
||||
parameter DATA_WIDTH = 2 ;
|
||||
parameter ADDR_WIDTH = 4 ;
|
||||
parameter RAM_DEPTH = 1 << ADDR_WIDTH;
|
||||
parameter DELAY = 3 ;
|
||||
|
||||
inout [DATA_WIDTH-1:0] DATA;
|
||||
input [ADDR_WIDTH-1:0] ADDR;
|
||||
input CSb; // active low chip select
|
||||
input WEb; // active low write control
|
||||
input OEb; // active output enable
|
||||
input clk; // clock
|
||||
|
||||
reg [DATA_WIDTH-1:0] data_out ;
|
||||
reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
|
||||
|
||||
// Tri-State Buffer control
|
||||
// output : When WEb = 1, oeb = 0, csb = 0
|
||||
assign DATA = (!CSb && !OEb && WEb) ? data_out : 2'bz;
|
||||
|
||||
// Memory Write Block
|
||||
// Write Operation : When WEb = 0, CSb = 0
|
||||
always @ (posedge clk)
|
||||
begin : MEM_WRITE
|
||||
if ( !CSb && !WEb ) begin
|
||||
mem[ADDR] = DATA;
|
||||
$display($time," Writing %m ABUS=%b DATA=%b",ADDR,DATA);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// Memory Read Block
|
||||
// Read Operation : When WEb = 1, CSb = 0
|
||||
always @ (posedge clk)
|
||||
begin : MEM_READ
|
||||
if (!CSb && WEb) begin
|
||||
data_out <= #(DELAY) mem[ADDR];
|
||||
$display($time," Reading %m ABUS=%b DATA=%b",ADDR,mem[ADDR]);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
library (sram_2_16_scn4m_subm_TT_3p3V_25C_lib){
|
||||
delay_model : "table_lookup";
|
||||
time_unit : "1ns" ;
|
||||
voltage_unit : "1v" ;
|
||||
current_unit : "1mA" ;
|
||||
resistance_unit : "1kohm" ;
|
||||
capacitive_load_unit(1 ,fF) ;
|
||||
leakage_power_unit : "1mW" ;
|
||||
pulling_resistance_unit :"1kohm" ;
|
||||
operating_conditions(OC){
|
||||
process : 1.0 ;
|
||||
voltage : 3.3 ;
|
||||
temperature : 25;
|
||||
}
|
||||
|
||||
input_threshold_pct_fall : 50.0 ;
|
||||
output_threshold_pct_fall : 50.0 ;
|
||||
input_threshold_pct_rise : 50.0 ;
|
||||
output_threshold_pct_rise : 50.0 ;
|
||||
slew_lower_threshold_pct_fall : 10.0 ;
|
||||
slew_upper_threshold_pct_fall : 90.0 ;
|
||||
slew_lower_threshold_pct_rise : 10.0 ;
|
||||
slew_upper_threshold_pct_rise : 90.0 ;
|
||||
|
||||
nom_voltage : 5.0;
|
||||
nom_temperature : 25;
|
||||
nom_process : 1.0;
|
||||
default_cell_leakage_power : 0.0 ;
|
||||
default_leakage_power_density : 0.0 ;
|
||||
default_input_pin_cap : 1.0 ;
|
||||
default_inout_pin_cap : 1.0 ;
|
||||
default_output_pin_cap : 0.0 ;
|
||||
default_max_transition : 0.5 ;
|
||||
default_fanout_load : 1.0 ;
|
||||
default_max_fanout : 4.0 ;
|
||||
default_connection_class : universal ;
|
||||
|
||||
lu_table_template(CELL_TABLE){
|
||||
variable_1 : input_net_transition;
|
||||
variable_2 : total_output_net_capacitance;
|
||||
index_1("0.0125, 0.05, 0.4");
|
||||
index_2("2.45605, 9.8242, 78.5936");
|
||||
}
|
||||
|
||||
lu_table_template(CONSTRAINT_TABLE){
|
||||
variable_1 : related_pin_transition;
|
||||
variable_2 : constrained_pin_transition;
|
||||
index_1("0.0125, 0.05, 0.4");
|
||||
index_2("0.0125, 0.05, 0.4");
|
||||
}
|
||||
|
||||
default_operating_conditions : OC;
|
||||
|
||||
|
||||
type (DATA){
|
||||
base_type : array;
|
||||
data_type : bit;
|
||||
bit_width : 2;
|
||||
bit_from : 0;
|
||||
bit_to : 1;
|
||||
}
|
||||
|
||||
type (ADDR){
|
||||
base_type : array;
|
||||
data_type : bit;
|
||||
bit_width : 4;
|
||||
bit_from : 0;
|
||||
bit_to : 3;
|
||||
}
|
||||
|
||||
cell (sram_2_16_scn4m_subm){
|
||||
memory(){
|
||||
type : ram;
|
||||
address_width : 4;
|
||||
word_width : 2;
|
||||
}
|
||||
interface_timing : true;
|
||||
dont_use : true;
|
||||
map_only : true;
|
||||
dont_touch : true;
|
||||
area : 69426.85;
|
||||
|
||||
leakage_power () {
|
||||
when : "CSb0";
|
||||
value : 0.000179;
|
||||
}
|
||||
cell_leakage_power : 0;
|
||||
bus(DIN0){
|
||||
bus_type : DATA;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
memory_write(){
|
||||
address : ADDR0;
|
||||
clocked_on : clk0;
|
||||
}
|
||||
pin(DIN0[1:0]){
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bus(DOUT0){
|
||||
bus_type : DATA;
|
||||
direction : output;
|
||||
max_capacitance : 78.5936;
|
||||
min_capacitance : 2.45605;
|
||||
memory_read(){
|
||||
address : ADDR0;
|
||||
}
|
||||
pin(DOUT0[1:0]){
|
||||
timing(){
|
||||
timing_sense : non_unate;
|
||||
related_pin : "clk0";
|
||||
timing_type : rising_edge;
|
||||
cell_rise(CELL_TABLE) {
|
||||
values("0.268, 0.268, 0.268",\
|
||||
"0.268, 0.268, 0.268",\
|
||||
"0.268, 0.268, 0.268");
|
||||
}
|
||||
cell_fall(CELL_TABLE) {
|
||||
values("0.268, 0.268, 0.268",\
|
||||
"0.268, 0.268, 0.268",\
|
||||
"0.268, 0.268, 0.268");
|
||||
}
|
||||
rise_transition(CELL_TABLE) {
|
||||
values("0.004, 0.004, 0.004",\
|
||||
"0.004, 0.004, 0.004",\
|
||||
"0.004, 0.004, 0.004");
|
||||
}
|
||||
fall_transition(CELL_TABLE) {
|
||||
values("0.004, 0.004, 0.004",\
|
||||
"0.004, 0.004, 0.004",\
|
||||
"0.004, 0.004, 0.004");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bus(ADDR0){
|
||||
bus_type : ADDR;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
max_transition : 0.4;
|
||||
pin(ADDR0[3:0]){
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin(CSb0){
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin(WEb0){
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin(clk0){
|
||||
clock : true;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
internal_power(){
|
||||
when : "!CSb0 & clk0 & !WEb0";
|
||||
rise_power(scalar){
|
||||
values("2.46222038320038");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("2.46222038320038");
|
||||
}
|
||||
}
|
||||
internal_power(){
|
||||
when : "!CSb0 & !clk0 & WEb0";
|
||||
rise_power(scalar){
|
||||
values("2.46222038320038");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("2.46222038320038");
|
||||
}
|
||||
}
|
||||
internal_power(){
|
||||
when : "CSb0";
|
||||
rise_power(scalar){
|
||||
values("0");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("0");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"min_pulse_width";
|
||||
related_pin : clk0;
|
||||
rise_constraint(scalar) {
|
||||
values("0.0");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0.0");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"minimum_period";
|
||||
related_pin : clk0;
|
||||
rise_constraint(scalar) {
|
||||
values("0");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
library (sram_2_16_scn4m_subm_TT_5V_25C_lib){
|
||||
delay_model : "table_lookup";
|
||||
time_unit : "1ns" ;
|
||||
voltage_unit : "1v" ;
|
||||
current_unit : "1mA" ;
|
||||
resistance_unit : "1kohm" ;
|
||||
capacitive_load_unit(1 ,fF) ;
|
||||
leakage_power_unit : "1mW" ;
|
||||
pulling_resistance_unit :"1kohm" ;
|
||||
operating_conditions(OC){
|
||||
process : 1.0 ;
|
||||
voltage : 5 ;
|
||||
temperature : 25;
|
||||
}
|
||||
|
||||
input_threshold_pct_fall : 50.0 ;
|
||||
output_threshold_pct_fall : 50.0 ;
|
||||
input_threshold_pct_rise : 50.0 ;
|
||||
output_threshold_pct_rise : 50.0 ;
|
||||
slew_lower_threshold_pct_fall : 10.0 ;
|
||||
slew_upper_threshold_pct_fall : 90.0 ;
|
||||
slew_lower_threshold_pct_rise : 10.0 ;
|
||||
slew_upper_threshold_pct_rise : 90.0 ;
|
||||
|
||||
nom_voltage : 5.0;
|
||||
nom_temperature : 25;
|
||||
nom_process : 1.0;
|
||||
default_cell_leakage_power : 0.0 ;
|
||||
default_leakage_power_density : 0.0 ;
|
||||
default_input_pin_cap : 1.0 ;
|
||||
default_inout_pin_cap : 1.0 ;
|
||||
default_output_pin_cap : 0.0 ;
|
||||
default_max_transition : 0.5 ;
|
||||
default_fanout_load : 1.0 ;
|
||||
default_max_fanout : 4.0 ;
|
||||
default_connection_class : universal ;
|
||||
|
||||
lu_table_template(CELL_TABLE){
|
||||
variable_1 : input_net_transition;
|
||||
variable_2 : total_output_net_capacitance;
|
||||
index_1("0.0125, 0.05, 0.4");
|
||||
index_2("2.45605, 9.8242, 78.5936");
|
||||
}
|
||||
|
||||
lu_table_template(CONSTRAINT_TABLE){
|
||||
variable_1 : related_pin_transition;
|
||||
variable_2 : constrained_pin_transition;
|
||||
index_1("0.0125, 0.05, 0.4");
|
||||
index_2("0.0125, 0.05, 0.4");
|
||||
}
|
||||
|
||||
default_operating_conditions : OC;
|
||||
|
||||
|
||||
type (DATA){
|
||||
base_type : array;
|
||||
data_type : bit;
|
||||
bit_width : 2;
|
||||
bit_from : 0;
|
||||
bit_to : 1;
|
||||
}
|
||||
|
||||
type (ADDR){
|
||||
base_type : array;
|
||||
data_type : bit;
|
||||
bit_width : 4;
|
||||
bit_from : 0;
|
||||
bit_to : 3;
|
||||
}
|
||||
|
||||
cell (sram_2_16_scn4m_subm){
|
||||
memory(){
|
||||
type : ram;
|
||||
address_width : 4;
|
||||
word_width : 2;
|
||||
}
|
||||
interface_timing : true;
|
||||
dont_use : true;
|
||||
map_only : true;
|
||||
dont_touch : true;
|
||||
area : 68347.21;
|
||||
|
||||
leakage_power () {
|
||||
when : "CSb0";
|
||||
value : 0.000179;
|
||||
}
|
||||
cell_leakage_power : 0;
|
||||
bus(DIN0){
|
||||
bus_type : DATA;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
memory_write(){
|
||||
address : ADDR0;
|
||||
clocked_on : clk0;
|
||||
}
|
||||
pin(DIN0[1:0]){
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bus(DOUT0){
|
||||
bus_type : DATA;
|
||||
direction : output;
|
||||
max_capacitance : 78.5936;
|
||||
min_capacitance : 2.45605;
|
||||
memory_read(){
|
||||
address : ADDR0;
|
||||
}
|
||||
pin(DOUT0[1:0]){
|
||||
timing(){
|
||||
timing_sense : non_unate;
|
||||
related_pin : "clk0";
|
||||
timing_type : rising_edge;
|
||||
cell_rise(CELL_TABLE) {
|
||||
values("0.268, 0.268, 0.268",\
|
||||
"0.268, 0.268, 0.268",\
|
||||
"0.268, 0.268, 0.268");
|
||||
}
|
||||
cell_fall(CELL_TABLE) {
|
||||
values("0.268, 0.268, 0.268",\
|
||||
"0.268, 0.268, 0.268",\
|
||||
"0.268, 0.268, 0.268");
|
||||
}
|
||||
rise_transition(CELL_TABLE) {
|
||||
values("0.004, 0.004, 0.004",\
|
||||
"0.004, 0.004, 0.004",\
|
||||
"0.004, 0.004, 0.004");
|
||||
}
|
||||
fall_transition(CELL_TABLE) {
|
||||
values("0.004, 0.004, 0.004",\
|
||||
"0.004, 0.004, 0.004",\
|
||||
"0.004, 0.004, 0.004");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bus(ADDR0){
|
||||
bus_type : ADDR;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
max_transition : 0.4;
|
||||
pin(ADDR0[3:0]){
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin(CSb0){
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin(WEb0){
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin(clk0){
|
||||
clock : true;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
internal_power(){
|
||||
when : "!CSb0 & clk0 & !WEb0";
|
||||
rise_power(scalar){
|
||||
values("2.46222038320038");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("2.46222038320038");
|
||||
}
|
||||
}
|
||||
internal_power(){
|
||||
when : "!CSb0 & !clk0 & WEb0";
|
||||
rise_power(scalar){
|
||||
values("2.46222038320038");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("2.46222038320038");
|
||||
}
|
||||
}
|
||||
internal_power(){
|
||||
when : "CSb0";
|
||||
rise_power(scalar){
|
||||
values("0");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("0");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"min_pulse_width";
|
||||
related_pin : clk0;
|
||||
rise_constraint(scalar) {
|
||||
values("0.0");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0.0");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"minimum_period";
|
||||
related_pin : clk0;
|
||||
rise_constraint(scalar) {
|
||||
values("0");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,625 @@
|
|||
library (sram_2_16_scn4m_subm_TT_5p0V_25C_lib){
|
||||
delay_model : "table_lookup";
|
||||
time_unit : "1ns" ;
|
||||
voltage_unit : "1v" ;
|
||||
current_unit : "1mA" ;
|
||||
resistance_unit : "1kohm" ;
|
||||
capacitive_load_unit(1 ,fF) ;
|
||||
leakage_power_unit : "1mW" ;
|
||||
pulling_resistance_unit :"1kohm" ;
|
||||
operating_conditions(OC){
|
||||
process : 1.0 ;
|
||||
voltage : 5.0 ;
|
||||
temperature : 25;
|
||||
}
|
||||
|
||||
input_threshold_pct_fall : 50.0 ;
|
||||
output_threshold_pct_fall : 50.0 ;
|
||||
input_threshold_pct_rise : 50.0 ;
|
||||
output_threshold_pct_rise : 50.0 ;
|
||||
slew_lower_threshold_pct_fall : 10.0 ;
|
||||
slew_upper_threshold_pct_fall : 90.0 ;
|
||||
slew_lower_threshold_pct_rise : 10.0 ;
|
||||
slew_upper_threshold_pct_rise : 90.0 ;
|
||||
|
||||
nom_voltage : 5.0;
|
||||
nom_temperature : 25;
|
||||
nom_process : 1.0;
|
||||
default_cell_leakage_power : 0.0 ;
|
||||
default_leakage_power_density : 0.0 ;
|
||||
default_input_pin_cap : 1.0 ;
|
||||
default_inout_pin_cap : 1.0 ;
|
||||
default_output_pin_cap : 0.0 ;
|
||||
default_max_transition : 0.5 ;
|
||||
default_fanout_load : 1.0 ;
|
||||
default_max_fanout : 4.0 ;
|
||||
default_connection_class : universal ;
|
||||
|
||||
lu_table_template(CELL_TABLE){
|
||||
variable_1 : input_net_transition;
|
||||
variable_2 : total_output_net_capacitance;
|
||||
index_1("0.0125, 0.05, 0.4");
|
||||
index_2("2.45605, 9.8242, 78.5936");
|
||||
}
|
||||
|
||||
lu_table_template(CONSTRAINT_TABLE){
|
||||
variable_1 : related_pin_transition;
|
||||
variable_2 : constrained_pin_transition;
|
||||
index_1("0.0125, 0.05, 0.4");
|
||||
index_2("0.0125, 0.05, 0.4");
|
||||
}
|
||||
|
||||
default_operating_conditions : OC;
|
||||
|
||||
|
||||
type (DATA){
|
||||
base_type : array;
|
||||
data_type : bit;
|
||||
bit_width : 2;
|
||||
bit_from : 0;
|
||||
bit_to : 1;
|
||||
}
|
||||
|
||||
type (ADDR){
|
||||
base_type : array;
|
||||
data_type : bit;
|
||||
bit_width : 4;
|
||||
bit_from : 0;
|
||||
bit_to : 3;
|
||||
}
|
||||
|
||||
cell (sram_2_16_scn4m_subm){
|
||||
memory(){
|
||||
type : ram;
|
||||
address_width : 4;
|
||||
word_width : 2;
|
||||
}
|
||||
interface_timing : true;
|
||||
dont_use : true;
|
||||
map_only : true;
|
||||
dont_touch : true;
|
||||
area : 0;
|
||||
|
||||
leakage_power () {
|
||||
when : "CSb0 & CSb1 & CSb2";
|
||||
value : 0.000436;
|
||||
}
|
||||
cell_leakage_power : 0;
|
||||
bus(DIN0){
|
||||
bus_type : DATA;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
memory_write(){
|
||||
address : ADDR0;
|
||||
clocked_on : clk0;
|
||||
}
|
||||
pin(DIN0[1:0]){
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bus(DOUT0){
|
||||
bus_type : DATA;
|
||||
direction : output;
|
||||
max_capacitance : 78.5936;
|
||||
min_capacitance : 2.45605;
|
||||
memory_read(){
|
||||
address : ADDR0;
|
||||
}
|
||||
pin(DOUT0[1:0]){
|
||||
timing(){
|
||||
timing_sense : non_unate;
|
||||
related_pin : "clk0";
|
||||
timing_type : rising_edge;
|
||||
cell_rise(CELL_TABLE) {
|
||||
values("0.079, 0.079, 0.079",\
|
||||
"0.079, 0.079, 0.079",\
|
||||
"0.079, 0.079, 0.079");
|
||||
}
|
||||
cell_fall(CELL_TABLE) {
|
||||
values("0.079, 0.079, 0.079",\
|
||||
"0.079, 0.079, 0.079",\
|
||||
"0.079, 0.079, 0.079");
|
||||
}
|
||||
rise_transition(CELL_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_transition(CELL_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bus(ADDR0){
|
||||
bus_type : ADDR;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
max_transition : 0.4;
|
||||
pin(ADDR0[3:0]){
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin(CSb0){
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin(WEb0){
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk0";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin(clk0){
|
||||
clock : true;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
internal_power(){
|
||||
when : "!CSb0 & clk0 & !WEb0";
|
||||
rise_power(scalar){
|
||||
values("15.41143495605");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("15.41143495605");
|
||||
}
|
||||
}
|
||||
internal_power(){
|
||||
when : "!CSb0 & !clk0 & WEb0";
|
||||
rise_power(scalar){
|
||||
values("15.41143495605");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("15.41143495605");
|
||||
}
|
||||
}
|
||||
internal_power(){
|
||||
when : "CSb0";
|
||||
rise_power(scalar){
|
||||
values("0");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("0");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"min_pulse_width";
|
||||
related_pin : clk0;
|
||||
rise_constraint(scalar) {
|
||||
values("0.0");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0.0");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"minimum_period";
|
||||
related_pin : clk0;
|
||||
rise_constraint(scalar) {
|
||||
values("0");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bus(DIN1){
|
||||
bus_type : DATA;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
memory_write(){
|
||||
address : ADDR1;
|
||||
clocked_on : clk1;
|
||||
}
|
||||
pin(DIN1[1:0]){
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk1";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk1";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bus(ADDR1){
|
||||
bus_type : ADDR;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
max_transition : 0.4;
|
||||
pin(ADDR1[3:0]){
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk1";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk1";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin(CSb1){
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk1";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk1";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin(clk1){
|
||||
clock : true;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
internal_power(){
|
||||
when : "!CSb1 & clk1";
|
||||
rise_power(scalar){
|
||||
values("15.41143495605");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("15.41143495605");
|
||||
}
|
||||
}
|
||||
internal_power(){
|
||||
when : "CSb1";
|
||||
rise_power(scalar){
|
||||
values("0");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("0");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"min_pulse_width";
|
||||
related_pin : clk1;
|
||||
rise_constraint(scalar) {
|
||||
values("0.0");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0.0");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"minimum_period";
|
||||
related_pin : clk1;
|
||||
rise_constraint(scalar) {
|
||||
values("0");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bus(DOUT2){
|
||||
bus_type : DATA;
|
||||
direction : output;
|
||||
max_capacitance : 78.5936;
|
||||
min_capacitance : 2.45605;
|
||||
memory_read(){
|
||||
address : ADDR2;
|
||||
}
|
||||
pin(DOUT2[1:0]){
|
||||
timing(){
|
||||
timing_sense : non_unate;
|
||||
related_pin : "clk2";
|
||||
timing_type : rising_edge;
|
||||
cell_rise(CELL_TABLE) {
|
||||
values("0.079, 0.079, 0.079",\
|
||||
"0.079, 0.079, 0.079",\
|
||||
"0.079, 0.079, 0.079");
|
||||
}
|
||||
cell_fall(CELL_TABLE) {
|
||||
values("0.079, 0.079, 0.079",\
|
||||
"0.079, 0.079, 0.079",\
|
||||
"0.079, 0.079, 0.079");
|
||||
}
|
||||
rise_transition(CELL_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_transition(CELL_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bus(ADDR2){
|
||||
bus_type : ADDR;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
max_transition : 0.4;
|
||||
pin(ADDR2[3:0]){
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk2";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk2";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin(CSb2){
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk2";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009",\
|
||||
"0.009, 0.009, 0.009");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : hold_rising;
|
||||
related_pin : "clk2";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001",\
|
||||
"0.001, 0.001, 0.001");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin(clk2){
|
||||
clock : true;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
internal_power(){
|
||||
when : "!CSb2 & !clk2";
|
||||
rise_power(scalar){
|
||||
values("15.41143495605");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("15.41143495605");
|
||||
}
|
||||
}
|
||||
internal_power(){
|
||||
when : "CSb2";
|
||||
rise_power(scalar){
|
||||
values("0");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("0");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"min_pulse_width";
|
||||
related_pin : clk2;
|
||||
rise_constraint(scalar) {
|
||||
values("0.0");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0.0");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"minimum_period";
|
||||
related_pin : clk2;
|
||||
rise_constraint(scalar) {
|
||||
values("0");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/* Style the button that is used to open and close the collapsible content */
|
||||
.collapsible {
|
||||
background-color: #eee;
|
||||
color: #444;
|
||||
cursor: pointer;
|
||||
padding: 18px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
text-align: left;
|
||||
outline: none;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */
|
||||
.active, .collapsible:hover {
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
/* Style the collapsible content. Note: hidden by default */
|
||||
.content {
|
||||
padding: 0 18px;
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
</ul>
|
||||
<link rel="stylesheet" href="static/index.css">
|
||||
|
||||
<button class="collapsible">files</button>
|
||||
<div class="content">
|
||||
{% for root, dir, files in os.walk(filedir) %}
|
||||
{% if root != filedir %}
|
||||
|
||||
|
||||
<button class="collapsible">{{ root }}</button>
|
||||
<div class="content">
|
||||
{% for f in files %}
|
||||
<button class="collapsible">{{ f }}</button>
|
||||
<div class="content">
|
||||
<a href="{{ root }}/{{ f }}">link</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var coll = document.getElementsByClassName("collapsible");
|
||||
var i;
|
||||
|
||||
for (i = 0; i < coll.length; i++) {
|
||||
coll[i].addEventListener("click", function() {
|
||||
this.classList.toggle("active");
|
||||
var content = this.nextElementSibling;
|
||||
if (content.style.display === "block") {
|
||||
content.style.display = "none";
|
||||
} else {
|
||||
content.style.display = "block";
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</ul>
|
||||
|
|
@ -1,12 +1,18 @@
|
|||
from flask_table import *
|
||||
|
||||
class timing_and_current_data(Table):
|
||||
"""
|
||||
Set up timing and current table columns and title information
|
||||
"""
|
||||
parameter = Col('Parameter')
|
||||
min = Col('Min')
|
||||
max = Col('Max')
|
||||
units = Col('Units')
|
||||
|
||||
class timing_and_current_data_item(object):
|
||||
"""
|
||||
Define timing and current data row element
|
||||
"""
|
||||
def __init__(self, parameter, min, max, units):
|
||||
self.parameter = parameter
|
||||
self.min = min
|
||||
|
|
|
|||
|
|
@ -0,0 +1,827 @@
|
|||
#!/usr/bin/python
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2011-2016 Aliaksei Chapyzhenka
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
# Translated to Python from original file:
|
||||
# https://github.com/drom/wavedrom/blob/master/src/WaveDrom.js
|
||||
#
|
||||
|
||||
import sys
|
||||
import json
|
||||
import math
|
||||
import waveskin
|
||||
|
||||
font_width = 7
|
||||
|
||||
lane = {
|
||||
"xs" : 20, # tmpgraphlane0.width
|
||||
"ys" : 20, # tmpgraphlane0.height
|
||||
"xg" : 120, # tmpgraphlane0.x
|
||||
"yg" : 0, # head gap
|
||||
"yh0" : 0, # head gap title
|
||||
"yh1" : 0, # head gap
|
||||
"yf0" : 0, # foot gap
|
||||
"yf1" : 0, # foot gap
|
||||
"y0" : 5, # tmpgraphlane0.y
|
||||
"yo" : 30, # tmpgraphlane1.y - y0
|
||||
"tgo" : -10, # tmptextlane0.x - xg
|
||||
"ym" : 15, # tmptextlane0.y - y0
|
||||
"xlabel" : 6, # tmptextlabel.x - xg
|
||||
"xmax" : 1,
|
||||
"scale" : 1,
|
||||
"head" : {},
|
||||
"foot" : {}
|
||||
}
|
||||
|
||||
def genBrick (texts, extra, times) :
|
||||
|
||||
R = []
|
||||
if len( texts ) == 4 :
|
||||
for j in range( times ):
|
||||
|
||||
R.append(texts[0])
|
||||
|
||||
for i in range ( extra ):
|
||||
R.append(texts[1])
|
||||
|
||||
R.append(texts[2])
|
||||
for i in range ( extra ):
|
||||
R.append(texts[3])
|
||||
|
||||
return R
|
||||
|
||||
if len( texts ) == 1 :
|
||||
texts.append(texts[0])
|
||||
|
||||
R.append(texts[0])
|
||||
for i in range (times * (2 * (extra + 1)) - 1) :
|
||||
R.append(texts[1])
|
||||
return R
|
||||
|
||||
def genFirstWaveBrick (text, extra, times) :
|
||||
|
||||
pattern = {
|
||||
'p': ['pclk', '111', 'nclk', '000'],
|
||||
'n': ['nclk', '000', 'pclk', '111'],
|
||||
'P': ['Pclk', '111', 'nclk', '000'],
|
||||
'N': ['Nclk', '000', 'pclk', '111'],
|
||||
'l': ['000'],
|
||||
'L': ['000'],
|
||||
'0': ['000'],
|
||||
'h': ['111'],
|
||||
'H': ['111'],
|
||||
'1': ['111'],
|
||||
'=': ['vvv-2'],
|
||||
'2': ['vvv-2'],
|
||||
'3': ['vvv-3'],
|
||||
'4': ['vvv-4'],
|
||||
'5': ['vvv-5'],
|
||||
'd': ['ddd'],
|
||||
'u': ['uuu'],
|
||||
'z': ['zzz']
|
||||
}
|
||||
|
||||
return genBrick( pattern.get( text, ['xxx'] ) , extra, times );
|
||||
|
||||
def genWaveBrick (text, extra, times) :
|
||||
|
||||
x1 = {'p':'pclk', 'n':'nclk', 'P':'Pclk', 'N':'Nclk', 'h':'pclk', 'l':'nclk', 'H':'Pclk', 'L':'Nclk'}
|
||||
x2 = {'0':'0', '1':'1', 'x':'x', 'd':'d', 'u':'u', 'z':'z', '=':'v', '2':'v', '3':'v', '4':'v', '5':'v' }
|
||||
x3 = {'0': '', '1': '', 'x': '', 'd': '', 'u': '', 'z': '', '=':'-2', '2':'-2', '3':'-3', '4':'-4', '5':'-5'}
|
||||
y1 = {
|
||||
'p':'0', 'n':'1',
|
||||
'P':'0', 'N':'1',
|
||||
'h':'1', 'l':'0',
|
||||
'H':'1', 'L':'0',
|
||||
'0':'0', '1':'1', 'x':'x', 'd':'d', 'u':'u', 'z':'z', '=':'v', '2':'v', '3':'v', '4':'v', '5':'v'}
|
||||
|
||||
y2 = {
|
||||
'p': '', 'n': '',
|
||||
'P': '', 'N': '',
|
||||
'h': '', 'l': '',
|
||||
'H': '', 'L': '',
|
||||
'0': '', '1': '', 'x': '', 'd': '', 'u': '', 'z': '', '=':'-2', '2':'-2', '3':'-3', '4':'-4', '5':'-5'}
|
||||
|
||||
x4 = {
|
||||
'p': '111', 'n': '000',
|
||||
'P': '111', 'N': '000',
|
||||
'h': '111', 'l': '000',
|
||||
'H': '111', 'L': '000',
|
||||
'0': '000', '1': '111', 'x': 'xxx', 'd': 'ddd', 'u': 'uuu', 'z': 'zzz',
|
||||
'=': 'vvv-2', '2': 'vvv-2', '3': 'vvv-3', '4': 'vvv-4', '5': 'vvv-5'}
|
||||
|
||||
x5 = {'p':'nclk', 'n':'pclk', 'P':'nclk', 'N':'pclk'}
|
||||
x6 = {'p': '000', 'n': '111', 'P': '000', 'N': '111'}
|
||||
xclude = {'hp':'111', 'Hp':'111', 'ln': '000', 'Ln': '000', 'nh':'111', 'Nh':'111', 'pl': '000', 'Pl':'000'}
|
||||
|
||||
#atext = text.split()
|
||||
atext = text
|
||||
|
||||
tmp0 = x4.get(atext[1])
|
||||
tmp1 = x1.get(atext[1])
|
||||
if tmp1 == None :
|
||||
tmp2 = x2.get(atext[1])
|
||||
if tmp2 == None :
|
||||
# unknown
|
||||
return genBrick(['xxx'], extra, times)
|
||||
else :
|
||||
tmp3 = y1.get(atext[0])
|
||||
if tmp3 == None :
|
||||
# unknown
|
||||
return genBrick(['xxx'], extra, times)
|
||||
|
||||
# soft curves
|
||||
return genBrick([tmp3 + 'm' + tmp2 + y2[atext[0]] + x3[atext[1]], tmp0], extra, times)
|
||||
|
||||
else :
|
||||
tmp4 = xclude.get(text)
|
||||
if tmp4 != None :
|
||||
tmp1 = tmp4
|
||||
|
||||
# sharp curves
|
||||
tmp2 = x5.get(atext[1])
|
||||
if tmp2 == None :
|
||||
# hlHL
|
||||
return genBrick([tmp1, tmp0], extra, times)
|
||||
else :
|
||||
# pnPN
|
||||
return genBrick([tmp1, tmp0, tmp2, x6[atext[1]]], extra, times)
|
||||
|
||||
def parseWaveLane (text, extra) :
|
||||
|
||||
R = []
|
||||
Stack = text
|
||||
Next = Stack[0]
|
||||
Stack = Stack[1:]
|
||||
|
||||
Repeats = 1
|
||||
while len(Stack) and ( Stack[0] == '.' or Stack[0] == '|' ): # repeaters parser
|
||||
Stack=Stack[1:]
|
||||
Repeats += 1
|
||||
|
||||
R.extend(genFirstWaveBrick(Next, extra, Repeats))
|
||||
|
||||
while len(Stack) :
|
||||
Top = Next
|
||||
Next = Stack[0]
|
||||
Stack = Stack[1:]
|
||||
Repeats = 1
|
||||
while len(Stack) and ( Stack[0] == '.' or Stack[0] == '|' ) : # repeaters parser
|
||||
Stack=Stack[1:]
|
||||
Repeats += 1
|
||||
R.extend(genWaveBrick((Top + Next), extra, Repeats))
|
||||
|
||||
for i in range( lane['phase'] ):
|
||||
R = R[1:]
|
||||
return R
|
||||
|
||||
def parseWaveLanes (sig) :
|
||||
|
||||
def data_extract (e) :
|
||||
tmp = e.get('data')
|
||||
if tmp == None : return None
|
||||
if is_type_str (tmp) : tmp=tmp.split()
|
||||
return tmp
|
||||
|
||||
content = []
|
||||
for sigx in sig :
|
||||
lane['period'] = sigx.get('period',1)
|
||||
lane['phase'] = int( sigx.get('phase',0 ) * 2 )
|
||||
sub_content=[]
|
||||
sub_content.append( [sigx.get('name',' '), sigx.get('phase',0 ) ] )
|
||||
sub_content.append( parseWaveLane( sigx['wave'], int(lane['period'] * lane['hscale'] - 1 ) ) if sigx.get('wave') else None )
|
||||
sub_content.append( data_extract(sigx) )
|
||||
content.append(sub_content)
|
||||
|
||||
return content
|
||||
|
||||
def findLaneMarkers (lanetext) :
|
||||
|
||||
lcount = 0
|
||||
gcount = 0
|
||||
ret = []
|
||||
for i in range( len( lanetext ) ) :
|
||||
if lanetext[i] == 'vvv-2' or lanetext[i] == 'vvv-3' or lanetext[i] == 'vvv-4' or lanetext[i] == 'vvv-5' :
|
||||
lcount += 1
|
||||
else :
|
||||
if lcount !=0 :
|
||||
ret.append(gcount - ((lcount + 1) / 2))
|
||||
lcount = 0
|
||||
|
||||
gcount += 1
|
||||
|
||||
if lcount != 0 :
|
||||
ret.append(gcount - ((lcount + 1) / 2))
|
||||
|
||||
return ret
|
||||
|
||||
def renderWaveLane (root, content, index) :
|
||||
|
||||
xmax = 0
|
||||
xgmax = 0
|
||||
glengths = []
|
||||
svgns = 'http://www.w3.org/2000/svg'
|
||||
xlinkns = 'http://www.w3.org/1999/xlink'
|
||||
xmlns = 'http://www.w3.org/XML/1998/namespace'
|
||||
for j in range( len(content) ):
|
||||
name = content[j][0][0]
|
||||
if name : # check name
|
||||
g = [
|
||||
'g',
|
||||
{
|
||||
'id': 'wavelane_' + str(j) + '_' + str(index),
|
||||
'transform': 'translate(0,' + str(lane['y0'] + j * lane['yo']) + ')'
|
||||
}
|
||||
]
|
||||
root.append(g)
|
||||
title = [
|
||||
'text',
|
||||
{
|
||||
'x': lane['tgo'],
|
||||
'y': lane['ym'],
|
||||
'class': 'info',
|
||||
'text-anchor': 'end',
|
||||
'xml:space': 'preserve'
|
||||
},
|
||||
['tspan', name]
|
||||
]
|
||||
g.append(title)
|
||||
|
||||
glengths.append( len(name) * font_width + font_width )
|
||||
|
||||
xoffset = content[j][0][1]
|
||||
xoffset = math.ceil(2 * xoffset) - 2 * xoffset if xoffset > 0 else -2 * xoffset
|
||||
gg = [
|
||||
'g',
|
||||
{
|
||||
'id': 'wavelane_draw_' + str(j) + '_' + str(index),
|
||||
'transform': 'translate(' + str( xoffset * lane['xs'] ) + ', 0)'
|
||||
}
|
||||
]
|
||||
g.append(gg)
|
||||
|
||||
if content[j][1] :
|
||||
for i in range( len(content[j][1]) ) :
|
||||
b = [
|
||||
'use',
|
||||
{
|
||||
#'id': 'use_' + str(i) + '_' + str(j) + '_' + str(index),
|
||||
'xmlns:xlink':xlinkns,
|
||||
'xlink:href': '#' + str( content[j][1][i] ),
|
||||
'transform': 'translate(' + str(i * lane['xs']) + ')'
|
||||
}
|
||||
]
|
||||
gg.append(b)
|
||||
|
||||
if content[j][2] and len(content[j][2]) :
|
||||
labels = findLaneMarkers(content[j][1])
|
||||
if len(labels) != 0 :
|
||||
for k in range( len(labels) ) :
|
||||
if content[j][2] and k < len(content[j][2]) :
|
||||
title = [
|
||||
'text',
|
||||
{
|
||||
'x': int(labels[k]) * lane['xs'] + lane['xlabel'],
|
||||
'y': lane['ym'],
|
||||
'text-anchor': 'middle',
|
||||
'xml:space': 'preserve'
|
||||
},
|
||||
['tspan',content[j][2][k]]
|
||||
]
|
||||
gg.append(title)
|
||||
|
||||
|
||||
if len(content[j][1]) > xmax :
|
||||
xmax = len(content[j][1])
|
||||
|
||||
lane['xmax'] = xmax
|
||||
lane['xg'] = xgmax + 20
|
||||
return glengths
|
||||
|
||||
def renderMarks (root, content, index) :
|
||||
|
||||
def captext ( g, cxt, anchor, y ) :
|
||||
|
||||
if cxt.get(anchor) and cxt[anchor].get('text') :
|
||||
tmark = [
|
||||
'text',
|
||||
{
|
||||
'x': float( cxt['xmax'] ) * float( cxt['xs'] ) / 2,
|
||||
'y': y,
|
||||
'text-anchor': 'middle',
|
||||
'fill': '#000',
|
||||
'xml:space': 'preserve'
|
||||
}, cxt[anchor]['text']
|
||||
]
|
||||
g.append(tmark)
|
||||
|
||||
def ticktock ( g, cxt, ref1, ref2, x, dx, y, length ) :
|
||||
L = []
|
||||
|
||||
if cxt.get(ref1) == None or cxt[ref1].get(ref2) == None :
|
||||
return
|
||||
|
||||
val = cxt[ref1][ref2]
|
||||
if is_type_str( val ) :
|
||||
val = val.split()
|
||||
elif type( val ) is int :
|
||||
offset = val
|
||||
val = []
|
||||
for i in range ( length ) :
|
||||
val.append(i + offset)
|
||||
|
||||
if type( val ) is list :
|
||||
if len( val ) == 0 :
|
||||
return
|
||||
elif len( val ) == 1 :
|
||||
offset = val[0]
|
||||
if is_type_str(offset) :
|
||||
L = val
|
||||
else :
|
||||
for i in range ( length ) :
|
||||
L[i] = i + offset
|
||||
|
||||
elif len( val ) == 2:
|
||||
offset = int(val[0])
|
||||
step = int(val[1])
|
||||
tmp = val[1].split('.')
|
||||
if len( tmp ) == 2 :
|
||||
dp = len( tmp[1] )
|
||||
|
||||
if is_type_str(offset) or is_type_str(step) :
|
||||
L = val
|
||||
else :
|
||||
offset = step * offset
|
||||
for i in range( length ) :
|
||||
L[i] = "{0:.",dp,"f}".format(step * i + offset)
|
||||
|
||||
else :
|
||||
L = val
|
||||
|
||||
else :
|
||||
return
|
||||
|
||||
for i in range( length ) :
|
||||
tmp = L[i]
|
||||
tmark = [
|
||||
'text',
|
||||
{
|
||||
'x': i * dx + x,
|
||||
'y': y,
|
||||
'text-anchor': 'middle',
|
||||
'class': 'muted',
|
||||
'xml:space': 'preserve'
|
||||
}, str(tmp)
|
||||
]
|
||||
g.append(tmark)
|
||||
|
||||
mstep = 2 * int(lane['hscale'])
|
||||
mmstep = mstep * lane['xs']
|
||||
marks = int( lane['xmax'] / mstep )
|
||||
gy = len( content ) * int(lane['yo'])
|
||||
|
||||
g = ['g', {'id': 'gmarks_' + str(index)}]
|
||||
root.insert(0,g)
|
||||
|
||||
for i in range( marks + 1):
|
||||
gg = [
|
||||
'path',
|
||||
{
|
||||
'id': 'gmark_' + str(i) + '_' + str(index),
|
||||
'd': 'm ' + str(i * mmstep) + ',' + '0' + ' 0,' + str(gy),
|
||||
'style': 'stroke:#888;stroke-width:0.5;stroke-dasharray:1,3'
|
||||
}
|
||||
]
|
||||
g.append( gg )
|
||||
|
||||
captext(g, lane, 'head', -33 if lane['yh0'] else -13 )
|
||||
captext(g, lane, 'foot', gy + ( 45 if lane['yf0'] else 25 ) )
|
||||
|
||||
ticktock( g, lane, 'head', 'tick', 0, mmstep, -5, marks + 1)
|
||||
ticktock( g, lane, 'head', 'tock', mmstep / 2, mmstep, -5, marks)
|
||||
ticktock( g, lane, 'foot', 'tick', 0, mmstep, gy + 15, marks + 1)
|
||||
ticktock( g, lane, 'foot', 'tock', mmstep / 2, mmstep, gy + 15, marks)
|
||||
|
||||
def renderArcs (root, source, index, top) :
|
||||
|
||||
Stack = []
|
||||
Edge = {'words': [], 'frm': 0, 'shape': '', 'to': 0, 'label': ''}
|
||||
Events = {}
|
||||
svgns = 'http://www.w3.org/2000/svg'
|
||||
xmlns = 'http://www.w3.org/XML/1998/namespace'
|
||||
|
||||
if source :
|
||||
for i in range (len (source) ) :
|
||||
lane['period'] = source[i].get('period',1)
|
||||
lane['phase'] = int( source[i].get('phase',0 ) * 2 )
|
||||
text = source[i].get('node')
|
||||
if text:
|
||||
Stack = text
|
||||
pos = 0
|
||||
while len( Stack ) :
|
||||
eventname = Stack[0]
|
||||
Stack=Stack[1:]
|
||||
if eventname != '.' :
|
||||
Events[eventname] = {
|
||||
'x' : str( int( float( lane['xs'] ) * (2 * pos * lane['period'] * lane['hscale'] - lane['phase'] ) + float( lane['xlabel'] ) ) ),
|
||||
'y' : str( int( i * lane['yo'] + lane['y0'] + float( lane['ys'] ) * 0.5 ) )
|
||||
}
|
||||
pos += 1
|
||||
|
||||
gg = [ 'g', { 'id' : 'wavearcs_' + str( index ) } ]
|
||||
root.append(gg)
|
||||
|
||||
if top.get('edge') :
|
||||
for i in range( len ( top['edge'] ) ) :
|
||||
Edge['words'] = top['edge'][i].split()
|
||||
Edge['label'] = top['edge'][i][len(Edge['words'][0]):]
|
||||
Edge['label'] = Edge['label'][1:]
|
||||
Edge['frm'] = Edge['words'][0][0]
|
||||
Edge['to'] = Edge['words'][0][-1]
|
||||
Edge['shape'] = Edge['words'][0][1:-1]
|
||||
frm = Events[Edge['frm']]
|
||||
to = Events[Edge['to']]
|
||||
gmark = [
|
||||
'path',
|
||||
{
|
||||
'id': 'gmark_' + Edge['frm'] + '_' + Edge['to'],
|
||||
'd': 'M ' + frm['x'] + ',' + frm['y'] + ' ' + to['x'] + ',' + to['y'],
|
||||
'style': 'fill:none;stroke:#00F;stroke-width:1'
|
||||
}
|
||||
]
|
||||
gg.append(gmark)
|
||||
dx = float( to['x'] ) - float( frm['x'] )
|
||||
dy = float( to['y'] ) - float( frm['y'] )
|
||||
lx = (float(frm['x']) + float(to['x'])) / 2
|
||||
ly = (float(frm['y']) + float(to['y'])) / 2
|
||||
pattern = {
|
||||
'~' : {'d': 'M ' + frm['x'] + ',' + frm['y'] + ' c ' + str(0.7 * dx) + ', 0 ' + str(0.3 * dx) + ', ' + str(dy) + ' ' + str(dx) + ', ' + str(dy) },
|
||||
'-~' : {'d': 'M ' + frm['x'] + ',' + frm['y'] + ' c ' + str(0.7 * dx) + ', 0 ' + str(dx) + ', ' + str(dy) + ' ' + str(dx) + ', ' + str(dy) },
|
||||
'~-' : {'d': 'M ' + frm['x'] + ',' + frm['y'] + ' c ' + '0' + ', 0 ' + str(0.3 * dx) + ', ' + str(dy) + ' ' + str(dx) + ', ' + str(dy) },
|
||||
'-|' : {'d': 'm ' + frm['x'] + ',' + frm['y'] + ' ' + str(dx) + ',0 0,' + str(dy)},
|
||||
'|-' : {'d': 'm ' + frm['x'] + ',' + frm['y'] + ' 0,' + str(dy) + ' ' + str(dx) + ',0'},
|
||||
'-|-' : {'d': 'm ' + frm['x'] + ',' + frm['y'] + ' ' + str(dx / 2) + ',0 0,' + str(dy) + ' ' + str(dx / 2) + ',0'},
|
||||
'->' : {'style': 'marker-end:url(#arrowhead);stroke:#0041c4;stroke-width:1;fill:none'},
|
||||
'~>' : {'style': 'marker-end:url(#arrowhead);stroke:#0041c4;stroke-width:1;fill:none', 'd': 'M ' + frm['x'] + ',' + frm['y'] + ' ' + 'c ' + str(0.7 * dx) + ', 0 ' + str(0.3 * dx) + ', ' + str(dy) + ' ' + str(dx) + ', ' + str(dy)},
|
||||
'-~>' : {'style': 'marker-end:url(#arrowhead);stroke:#0041c4;stroke-width:1;fill:none', 'd': 'M ' + frm['x'] + ',' + frm['y'] + ' ' + 'c ' + str(0.7 * dx) + ', 0 ' + str(dx) + ', ' + str(dy) + ' ' + str(dx) + ', ' + str(dy)},
|
||||
'~->' : {'style': 'marker-end:url(#arrowhead);stroke:#0041c4;stroke-width:1;fill:none', 'd': 'M ' + frm['x'] + ',' + frm['y'] + ' ' + 'c ' + '0' + ', 0 ' + str(0.3 * dx) + ', ' + str(dy) + ' ' + str(dx) + ', ' + str(dy)},
|
||||
'-|>' : {'style': 'marker-end:url(#arrowhead);stroke:#0041c4;stroke-width:1;fill:none', 'd': 'm ' + frm['x'] + ',' + frm['y'] + ' ' + str(dx) + ',0 0,' + str(dy)},
|
||||
'|->' : {'style': 'marker-end:url(#arrowhead);stroke:#0041c4;stroke-width:1;fill:none', 'd': 'm ' + frm['x'] + ',' + frm['y'] + ' 0,' + str(dy) + ' ' + str(dx) + ',0'},
|
||||
'-|->' : {'style': 'marker-end:url(#arrowhead);stroke:#0041c4;stroke-width:1;fill:none', 'd': 'm ' + frm['x'] + ',' + frm['y'] + ' ' + str(dx / 2) + ',0 0,' + str(dy) + ' ' + str(dx / 2) + ',0'},
|
||||
'<->' : {'style': 'marker-end:url(#arrowhead);marker-start:url(#arrowtail);stroke:#0041c4;stroke-width:1;fill:none'},
|
||||
'<~>' : {'style': 'marker-end:url(#arrowhead);marker-start:url(#arrowtail);stroke:#0041c4;stroke-width:1;fill:none','d': 'M ' + frm['x'] + ',' + frm['y'] + ' ' + 'c ' + str(0.7 * dx) + ', 0 ' + str(0.3 * dx) + ', ' + str(dy) + ' ' + str(dx) + ', ' + str(dy)},
|
||||
'<-~>' : {'style': 'marker-end:url(#arrowhead);marker-start:url(#arrowtail);stroke:#0041c4;stroke-width:1;fill:none','d': 'M ' + frm['x'] + ',' + frm['y'] + ' ' + 'c ' + str(0.7 * dx) + ', 0 ' + str(dx) + ', ' + str(dy) + ' ' + str(dx) + ', ' + str(dy)},
|
||||
'<-|>' : {'style': 'marker-end:url(#arrowhead);marker-start:url(#arrowtail);stroke:#0041c4;stroke-width:1;fill:none','d': 'm ' + frm['x'] + ',' + frm['y'] + ' ' + str(dx) + ',0 0,' + str(dy)},
|
||||
'<-|->': {'style': 'marker-end:url(#arrowhead);marker-start:url(#arrowtail);stroke:#0041c4;stroke-width:1;fill:none','d': 'm ' + frm['x'] + ',' + frm['y'] + ' ' + str(dx / 2) + ',0 0,' + str(dy) + ' ' + str(dx / 2) + ',0'}
|
||||
}
|
||||
gmark[1].update( pattern.get( Edge['shape'], { 'style': 'fill:none;stroke:#00F;stroke-width:1' } ) )
|
||||
|
||||
if Edge['label']:
|
||||
if Edge['shape'] == '-~' :
|
||||
lx = float(frm['x']) + (float(to['x']) - float(frm['x'])) * 0.75
|
||||
if Edge['shape'] == '~-' :
|
||||
lx = float(frm['x']) + (float(to['x']) - float(frm['x'])) * 0.25
|
||||
if Edge['shape'] == '-|' :
|
||||
lx = float(to['x'])
|
||||
if Edge['shape'] == '|-' :
|
||||
lx = float(frm['x'])
|
||||
if Edge['shape'] == '-~>':
|
||||
lx = float(frm['x']) + (float(to['x']) - float(frm['x'])) * 0.75
|
||||
if Edge['shape'] == '~->':
|
||||
lx = float(frm['x']) + (float(to['x']) - float(frm['x'])) * 0.25
|
||||
if Edge['shape'] == '-|>' :
|
||||
lx = float(to['x'])
|
||||
if Edge['shape'] == '|->' :
|
||||
lx = float(frm['x'])
|
||||
if Edge['shape'] == '<-~>':
|
||||
lx = float(frm['x']) + (float(to['x']) - float(frm['x'])) * 0.75
|
||||
if Edge['shape'] =='<-|>' :
|
||||
lx = float(to['x'])
|
||||
|
||||
lwidth = len( Edge['label'] ) * font_width
|
||||
label = [
|
||||
'text',
|
||||
{
|
||||
'style': 'font-size:10px;',
|
||||
'text-anchor': 'middle',
|
||||
'xml:space': 'preserve',
|
||||
'x': int( lx ),
|
||||
'y': int( ly + 3 )
|
||||
},
|
||||
[ 'tspan', Edge['label'] ]
|
||||
]
|
||||
underlabel = [
|
||||
'rect',
|
||||
{
|
||||
'height': 9,
|
||||
'style': 'fill:#FFF;',
|
||||
'width': lwidth,
|
||||
'x': int( lx - lwidth / 2 ),
|
||||
'y': int( ly - 5 )
|
||||
}
|
||||
]
|
||||
gg.append(underlabel)
|
||||
gg.append(label)
|
||||
|
||||
for k in Events:
|
||||
if k.islower() :
|
||||
if int( Events[k]['x'] ) > 0 :
|
||||
lwidth = len( k ) * font_width
|
||||
underlabel = [
|
||||
'rect',
|
||||
{
|
||||
'x': float( Events[k]['x'] ) - float(lwidth) / 2,
|
||||
'y': int( Events[k]['y'] ) - 4,
|
||||
'height': 8,
|
||||
'width': lwidth,
|
||||
'style': 'fill:#FFF;'
|
||||
}
|
||||
]
|
||||
gg.append(underlabel)
|
||||
label = [
|
||||
'text',
|
||||
{
|
||||
'style': 'font-size:8px;',
|
||||
'x': int( Events[k]['x'] ),
|
||||
'y': int( Events[k]['y'] ) + 2,
|
||||
'width': lwidth,
|
||||
'text-anchor': 'middle'
|
||||
},
|
||||
k
|
||||
]
|
||||
gg.append(label)
|
||||
|
||||
def parseConfig (source) :
|
||||
|
||||
lane['hscale'] = 1
|
||||
if lane.get('hscale0') :
|
||||
lane['hscale'] = lane['hscale0']
|
||||
|
||||
if source and source.get('config') and source.get('config').get('hscale'):
|
||||
hscale = round(source.get('config').get('hscale'))
|
||||
if hscale > 0 :
|
||||
if hscale > 100 : hscale = 100
|
||||
lane['hscale'] = hscale
|
||||
|
||||
lane['yh0'] = 0
|
||||
lane['yh1'] = 0
|
||||
if source and source.get('head') :
|
||||
lane['head'] = source['head']
|
||||
if source.get('head').get('tick',0) == 0 : lane['yh0'] = 20
|
||||
if source.get('head').get('tock',0) == 0 : lane['yh0'] = 20
|
||||
if source.get('head').get('text') : lane['yh1'] = 46; lane['head']['text'] = source['head']['text']
|
||||
|
||||
lane['yf0'] = 0
|
||||
lane['yf1'] = 0
|
||||
if source and source.get('foot') :
|
||||
lane['foot'] = source['foot']
|
||||
if source.get('foot').get('tick',0) == 0 : lane['yf0'] = 20
|
||||
if source.get('foot').get('tock',0) == 0 : lane['yf0'] = 20
|
||||
if source.get('foot').get('text') : lane['yf1'] = 46; lane['foot']['text'] = source['foot']['text']
|
||||
|
||||
def rec (tmp, state) :
|
||||
|
||||
name = str( tmp[0] )
|
||||
delta_x = 25
|
||||
|
||||
state['x'] += delta_x
|
||||
for i in range( len( tmp ) ) :
|
||||
if type( tmp[i] ) is list :
|
||||
old_y = state['y']
|
||||
rec( tmp[i], state )
|
||||
state['groups'].append( {'x':state['xx'], 'y':old_y, 'height':state['y'] - old_y, 'name': state['name'] } )
|
||||
elif type( tmp[i] ) is dict :
|
||||
state['lanes'].append(tmp[i])
|
||||
state['width'].append(state['x'])
|
||||
state['y'] += 1
|
||||
|
||||
state['xx'] = state['x']
|
||||
state['x'] -= delta_x
|
||||
state['name'] = name
|
||||
|
||||
def insertSVGTemplate (index, parent, source) :
|
||||
|
||||
e = waveskin.WaveSkin['default']
|
||||
|
||||
if source.get('config') and source.get('config').get('skin') :
|
||||
if waveskin.WaveSkin.get( source.get('config').get('skin') ) :
|
||||
e = waveskin.WaveSkin[ source.get('config').get('skin') ]
|
||||
|
||||
if index == 0 :
|
||||
lane['xs'] = int( e[3][1][2][1]['width'] )
|
||||
lane['ys'] = int( e[3][1][2][1]['height'] )
|
||||
lane['xlabel'] = int( e[3][1][2][1]['x'] )
|
||||
lane['ym'] = int( e[3][1][2][1]['y'] )
|
||||
|
||||
else :
|
||||
e = ['svg', {'id': 'svg', 'xmlns': 'http://www.w3.org/2000/svg', 'xmlns:xlink': 'http://www.w3.org/1999/xlink', 'height': '0'},
|
||||
['g', {'id': 'waves'},
|
||||
['g', {'id': 'lanes'}],
|
||||
['g', {'id': 'groups'}]
|
||||
]
|
||||
]
|
||||
|
||||
e[-1][1]['id'] = 'waves_' + str(index)
|
||||
e[-1][2][1]['id'] = 'lanes_' + str(index)
|
||||
e[-1][3][1]['id'] = 'groups_' + str(index)
|
||||
e[1]['id'] = 'svgcontent_' + str(index)
|
||||
e[1]['height'] = 0
|
||||
|
||||
parent.extend(e)
|
||||
|
||||
def renderWaveForm (index, source, output) :
|
||||
|
||||
xmax = 0
|
||||
root = []
|
||||
groups = []
|
||||
|
||||
if source.get('signal'):
|
||||
insertSVGTemplate(index, output, source)
|
||||
parseConfig( source )
|
||||
ret = {'x':0, 'y':0, 'xmax':0, 'width':[], 'lanes':[], 'groups':[] }
|
||||
rec( source['signal'], ret )
|
||||
content = parseWaveLanes(ret['lanes'])
|
||||
glengths = renderWaveLane(root, content, index)
|
||||
for i in range( len( glengths ) ):
|
||||
xmax = max( xmax, ( glengths[i] + ret['width'][i] ) )
|
||||
renderMarks(root, content, index)
|
||||
renderArcs(root, ret['lanes'], index, source)
|
||||
renderGaps(root, ret['lanes'], index)
|
||||
renderGroups(groups, ret['groups'], index)
|
||||
lane['xg'] = int( math.ceil( float( xmax - lane['tgo'] ) / float(lane['xs'] ) ) ) * lane['xs']
|
||||
width = (lane['xg'] + lane['xs'] * (lane['xmax'] + 1) )
|
||||
height = len(content) * lane['yo'] + lane['yh0'] + lane['yh1'] + lane['yf0'] + lane['yf1']
|
||||
output[1]={
|
||||
'id' :'svgcontent_' + str(index),
|
||||
'xmlns' :"http://www.w3.org/2000/svg",
|
||||
'xmlns:xlink':"http://www.w3.org/1999/xlink",
|
||||
'width' :str(width),
|
||||
'height' :str(height),
|
||||
'viewBox' :'0 0 ' + str(width) + ' ' + str(height),
|
||||
'overflow' :"hidden"
|
||||
}
|
||||
output[-1][2][1]['transform']='translate(' + str(lane['xg'] + 0.5) + ', ' + str((float(lane['yh0']) + float(lane['yh1'])) + 0.5) + ')'
|
||||
|
||||
output[-1][2].extend(root)
|
||||
output[-1][3].extend(groups)
|
||||
|
||||
def renderGroups (root, groups, index) :
|
||||
|
||||
svgns = 'http://www.w3.org/2000/svg',
|
||||
xmlns = 'http://www.w3.org/XML/1998/namespace'
|
||||
|
||||
for i in range( len( groups ) ) :
|
||||
group = [
|
||||
'path',
|
||||
{
|
||||
'id': 'group_' + str(i) + '_' + str(index),
|
||||
'd': 'm ' + str( groups[i]['x'] + 0.5 ) + ',' + str( groups[i]['y']* lane['yo'] + 3.5 + lane['yh0'] + lane['yh1'] ) + ' c -3,0 -5,2 -5,5 l 0,' + str( int( groups[i]['height'] * lane['yo'] - 16 ) ) + ' c 0,3 2,5 5,5',
|
||||
'style': 'stroke:#0041c4;stroke-width:1;fill:none'
|
||||
}
|
||||
]
|
||||
root.append(group)
|
||||
|
||||
name = groups[i]['name']
|
||||
x = str( int( groups[i]['x'] - 10 ) )
|
||||
y = str( int( lane['yo'] * (groups[i]['y'] + (float(groups[i]['height']) / 2)) + lane['yh0'] + lane['yh1'] ) )
|
||||
label = [
|
||||
['g',
|
||||
{'transform': 'translate(' + x + ',' + y + ')'},
|
||||
['g', {'transform': 'rotate(270)'},
|
||||
'text',
|
||||
{
|
||||
'text-anchor': 'middle',
|
||||
'class': 'info',
|
||||
'xml:space' : 'preserve'
|
||||
},
|
||||
['tspan',name]
|
||||
]
|
||||
]
|
||||
]
|
||||
root.append(label)
|
||||
|
||||
def renderGaps (root, source, index) :
|
||||
|
||||
Stack = []
|
||||
svgns = 'http://www.w3.org/2000/svg',
|
||||
xlinkns = 'http://www.w3.org/1999/xlink'
|
||||
|
||||
if source:
|
||||
|
||||
gg = [
|
||||
'g',
|
||||
{ 'id': 'wavegaps_' + str(index) }
|
||||
]
|
||||
|
||||
for i in range( len( source )):
|
||||
lane['period'] = source[i].get('period',1)
|
||||
lane['phase'] = int( source[i].get('phase',0 ) * 2 )
|
||||
|
||||
g = [
|
||||
'g',
|
||||
{
|
||||
'id': 'wavegap_' + str(i) + '_' + str(index),
|
||||
'transform': 'translate(0,' + str(lane['y0'] + i * lane['yo']) + ')'
|
||||
}
|
||||
]
|
||||
gg.append(g)
|
||||
|
||||
if source[i].get('wave'):
|
||||
text = source[i]['wave']
|
||||
Stack = text
|
||||
pos = 0
|
||||
while len( Stack ) :
|
||||
c = Stack [0]
|
||||
Stack = Stack[1:]
|
||||
if c == '|' :
|
||||
b = [
|
||||
'use',
|
||||
{
|
||||
'xmlns:xlink':xlinkns,
|
||||
'xlink:href':'#gap',
|
||||
'transform': 'translate(' + str(int(float(lane['xs']) * ((2 * pos + 1) * float(lane['period']) * float(lane['hscale']) - float(lane['phase'])))) + ')'
|
||||
}
|
||||
]
|
||||
g.append(b)
|
||||
pos += 1
|
||||
|
||||
root.append( gg )
|
||||
|
||||
def is_type_str( var ) :
|
||||
if sys.version_info[0] < 3:
|
||||
return type( var ) is str or type( var ) is unicode
|
||||
else:
|
||||
return type( var ) is str
|
||||
|
||||
def convert_to_svg( root ) :
|
||||
|
||||
svg_output = ''
|
||||
|
||||
if type( root ) is list:
|
||||
if len(root) >= 2 and type( root[1] ) is dict:
|
||||
if len( root ) == 2 :
|
||||
svg_output += '<' + root[0] + convert_to_svg( root[1] ) + '/>\n'
|
||||
elif len( root ) >= 3 :
|
||||
svg_output += '<' + root[0] + convert_to_svg( root[1] ) + '>\n'
|
||||
if len( root ) == 3:
|
||||
svg_output += convert_to_svg( root[2] )
|
||||
else:
|
||||
svg_output += convert_to_svg( root[2:] )
|
||||
svg_output += '</' + root[0] + '>\n'
|
||||
elif type( root[0] ) is list:
|
||||
for eleml in root:
|
||||
svg_output += convert_to_svg( eleml )
|
||||
else:
|
||||
svg_output += '<' + root[0] + '>\n'
|
||||
for eleml in root[1:]:
|
||||
svg_output += convert_to_svg( eleml )
|
||||
svg_output += '</' + root[0] + '>\n'
|
||||
elif type( root ) is dict:
|
||||
for elemd in root :
|
||||
svg_output += ' ' + elemd + '="' + str(root[elemd]) + '"'
|
||||
else:
|
||||
svg_output += root
|
||||
|
||||
return svg_output
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if len( sys.argv ) != 5:
|
||||
print ( 'Usage : ' + sys.argv[0] + ' source <input.json> svg <output.svg>' )
|
||||
exit(1)
|
||||
|
||||
if sys.argv[3] != 'svg' :
|
||||
print ( 'Error: only SVG format supported.' )
|
||||
exit(1)
|
||||
|
||||
output=[]
|
||||
inputfile = sys.argv[2]
|
||||
outputfile = sys.argv[4]
|
||||
|
||||
with open(inputfile,'r') as f:
|
||||
jinput = json.load(f)
|
||||
|
||||
renderWaveForm(0,jinput,output)
|
||||
svg_output = convert_to_svg(output)
|
||||
|
||||
with open(outputfile,'w') as f:
|
||||
f.write( svg_output )
|
||||
|
|
@ -0,0 +1 @@
|
|||
468eb9a4a038201c2b0004fe6e4ae9b2d37fdd57
|
||||
|
|
@ -114,6 +114,11 @@ def check_versions():
|
|||
except:
|
||||
OPTS.datasheet_gen = 0
|
||||
|
||||
try:
|
||||
import coverage
|
||||
OPTS.coverage = 1
|
||||
except:
|
||||
OPTS.coverage = 0
|
||||
|
||||
def init_openram(config_file, is_unit_test=True):
|
||||
"""Initialize the technology, paths, simulators, etc."""
|
||||
|
|
@ -200,6 +205,7 @@ def read_config(config_file, is_unit_test=True):
|
|||
config_file = re.sub(r'\.py$', "", config_file)
|
||||
# Expand the user if it is used
|
||||
config_file = os.path.expanduser(config_file)
|
||||
OPTS.config_file = config_file
|
||||
# Add the path to the system path so we can import things in the other directory
|
||||
dir_name = os.path.dirname(config_file)
|
||||
file_name = os.path.basename(config_file)
|
||||
|
|
@ -247,7 +253,7 @@ def read_config(config_file, is_unit_test=True):
|
|||
OPTS.num_words,
|
||||
ports,
|
||||
OPTS.tech_name)
|
||||
|
||||
|
||||
|
||||
|
||||
def end_openram():
|
||||
|
|
@ -387,13 +393,17 @@ def import_tech():
|
|||
OPTS.temperatures = tech.spice["temperatures"]
|
||||
|
||||
|
||||
def print_time(name, now_time, last_time=None):
|
||||
def print_time(name, now_time, last_time=None, indentation=2):
|
||||
""" Print a statement about the time delta. """
|
||||
if last_time:
|
||||
time = str(round((now_time-last_time).total_seconds(),1)) + " seconds"
|
||||
else:
|
||||
time = now_time.strftime('%m/%d/%Y %H:%M:%S')
|
||||
print("** {0}: {1}".format(name,time))
|
||||
global OPTS
|
||||
|
||||
# Don't print during testing
|
||||
if not OPTS.is_unit_test or OPTS.debug_level>0:
|
||||
if last_time:
|
||||
time = str(round((now_time-last_time).total_seconds(),1)) + " seconds"
|
||||
else:
|
||||
time = now_time.strftime('%m/%d/%Y %H:%M:%S')
|
||||
print("{0} {1}: {2}".format("*"*indentation,name,time))
|
||||
|
||||
|
||||
def report_status():
|
||||
|
|
@ -410,6 +420,7 @@ def report_status():
|
|||
debug.error("Tech name must be specified in config file.")
|
||||
|
||||
print("Technology: {0}".format(OPTS.tech_name))
|
||||
print("Total size: {} kbits".format(OPTS.word_size*OPTS.num_words*OPTS.num_banks))
|
||||
print("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size,
|
||||
OPTS.num_words,
|
||||
OPTS.num_banks))
|
||||
|
|
|
|||
|
|
@ -1244,4 +1244,33 @@ class bank(design.design):
|
|||
results.append(decoder_delay + word_driver_delay + bitcell_array_delay + column_mux_delay + bl_t_data_out_delay)
|
||||
|
||||
return results
|
||||
|
||||
def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True):
|
||||
"""Get the all the stage efforts for each stage in the path within the bank clk_buf to a wordline"""
|
||||
#Decoder is assumed to have settled before the negative edge of the clock. Delay model relies on this assumption
|
||||
stage_effort_list = []
|
||||
wordline_cout = self.bitcell_array.get_wordline_cin() + external_cout
|
||||
stage_effort_list += self.wordline_driver.determine_wordline_stage_efforts(wordline_cout,inp_is_rise)
|
||||
|
||||
return stage_effort_list
|
||||
|
||||
def get_wl_en_cin(self):
|
||||
"""Get the relative capacitance of all the clk connections in the bank"""
|
||||
#wl_en only used in the wordline driver.
|
||||
total_clk_cin = self.wordline_driver.get_wl_en_cin()
|
||||
return total_clk_cin
|
||||
|
||||
def get_clk_bar_cin(self):
|
||||
"""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.
|
||||
|
||||
#Precharges are the all the same in Mulitport, one is picked
|
||||
port = self.read_ports[0]
|
||||
total_clk_bar_cin = self.precharge_array[port].get_en_cin()
|
||||
return total_clk_bar_cin
|
||||
|
||||
def get_sen_cin(self):
|
||||
"""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.
|
||||
total_sen_cin = self.sense_amp_array.get_en_cin()
|
||||
return total_sen_cin
|
||||
|
|
@ -204,3 +204,10 @@ class bitcell_array(design.design):
|
|||
def input_load(self):
|
||||
wl_wire = self.gen_wl_wire()
|
||||
return wl_wire.return_input_cap()
|
||||
|
||||
def get_wordline_cin(self):
|
||||
"""Get the relative input capacitance from the wordline connections in all the bitcell"""
|
||||
#A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns
|
||||
bitcell_wl_cin = self.cell.get_wl_cin()
|
||||
total_cin = bitcell_wl_cin * self.column_size
|
||||
return total_cin
|
||||
|
|
@ -13,13 +13,14 @@ from dff_buf_array import dff_buf_array
|
|||
import math
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
import logical_effort
|
||||
|
||||
class control_logic(design.design):
|
||||
"""
|
||||
Dynamically generated Control logic for the total SRAM circuit.
|
||||
"""
|
||||
|
||||
def __init__(self, num_rows, words_per_row, port_type="rw"):
|
||||
def __init__(self, num_rows, words_per_row, sram=None, port_type="rw"):
|
||||
""" Constructor """
|
||||
name = "control_logic_" + port_type
|
||||
design.design.__init__(self, name)
|
||||
|
|
@ -29,6 +30,14 @@ class control_logic(design.design):
|
|||
self.words_per_row = words_per_row
|
||||
self.port_type = port_type
|
||||
|
||||
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.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.
|
||||
|
||||
if self.port_type == "rw":
|
||||
self.num_control_signals = 2
|
||||
else:
|
||||
|
|
@ -101,24 +110,138 @@ class control_logic(design.design):
|
|||
c = reload(__import__(OPTS.replica_bitline))
|
||||
replica_bitline = getattr(c, OPTS.replica_bitline)
|
||||
|
||||
delay_stages, delay_fanout = self.get_delay_chain_size()
|
||||
delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
|
||||
bitcell_loads = int(math.ceil(self.num_rows / 2.0))
|
||||
self.replica_bitline = replica_bitline(delay_stages, delay_fanout, bitcell_loads, name="replica_bitline_"+self.port_type)
|
||||
self.replica_bitline = replica_bitline([delay_fanout_heuristic]*delay_stages_heuristic, bitcell_loads, name="replica_bitline_"+self.port_type)
|
||||
|
||||
if self.sram != None:
|
||||
self.set_sen_wl_delays()
|
||||
|
||||
if self.sram != None and self.enable_delay_chain_resizing and not self.does_sen_total_timing_match(): #check condition based on resizing method
|
||||
#This resizes to match fall and rise delays, can make the delay chain weird sizes.
|
||||
# stage_list = self.get_dynamic_delay_fanout_list(delay_stages_heuristic, delay_fanout_heuristic)
|
||||
# self.replica_bitline = replica_bitline(stage_list, bitcell_loads, name="replica_bitline_resized_"+self.port_type)
|
||||
|
||||
#This resizes based on total delay.
|
||||
delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic)
|
||||
self.replica_bitline = replica_bitline([delay_fanout]*delay_stages, bitcell_loads, name="replica_bitline_resized_"+self.port_type)
|
||||
|
||||
self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing
|
||||
|
||||
self.add_mod(self.replica_bitline)
|
||||
|
||||
def get_delay_chain_size(self):
|
||||
"""Determine the size of the delay chain used for the Sense Amp Enable """
|
||||
def get_heuristic_delay_chain_size(self):
|
||||
"""Use a basic heuristic to determine the size of the delay chain used for the Sense Amp Enable """
|
||||
# FIXME: These should be tuned according to the additional size parameters
|
||||
delay_fanout = 3 # This can be anything >=2
|
||||
# Delay stages Must be non-inverting
|
||||
if self.words_per_row >= 8:
|
||||
if self.words_per_row >= 4:
|
||||
delay_stages = 8
|
||||
elif self.words_per_row == 4:
|
||||
elif self.words_per_row == 2:
|
||||
delay_stages = 6
|
||||
else:
|
||||
delay_stages = 4
|
||||
|
||||
return (delay_stages, delay_fanout)
|
||||
|
||||
def set_sen_wl_delays(self):
|
||||
"""Set delays for wordline and sense amp enable"""
|
||||
self.wl_delay_rise,self.wl_delay_fall = self.get_delays_to_wl()
|
||||
self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen()
|
||||
self.wl_delay = self.wl_delay_rise+self.wl_delay_fall
|
||||
self.sen_delay = self.sen_delay_rise+self.sen_delay_fall
|
||||
|
||||
def does_sen_rise_fall_timing_match(self):
|
||||
"""Compare the relative rise/fall delays of the sense amp enable and wordline"""
|
||||
self.set_sen_wl_delays()
|
||||
#This is not necessarily more reliable than total delay in some cases.
|
||||
if (self.wl_delay_rise*self.wl_timing_tolerance >= self.sen_delay_rise or
|
||||
self.wl_delay_fall*self.wl_timing_tolerance >= self.sen_delay_fall):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def does_sen_total_timing_match(self):
|
||||
"""Compare the total delays of the sense amp enable and wordline"""
|
||||
self.set_sen_wl_delays()
|
||||
#The sen delay must always be bigger than than the wl delay. This decides how much larger the sen delay must be before
|
||||
#a re-size is warranted.
|
||||
if self.wl_delay*self.wl_timing_tolerance >= self.sen_delay:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def get_dynamic_delay_chain_size(self, previous_stages, previous_fanout):
|
||||
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
|
||||
from math import ceil
|
||||
previous_delay_chain_delay = (previous_fanout+1+self.parasitic_inv_delay)*previous_stages
|
||||
debug.info(2, "Previous delay chain produced {} delay units".format(previous_delay_chain_delay))
|
||||
|
||||
delay_fanout = 3 # This can be anything >=2
|
||||
#The delay chain uses minimum sized inverters. There are (fanout+1)*stages inverters and each
|
||||
#inverter adds 1 unit of delay (due to minimum size). This also depends on the pinv value
|
||||
required_delay = self.wl_delay*self.wl_timing_tolerance - (self.sen_delay-previous_delay_chain_delay)
|
||||
debug.check(required_delay > 0, "Cannot size delay chain to have negative delay")
|
||||
delay_stages = ceil(required_delay/(delay_fanout+1+self.parasitic_inv_delay))
|
||||
if delay_stages%2 == 1: #force an even number of stages.
|
||||
delay_stages+=1
|
||||
#Fanout can be varied as well but is a little more complicated but potentially optimal.
|
||||
debug.info(1, "Setting delay chain to {} stages with {} fanout to match {} delay".format(delay_stages, delay_fanout, required_delay))
|
||||
return (delay_stages, delay_fanout)
|
||||
|
||||
def get_dynamic_delay_fanout_list(self, previous_stages, previous_fanout):
|
||||
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
|
||||
|
||||
previous_delay_chain_delay = (previous_fanout+1+self.parasitic_inv_delay)*previous_stages
|
||||
debug.info(2, "Previous delay chain produced {} delay units".format(previous_delay_chain_delay))
|
||||
|
||||
fanout_rise = fanout_fall = 2 # This can be anything >=2
|
||||
#The delay chain uses minimum sized inverters. There are (fanout+1)*stages inverters and each
|
||||
#inverter adds 1 unit of delay (due to minimum size). This also depends on the pinv value
|
||||
required_delay_fall = self.wl_delay_fall*self.wl_timing_tolerance - (self.sen_delay_fall-previous_delay_chain_delay/2)
|
||||
required_delay_rise = self.wl_delay_rise*self.wl_timing_tolerance - (self.sen_delay_rise-previous_delay_chain_delay/2)
|
||||
debug.info(2,"Required delays from chain: fall={}, rise={}".format(required_delay_fall,required_delay_rise))
|
||||
|
||||
#The stages need to be equal (or at least a even number of stages with matching rise/fall delays)
|
||||
while True:
|
||||
stages_fall = self.calculate_stages_with_fixed_fanout(required_delay_fall,fanout_fall)
|
||||
stages_rise = self.calculate_stages_with_fixed_fanout(required_delay_rise,fanout_rise)
|
||||
debug.info(1,"Fall stages={}, rise stages={}".format(stages_fall,stages_rise))
|
||||
if stages_fall == stages_rise:
|
||||
break
|
||||
elif abs(stages_fall-stages_rise) == 1:
|
||||
break
|
||||
#There should also be a condition to make sure the fanout does not get too large.
|
||||
#Otherwise, increase the fanout of delay with the most stages, calculate new stages
|
||||
elif stages_fall>stages_rise:
|
||||
fanout_fall+=1
|
||||
else:
|
||||
fanout_rise+=1
|
||||
|
||||
total_stages = max(stages_fall,stages_rise)*2
|
||||
debug.info(1, "New Delay chain: stages={}, fanout_rise={}, fanout_fall={}".format(total_stages, fanout_rise, fanout_fall))
|
||||
|
||||
#Creates interleaved fanout list of rise/fall delays. Assumes fall is the first stage.
|
||||
stage_list = [fanout_fall if i%2==0 else fanout_rise for i in range(total_stages)]
|
||||
return stage_list
|
||||
|
||||
def calculate_stages_with_fixed_fanout(self, required_delay, fanout):
|
||||
from math import ceil
|
||||
#Delay being negative is not an error. It implies that any amount of stages would have a negative effect on the overall delay
|
||||
if required_delay <= 3+self.parasitic_inv_delay: #3 is the minimum delay per stage (with pinv=0).
|
||||
return 1
|
||||
delay_stages = ceil(required_delay/(fanout+1+self.parasitic_inv_delay))
|
||||
return delay_stages
|
||||
|
||||
def calculate_stage_list(self, total_stages, fanout_rise, fanout_fall):
|
||||
"""Produces a list of fanouts which determine the size of the delay chain. List length is the number of stages.
|
||||
Assumes the first stage is falling.
|
||||
"""
|
||||
stage_list = []
|
||||
for i in range(total_stages):
|
||||
if i%2 == 0:
|
||||
stage_list.append()
|
||||
|
||||
def setup_signal_busses(self):
|
||||
""" Setup bus names, determine the size of the busses etc """
|
||||
|
||||
|
|
@ -663,5 +786,71 @@ class control_logic(design.design):
|
|||
offset=pin.ll(),
|
||||
height=pin.height(),
|
||||
width=pin.width())
|
||||
|
||||
|
||||
def get_delays_to_wl(self):
|
||||
"""Get the delay (in delay units) of the clk to a wordline in the bitcell array"""
|
||||
debug.check(self.sram.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
|
||||
stage_efforts = self.determine_wordline_stage_efforts()
|
||||
clk_to_wl_rise,clk_to_wl_fall = logical_effort.calculate_relative_rise_fall_delays(stage_efforts, self.parasitic_inv_delay)
|
||||
total_delay = clk_to_wl_rise + clk_to_wl_fall
|
||||
debug.info(1, "Clock to wl delay is rise={:.3f}, fall={:.3f}, total={:.3f} in delay units".format(clk_to_wl_rise, clk_to_wl_fall,total_delay))
|
||||
return clk_to_wl_rise,clk_to_wl_fall
|
||||
|
||||
|
||||
def determine_wordline_stage_efforts(self):
|
||||
"""Follows the gated_clk_bar -> wl_en -> wordline signal for the total path efforts"""
|
||||
stage_effort_list = []
|
||||
|
||||
#Initial direction of gated_clk_bar signal for this path
|
||||
is_clk_bar_rise = True
|
||||
|
||||
#Calculate the load on wl_en within the module and add it to external load
|
||||
external_cout = self.sram.get_wl_en_cin()
|
||||
#First stage is the clock buffer
|
||||
stage_effort_list += self.clkbuf.get_output_stage_efforts(external_cout, is_clk_bar_rise)
|
||||
last_stage_is_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
#Then ask the sram for the other path delays (from the bank)
|
||||
stage_effort_list += self.sram.determine_wordline_stage_efforts(last_stage_is_rise)
|
||||
|
||||
return stage_effort_list
|
||||
|
||||
def get_delays_to_sen(self):
|
||||
"""Get the delay (in delay units) of the clk to a sense amp enable.
|
||||
This does not incorporate the delay of the replica bitline.
|
||||
"""
|
||||
debug.check(self.sram.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
|
||||
stage_efforts = self.determine_sa_enable_stage_efforts()
|
||||
clk_to_sen_rise, clk_to_sen_fall = logical_effort.calculate_relative_rise_fall_delays(stage_efforts, self.parasitic_inv_delay)
|
||||
total_delay = clk_to_sen_rise + clk_to_sen_fall
|
||||
debug.info(1, "Clock to s_en delay is rise={:.3f}, fall={:.3f}, total={:.3f} in delay units".format(clk_to_sen_rise, clk_to_sen_fall,total_delay))
|
||||
return clk_to_sen_rise, clk_to_sen_fall
|
||||
|
||||
def determine_sa_enable_stage_efforts(self):
|
||||
"""Follows the gated_clk_bar signal to the sense amp enable signal adding each stages stage effort to a list"""
|
||||
stage_effort_list = []
|
||||
#Calculate the load on clk_buf_bar
|
||||
ext_clk_buf_cout = self.sram.get_clk_bar_cin()
|
||||
|
||||
#Initial direction of clock signal for this path
|
||||
last_stage_rise = True
|
||||
|
||||
#First stage, gated_clk_bar -(and2)-> rbl_in. Only for RW ports.
|
||||
if self.port_type == "rw":
|
||||
stage1_cout = self.replica_bitline.get_en_cin()
|
||||
stage_effort_list += self.and2.get_output_stage_efforts(stage1_cout, last_stage_rise)
|
||||
last_stage_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
#Replica bitline stage, rbl_in -(rbl)-> pre_s_en
|
||||
stage2_cout = self.buf8.get_cin()
|
||||
stage_effort_list += self.replica_bitline.determine_sen_stage_efforts(stage2_cout, last_stage_rise)
|
||||
last_stage_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
#buffer stage, pre_s_en -(buffer)-> s_en
|
||||
stage3_cout = self.sram.get_sen_cin()
|
||||
stage_effort_list += self.buf8.get_output_stage_efforts(stage3_cout, last_stage_rise)
|
||||
last_stage_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
return stage_effort_list
|
||||
|
||||
|
|
@ -219,4 +219,23 @@ class delay_chain(design.design):
|
|||
start=mid_point,
|
||||
end=mid_point.scale(1,0))
|
||||
|
||||
def get_cin(self):
|
||||
"""Get the enable input ralative capacitance"""
|
||||
#Only 1 input to the delay chain which is connected to an inverter.
|
||||
dc_cin = self.inv.get_cin()
|
||||
return dc_cin
|
||||
|
||||
def determine_delayed_en_stage_efforts(self, ext_delayed_en_cout, inp_is_rise=True):
|
||||
"""Get the stage efforts from the en to s_en. Does not compute the delay for the bitline load."""
|
||||
stage_effort_list = []
|
||||
#Add a stage to the list for every stage in delay chain. Stages only differ in fanout except the last which has an external cout.
|
||||
last_stage_is_rise = inp_is_rise
|
||||
for stage_fanout in self.fanout_list:
|
||||
stage_cout = self.inv.get_cin()*(stage_fanout+1)
|
||||
if len(stage_effort_list) == len(self.fanout_list)-1: #last stage
|
||||
stage_cout+=ext_delayed_en_cout
|
||||
stage = self.inv.get_effort_stage(stage_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage)
|
||||
last_stage_is_rise = stage.is_rise
|
||||
|
||||
return stage_effort_list
|
||||
|
|
@ -2,7 +2,7 @@ import globals
|
|||
import design
|
||||
from math import log
|
||||
import design
|
||||
from tech import GDS,layer
|
||||
from tech import GDS,layer,spice,parameter
|
||||
import utils
|
||||
|
||||
class dff(design.design):
|
||||
|
|
@ -23,7 +23,6 @@ class dff(design.design):
|
|||
|
||||
def analytical_power(self, proc, vdd, temp, load):
|
||||
"""Returns dynamic and leakage power. Results in nW"""
|
||||
from tech import spice
|
||||
c_eff = self.calculate_effective_capacitance(load)
|
||||
f = spice["default_event_rate"]
|
||||
power_dyn = c_eff*vdd*vdd*f
|
||||
|
|
@ -34,7 +33,7 @@ class dff(design.design):
|
|||
|
||||
def calculate_effective_capacitance(self, load):
|
||||
"""Computes effective capacitance. Results in fF"""
|
||||
from tech import spice, parameter
|
||||
from tech import parameter
|
||||
c_load = load
|
||||
c_para = spice["flop_para_cap"]#ff
|
||||
transition_prob = spice["flop_transition_prob"]
|
||||
|
|
@ -42,7 +41,12 @@ class dff(design.design):
|
|||
|
||||
def analytical_delay(self, slew, load = 0.0):
|
||||
# dont know how to calculate this now, use constant in tech file
|
||||
from tech import spice
|
||||
result = self.return_delay(spice["dff_delay"], spice["dff_slew"])
|
||||
return result
|
||||
|
||||
def get_clk_cin(self):
|
||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
|
||||
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
|
||||
#Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width.
|
||||
return parameter["dff_clk_cin"]
|
||||
|
||||
|
|
|
|||
|
|
@ -157,3 +157,9 @@ class dff_array(design.design):
|
|||
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
return self.dff.analytical_delay(slew=slew, load=load)
|
||||
|
||||
def get_clk_cin(self):
|
||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
|
||||
dff_clk_cin = self.dff.get_clk_cin()
|
||||
total_cin = dff_clk_cin * self.rows * self.columns
|
||||
return total_cin
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import debug
|
||||
import design
|
||||
from tech import drc
|
||||
from tech import drc,parameter
|
||||
from math import log
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
|
|
@ -177,3 +177,9 @@ class dff_buf(design.design):
|
|||
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
|
||||
return dff_delay + inv1_delay + inv2_delay
|
||||
|
||||
def get_clk_cin(self):
|
||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
|
||||
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
|
||||
#Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width.
|
||||
#FIXME: Dff changed in a past commit. The parameter need to be updated.
|
||||
return parameter["dff_clk_cin"]
|
||||
|
|
@ -184,3 +184,9 @@ class dff_buf_array(design.design):
|
|||
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
return self.dff.analytical_delay(slew=slew, load=load)
|
||||
|
||||
def get_clk_cin(self):
|
||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
|
||||
dff_clk_cin = self.dff.get_clk_cin()
|
||||
total_cin = dff_clk_cin * self.rows * self.columns
|
||||
return total_cin
|
||||
|
|
@ -150,3 +150,6 @@ class dff_inv(design.design):
|
|||
inv1_delay = self.inv1.analytical_delay(slew=dff_delay.slew, load=load)
|
||||
return dff_delay + inv1_delay
|
||||
|
||||
def get_clk_cin(self):
|
||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
|
||||
return self.dff.get_clk_cin()
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
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.
|
||||
"""
|
||||
unique_id = 1
|
||||
|
||||
def __init__(self, rows, columns, inv_size=2, name=""):
|
||||
self.rows = rows
|
||||
self.columns = columns
|
||||
|
||||
if name=="":
|
||||
name = "dff_inv_array_{0}x{1}_{2}".format(rows, columns, dff_inv_array.unique_id)
|
||||
dff_inv_array.unique_id += 1
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
self.inv_size = inv_size
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.create_dff_array()
|
||||
|
||||
def create_layout(self):
|
||||
self.width = self.columns * self.dff.width
|
||||
self.height = self.rows * self.dff.height
|
||||
|
||||
self.place_dff_array()
|
||||
self.add_layout_pins()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_modules(self):
|
||||
self.dff = dff_inv.dff_inv(self.inv_size)
|
||||
self.add_mod(self.dff)
|
||||
|
||||
def add_pins(self):
|
||||
for row in range(self.rows):
|
||||
for col in range(self.columns):
|
||||
self.add_pin(self.get_din_name(row,col))
|
||||
for row in range(self.rows):
|
||||
for col in range(self.columns):
|
||||
self.add_pin(self.get_dout_name(row,col))
|
||||
self.add_pin(self.get_dout_bar_name(row,col))
|
||||
self.add_pin("clk")
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def create_dff_array(self):
|
||||
self.dff_insts={}
|
||||
for row in range(self.rows):
|
||||
for col in range(self.columns):
|
||||
name = "Xdff_r{0}_c{1}".format(row,col)
|
||||
self.dff_insts[row,col]=self.add_inst(name=name,
|
||||
mod=self.dff)
|
||||
self.connect_inst([self.get_din_name(row,col),
|
||||
self.get_dout_name(row,col),
|
||||
self.get_dout_bar_name(row,col),
|
||||
"clk",
|
||||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
def place_dff_array(self):
|
||||
for row in range(self.rows):
|
||||
for col in range(self.columns):
|
||||
name = "Xdff_r{0}_c{1}".format(row,col)
|
||||
if (row % 2 == 0):
|
||||
base = vector(col*self.dff.width,row*self.dff.height)
|
||||
mirror = "R0"
|
||||
else:
|
||||
base = vector(col*self.dff.width,(row+1)*self.dff.height)
|
||||
mirror = "MX"
|
||||
self.dff_insts[row,col].place(offset=base,
|
||||
mirror=mirror)
|
||||
|
||||
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 row in range(self.rows):
|
||||
for col in range(self.columns):
|
||||
# Adds power pin on left of row
|
||||
vdd_pin=self.dff_insts[row,col].get_pin("vdd")
|
||||
self.add_power_pin("vdd", vdd_pin.lc())
|
||||
|
||||
# Adds gnd pin on left of row
|
||||
gnd_pin=self.dff_insts[row,col].get_pin("gnd")
|
||||
self.add_power_pin("gnd", gnd_pin.lc())
|
||||
|
||||
|
||||
for row in range(self.rows):
|
||||
for col in range(self.columns):
|
||||
din_pin = self.dff_insts[row,col].get_pin("D")
|
||||
debug.check(din_pin.layer=="metal2","DFF D pin not on metal2")
|
||||
self.add_layout_pin(text=self.get_din_name(row,col),
|
||||
layer=din_pin.layer,
|
||||
offset=din_pin.ll(),
|
||||
width=din_pin.width(),
|
||||
height=din_pin.height())
|
||||
|
||||
dout_pin = self.dff_insts[row,col].get_pin("Q")
|
||||
debug.check(dout_pin.layer=="metal2","DFF Q pin not on metal2")
|
||||
self.add_layout_pin(text=self.get_dout_name(row,col),
|
||||
layer=dout_pin.layer,
|
||||
offset=dout_pin.ll(),
|
||||
width=dout_pin.width(),
|
||||
height=dout_pin.height())
|
||||
|
||||
dout_bar_pin = self.dff_insts[row,col].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(row,col),
|
||||
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")
|
||||
clk_ypos = 2*self.m3_pitch+self.m3_width
|
||||
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_segment_center(text="clk",
|
||||
layer="metal3",
|
||||
start=vector(0,clk_ypos),
|
||||
end=vector(self.width,clk_ypos))
|
||||
for col in range(self.columns):
|
||||
clk_pin = self.dff_insts[0,col].get_pin("clk")
|
||||
# Make a vertical strip for each column
|
||||
self.add_rect(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=vector(clk_pin.cx(),clk_ypos))
|
||||
|
||||
|
||||
|
||||
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
return self.dff.analytical_delay(slew=slew, load=load)
|
||||
|
||||
def get_clk_cin(self):
|
||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
|
||||
dff_clk_cin = self.dff.get_clk_cin()
|
||||
total_cin = dff_clk_cin * self.rows * self.columns
|
||||
return total_cin
|
||||
|
|
@ -102,3 +102,9 @@ class precharge_array(design.design):
|
|||
for i in range(self.columns):
|
||||
offset = vector(self.pc_cell.width * i, 0)
|
||||
self.local_insts[i].place(offset)
|
||||
|
||||
def get_en_cin(self):
|
||||
"""Get the relative capacitance of all the clk connections in the precharge array"""
|
||||
#Assume single port
|
||||
precharge_en_cin = self.pc_cell.get_en_cin()
|
||||
return precharge_en_cin*self.columns
|
||||
|
|
@ -15,12 +15,11 @@ class replica_bitline(design.design):
|
|||
line and rows is the height of the replica bit loads.
|
||||
"""
|
||||
|
||||
def __init__(self, delay_stages, delay_fanout, bitcell_loads, name="replica_bitline"):
|
||||
def __init__(self, delay_fanout_list, bitcell_loads, name="replica_bitline"):
|
||||
design.design.__init__(self, name)
|
||||
|
||||
self.bitcell_loads = bitcell_loads
|
||||
self.delay_stages = delay_stages
|
||||
self.delay_fanout = delay_fanout
|
||||
self.delay_fanout_list = delay_fanout_list
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
@ -95,7 +94,7 @@ class replica_bitline(design.design):
|
|||
|
||||
# FIXME: The FO and depth of this should be tuned
|
||||
from delay_chain import delay_chain
|
||||
self.delay_chain = delay_chain([self.delay_fanout]*self.delay_stages)
|
||||
self.delay_chain = delay_chain(self.delay_fanout_list)
|
||||
self.add_mod(self.delay_chain)
|
||||
|
||||
self.inv = pinv()
|
||||
|
|
@ -601,4 +600,35 @@ class replica_bitline(design.design):
|
|||
offset=pin.ll(),
|
||||
height=pin.height(),
|
||||
width=pin.width())
|
||||
|
||||
|
||||
def get_en_cin(self):
|
||||
"""Get the enable input relative capacitance"""
|
||||
#The enable is only connected to the delay, get the cin from that module
|
||||
en_cin = self.delay_chain.get_cin()
|
||||
return en_cin
|
||||
|
||||
def determine_sen_stage_efforts(self, ext_cout, inp_is_rise=True):
|
||||
"""Get the stage efforts from the en to s_en. Does not compute the delay for the bitline load."""
|
||||
stage_effort_list = []
|
||||
#Stage 1 is the delay chain
|
||||
stage1_cout = self.get_delayed_en_cin()
|
||||
stage1 = self.delay_chain.determine_delayed_en_stage_efforts(stage1_cout, inp_is_rise)
|
||||
stage_effort_list += stage1
|
||||
|
||||
#There is a disconnect between the delay chain and inverter. The rise/fall of the input to the inverter
|
||||
#Will be the negation of the previous stage.
|
||||
last_stage_is_rise = not stage_effort_list[-1].is_rise
|
||||
|
||||
#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.
|
||||
stage2 = self.inv.get_effort_stage(ext_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage2)
|
||||
|
||||
return stage_effort_list
|
||||
|
||||
def get_delayed_en_cin(self):
|
||||
"""Get the fanout capacitance (relative) of the delayed enable from the delay chain."""
|
||||
access_tx_cin = self.access_tx.get_cin()
|
||||
rbc_cin = self.replica_bitcell.get_wl_cin()
|
||||
return access_tx_cin + rbc_cin
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import design
|
||||
import debug
|
||||
import utils
|
||||
from tech import GDS,layer
|
||||
from tech import GDS,layer, parameter,drc
|
||||
|
||||
class sense_amp(design.design):
|
||||
"""
|
||||
|
|
@ -43,3 +43,9 @@ class sense_amp(design.design):
|
|||
#Power in this module currently not defined. Returns 0 nW (leakage and dynamic).
|
||||
total_power = self.return_power()
|
||||
return total_power
|
||||
|
||||
def get_en_cin(self):
|
||||
"""Get the relative capacitance of sense amp enable gate cin"""
|
||||
pmos_cin = parameter["sa_en_pmos_size"]/drc("minwidth_tx")
|
||||
nmos_cin = parameter["sa_en_nmos_size"]/drc("minwidth_tx")
|
||||
return 2*pmos_cin + nmos_cin
|
||||
|
|
@ -140,3 +140,7 @@ class sense_amp_array(design.design):
|
|||
def analytical_delay(self, slew, load=0.0):
|
||||
return self.amp.analytical_delay(slew=slew, load=load)
|
||||
|
||||
def get_en_cin(self):
|
||||
"""Get the relative capacitance of all the sense amp enable connections in the array"""
|
||||
sense_amp_en_cin = self.amp.get_en_cin()
|
||||
return sense_amp_en_cin * self.words_per_row
|
||||
|
|
@ -216,4 +216,25 @@ class wordline_driver(design.design):
|
|||
|
||||
|
||||
def input_load(self):
|
||||
"""Gets the capacitance of the wordline driver in absolute units (fF)"""
|
||||
return self.nand2.input_load()
|
||||
|
||||
def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True):
|
||||
"""Follows the clk_buf to a wordline signal adding each stages stage effort to a list"""
|
||||
stage_effort_list = []
|
||||
|
||||
stage1_cout = self.inv.get_cin()
|
||||
stage1 = self.nand2.get_effort_stage(stage1_cout, inp_is_rise)
|
||||
stage_effort_list.append(stage1)
|
||||
last_stage_is_rise = stage1.is_rise
|
||||
|
||||
stage2 = self.inv.get_effort_stage(external_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage2)
|
||||
|
||||
return stage_effort_list
|
||||
|
||||
def get_wl_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.
|
||||
total_cin = self.nand2.get_cin() * self.rows
|
||||
return total_cin
|
||||
|
|
@ -26,15 +26,15 @@ if len(args) != 1:
|
|||
# These depend on arguments, so don't load them until now.
|
||||
import debug
|
||||
|
||||
# Keep track of running stats
|
||||
start_time = datetime.datetime.now()
|
||||
print_time("Start",start_time)
|
||||
|
||||
init_openram(config_file=args[0], is_unit_test=False)
|
||||
|
||||
# Only print banner here so it's not in unit tests
|
||||
print_banner()
|
||||
|
||||
# Keep track of running stats
|
||||
start_time = datetime.datetime.now()
|
||||
print_time("Start",start_time)
|
||||
|
||||
# Output info about this run
|
||||
report_status()
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ c = sram_config(word_size=OPTS.word_size,
|
|||
print("Words per row: {}".format(c.words_per_row))
|
||||
|
||||
#from parser import *
|
||||
output_extensions = ["sp","v","lib"]
|
||||
output_extensions = ["sp","v","lib","py"]
|
||||
if OPTS.datasheet_gen:
|
||||
output_extensions.append("html")
|
||||
if not OPTS.netlist_only:
|
||||
|
|
|
|||
|
|
@ -125,4 +125,15 @@ class pand2(pgate.pgate):
|
|||
inv_delay = self.inv.analytical_delay(slew=nand_delay.slew, load=load)
|
||||
return nand_delay + inv_delay
|
||||
|
||||
|
||||
def get_output_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_effort_stage(stage1_cout, inp_is_rise)
|
||||
stage_effort_list.append(stage1)
|
||||
last_stage_is_rise = stage1.is_rise
|
||||
|
||||
stage2 = self.inv.get_effort_stage(external_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage2)
|
||||
|
||||
return stage_effort_list
|
||||
|
|
|
|||
|
|
@ -125,4 +125,20 @@ class pbuf(pgate.pgate):
|
|||
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
|
||||
return inv1_delay + inv2_delay
|
||||
|
||||
|
||||
def get_output_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||
"""Get the stage efforts of the A -> Z path"""
|
||||
stage_effort_list = []
|
||||
stage1_cout = self.inv2.get_cin()
|
||||
stage1 = self.inv1.get_effort_stage(stage1_cout, inp_is_rise)
|
||||
stage_effort_list.append(stage1)
|
||||
last_stage_is_rise = stage1.is_rise
|
||||
|
||||
stage2 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage2)
|
||||
|
||||
return stage_effort_list
|
||||
|
||||
def get_cin(self):
|
||||
"""Returns the relative capacitance of the input"""
|
||||
input_cin = self.inv1.get_cin()
|
||||
return input_cin
|
||||
|
|
@ -7,6 +7,7 @@ from vector import vector
|
|||
from math import ceil
|
||||
from globals import OPTS
|
||||
from utils import round_to_grid
|
||||
import logical_effort
|
||||
|
||||
class pinv(pgate.pgate):
|
||||
"""
|
||||
|
|
@ -29,7 +30,8 @@ class pinv(pgate.pgate):
|
|||
pinv.unique_id += 1
|
||||
pgate.pgate.__init__(self, name, height)
|
||||
debug.info(2, "create pinv structure {0} with size of {1}".format(name, size))
|
||||
|
||||
|
||||
self.size = size
|
||||
self.nmos_size = size
|
||||
self.pmos_size = beta*size
|
||||
self.beta = beta
|
||||
|
|
@ -281,3 +283,14 @@ class pinv(pgate.pgate):
|
|||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
||||
transition_prob = spice["inv_transition_prob"]
|
||||
return transition_prob*(c_load + c_para)
|
||||
|
||||
def get_cin(self):
|
||||
"""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
|
||||
|
||||
def get_effort_stage(self, cout, inp_is_rise=True):
|
||||
"""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.
|
||||
"""
|
||||
parasitic_delay = 1
|
||||
return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
|
||||
|
|
|
|||
|
|
@ -187,3 +187,34 @@ class pinvbuf(design.design):
|
|||
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
|
||||
return inv1_delay + inv2_delay
|
||||
|
||||
def determine_clk_buf_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||
"""Get the stage efforts of the clk -> clk_buf path"""
|
||||
stage_effort_list = []
|
||||
stage1_cout = self.inv1.get_cin() + self.inv2.get_cin()
|
||||
stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise)
|
||||
stage_effort_list.append(stage1)
|
||||
last_stage_is_rise = stage1.is_rise
|
||||
|
||||
stage2 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage2)
|
||||
|
||||
return stage_effort_list
|
||||
|
||||
def determine_clk_buf_bar_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||
"""Get the stage efforts of the clk -> clk_buf path"""
|
||||
#After (almost) every stage, the direction of the signal inverts.
|
||||
stage_effort_list = []
|
||||
stage1_cout = self.inv1.get_cin() + self.inv2.get_cin()
|
||||
stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise)
|
||||
stage_effort_list.append(stage1)
|
||||
last_stage_is_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
stage2_cout = self.inv2.get_cin()
|
||||
stage2 = self.inv1.get_effort_stage(stage2_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage2)
|
||||
last_stage_is_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
stage3 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise)
|
||||
stage_effort_list.append(stage3)
|
||||
|
||||
return stage_effort_list
|
||||
|
|
@ -5,6 +5,7 @@ from tech import drc, parameter, spice
|
|||
from ptx import ptx
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
import logical_effort
|
||||
|
||||
class pnand2(pgate.pgate):
|
||||
"""
|
||||
|
|
@ -21,6 +22,7 @@ class pnand2(pgate.pgate):
|
|||
pgate.pgate.__init__(self, name, height)
|
||||
debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size))
|
||||
|
||||
self.size = size
|
||||
self.nmos_size = 2*size
|
||||
self.pmos_size = parameter["beta"]*size
|
||||
self.nmos_width = self.nmos_size*drc("minwidth_tx")
|
||||
|
|
@ -248,3 +250,14 @@ class pnand2(pgate.pgate):
|
|||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
||||
transition_prob = spice["nand2_transition_prob"]
|
||||
return transition_prob*(c_load + c_para)
|
||||
|
||||
def get_cin(self):
|
||||
"""Return the relative input capacitance of a single input"""
|
||||
return self.nmos_size+self.pmos_size
|
||||
|
||||
def get_effort_stage(self, cout, inp_is_rise=True):
|
||||
"""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.
|
||||
"""
|
||||
parasitic_delay = 2
|
||||
return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
|
||||
|
|
@ -23,6 +23,7 @@ class pnand3(pgate.pgate):
|
|||
|
||||
# We have trouble pitch matching a 3x sizes to the bitcell...
|
||||
# If we relax this, we could size this better.
|
||||
self.size = size
|
||||
self.nmos_size = 2*size
|
||||
self.pmos_size = parameter["beta"]*size
|
||||
self.nmos_width = self.nmos_size*drc("minwidth_tx")
|
||||
|
|
@ -261,3 +262,14 @@ class pnand3(pgate.pgate):
|
|||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
||||
transition_prob = spice["nand3_transition_prob"]
|
||||
return transition_prob*(c_load + c_para)
|
||||
|
||||
def get_cin(self):
|
||||
"""Return the relative input capacitance of a single input"""
|
||||
return self.nmos_size+self.pmos_size
|
||||
|
||||
def get_effort_stage(self, cout, inp_is_rise=True):
|
||||
"""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.
|
||||
"""
|
||||
parasitic_delay = 3
|
||||
return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
|
||||
|
|
@ -263,3 +263,9 @@ class precharge(pgate.pgate):
|
|||
|
||||
self.add_path("metal2", [ left_pos, right_pos], self.bl_contact.height)
|
||||
|
||||
def get_en_cin(self):
|
||||
"""Get the relative capacitance of the enable in the precharge cell"""
|
||||
#The enable connect to three pmos gates. They all use the same size pmos.
|
||||
pmos_cin = self.pmos.get_cin()
|
||||
return 3*pmos_cin
|
||||
|
||||
|
|
@ -353,4 +353,6 @@ class ptx(design.design):
|
|||
if self.connect_active:
|
||||
self.connect_fingered_active(drain_positions, source_positions)
|
||||
|
||||
|
||||
def get_cin(self):
|
||||
"""Returns the relative gate cin of the tx"""
|
||||
return self.tx_width/drc("minwidth_tx")
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import pstats
|
||||
p = pstats.Stats('profile.dat')
|
||||
p.strip_dirs()
|
||||
p.sort_stats('cumulative')
|
||||
p.print_stats(50)
|
||||
|
|
@ -46,12 +46,13 @@ class router(router_tech):
|
|||
|
||||
### The pin data structures
|
||||
# A map of pin names to a set of pin_layout structures
|
||||
# (i.e. pins with a given label)
|
||||
self.pins = {}
|
||||
# This is a set of all pins (ignoring names) so that can quickly not create blockages for pins
|
||||
# (They will be blocked based on the names we are routing)
|
||||
# (They will be blocked when we are routing other nets based on their name.)
|
||||
self.all_pins = set()
|
||||
|
||||
# A map of pin names to a list of pin groups
|
||||
# The labeled pins above categorized into pin groups that are touching/connected.
|
||||
self.pin_groups = {}
|
||||
|
||||
### The blockage data structures
|
||||
|
|
@ -122,16 +123,6 @@ class router(router_tech):
|
|||
debug.info(3,"Retrieved pin {}".format(str(pin)))
|
||||
|
||||
|
||||
|
||||
def find_pins(self,pin_name):
|
||||
"""
|
||||
Finds the pin shapes and converts to tracks.
|
||||
Pin can either be a label or a location,layer pair: [[x,y],layer].
|
||||
"""
|
||||
debug.info(1,"Finding pins for {}.".format(pin_name))
|
||||
self.retrieve_pins(pin_name)
|
||||
self.analyze_pins(pin_name)
|
||||
|
||||
def find_blockages(self):
|
||||
"""
|
||||
Iterate through all the layers and write the obstacles to the routing grid.
|
||||
|
|
@ -142,7 +133,6 @@ class router(router_tech):
|
|||
for layer in [self.vert_layer_number,self.horiz_layer_number]:
|
||||
self.retrieve_blockages(layer)
|
||||
|
||||
|
||||
def find_pins_and_blockages(self, pin_list):
|
||||
"""
|
||||
Find the pins and blockages in the design
|
||||
|
|
@ -150,31 +140,53 @@ class router(router_tech):
|
|||
# This finds the pin shapes and sorts them into "groups" that are connected
|
||||
# This must come before the blockages, so we can not count the pins themselves
|
||||
# as blockages.
|
||||
for pin in pin_list:
|
||||
self.find_pins(pin)
|
||||
start_time = datetime.now()
|
||||
for pin_name in pin_list:
|
||||
self.retrieve_pins(pin_name)
|
||||
print_time("Retrieving pins",datetime.now(), start_time, 4)
|
||||
|
||||
start_time = datetime.now()
|
||||
for pin_name in pin_list:
|
||||
self.analyze_pins(pin_name)
|
||||
print_time("Analyzing pins",datetime.now(), start_time, 4)
|
||||
|
||||
# This will get all shapes as blockages and convert to grid units
|
||||
# This ignores shapes that were pins
|
||||
start_time = datetime.now()
|
||||
self.find_blockages()
|
||||
print_time("Finding blockages",datetime.now(), start_time, 4)
|
||||
|
||||
# Convert the blockages to grid units
|
||||
start_time = datetime.now()
|
||||
self.convert_blockages()
|
||||
print_time("Converting blockages",datetime.now(), start_time, 4)
|
||||
|
||||
# This will convert the pins to grid units
|
||||
# It must be done after blockages to ensure no DRCs between expanded pins and blocked grids
|
||||
start_time = datetime.now()
|
||||
for pin in pin_list:
|
||||
self.convert_pins(pin)
|
||||
|
||||
#for pin in pin_list:
|
||||
# self.combine_adjacent_pins(pin)
|
||||
print_time("Converting pins",datetime.now(), start_time, 4)
|
||||
|
||||
# Combine adjacent pins into pin groups to reduce run-time
|
||||
# by reducing the number of maze routes.
|
||||
# This algorithm is > O(n^2) so remove it for now
|
||||
# start_time = datetime.now()
|
||||
# for pin in pin_list:
|
||||
# self.combine_adjacent_pins(pin)
|
||||
# print_time("Combining adjacent pins",datetime.now(), start_time, 4)
|
||||
|
||||
|
||||
# Separate any adjacent grids of differing net names that overlap
|
||||
# Must be done before enclosing pins
|
||||
start_time = datetime.now()
|
||||
self.separate_adjacent_pins(0)
|
||||
print_time("Separating adjacent pins",datetime.now(), start_time, 4)
|
||||
|
||||
# Enclose the continguous grid units in a metal rectangle to fix some DRCs
|
||||
start_time = datetime.now()
|
||||
self.enclose_pins()
|
||||
|
||||
print_time("Enclosing pins",datetime.now(), start_time, 4)
|
||||
|
||||
def combine_adjacent_pins(self, pin_name):
|
||||
"""
|
||||
|
|
@ -672,37 +684,108 @@ class router(router_tech):
|
|||
|
||||
def analyze_pins(self, pin_name):
|
||||
"""
|
||||
Analyze the shapes of a pin and combine them into groups which are connected.
|
||||
Analyze the shapes of a pin and combine them into pin_groups which are connected.
|
||||
"""
|
||||
debug.info(2,"Analyzing pin groups for {}.".format(pin_name))
|
||||
|
||||
pin_set = self.pins[pin_name]
|
||||
|
||||
# Put each pin in an equivalence class of it's own
|
||||
equiv_classes = [set([x]) for x in pin_set]
|
||||
def combine_classes(equiv_classes):
|
||||
for class1 in equiv_classes:
|
||||
for class2 in equiv_classes:
|
||||
if class1 == class2:
|
||||
continue
|
||||
# Compare each pin in each class,
|
||||
# and if any overlap, update equiv_classes to include the combined the class
|
||||
for p1 in class1:
|
||||
for p2 in class2:
|
||||
if p1.overlaps(p2):
|
||||
combined_class = class1 | class2
|
||||
equiv_classes.remove(class1)
|
||||
equiv_classes.remove(class2)
|
||||
equiv_classes.append(combined_class)
|
||||
return(equiv_classes)
|
||||
return(equiv_classes)
|
||||
# This will be a list of pin tuples that overlap
|
||||
overlap_list = []
|
||||
|
||||
old_length = math.inf
|
||||
while (len(equiv_classes)<old_length):
|
||||
old_length = len(equiv_classes)
|
||||
equiv_classes = combine_classes(equiv_classes)
|
||||
# Sort the rectangles into a list with lower/upper y coordinates
|
||||
bottom_y_coordinates = [(x.by(), x, "bottom") for x in pin_set]
|
||||
top_y_coordinates = [(x.uy(), x, "top") for x in pin_set]
|
||||
y_coordinates = bottom_y_coordinates + top_y_coordinates
|
||||
y_coordinates.sort(key=lambda x: x[0])
|
||||
|
||||
self.pin_groups[pin_name] = [pin_group(name=pin_name, pin_set=x, router=self) for x in equiv_classes]
|
||||
# Map the pins to the lower indices
|
||||
bottom_index_map = {x[1]:i for i,x in enumerate(y_coordinates) if x[2]=="bottom"}
|
||||
top_index_map = {x[1]:i for i,x in enumerate(y_coordinates) if x[2]=="bottom"}
|
||||
|
||||
# Sort the pin list by x coordinate
|
||||
pin_list = list(pin_set)
|
||||
pin_list.sort(key=lambda x: x.lx())
|
||||
|
||||
# for shapes in x order
|
||||
for pin in pin_list:
|
||||
# start at pin's lower y coordinate
|
||||
bottom_index = bottom_index_map[pin]
|
||||
compared_pins = set()
|
||||
for i in range(bottom_index,len(y_coordinates)):
|
||||
compare_pin = y_coordinates[i][1]
|
||||
# Don't overlap yourself
|
||||
if pin==compare_pin:
|
||||
continue
|
||||
# Done when we encounter any shape above the pin
|
||||
if compare_pin.by() > pin.uy():
|
||||
break
|
||||
# Don't double compare the same pin twice
|
||||
if compare_pin in compared_pins:
|
||||
continue
|
||||
compared_pins.add(compare_pin)
|
||||
# If we overlap, add them to the list
|
||||
if pin.overlaps(compare_pin):
|
||||
overlap_list.append((pin,compare_pin))
|
||||
|
||||
# Initial unique group assignments
|
||||
group_id = {}
|
||||
gid = 1
|
||||
for pin in pin_list:
|
||||
group_id[pin] = gid
|
||||
gid += 1
|
||||
|
||||
for p in overlap_list:
|
||||
(p1,p2) = p
|
||||
for pin in pin_list:
|
||||
if group_id[pin] == group_id[p2]:
|
||||
group_id[pin] = group_id[p1]
|
||||
|
||||
|
||||
# For each pin add it to it's group
|
||||
group_map = {}
|
||||
for pin in pin_list:
|
||||
gid = group_id[pin]
|
||||
if gid not in group_map.keys():
|
||||
group_map[gid] = pin_group(name=pin_name, pin_set=[], router=self)
|
||||
# We always add it to the first set since they are touching
|
||||
group_map[gid].pins[0].add(pin)
|
||||
|
||||
self.pin_groups[pin_name] = list(group_map.values())
|
||||
|
||||
# This is the old O(n^2) implementation
|
||||
# def analyze_pins(self, pin_name):
|
||||
# """
|
||||
# Analyze the shapes of a pin and combine them into pin_groups which are connected.
|
||||
# """
|
||||
# debug.info(2,"Analyzing pin groups for {}.".format(pin_name))
|
||||
|
||||
# pin_set = self.pins[pin_name]
|
||||
|
||||
# # Put each pin in an equivalence class of it's own
|
||||
# equiv_classes = [set([x]) for x in pin_set]
|
||||
# def combine_classes(equiv_classes):
|
||||
# for class1 in equiv_classes:
|
||||
# for class2 in equiv_classes:
|
||||
# if class1 == class2:
|
||||
# continue
|
||||
# # Compare each pin in each class,
|
||||
# # and if any overlap, update equiv_classes to include the combined the class
|
||||
# for p1 in class1:
|
||||
# for p2 in class2:
|
||||
# if p1.overlaps(p2):
|
||||
# combined_class = class1 | class2
|
||||
# equiv_classes.remove(class1)
|
||||
# equiv_classes.remove(class2)
|
||||
# equiv_classes.append(combined_class)
|
||||
# return(equiv_classes)
|
||||
# return(equiv_classes)
|
||||
|
||||
# old_length = math.inf
|
||||
# while (len(equiv_classes)<old_length):
|
||||
# old_length = len(equiv_classes)
|
||||
# equiv_classes = combine_classes(equiv_classes)
|
||||
|
||||
# self.pin_groups[pin_name] = [pin_group(name=pin_name, pin_set=x, router=self) for x in equiv_classes]
|
||||
|
||||
def convert_pins(self, pin_name):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -65,9 +65,12 @@ class supply_router(router):
|
|||
self.create_routing_grid()
|
||||
|
||||
# Get the pin shapes
|
||||
start_time = datetime.now()
|
||||
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
||||
print_time("Finding pins and blockages",datetime.now(), start_time, 3)
|
||||
|
||||
# Add the supply rails in a mesh network and connect H/V with vias
|
||||
start_time = datetime.now()
|
||||
# Block everything
|
||||
self.prepare_blockages(self.gnd_name)
|
||||
# Determine the rail locations
|
||||
|
|
@ -77,15 +80,19 @@ class supply_router(router):
|
|||
self.prepare_blockages(self.vdd_name)
|
||||
# Determine the rail locations
|
||||
self.route_supply_rails(self.vdd_name,1)
|
||||
|
||||
print_time("Routing supply rails",datetime.now(), start_time, 3)
|
||||
|
||||
start_time = datetime.now()
|
||||
self.route_simple_overlaps(vdd_name)
|
||||
self.route_simple_overlaps(gnd_name)
|
||||
print_time("Simple overlap routing",datetime.now(), start_time, 3)
|
||||
|
||||
# Route the supply pins to the supply rails
|
||||
# Route vdd first since we want it to be shorter
|
||||
start_time = datetime.now()
|
||||
self.route_pins_to_rails(vdd_name)
|
||||
self.route_pins_to_rails(gnd_name)
|
||||
|
||||
print_time("Maze routing supplies",datetime.now(), start_time, 3)
|
||||
#self.write_debug_gds("final.gds",False)
|
||||
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
python3 -m cProfile -o profile.dat ./openram.py example_config_scn4m_subm.py -v
|
||||
echo "Run view_profile.py to view results"
|
||||
|
|
@ -105,13 +105,21 @@ class sram():
|
|||
print("Trimming netlist to speed up characterization.")
|
||||
lib(out_dir=OPTS.output_path, sram=self.s, sp_file=sp_file)
|
||||
print_time("Characterization", datetime.datetime.now(), start_time)
|
||||
|
||||
|
||||
|
||||
# Write the config file
|
||||
start_time = datetime.datetime.now()
|
||||
from shutil import copyfile
|
||||
copyfile(OPTS.config_file + '.py', OPTS.output_path + OPTS.output_name + '.py')
|
||||
print("Config: writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py'))
|
||||
print_time("Config", datetime.datetime.now(), start_time)
|
||||
|
||||
# Write the datasheet
|
||||
start_time = datetime.datetime.now()
|
||||
from datasheet_gen import datasheet_gen
|
||||
dname = OPTS.output_path + self.s.name + ".html"
|
||||
print("Datasheet: writing to {0}".format(dname))
|
||||
datasheet_gen.datasheet_write(dname)
|
||||
datasheet_gen.datasheet_write(self.s,dname)
|
||||
print_time("Datasheet", datetime.datetime.now(), start_time)
|
||||
|
||||
# Write a verilog model
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from datetime import datetime
|
|||
from importlib import reload
|
||||
from vector import vector
|
||||
from globals import OPTS, print_time
|
||||
|
||||
import logical_effort
|
||||
from design import design
|
||||
|
||||
class sram_base(design):
|
||||
|
|
@ -21,7 +21,9 @@ class sram_base(design):
|
|||
sram_config.set_local_config(self)
|
||||
|
||||
self.bank_insts = []
|
||||
|
||||
|
||||
#For logical effort delay calculations.
|
||||
self.all_mods_except_control_done = False
|
||||
|
||||
def add_pins(self):
|
||||
""" Add pins for entire SRAM. """
|
||||
|
|
@ -237,26 +239,6 @@ class sram_base(design):
|
|||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
c = reload(__import__(OPTS.control_logic))
|
||||
self.mod_control_logic = getattr(c, OPTS.control_logic)
|
||||
|
||||
# Create the control logic module for each port type
|
||||
if len(self.readwrite_ports)>0:
|
||||
self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
|
||||
words_per_row=self.words_per_row,
|
||||
port_type="rw")
|
||||
self.add_mod(self.control_logic_rw)
|
||||
if len(self.writeonly_ports)>0:
|
||||
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
|
||||
words_per_row=self.words_per_row,
|
||||
port_type="w")
|
||||
self.add_mod(self.control_logic_w)
|
||||
if len(self.readonly_ports)>0:
|
||||
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
|
||||
words_per_row=self.words_per_row,
|
||||
port_type="r")
|
||||
self.add_mod(self.control_logic_r)
|
||||
|
||||
# Create the address and control flops (but not the clk)
|
||||
from dff_array import dff_array
|
||||
|
|
@ -286,7 +268,32 @@ class sram_base(design):
|
|||
|
||||
self.supply_rail_width = self.bank.supply_rail_width
|
||||
self.supply_rail_pitch = self.bank.supply_rail_pitch
|
||||
|
||||
#The control logic can resize itself based on the other modules. Requires all other modules added before control logic.
|
||||
self.all_mods_except_control_done = True
|
||||
|
||||
c = reload(__import__(OPTS.control_logic))
|
||||
self.mod_control_logic = getattr(c, OPTS.control_logic)
|
||||
|
||||
# Create the control logic module for each port type
|
||||
if len(self.readwrite_ports)>0:
|
||||
self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
|
||||
words_per_row=self.words_per_row,
|
||||
sram=self,
|
||||
port_type="rw")
|
||||
self.add_mod(self.control_logic_rw)
|
||||
if len(self.writeonly_ports)>0:
|
||||
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
|
||||
words_per_row=self.words_per_row,
|
||||
sram=self,
|
||||
port_type="w")
|
||||
self.add_mod(self.control_logic_w)
|
||||
if len(self.readonly_ports)>0:
|
||||
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
|
||||
words_per_row=self.words_per_row,
|
||||
sram=self,
|
||||
port_type="r")
|
||||
self.add_mod(self.control_logic_r)
|
||||
|
||||
def create_bank(self,bank_num):
|
||||
""" Create a bank """
|
||||
|
|
@ -490,5 +497,38 @@ class sram_base(design):
|
|||
def analytical_delay(self, vdd, slew,load):
|
||||
""" LH and HL are the same in analytical model. """
|
||||
return self.bank.analytical_delay(vdd,slew,load)
|
||||
|
||||
|
||||
def determine_wordline_stage_efforts(self, inp_is_rise=True):
|
||||
"""Get the all the stage efforts for each stage in the path from clk_buf to a wordline"""
|
||||
stage_effort_list = []
|
||||
|
||||
#Clk_buf originates from the control logic so only the bank is related to the wordline path
|
||||
external_wordline_cout = 0 #No loading on the wordline other than in the bank.
|
||||
stage_effort_list += self.bank.determine_wordline_stage_efforts(external_wordline_cout, inp_is_rise)
|
||||
|
||||
return stage_effort_list
|
||||
|
||||
def get_wl_en_cin(self):
|
||||
"""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
|
||||
bank_clk_cin = self.bank.get_wl_en_cin()
|
||||
|
||||
return bank_clk_cin
|
||||
|
||||
def get_clk_bar_cin(self):
|
||||
"""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.
|
||||
#Only the precharge cells use this signal (other than the control logic)
|
||||
bank_clk_cin = self.bank.get_clk_bar_cin()
|
||||
return bank_clk_cin
|
||||
|
||||
def get_sen_cin(self):
|
||||
"""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)
|
||||
bank_sen_cin = self.bank.get_sen_cin()
|
||||
return bank_sen_cin
|
||||
|
||||
|
||||
|
||||
|
|
@ -11,8 +11,6 @@ import globals
|
|||
from globals import OPTS
|
||||
import debug
|
||||
|
||||
#os.system("chmod u+x 04_pdriver_test.py")
|
||||
|
||||
class pdriver_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class replica_bitline_multiport_test(openram_test):
|
|||
OPTS.num_w_ports = 0
|
||||
|
||||
debug.info(2, "Testing 1rw 1r RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||
a = replica_bitline.replica_bitline(stages*[fanout],rows)
|
||||
self.local_check(a)
|
||||
|
||||
# check replica bitline in pbitcell multi-port
|
||||
|
|
@ -39,7 +39,7 @@ class replica_bitline_multiport_test(openram_test):
|
|||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(2, "Testing RBL pbitcell 1rw with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||
a = replica_bitline.replica_bitline(stages*[fanout],rows)
|
||||
self.local_check(a)
|
||||
|
||||
OPTS.num_rw_ports = 1
|
||||
|
|
@ -47,7 +47,7 @@ class replica_bitline_multiport_test(openram_test):
|
|||
OPTS.num_r_ports = 1
|
||||
|
||||
debug.info(2, "Testing RBL pbitcell 1rw 1w 1r with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||
a = replica_bitline.replica_bitline(stages*[fanout],rows)
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -22,14 +22,14 @@ class replica_bitline_test(openram_test):
|
|||
fanout=4
|
||||
rows=13
|
||||
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||
a = replica_bitline.replica_bitline(stages*[fanout],rows)
|
||||
self.local_check(a)
|
||||
#debug.error("Exiting...", 1)
|
||||
|
||||
stages=8
|
||||
rows=100
|
||||
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||
a = replica_bitline.replica_bitline(stages*[fanout],rows)
|
||||
self.local_check(a)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class timing_sram_test(openram_test):
|
|||
from importlib import reload
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import delay
|
||||
from characterizer import delay, bitline_delay
|
||||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=1,
|
||||
|
|
@ -43,35 +43,37 @@ class timing_sram_test(openram_test):
|
|||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
d = delay(s.s, tempspice, corner)
|
||||
bl = bitline_delay(s.s, tempspice, corner)
|
||||
import tech
|
||||
loads = [tech.spice["msflop_in_cap"]*4]
|
||||
slews = [tech.spice["rise_time"]*2]
|
||||
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
|
||||
#bitline_swing = bl.analyze(probe_address, probe_data, slews, loads)
|
||||
#Combine info about port into all data
|
||||
data.update(port_data[0])
|
||||
|
||||
if OPTS.tech_name == "freepdk45":
|
||||
golden_data = {'delay_hl': [2.6232],
|
||||
'delay_lh': [0.2775342],
|
||||
'leakage_power': 0.0020258999999999997,
|
||||
'min_period': 4.844,
|
||||
'read0_power': [0.0557804],
|
||||
'read1_power': [0.0525619],
|
||||
'slew_hl': [0.1082014],
|
||||
'slew_lh': [0.0238257],
|
||||
'write0_power': [0.0456528],
|
||||
'write1_power': [0.0442747]}
|
||||
golden_data = {'delay_hl': [0.2011],
|
||||
'delay_lh': [0.2011],
|
||||
'leakage_power': 0.002,
|
||||
'min_period': 0.41,
|
||||
'read0_power': [0.63604],
|
||||
'read1_power': [0.6120599999999999],
|
||||
'slew_hl': [0.10853],
|
||||
'slew_lh': [0.10853],
|
||||
'write0_power': [0.51742],
|
||||
'write1_power': [0.51095]}
|
||||
elif OPTS.tech_name == "scn4m_subm":
|
||||
golden_data = {'delay_hl': [6.079300000000001],
|
||||
'delay_lh': [1.7767000000000002],
|
||||
'leakage_power': 0.026282499999999997,
|
||||
'min_period': 9.375,
|
||||
'read0_power': [6.5802],
|
||||
'read1_power': [6.2815],
|
||||
'slew_hl': [0.7396921999999999],
|
||||
'slew_lh': [0.3397355],
|
||||
'write0_power': [5.7337],
|
||||
'write1_power': [5.8691]}
|
||||
golden_data = {'delay_hl': [1.3911],
|
||||
'delay_lh': [1.3911],
|
||||
'leakage_power': 0.0278488,
|
||||
'min_period': 2.812,
|
||||
'read0_power': [22.1183],
|
||||
'read1_power': [21.4388],
|
||||
'slew_hl': [0.7397553],
|
||||
'slew_lh': [0.7397553],
|
||||
'write0_power': [19.4103],
|
||||
'write1_power': [20.1167]}
|
||||
else:
|
||||
self.assertTrue(False) # other techs fail
|
||||
# Check if no too many or too few results
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class timing_setup_test(openram_test):
|
|||
data = sh.analyze(slews,slews)
|
||||
#print data
|
||||
if OPTS.tech_name == "freepdk45":
|
||||
golden_data = {'hold_times_HL': [-0.0097656],
|
||||
golden_data = {'hold_times_HL': [-0.0158691],
|
||||
'hold_times_LH': [-0.0158691],
|
||||
'setup_times_HL': [0.026855499999999997],
|
||||
'setup_times_LH': [0.032959]}
|
||||
|
|
|
|||
|
|
@ -51,27 +51,27 @@ class timing_sram_test(openram_test):
|
|||
data.update(port_data[0])
|
||||
|
||||
if OPTS.tech_name == "freepdk45":
|
||||
golden_data = {'delay_hl': [2.625351],
|
||||
'delay_lh': [0.28080869999999997],
|
||||
'leakage_power': 0.001040682,
|
||||
'min_period': 4.844,
|
||||
'read0_power': [0.0553667],
|
||||
'read1_power': [0.05177618],
|
||||
'slew_hl': [0.1099853],
|
||||
'slew_lh': [0.02568626],
|
||||
'write0_power': [0.04517803],
|
||||
'write1_power': [0.04449207]}
|
||||
golden_data = {'delay_hl': [0.20443139999999999],
|
||||
'delay_lh': [0.20443139999999999],
|
||||
'leakage_power': 0.0017840640000000001,
|
||||
'min_period': 0.41,
|
||||
'read0_power': [0.6435831],
|
||||
'read1_power': [0.6233463],
|
||||
'slew_hl': [0.1138734],
|
||||
'slew_lh': [0.1138734],
|
||||
'write0_power': [0.5205761],
|
||||
'write1_power': [0.5213689]}
|
||||
elif OPTS.tech_name == "scn4m_subm":
|
||||
golden_data = {'delay_hl': [6.45408],
|
||||
'delay_lh': [2.0787519999999997],
|
||||
'leakage_power': 0.001177846,
|
||||
'min_period': 9.688,
|
||||
'read0_power': [7.088419],
|
||||
'read1_power': [6.824107000000001],
|
||||
'slew_hl': [0.7980976999999999],
|
||||
'slew_lh': [0.3393389],
|
||||
'write0_power': [5.982207],
|
||||
'write1_power': [6.28866]}
|
||||
golden_data = {'delay_hl': [1.610911],
|
||||
'delay_lh': [1.610911],
|
||||
'leakage_power': 0.0023593859999999998,
|
||||
'min_period': 3.281,
|
||||
'read0_power': [20.763569999999998],
|
||||
'read1_power': [20.32745],
|
||||
'slew_hl': [0.7986348999999999],
|
||||
'slew_lh': [0.7986348999999999],
|
||||
'write0_power': [17.58272],
|
||||
'write1_power': [18.523419999999998]}
|
||||
else:
|
||||
self.assertTrue(False) # other techs fail
|
||||
|
||||
|
|
|
|||
|
|
@ -11,13 +11,14 @@ import globals
|
|||
from globals import OPTS
|
||||
import debug
|
||||
|
||||
@unittest.skip("SKIPPING 22_psram_1bank_2mux_1rw_1r_1w_func_test, third port reads are broken?")
|
||||
#@unittest.skip("SKIPPING 22_psram_1bank_2mux_1rw_1r_1w_func_test, third port reads are broken?")
|
||||
class psram_1bank_2mux_1rw_1r_1w_func_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.netlist_only = True
|
||||
OPTS.trim_netlist = False
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.replica_bitcell="replica_pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
|
|
@ -28,7 +29,7 @@ class psram_1bank_2mux_1rw_1r_1w_func_test(openram_test):
|
|||
from importlib import reload
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import functional
|
||||
from characterizer import functional, delay
|
||||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
|
|
@ -48,8 +49,10 @@ class psram_1bank_2mux_1rw_1r_1w_func_test(openram_test):
|
|||
s.sp_write(tempspice)
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
d = delay(s.s, tempspice, corner)
|
||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
||||
|
||||
f.num_cycles = 10
|
||||
(fail, error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
|
|
|
|||
|
|
@ -11,13 +11,14 @@ import globals
|
|||
from globals import OPTS
|
||||
import debug
|
||||
|
||||
@unittest.skip("SKIPPING 22_psram_1bank_4mux_func_test, third port reads are broken?")
|
||||
#@unittest.skip("SKIPPING 22_psram_1bank_4mux_func_test, third port reads are broken?")
|
||||
class psram_1bank_4mux_func_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.netlist_only = True
|
||||
OPTS.trim_netlist = False
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.replica_bitcell="replica_pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
|
|
@ -28,7 +29,7 @@ class psram_1bank_4mux_func_test(openram_test):
|
|||
from importlib import reload
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import functional
|
||||
from characterizer import functional, delay
|
||||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
|
|
@ -44,12 +45,14 @@ class psram_1bank_4mux_func_test(openram_test):
|
|||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram")
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
d = delay(s.s, tempspice, corner)
|
||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
||||
|
||||
f.num_cycles = 10
|
||||
(fail, error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class psram_1bank_8mux_func_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.netlist_only = True
|
||||
OPTS.trim_netlist = False
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.replica_bitcell="replica_pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
|
|
@ -28,7 +29,7 @@ class psram_1bank_8mux_func_test(openram_test):
|
|||
from importlib import reload
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import functional
|
||||
from characterizer import functional, delay
|
||||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
|
|
@ -44,12 +45,14 @@ class psram_1bank_8mux_func_test(openram_test):
|
|||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram")
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
d = delay(s.s, tempspice, corner)
|
||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
||||
|
||||
f.num_cycles = 10
|
||||
(fail, error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class psram_1bank_nomux_func_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.netlist_only = True
|
||||
OPTS.trim_netlist = False
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.replica_bitcell="replica_pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
|
|
@ -28,7 +29,7 @@ class psram_1bank_nomux_func_test(openram_test):
|
|||
from importlib import reload
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import functional
|
||||
from characterizer import functional, delay
|
||||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
|
|
@ -44,12 +45,14 @@ class psram_1bank_nomux_func_test(openram_test):
|
|||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram")
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
d = delay(s.s, tempspice, corner)
|
||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
||||
|
||||
f.num_cycles = 10
|
||||
(fail, error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
|
|
|
|||
|
|
@ -18,12 +18,13 @@ class sram_1bank_2mux_func_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.netlist_only = True
|
||||
OPTS.trim_netlist = False
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
from importlib import reload
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import functional
|
||||
from characterizer import functional, delay
|
||||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
|
|
@ -40,10 +41,12 @@ class sram_1bank_2mux_func_test(openram_test):
|
|||
s.sp_write(tempspice)
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
d = delay(s.s, tempspice, corner)
|
||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
||||
|
||||
f.num_cycles = 10
|
||||
(fail, error) = f.run()
|
||||
(fail, error) = f.run(feasible_period)
|
||||
self.assertTrue(fail,error)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -18,12 +18,13 @@ class sram_1bank_4mux_func_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.netlist_only = True
|
||||
OPTS.trim_netlist = False
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
from importlib import reload
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import functional
|
||||
from characterizer import functional, delay
|
||||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
|
|
@ -36,12 +37,14 @@ class sram_1bank_4mux_func_test(openram_test):
|
|||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram")
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
d = delay(s.s, tempspice, corner)
|
||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
||||
|
||||
f.num_cycles = 10
|
||||
(fail, error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
|
|
|
|||
|
|
@ -18,12 +18,13 @@ class sram_1bank_8mux_func_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.netlist_only = True
|
||||
OPTS.trim_netlist = False
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
from importlib import reload
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import functional
|
||||
from characterizer import functional, delay
|
||||
if not OPTS.spice_exe:
|
||||
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
|
||||
|
||||
|
|
@ -39,13 +40,14 @@ class sram_1bank_8mux_func_test(openram_test):
|
|||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram")
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
d = delay(s.s, tempspice, corner)
|
||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
||||
|
||||
f.num_cycles = 10
|
||||
(fail, error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class psram_1bank_nomux_func_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.netlist_only = True
|
||||
OPTS.trim_netlist = False
|
||||
OPTS.bitcell = "bitcell_1rw_1r"
|
||||
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
|
||||
OPTS.num_rw_ports = 1
|
||||
|
|
@ -28,7 +29,7 @@ class psram_1bank_nomux_func_test(openram_test):
|
|||
from importlib import reload
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import functional
|
||||
from characterizer import functional, delay
|
||||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
|
|
@ -41,12 +42,14 @@ class psram_1bank_nomux_func_test(openram_test):
|
|||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram")
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
d = delay(s.s, tempspice, corner)
|
||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
||||
|
||||
f.num_cycles = 10
|
||||
(fail, error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ import getpass
|
|||
class openram_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))
|
||||
globals.init_openram("{0}/tests/config_20_{1}".format(OPENRAM_HOME,OPTS.tech_name))
|
||||
|
||||
debug.info(1, "Testing top-level openram.py with 2-bit, 16 word SRAM.")
|
||||
out_file = "testsram"
|
||||
|
|
@ -41,14 +42,16 @@ class openram_test(openram_test):
|
|||
verbosity += " -v"
|
||||
|
||||
|
||||
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))
|
||||
# Always perform code coverage
|
||||
exe_name = "coverage run -p {0}/openram.py ".format(OPENRAM_HOME)
|
||||
cmd = "{0} -n -o {1} -p {2} {3} config_20_{4}.py 2>&1 > {5}/output.log".format(exe_name,
|
||||
if OPTS.coverage == 0:
|
||||
debug.warning("Failed to find coverage installation. This can be installed with pip3 install coverage")
|
||||
exe_name = "coverage run -p {0}/openram.py ".format(OPENRAM_HOME)
|
||||
config_name = "{0}config_20_{1}.py".format(OPENRAM_HOME + "/tests/",OPTS.tech_name)
|
||||
cmd = "{0} -n -o {1} -p {2} {3} {4} 2>&1 > {5}/output.log".format(exe_name,
|
||||
out_file,
|
||||
out_path,
|
||||
verbosity,
|
||||
OPTS.tech_name,
|
||||
config_name,
|
||||
out_path)
|
||||
debug.info(1, cmd)
|
||||
os.system(cmd)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,17 @@ class openram_test(unittest.TestCase):
|
|||
if OPTS.purge_temp:
|
||||
self.cleanup()
|
||||
|
||||
def find_feasible_test_period(self, delay_obj, sram, load, slew):
|
||||
"""Creates a delay simulation to determine a feasible period for the functional tests to run.
|
||||
Only determines the feasible period for a single port and assumes that for all ports for performance.
|
||||
"""
|
||||
debug.info(1, "Finding feasible period for current test.")
|
||||
delay_obj.set_load_slew(load, slew)
|
||||
delay_obj.set_probe(probe_address="1"*sram.addr_size, probe_data=(sram.word_size-1))
|
||||
test_port = delay_obj.read_ports[0] #Only test one port, assumes other ports have similar period.
|
||||
delay_obj.find_feasible_period_one_port(test_port)
|
||||
return delay_obj.period
|
||||
|
||||
def cleanup(self):
|
||||
""" Reset the duplicate checker and cleanup files. """
|
||||
files = glob.glob(OPTS.openram_temp + '*')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
import pstats
|
||||
p = pstats.Stats(‘profile.dat’)
|
||||
p.strip_dirs()
|
||||
p.sort_stats(‘cumulative’)
|
||||
p.print_stats(50)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -6,8 +6,8 @@ MM7 RA_to_R_left Q_bar gnd gnd NMOS_VTG W=180.0n L=50n m=1
|
|||
MM6 RA_to_R_left wl1 bl1 gnd NMOS_VTG W=180.0n L=50n m=1
|
||||
MM5 Q wl0 bl0 gnd NMOS_VTG W=135.00n L=50n m=1
|
||||
MM4 Q_bar wl0 br0 gnd NMOS_VTG W=135.00n L=50n m=1
|
||||
MM1 Q Q_bar gnd gnd NMOS_VTG W=270.0n L=50n m=1
|
||||
MM0 Q_bar Q gnd gnd NMOS_VTG W=270.0n L=50n m=1
|
||||
MM1 Q Q_bar gnd gnd NMOS_VTG W=205.0n L=50n m=1
|
||||
MM0 Q_bar Q gnd gnd NMOS_VTG W=205.0n L=50n m=1
|
||||
MM3 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n m=1
|
||||
MM2 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n m=1
|
||||
.ENDS
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ MM7 RA_to_R_left vdd gnd gnd NMOS_VTG W=180.0n L=50n m=1
|
|||
MM6 RA_to_R_left wl1 bl1 gnd NMOS_VTG W=180.0n L=50n m=1
|
||||
MM5 Q wl0 bl0 gnd NMOS_VTG W=135.00n L=50n m=1
|
||||
MM4 vdd wl0 br0 gnd NMOS_VTG W=135.00n L=50n m=1
|
||||
MM1 Q vdd gnd gnd NMOS_VTG W=270.0n L=50n m=1
|
||||
MM0 vdd Q gnd gnd NMOS_VTG W=270.0n L=50n m=1
|
||||
MM1 Q vdd gnd gnd NMOS_VTG W=205.0n L=50n m=1
|
||||
MM0 vdd Q gnd gnd NMOS_VTG W=205.0n L=50n m=1
|
||||
MM3 Q vdd vdd vdd PMOS_VTG W=90n L=50n m=1
|
||||
MM2 vdd Q vdd vdd PMOS_VTG W=90n L=50n m=1
|
||||
.ENDS
|
||||
|
|
|
|||
|
|
@ -328,6 +328,13 @@ spice["nand2_transition_prob"] = .1875 # Transition probability of 2-input na
|
|||
spice["nand3_transition_prob"] = .1094 # Transition probability of 3-input nand.
|
||||
spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor.
|
||||
|
||||
#Logical Effort relative values for the Handmade cells
|
||||
parameter["dff_clk_cin"] = 30.6 #relative capacitance
|
||||
parameter["6tcell_wl_cin"] = 3 #relative capacitance
|
||||
parameter["min_inv_para_delay"] = .5 #Tau delay units
|
||||
parameter["sa_en_pmos_size"] = .72 #micro-meters
|
||||
parameter["sa_en_nmos_size"] = .27 #micro-meters
|
||||
|
||||
###################################################
|
||||
##END Spice Simulation Parameters
|
||||
###################################################
|
||||
|
|
|
|||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue