Merge branch 'dev' of github.com:VLSIDA/PrivateRAM into dev
|
|
@ -5,3 +5,4 @@
|
||||||
*.out
|
*.out
|
||||||
*.toc
|
*.toc
|
||||||
*.synctex.gz
|
*.synctex.gz
|
||||||
|
**/model_data
|
||||||
17
README.md
|
|
@ -26,19 +26,34 @@ predictive and fabricable technologies.
|
||||||
|
|
||||||
# Basic Setup
|
# Basic Setup
|
||||||
|
|
||||||
|
## Docker Image
|
||||||
|
|
||||||
|
We have a pre-configured Ubuntu [Docker](https://www.docker.com/) image
|
||||||
|
available that has all tools installed for the [SCMOS] process. It is
|
||||||
|
available at [docker hub](https://hub.docker.com/r/vlsida/openram-ubuntu).
|
||||||
|
Please see
|
||||||
|
[our README.md](https://github.com/VLSIDA/openram-docker-images/blob/master/README.md)
|
||||||
|
for information on how to use this docker image.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
The OpenRAM compiler has very few dependencies:
|
The OpenRAM compiler has very few dependencies:
|
||||||
+ [Ngspice] 26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later)
|
+ [Ngspice] 26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later)
|
||||||
+ Python 3.5 or higher
|
+ Python 3.5 or higher
|
||||||
+ Python numpy (pip3 install numpy to install)
|
+ Python numpy (pip3 install numpy to install)
|
||||||
|
+ Python scipy (pip3 install scipy to install)
|
||||||
|
|
||||||
If you want to perform DRC and LVS, you will need either:
|
If you want to perform DRC and LVS, you will need either:
|
||||||
+ Calibre (for [FreePDK45])
|
+ Calibre (for [FreePDK45])
|
||||||
+ [Magic] + [Netgen] (for [SCMOS])
|
+ [Magic] 8.2.79 or higher (for [SCMOS])
|
||||||
|
+ [Netgen] 1.5 (for [SCMOS])
|
||||||
|
|
||||||
You must set two environment variables:
|
You must set two environment variables:
|
||||||
+ OPENRAM\_HOME should point to the compiler source directory.
|
+ OPENRAM\_HOME should point to the compiler source directory.
|
||||||
+ OPENERAM\_TECH should point to a root technology directory.
|
+ OPENERAM\_TECH should point to a root technology directory.
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
|
||||||
For example add this to your .bashrc:
|
For example add this to your .bashrc:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ class contact(hierarchy_design.hierarchy_design):
|
||||||
width=well_width,
|
width=well_width,
|
||||||
height=well_height)
|
height=well_height)
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, corner, load):
|
||||||
""" Get total power of a module """
|
""" Get total power of a module """
|
||||||
return self.return_power()
|
return self.return_power()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,11 +88,11 @@ class design(hierarchy_design):
|
||||||
self.readonly_ports.append(port_number)
|
self.readonly_ports.append(port_number)
|
||||||
port_number += 1
|
port_number += 1
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, corner, load):
|
||||||
""" Get total power of a module """
|
""" Get total power of a module """
|
||||||
total_module_power = self.return_power()
|
total_module_power = self.return_power()
|
||||||
for inst in self.insts:
|
for inst in self.insts:
|
||||||
total_module_power += inst.mod.analytical_power(proc, vdd, temp, load)
|
total_module_power += inst.mod.analytical_power(corner, load)
|
||||||
return total_module_power
|
return total_module_power
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
|
|
||||||
global total_drc_errors
|
global total_drc_errors
|
||||||
global total_lvs_errors
|
global total_lvs_errors
|
||||||
tempspice = OPTS.openram_temp + "/temp.sp"
|
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp,self.name)
|
||||||
tempgds = OPTS.openram_temp + "/temp.gds"
|
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp,self.name)
|
||||||
self.sp_write(tempspice)
|
self.sp_write(tempspice)
|
||||||
self.gds_write(tempgds)
|
self.gds_write(tempgds)
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
|
|
||||||
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
||||||
global total_drc_errors
|
global total_drc_errors
|
||||||
tempgds = OPTS.openram_temp + "/temp.gds"
|
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp,self.name)
|
||||||
self.gds_write(tempgds)
|
self.gds_write(tempgds)
|
||||||
num_errors = verify.run_drc(self.name, tempgds, final_verification)
|
num_errors = verify.run_drc(self.name, tempgds, final_verification)
|
||||||
total_drc_errors += num_errors
|
total_drc_errors += num_errors
|
||||||
|
|
@ -110,8 +110,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
|
|
||||||
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
||||||
global total_lvs_errors
|
global total_lvs_errors
|
||||||
tempspice = OPTS.openram_temp + "/temp.sp"
|
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp,self.name)
|
||||||
tempgds = OPTS.openram_temp + "/temp.gds"
|
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp,self.name)
|
||||||
self.sp_write(tempspice)
|
self.sp_write(tempspice)
|
||||||
self.gds_write(tempgds)
|
self.gds_write(tempgds)
|
||||||
num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification)
|
num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import debug
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import math
|
import math
|
||||||
|
import tech
|
||||||
|
|
||||||
class spice():
|
class spice():
|
||||||
"""
|
"""
|
||||||
|
|
@ -218,7 +219,7 @@ class spice():
|
||||||
del usedMODS
|
del usedMODS
|
||||||
spfile.close()
|
spfile.close()
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
"""Inform users undefined delay module while building new modules"""
|
"""Inform users undefined delay module while building new modules"""
|
||||||
debug.warning("Design Class {0} delay function needs to be defined"
|
debug.warning("Design Class {0} delay function needs to be defined"
|
||||||
.format(self.__class__.__name__))
|
.format(self.__class__.__name__))
|
||||||
|
|
@ -228,13 +229,19 @@ class spice():
|
||||||
# return 0 to keep code running while building
|
# return 0 to keep code running while building
|
||||||
return delay_data(0.0, 0.0)
|
return delay_data(0.0, 0.0)
|
||||||
|
|
||||||
def cal_delay_with_rc(self, r, c ,slew, swing = 0.5):
|
def cal_delay_with_rc(self, corner, r, c ,slew, swing = 0.5):
|
||||||
"""
|
"""
|
||||||
Calculate the delay of a mosfet by
|
Calculate the delay of a mosfet by
|
||||||
modeling it as a resistance driving a capacitance
|
modeling it as a resistance driving a capacitance
|
||||||
"""
|
"""
|
||||||
swing_factor = abs(math.log(1-swing)) # time constant based on swing
|
swing_factor = abs(math.log(1-swing)) # time constant based on swing
|
||||||
|
proc,vdd,temp = corner
|
||||||
|
#FIXME: type of delay is needed to know which process to use.
|
||||||
|
proc_mult = max(self.get_process_delay_factor(proc))
|
||||||
|
volt_mult = self.get_voltage_delay_factor(vdd)
|
||||||
|
temp_mult = self.get_temp_delay_factor(temp)
|
||||||
delay = swing_factor * r * c #c is in ff and delay is in fs
|
delay = swing_factor * r * c #c is in ff and delay is in fs
|
||||||
|
delay = delay * proc_mult * volt_mult * temp_mult
|
||||||
delay = delay * 0.001 #make the unit to ps
|
delay = delay * 0.001 #make the unit to ps
|
||||||
|
|
||||||
# Output slew should be linear to input slew which is described
|
# Output slew should be linear to input slew which is described
|
||||||
|
|
@ -247,6 +254,36 @@ class spice():
|
||||||
slew = delay * 0.6 * 2 + 0.005 * slew
|
slew = delay * 0.6 * 2 + 0.005 * slew
|
||||||
return delay_data(delay = delay, slew = slew)
|
return delay_data(delay = delay, slew = slew)
|
||||||
|
|
||||||
|
def get_process_delay_factor(self, proc):
|
||||||
|
"""Returns delay increase estimate based off process
|
||||||
|
Currently does +/-10 for fast/slow corners."""
|
||||||
|
proc_factors = []
|
||||||
|
for mos_proc in proc:
|
||||||
|
if mos_proc == 'T':
|
||||||
|
proc_factors.append(1.0)
|
||||||
|
elif mos_proc == 'F':
|
||||||
|
proc_factors.append(0.9)
|
||||||
|
elif mos_proc == 'S':
|
||||||
|
proc_factors.append(1.1)
|
||||||
|
return proc_factors
|
||||||
|
|
||||||
|
def get_voltage_delay_factor(self, voltage):
|
||||||
|
"""Returns delay increase due to voltage.
|
||||||
|
Implemented as linear factor based off nominal voltage.
|
||||||
|
"""
|
||||||
|
return tech.spice['vdd_nominal']/voltage
|
||||||
|
|
||||||
|
def get_temp_delay_factor(self, temp):
|
||||||
|
"""Returns delay increase due to temperature (in C).
|
||||||
|
Determines effect on threshold voltage and then linear factor is estimated.
|
||||||
|
"""
|
||||||
|
#Some portions of equation condensed (phi_t = k*T/q for T in Kelvin) in mV
|
||||||
|
#(k/q)/100 = .008625, The division 100 simplifies the conversion from C to K and mV to V
|
||||||
|
thermal_voltage_nom = .008625*tech.spice["temp_nominal"]
|
||||||
|
thermal_voltage = .008625*temp
|
||||||
|
vthresh = (tech.spice["v_threshold_typical"]+2*(thermal_voltage-thermal_voltage_nom))
|
||||||
|
#Calculate effect on Vdd-Vth. The current vdd is not used here. A separate vdd factor is calculated.
|
||||||
|
return (tech.spice['vdd_nominal'] - tech.spice["v_threshold_typical"])/(tech.spice['vdd_nominal']-vthresh)
|
||||||
|
|
||||||
def return_delay(self, delay, slew):
|
def return_delay(self, delay, slew):
|
||||||
return delay_data(delay, slew)
|
return delay_data(delay, slew)
|
||||||
|
|
@ -254,6 +291,22 @@ class spice():
|
||||||
def generate_rc_net(self,lump_num, wire_length, wire_width):
|
def generate_rc_net(self,lump_num, wire_length, wire_width):
|
||||||
return wire_spice_model(lump_num, wire_length, wire_width)
|
return wire_spice_model(lump_num, wire_length, wire_width)
|
||||||
|
|
||||||
|
def calc_dynamic_power(self, corner, c, freq, swing=1.0):
|
||||||
|
"""
|
||||||
|
Calculate dynamic power using effective capacitance, frequency, and corner (PVT)
|
||||||
|
"""
|
||||||
|
proc,vdd,temp = corner
|
||||||
|
net_vswing = vdd*swing
|
||||||
|
power_dyn = c*vdd*net_vswing*freq
|
||||||
|
|
||||||
|
#Apply process and temperature factors. Roughly, process and Vdd affect the delay which affects the power.
|
||||||
|
#No other estimations are currently used. Increased delay->slower freq.->less power
|
||||||
|
proc_div = max(self.get_process_delay_factor(proc))
|
||||||
|
temp_div = self.get_temp_delay_factor(temp)
|
||||||
|
power_dyn = power_dyn/(proc_div*temp_div)
|
||||||
|
|
||||||
|
return power_dyn
|
||||||
|
|
||||||
def return_power(self, dynamic=0.0, leakage=0.0):
|
def return_power(self, dynamic=0.0, leakage=0.0):
|
||||||
return power_data(dynamic, leakage)
|
return power_data(dynamic, leakage)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class bitcell(design.design):
|
||||||
self.height = bitcell.height
|
self.height = bitcell.height
|
||||||
self.pin_map = bitcell.pin_map
|
self.pin_map = bitcell.pin_map
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0, swing = 0.5):
|
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
|
||||||
# delay of bit cell is not like a driver(from WL)
|
# delay of bit cell is not like a driver(from WL)
|
||||||
# so the slew used should be 0
|
# so the slew used should be 0
|
||||||
# it should not be slew dependent?
|
# it should not be slew dependent?
|
||||||
|
|
@ -33,7 +33,7 @@ class bitcell(design.design):
|
||||||
from tech import spice
|
from tech import spice
|
||||||
r = spice["min_tx_r"]*3
|
r = spice["min_tx_r"]*3
|
||||||
c_para = spice["min_tx_drain_c"]
|
c_para = spice["min_tx_drain_c"]
|
||||||
result = self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew, swing = swing)
|
result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = swing)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -66,7 +66,7 @@ class bitcell(design.design):
|
||||||
column_pins = ["br"]
|
column_pins = ["br"]
|
||||||
return column_pins
|
return column_pins
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Bitcell power in nW. Only characterizes leakage."""
|
"""Bitcell power in nW. Only characterizes leakage."""
|
||||||
from tech import spice
|
from tech import spice
|
||||||
leakage = spice["bitcell_leakage"]
|
leakage = spice["bitcell_leakage"]
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class bitcell_1rw_1r(design.design):
|
||||||
self.height = bitcell_1rw_1r.height
|
self.height = bitcell_1rw_1r.height
|
||||||
self.pin_map = bitcell_1rw_1r.pin_map
|
self.pin_map = bitcell_1rw_1r.pin_map
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0, swing = 0.5):
|
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
|
||||||
# delay of bit cell is not like a driver(from WL)
|
# delay of bit cell is not like a driver(from WL)
|
||||||
# so the slew used should be 0
|
# so the slew used should be 0
|
||||||
# it should not be slew dependent?
|
# it should not be slew dependent?
|
||||||
|
|
@ -33,7 +33,7 @@ class bitcell_1rw_1r(design.design):
|
||||||
from tech import spice
|
from tech import spice
|
||||||
r = spice["min_tx_r"]*3
|
r = spice["min_tx_r"]*3
|
||||||
c_para = spice["min_tx_drain_c"]
|
c_para = spice["min_tx_drain_c"]
|
||||||
result = self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew, swing = swing)
|
result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = swing)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -89,7 +89,7 @@ class bitcell_1rw_1r(design.design):
|
||||||
column_pins = ["br0"]
|
column_pins = ["br0"]
|
||||||
return column_pins
|
return column_pins
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Bitcell power in nW. Only characterizes leakage."""
|
"""Bitcell power in nW. Only characterizes leakage."""
|
||||||
from tech import spice
|
from tech import spice
|
||||||
leakage = spice["bitcell_leakage"]
|
leakage = spice["bitcell_leakage"]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
import design
|
||||||
|
import debug
|
||||||
|
import utils
|
||||||
|
from tech import GDS,layer,parameter,drc
|
||||||
|
|
||||||
|
class bitcell_1w_1r(design.design):
|
||||||
|
"""
|
||||||
|
A single bit cell (6T, 8T, etc.) This module implements the
|
||||||
|
single memory cell used in the design. It is a hand-made cell, so
|
||||||
|
the layout and netlist should be available in the technology
|
||||||
|
library.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
|
||||||
|
(width,height) = utils.get_libcell_size("cell_1w_1r", GDS["unit"], layer["boundary"])
|
||||||
|
pin_map = utils.get_libcell_pins(pin_names, "cell_1w_1r", GDS["unit"])
|
||||||
|
|
||||||
|
def __init__(self, name=""):
|
||||||
|
# Ignore the name argument
|
||||||
|
design.design.__init__(self, "cell_1w_1r")
|
||||||
|
debug.info(2, "Create bitcell with 1W and 1R Port")
|
||||||
|
|
||||||
|
self.width = bitcell_1w_1r.width
|
||||||
|
self.height = bitcell_1w_1r.height
|
||||||
|
self.pin_map = bitcell_1w_1r.pin_map
|
||||||
|
|
||||||
|
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
|
||||||
|
# delay of bit cell is not like a driver(from WL)
|
||||||
|
# so the slew used should be 0
|
||||||
|
# it should not be slew dependent?
|
||||||
|
# because the value is there
|
||||||
|
# the delay is only over half transsmission gate
|
||||||
|
from tech import spice
|
||||||
|
r = spice["min_tx_r"]*3
|
||||||
|
c_para = spice["min_tx_drain_c"]
|
||||||
|
result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = swing)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def list_bitcell_pins(self, col, row):
|
||||||
|
""" Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """
|
||||||
|
bitcell_pins = ["bl0_{0}".format(col),
|
||||||
|
"br0_{0}".format(col),
|
||||||
|
"bl1_{0}".format(col),
|
||||||
|
"br1_{0}".format(col),
|
||||||
|
"wl0_{0}".format(row),
|
||||||
|
"wl1_{0}".format(row),
|
||||||
|
"vdd",
|
||||||
|
"gnd"]
|
||||||
|
return bitcell_pins
|
||||||
|
|
||||||
|
def list_all_wl_names(self):
|
||||||
|
""" Creates a list of all wordline pin names """
|
||||||
|
row_pins = ["wl0", "wl1"]
|
||||||
|
return row_pins
|
||||||
|
|
||||||
|
def list_all_bitline_names(self):
|
||||||
|
""" Creates a list of all bitline pin names (both bl and br) """
|
||||||
|
column_pins = ["bl0", "br0", "bl1", "br1"]
|
||||||
|
return column_pins
|
||||||
|
|
||||||
|
def list_all_bl_names(self):
|
||||||
|
""" Creates a list of all bl pins names """
|
||||||
|
column_pins = ["bl0", "bl1"]
|
||||||
|
return column_pins
|
||||||
|
|
||||||
|
def list_all_br_names(self):
|
||||||
|
""" Creates a list of all br pins names """
|
||||||
|
column_pins = ["br0", "br1"]
|
||||||
|
return column_pins
|
||||||
|
|
||||||
|
def list_read_bl_names(self):
|
||||||
|
""" Creates a list of bl pin names associated with read ports """
|
||||||
|
column_pins = ["bl0", "bl1"]
|
||||||
|
return column_pins
|
||||||
|
|
||||||
|
def list_read_br_names(self):
|
||||||
|
""" Creates a list of br pin names associated with read ports """
|
||||||
|
column_pins = ["br0", "br1"]
|
||||||
|
return column_pins
|
||||||
|
|
||||||
|
def list_write_bl_names(self):
|
||||||
|
""" Creates a list of bl pin names associated with write ports """
|
||||||
|
column_pins = ["bl0"]
|
||||||
|
return column_pins
|
||||||
|
|
||||||
|
def list_write_br_names(self):
|
||||||
|
""" Creates a list of br pin names asscociated with write ports"""
|
||||||
|
column_pins = ["br0"]
|
||||||
|
return column_pins
|
||||||
|
|
||||||
|
def analytical_power(self, corner, load):
|
||||||
|
"""Bitcell power in nW. Only characterizes leakage."""
|
||||||
|
from tech import spice
|
||||||
|
leakage = spice["bitcell_leakage"]
|
||||||
|
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"""
|
||||||
|
#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
|
||||||
|
|
@ -866,15 +866,15 @@ class pbitcell(design.design):
|
||||||
vdd_pos = self.inverter_pmos_right.get_pin("D").center()
|
vdd_pos = self.inverter_pmos_right.get_pin("D").center()
|
||||||
self.add_path("metal1", [Q_bar_pos, vdd_pos])
|
self.add_path("metal1", [Q_bar_pos, vdd_pos])
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0, swing = 0.5):
|
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
|
||||||
#FIXME: Delay copied exactly over from bitcell
|
#FIXME: Delay copied exactly over from bitcell
|
||||||
from tech import spice
|
from tech import spice
|
||||||
r = spice["min_tx_r"]*3
|
r = spice["min_tx_r"]*3
|
||||||
c_para = spice["min_tx_drain_c"]
|
c_para = spice["min_tx_drain_c"]
|
||||||
result = self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew, swing = swing)
|
result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = swing)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Bitcell power in nW. Only characterizes leakage."""
|
"""Bitcell power in nW. Only characterizes leakage."""
|
||||||
from tech import spice
|
from tech import spice
|
||||||
leakage = spice["bitcell_leakage"]
|
leakage = spice["bitcell_leakage"]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import design
|
||||||
|
import debug
|
||||||
|
import utils
|
||||||
|
from tech import GDS,layer,drc,parameter
|
||||||
|
|
||||||
|
class replica_bitcell_1w_1r(design.design):
|
||||||
|
"""
|
||||||
|
A single bit cell which is forced to store a 0.
|
||||||
|
This module implements the single memory cell used in the design. It
|
||||||
|
is a hand-made cell, so the layout and netlist should be available in
|
||||||
|
the technology library. """
|
||||||
|
|
||||||
|
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
|
||||||
|
(width,height) = utils.get_libcell_size("replica_cell_1w_1r", GDS["unit"], layer["boundary"])
|
||||||
|
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1w_1r", GDS["unit"])
|
||||||
|
|
||||||
|
def __init__(self, name=""):
|
||||||
|
# Ignore the name argument
|
||||||
|
design.design.__init__(self, "replica_cell_1w_1r")
|
||||||
|
debug.info(2, "Create replica bitcell 1w+1r object")
|
||||||
|
|
||||||
|
self.width = replica_bitcell_1w_1r.width
|
||||||
|
self.height = replica_bitcell_1w_1r.height
|
||||||
|
self.pin_map = replica_bitcell_1w_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
|
||||||
|
|
@ -9,6 +9,8 @@ from .functional import *
|
||||||
from .worst_case import *
|
from .worst_case import *
|
||||||
from .simulation import *
|
from .simulation import *
|
||||||
from .bitline_delay import *
|
from .bitline_delay import *
|
||||||
|
from .measurements import *
|
||||||
|
from .model_check import *
|
||||||
|
|
||||||
debug.info(1,"Initializing characterizer...")
|
debug.info(1,"Initializing characterizer...")
|
||||||
OPTS.spice_exe = ""
|
OPTS.spice_exe = ""
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,23 @@ class bitline_delay(delay):
|
||||||
self.period = tech.spice["feasible_period"]
|
self.period = tech.spice["feasible_period"]
|
||||||
self.is_bitline_measure = True
|
self.is_bitline_measure = True
|
||||||
|
|
||||||
|
def create_signal_names(self):
|
||||||
|
delay.create_signal_names(self)
|
||||||
|
self.bl_signal_names = ["Xsram.Xbank0.bl", "Xsram.Xbank0.br"]
|
||||||
|
self.sen_name = "Xsram.s_en"
|
||||||
|
|
||||||
def create_measurement_names(self):
|
def create_measurement_names(self):
|
||||||
"""Create measurement names. The names themselves currently define the type of measurement"""
|
"""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.
|
#Altering the names will crash the characterizer. TODO: object orientated approach to the measurements.
|
||||||
self.bitline_meas_names = ["bl_volt", "br_volt"]
|
self.bl_volt_meas_names = ["volt_bl", "volt_br"]
|
||||||
|
self.bl_delay_meas_names = ["delay_bl", "delay_br"] #only used in SPICE simulation
|
||||||
|
self.bl_delay_result_name = "delay_bl_vth" #Used in the return value
|
||||||
|
|
||||||
|
def set_probe(self,probe_address, probe_data):
|
||||||
|
""" Probe address and data can be set separately to utilize other
|
||||||
|
functions in this characterizer besides analyze."""
|
||||||
|
delay.set_probe(self,probe_address, probe_data)
|
||||||
|
self.bitline_column = self.get_data_bit_column_number(probe_address, probe_data)
|
||||||
|
|
||||||
def write_delay_measures(self):
|
def write_delay_measures(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -38,26 +51,52 @@ class bitline_delay(delay):
|
||||||
self.sf.write("* {}\n".format(comment))
|
self.sf.write("* {}\n".format(comment))
|
||||||
|
|
||||||
for read_port in self.targ_read_ports:
|
for read_port in self.targ_read_ports:
|
||||||
self.write_bitline_measures_read_port(read_port)
|
self.write_bitline_voltage_measures(read_port)
|
||||||
|
self.write_bitline_delay_measures(read_port)
|
||||||
|
|
||||||
def write_bitline_measures_read_port(self, port):
|
def write_bitline_voltage_measures(self, port):
|
||||||
|
"""
|
||||||
|
Add measurments to capture the bitline voltages at 50% Sense amp enable
|
||||||
|
"""
|
||||||
|
debug.info(2, "Measuring bitline column={}, port={}".format(self.bitline_column,port))
|
||||||
|
if len(self.all_ports) == 1: #special naming case for single port sram bitlines
|
||||||
|
bitline_port = ""
|
||||||
|
else:
|
||||||
|
bitline_port = str(port)
|
||||||
|
|
||||||
|
sen_port_name = "{}{}".format(self.sen_name,port)
|
||||||
|
for (measure_name, bl_signal_name) in zip(self.bl_volt_meas_names, self.bl_signal_names):
|
||||||
|
bl_port_name = "{}{}_{}".format(bl_signal_name, bitline_port, self.bitline_column)
|
||||||
|
measure_port_name = "{}{}".format(measure_name,port)
|
||||||
|
self.stim.gen_meas_find_voltage(measure_port_name, sen_port_name, bl_port_name, .5, "RISE", self.cycle_times[self.measure_cycles[port]["read0"]])
|
||||||
|
|
||||||
|
def write_bitline_delay_measures(self, port):
|
||||||
"""
|
"""
|
||||||
Write the measure statements to quantify the delay and power results for a read port.
|
Write the measure statements to quantify the delay and power results for a read port.
|
||||||
"""
|
"""
|
||||||
# add measure statements for delays/slews
|
# add measure statements for delays/slews
|
||||||
measure_bitline = self.get_data_bit_column_number(self.probe_address, self.probe_data)
|
for (measure_name, bl_signal_name) in zip(self.bl_delay_meas_names, self.bl_signal_names):
|
||||||
debug.info(2, "Measuring bitline column={}".format(measure_bitline))
|
meas_values = self.get_delay_meas_values(measure_name, bl_signal_name, port)
|
||||||
for port in self.targ_read_ports:
|
self.stim.gen_meas_delay(*meas_values)
|
||||||
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)
|
def get_delay_meas_values(self, delay_name, bitline_name, port):
|
||||||
bl_name = "Xsram.Xbank0.bl{}_{}".format(bitline_port, measure_bitline)
|
"""Get the values needed to generate a Spice measurement statement based on the name of the measurement."""
|
||||||
br_name = "Xsram.Xbank0.br{}_{}".format(bitline_port, measure_bitline)
|
if len(self.all_ports) == 1: #special naming case for single port sram bitlines
|
||||||
self.stim.gen_meas_find_voltage("bl_volt", sen_name, bl_name, .5, "RISE", self.cycle_times[self.measure_cycles[port]["read0"]])
|
bitline_port = ""
|
||||||
self.stim.gen_meas_find_voltage("br_volt", sen_name, br_name, .5, "RISE", self.cycle_times[self.measure_cycles[port]["read0"]])
|
else:
|
||||||
|
bitline_port = str(port)
|
||||||
|
|
||||||
|
meas_name="{0}{1}".format(delay_name, port)
|
||||||
|
targ_name = "{0}{1}_{2}".format(bitline_name,bitline_port,self.bitline_column)
|
||||||
|
half_vdd = 0.5 * self.vdd_voltage
|
||||||
|
trig_val = half_vdd
|
||||||
|
targ_val = self.vdd_voltage-tech.spice["v_threshold_typical"]
|
||||||
|
trig_name = "clk{0}".format(port)
|
||||||
|
trig_dir="FALL"
|
||||||
|
targ_dir="FALL"
|
||||||
|
#Half period added to delay measurement to negative clock edge
|
||||||
|
trig_td = targ_td = self.cycle_times[self.measure_cycles[port]["read0"]] + self.period/2
|
||||||
|
return (meas_name,trig_name,targ_name,trig_val,targ_val,trig_dir,targ_dir,trig_td,targ_td)
|
||||||
|
|
||||||
def gen_test_cycles_one_port(self, read_port, write_port):
|
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)
|
"""Sets a list of key time-points [ns] of the waveform (each rising edge)
|
||||||
|
|
@ -89,6 +128,7 @@ class bitline_delay(delay):
|
||||||
self.add_read("R data 0 address {} to check W0 worked".format(self.probe_address),
|
self.add_read("R data 0 address {} to check W0 worked".format(self.probe_address),
|
||||||
self.probe_address,data_zeros,read_port)
|
self.probe_address,data_zeros,read_port)
|
||||||
self.measure_cycles[read_port]["read0"] = len(self.cycle_times)-1
|
self.measure_cycles[read_port]["read0"] = len(self.cycle_times)-1
|
||||||
|
|
||||||
def get_data_bit_column_number(self, probe_address, probe_data):
|
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"""
|
"""Calculates bitline column number of data bit under test using bit position and mux size"""
|
||||||
if self.sram.col_addr_size>0:
|
if self.sram.col_addr_size>0:
|
||||||
|
|
@ -115,19 +155,70 @@ class bitline_delay(delay):
|
||||||
self.stim.run_sim() #running sim prodoces spice output file.
|
self.stim.run_sim() #running sim prodoces spice output file.
|
||||||
|
|
||||||
for port in self.targ_read_ports:
|
for port in self.targ_read_ports:
|
||||||
bitlines_meas_vals = {}
|
#Parse and check the voltage measurements
|
||||||
for mname in self.bitline_meas_names:
|
bl_volt_meas_dict = {}
|
||||||
bitlines_meas_vals[mname] = parse_spice_list("timing", mname)
|
for mname in self.bl_volt_meas_names:
|
||||||
#Check that power parsing worked.
|
mname_port = "{}{}".format(mname,port)
|
||||||
for name, val in bitlines_meas_vals.items():
|
volt_meas_val = parse_spice_list("timing", mname_port)
|
||||||
if type(val)!=float:
|
if type(volt_meas_val)!=float:
|
||||||
debug.error("Failed to Parse Bitline Values:\n\t\t{0}".format(bitlines_meas_vals),1) #Printing the entire dict looks bad.
|
debug.error("Failed to Parse Bitline Voltage:\n\t\t{0}={1}".format(mname,volt_meas_val),1)
|
||||||
result[port].update(bitlines_meas_vals)
|
bl_volt_meas_dict[mname] = volt_meas_val
|
||||||
|
result[port].update(bl_volt_meas_dict)
|
||||||
|
|
||||||
|
#Parse and check the delay measurements. Intended that one measurement will fail, save the delay that did not fail.
|
||||||
|
bl_delay_meas_dict = {}
|
||||||
|
values_added = 0 #For error checking
|
||||||
|
for mname in self.bl_delay_meas_names: #Parse
|
||||||
|
mname_port = "{}{}".format(mname,port)
|
||||||
|
delay_meas_val = parse_spice_list("timing", mname_port)
|
||||||
|
if type(delay_meas_val)==float: #Only add if value is float, do not error.
|
||||||
|
bl_delay_meas_dict[self.bl_delay_result_name] = delay_meas_val * 1e9 #convert to ns
|
||||||
|
values_added+=1
|
||||||
|
debug.check(values_added>0, "Bitline delay measurements failed in SPICE simulation.")
|
||||||
|
debug.check(values_added<2, "Both bitlines experienced a Vth drop, check simulation results.")
|
||||||
|
result[port].update(bl_delay_meas_dict)
|
||||||
|
|
||||||
# The delay is from the negative edge for our SRAM
|
# The delay is from the negative edge for our SRAM
|
||||||
return (True,result)
|
return (True,result)
|
||||||
|
|
||||||
|
def check_bitline_all_results(self, results):
|
||||||
|
"""Checks the bitline values measured for each tested port"""
|
||||||
|
for port in self.targ_read_ports:
|
||||||
|
self.check_bitline_port_results(results[port])
|
||||||
|
|
||||||
|
def check_bitline_port_results(self, port_results):
|
||||||
|
"""Performs three different checks for the bitline values: functionality, bitline swing from vdd, and differential bit swing"""
|
||||||
|
bl_volt, br_volt = port_results["volt_bl"], port_results["volt_br"]
|
||||||
|
self.check_functionality(bl_volt,br_volt)
|
||||||
|
self.check_swing_from_vdd(bl_volt,br_volt)
|
||||||
|
self.check_differential_swing(bl_volt,br_volt)
|
||||||
|
|
||||||
|
def check_functionality(self, bl_volt, br_volt):
|
||||||
|
"""Checks whether the read failed or not. Measured values are hardcoded with the intention of reading a 0."""
|
||||||
|
if bl_volt > br_volt:
|
||||||
|
debug.error("Read failure. Value 1 was read instead of 0.",1)
|
||||||
|
|
||||||
|
def check_swing_from_vdd(self, bl_volt, br_volt):
|
||||||
|
"""Checks difference on discharging bitline from VDD to see if it is within margin of the RBL height parameter."""
|
||||||
|
if bl_volt < br_volt:
|
||||||
|
discharge_volt = bl_volt
|
||||||
|
else:
|
||||||
|
discharge_volt = br_volt
|
||||||
|
desired_bl_volt = tech.parameter["rbl_height_percentage"]*self.vdd_voltage
|
||||||
|
debug.info(1, "Active bitline={:.3f}v, Desired bitline={:.3f}v".format(discharge_volt,desired_bl_volt))
|
||||||
|
vdd_error_margin = .2 #20% of vdd margin for bitline, a little high for now.
|
||||||
|
if abs(discharge_volt - desired_bl_volt) > vdd_error_margin*self.vdd_voltage:
|
||||||
|
debug.warning("Bitline voltage is not within {}% Vdd margin. Delay chain/RBL could need resizing.".format(vdd_error_margin*100))
|
||||||
|
|
||||||
|
def check_differential_swing(self, bl_volt, br_volt):
|
||||||
|
"""This check looks at the difference between the bitline voltages. This needs to be large enough to prevent
|
||||||
|
sensing errors."""
|
||||||
|
bitline_swing = abs(bl_volt-br_volt)
|
||||||
|
debug.info(1,"Bitline swing={:.3f}v".format(bitline_swing))
|
||||||
|
vdd_error_margin = .2 #20% of vdd margin for bitline, a little high for now.
|
||||||
|
if bitline_swing < vdd_error_margin*self.vdd_voltage:
|
||||||
|
debug.warning("Bitline swing less than {}% Vdd margin. Sensing errors more likely to occur.".format(vdd_error_margin))
|
||||||
|
|
||||||
def analyze(self, probe_address, probe_data, slews, loads):
|
def analyze(self, probe_address, probe_data, slews, loads):
|
||||||
"""Measures the bitline swing of the differential bitlines (bl/br) at 50% s_en """
|
"""Measures the bitline swing of the differential bitlines (bl/br) at 50% s_en """
|
||||||
self.set_probe(probe_address, probe_data)
|
self.set_probe(probe_address, probe_data)
|
||||||
|
|
@ -141,10 +232,10 @@ class bitline_delay(delay):
|
||||||
debug.info(1,"Bitline swing test: corner {}".format(self.corner))
|
debug.info(1,"Bitline swing test: corner {}".format(self.corner))
|
||||||
(success, results)=self.run_delay_simulation()
|
(success, results)=self.run_delay_simulation()
|
||||||
debug.check(success, "Bitline Failed: period {}".format(self.period))
|
debug.check(success, "Bitline Failed: period {}".format(self.period))
|
||||||
for mname in self.bitline_meas_names:
|
debug.info(1,"Bitline values (voltages/delays):\n\t {}".format(results[read_port]))
|
||||||
bitline_swings[mname] = results[read_port][mname]
|
self.check_bitline_all_results(results)
|
||||||
debug.info(1,"Bitline values (bl/br): {}".format(bitline_swings))
|
|
||||||
return bitline_swings
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,3 +80,10 @@ def convert_to_float(number):
|
||||||
debug.error("Invalid number: {0}".format(number),1)
|
debug.error("Invalid number: {0}".format(number),1)
|
||||||
|
|
||||||
return float_value
|
return float_value
|
||||||
|
|
||||||
|
def check_dict_values_is_float(dict):
|
||||||
|
"""Checks if all the values are floats. Useful for checking failed Spice measurements."""
|
||||||
|
for key, value in dict.items():
|
||||||
|
if type(value)!=float:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
@ -8,6 +8,7 @@ from .charutils import *
|
||||||
import utils
|
import utils
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from .simulation import simulation
|
from .simulation import simulation
|
||||||
|
from .measurements import *
|
||||||
|
|
||||||
class delay(simulation):
|
class delay(simulation):
|
||||||
"""Functions to measure the delay and power of an SRAM at a given address and
|
"""Functions to measure the delay and power of an SRAM at a given address and
|
||||||
|
|
@ -35,16 +36,91 @@ class delay(simulation):
|
||||||
self.period = 0
|
self.period = 0
|
||||||
self.set_load_slew(0,0)
|
self.set_load_slew(0,0)
|
||||||
self.set_corner(corner)
|
self.set_corner(corner)
|
||||||
self.create_signal_names()
|
|
||||||
|
|
||||||
#Create global measure names. Should maybe be an input at some point.
|
|
||||||
self.create_measurement_names()
|
|
||||||
|
|
||||||
def create_measurement_names(self):
|
def create_measurement_names(self):
|
||||||
"""Create measurement names. The names themselves currently define the type of measurement"""
|
"""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.
|
#Altering the names will crash the characterizer. TODO: object orientated approach to the measurements.
|
||||||
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
|
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
|
||||||
self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"]
|
self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"]
|
||||||
|
self.voltage_when_names = ["volt_bl", "volt_br"]
|
||||||
|
self.bitline_delay_names = ["delay_bl", "delay_br"]
|
||||||
|
|
||||||
|
def create_measurement_objects(self):
|
||||||
|
"""Create the measurements used for read and write ports"""
|
||||||
|
self.create_read_port_measurement_objects()
|
||||||
|
self.create_write_port_measurement_objects()
|
||||||
|
|
||||||
|
def create_read_port_measurement_objects(self):
|
||||||
|
"""Create the measurements used for read ports: delays, slews, powers"""
|
||||||
|
|
||||||
|
self.read_meas_objs = []
|
||||||
|
trig_delay_name = "clk{0}"
|
||||||
|
targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) #Empty values are the port and probe data bit
|
||||||
|
self.read_meas_objs.append(delay_measure("delay_lh", trig_delay_name, targ_name, "RISE", "RISE", measure_scale=1e9))
|
||||||
|
self.read_meas_objs[-1].meta_str = "read1" #Used to index time delay values when measurements written to spice file.
|
||||||
|
self.read_meas_objs.append(delay_measure("delay_hl", trig_delay_name, targ_name, "FALL", "FALL", measure_scale=1e9))
|
||||||
|
self.read_meas_objs[-1].meta_str = "read0"
|
||||||
|
|
||||||
|
self.read_meas_objs.append(slew_measure("slew_lh", targ_name, "RISE", measure_scale=1e9))
|
||||||
|
self.read_meas_objs[-1].meta_str = "read1"
|
||||||
|
self.read_meas_objs.append(slew_measure("slew_hl", targ_name, "FALL", measure_scale=1e9))
|
||||||
|
self.read_meas_objs[-1].meta_str = "read0"
|
||||||
|
|
||||||
|
self.read_meas_objs.append(power_measure("read1_power", "RISE", measure_scale=1e3))
|
||||||
|
self.read_meas_objs[-1].meta_str = "read1"
|
||||||
|
self.read_meas_objs.append(power_measure("read0_power", "FALL", measure_scale=1e3))
|
||||||
|
self.read_meas_objs[-1].meta_str = "read0"
|
||||||
|
|
||||||
|
#This will later add a half-period to the spice time delay. Only for reading 0.
|
||||||
|
for obj in self.read_meas_objs:
|
||||||
|
if obj.meta_str is "read0":
|
||||||
|
obj.meta_add_delay = True
|
||||||
|
|
||||||
|
trig_name = "Xsram.s_en{}" #Sense amp enable
|
||||||
|
if len(self.all_ports) == 1: #special naming case for single port sram bitlines which does not include the port in name
|
||||||
|
port_format = ""
|
||||||
|
else:
|
||||||
|
port_format = "{}"
|
||||||
|
|
||||||
|
bl_name = "Xsram.Xbank0.bl{}_{}".format(port_format, self.bitline_column)
|
||||||
|
br_name = "Xsram.Xbank0.br{}_{}".format(port_format, self.bitline_column)
|
||||||
|
self.read_meas_objs.append(voltage_when_measure(self.voltage_when_names[0], trig_name, bl_name, "RISE", .5))
|
||||||
|
self.read_meas_objs.append(voltage_when_measure(self.voltage_when_names[1], trig_name, br_name, "RISE", .5))
|
||||||
|
|
||||||
|
#These are read values but need to be separated for unique error checking.
|
||||||
|
self.create_bitline_delay_measurement_objects()
|
||||||
|
|
||||||
|
def create_bitline_delay_measurement_objects(self):
|
||||||
|
"""Create the measurements used for bitline delay values. Due to unique error checking, these are separated from other measurements.
|
||||||
|
These measurements are only associated with read values
|
||||||
|
"""
|
||||||
|
self.bitline_delay_objs = []
|
||||||
|
trig_name = "clk{0}"
|
||||||
|
if len(self.all_ports) == 1: #special naming case for single port sram bitlines which does not include the port in name
|
||||||
|
port_format = ""
|
||||||
|
else:
|
||||||
|
port_format = "{}"
|
||||||
|
bl_name = "Xsram.Xbank0.bl{}_{}".format(port_format, self.bitline_column)
|
||||||
|
br_name = "Xsram.Xbank0.br{}_{}".format(port_format, self.bitline_column)
|
||||||
|
targ_val = (self.vdd_voltage - tech.spice["v_threshold_typical"])/self.vdd_voltage #Calculate as a percentage of vdd
|
||||||
|
|
||||||
|
targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) #Empty values are the port and probe data bit
|
||||||
|
self.bitline_delay_objs.append(delay_measure(self.bitline_delay_names[0], trig_name, bl_name, "FALL", "FALL", targ_vdd=targ_val, measure_scale=1e9))
|
||||||
|
self.bitline_delay_objs[-1].meta_str = "read0"
|
||||||
|
self.bitline_delay_objs.append(delay_measure(self.bitline_delay_names[1], trig_name, br_name, "FALL", "FALL", targ_vdd=targ_val, measure_scale=1e9))
|
||||||
|
self.bitline_delay_objs[-1].meta_str = "read1"
|
||||||
|
#Enforces the time delay on the bitline measurements for read0 or read1
|
||||||
|
for obj in self.bitline_delay_objs:
|
||||||
|
obj.meta_add_delay = True
|
||||||
|
|
||||||
|
def create_write_port_measurement_objects(self):
|
||||||
|
"""Create the measurements used for read ports: delays, slews, powers"""
|
||||||
|
self.write_meas_objs = []
|
||||||
|
|
||||||
|
self.write_meas_objs.append(power_measure("write1_power", "RISE", measure_scale=1e3))
|
||||||
|
self.write_meas_objs[-1].meta_str = "write1"
|
||||||
|
self.write_meas_objs.append(power_measure("write0_power", "FALL", measure_scale=1e3))
|
||||||
|
self.write_meas_objs[-1].meta_str = "write0"
|
||||||
|
|
||||||
def create_signal_names(self):
|
def create_signal_names(self):
|
||||||
self.addr_name = "A"
|
self.addr_name = "A"
|
||||||
|
|
@ -198,86 +274,75 @@ class delay(simulation):
|
||||||
|
|
||||||
self.sf.close()
|
self.sf.close()
|
||||||
|
|
||||||
def get_delay_meas_values(self, delay_name, port):
|
def get_read_measure_variants(self, port, measure_obj):
|
||||||
"""Get the values needed to generate a Spice measurement statement based on the name of the measurement."""
|
"""Checks the measurement object and calls respective function for related measurement inputs."""
|
||||||
debug.check('lh' in delay_name or 'hl' in delay_name, "Measure command {0} does not contain direction (lh/hl)")
|
meas_type = type(measure_obj)
|
||||||
trig_clk_name = "clk{0}".format(port)
|
if meas_type is delay_measure or meas_type is slew_measure:
|
||||||
meas_name="{0}{1}".format(delay_name, port)
|
return self.get_delay_measure_variants(port, measure_obj)
|
||||||
targ_name = "{0}".format("{0}{1}_{2}".format(self.dout_name,port,self.probe_data))
|
elif meas_type is power_measure:
|
||||||
half_vdd = 0.5 * self.vdd_voltage
|
return self.get_power_measure_variants(port, measure_obj, "read")
|
||||||
trig_slew_low = 0.1 * self.vdd_voltage
|
elif meas_type is voltage_when_measure:
|
||||||
targ_slew_high = 0.9 * self.vdd_voltage
|
return self.get_volt_when_measure_variants(port, measure_obj)
|
||||||
if 'delay' in delay_name:
|
|
||||||
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"]]
|
|
||||||
|
|
||||||
elif 'slew' in delay_name:
|
|
||||||
trig_name = targ_name
|
|
||||||
if 'lh' in delay_name:
|
|
||||||
trig_val = trig_slew_low
|
|
||||||
targ_val = targ_slew_high
|
|
||||||
targ_dir = trig_dir = "RISE"
|
|
||||||
trig_td = targ_td = self.cycle_times[self.measure_cycles[port]["read1"]]
|
|
||||||
else:
|
|
||||||
trig_val = targ_slew_high
|
|
||||||
targ_val = trig_slew_low
|
|
||||||
targ_dir = trig_dir = "FALL"
|
|
||||||
trig_td = targ_td = self.cycle_times[self.measure_cycles[port]["read0"]]
|
|
||||||
else:
|
else:
|
||||||
debug.error(1, "Measure command {0} not recognized".format(delay_name))
|
debug.error("Input function not defined for measurement type={}".format(meas_type))
|
||||||
return (meas_name,trig_name,targ_name,trig_val,targ_val,trig_dir,targ_dir,trig_td,targ_td)
|
|
||||||
|
def get_delay_measure_variants(self, port, delay_obj):
|
||||||
|
"""Get the measurement values that can either vary from simulation to simulation (vdd, address) or port to port (time delays)"""
|
||||||
|
#Return value is intended to match the delay measure format: trig_td, targ_td, vdd, port
|
||||||
|
#vdd is arguably constant as that is true for a single lib file.
|
||||||
|
if delay_obj.meta_str == "read0":
|
||||||
|
#Falling delay are measured starting from neg. clk edge. Delay adjusted to that.
|
||||||
|
meas_cycle_delay = self.cycle_times[self.measure_cycles[port][delay_obj.meta_str]]
|
||||||
|
elif delay_obj.meta_str == "read1":
|
||||||
|
meas_cycle_delay = self.cycle_times[self.measure_cycles[port][delay_obj.meta_str]]
|
||||||
|
else:
|
||||||
|
debug.error("Unrecognised delay Index={}".format(delay_obj.meta_str),1)
|
||||||
|
|
||||||
|
if delay_obj.meta_add_delay:
|
||||||
|
meas_cycle_delay += self.period/2
|
||||||
|
|
||||||
|
return (meas_cycle_delay, meas_cycle_delay, self.vdd_voltage, port)
|
||||||
|
|
||||||
|
def get_power_measure_variants(self, port, power_obj, operation):
|
||||||
|
"""Get the measurement values that can either vary port to port (time delays)"""
|
||||||
|
#Return value is intended to match the power measure format: t_initial, t_final, port
|
||||||
|
t_initial = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]]
|
||||||
|
t_final = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]+1]
|
||||||
|
|
||||||
|
return (t_initial, t_final, port)
|
||||||
|
|
||||||
|
def get_volt_when_measure_variants(self, port, power_obj):
|
||||||
|
"""Get the measurement values that can either vary port to port (time delays)"""
|
||||||
|
#Only checking 0 value reads for now.
|
||||||
|
t_trig = meas_cycle_delay = self.cycle_times[self.measure_cycles[port]["read0"]]
|
||||||
|
|
||||||
|
return (t_trig, self.vdd_voltage, port)
|
||||||
|
|
||||||
def write_delay_measures_read_port(self, port):
|
def write_delay_measures_read_port(self, port):
|
||||||
"""
|
"""
|
||||||
Write the measure statements to quantify the delay and power results for a read port.
|
Write the measure statements to quantify the delay and power results for a read port.
|
||||||
"""
|
"""
|
||||||
# add measure statements for delays/slews
|
# add measure statements for delays/slews
|
||||||
for dname in self.delay_meas_names:
|
for measure in self.read_meas_objs+self.bitline_delay_objs:
|
||||||
meas_values = self.get_delay_meas_values(dname, port)
|
measure_variant_inp_tuple = self.get_read_measure_variants(port, measure)
|
||||||
self.stim.gen_meas_delay(*meas_values)
|
measure.write_measure(self.stim, measure_variant_inp_tuple)
|
||||||
|
|
||||||
# add measure statements for power
|
def get_write_measure_variants(self, port, measure_obj):
|
||||||
for pname in self.power_meas_names:
|
"""Checks the measurement object and calls respective function for related measurement inputs."""
|
||||||
if "read" not in pname:
|
meas_type = type(measure_obj)
|
||||||
continue
|
if meas_type is power_measure:
|
||||||
#Different naming schemes are used for the measure cycle dict and measurement names.
|
return self.get_power_measure_variants(port, measure_obj, "write")
|
||||||
#TODO: make them the same so they can be indexed the same.
|
else:
|
||||||
if '1' in pname:
|
debug.error("Input function not defined for measurement type={}".format(meas_type))
|
||||||
t_initial = self.cycle_times[self.measure_cycles[port]["read1"]]
|
|
||||||
t_final = self.cycle_times[self.measure_cycles[port]["read1"]+1]
|
|
||||||
elif '0' in pname:
|
|
||||||
t_initial = self.cycle_times[self.measure_cycles[port]["read0"]]
|
|
||||||
t_final = self.cycle_times[self.measure_cycles[port]["read0"]+1]
|
|
||||||
self.stim.gen_meas_power(meas_name="{0}{1}".format(pname, port),
|
|
||||||
t_initial=t_initial,
|
|
||||||
t_final=t_final)
|
|
||||||
|
|
||||||
def write_delay_measures_write_port(self, port):
|
def write_delay_measures_write_port(self, port):
|
||||||
"""
|
"""
|
||||||
Write the measure statements to quantify the power results for a write port.
|
Write the measure statements to quantify the power results for a write port.
|
||||||
"""
|
"""
|
||||||
# add measure statements for power
|
# add measure statements for power
|
||||||
for pname in self.power_meas_names:
|
for measure in self.write_meas_objs:
|
||||||
if "write" not in pname:
|
measure_variant_inp_tuple = self.get_write_measure_variants(port, measure)
|
||||||
continue
|
measure.write_measure(self.stim, measure_variant_inp_tuple)
|
||||||
t_initial = self.cycle_times[self.measure_cycles[port]["write0"]]
|
|
||||||
t_final = self.cycle_times[self.measure_cycles[port]["write0"]+1]
|
|
||||||
if '1' in pname:
|
|
||||||
t_initial = self.cycle_times[self.measure_cycles[port]["write1"]]
|
|
||||||
t_final = self.cycle_times[self.measure_cycles[port]["write1"]+1]
|
|
||||||
|
|
||||||
self.stim.gen_meas_power(meas_name="{0}{1}".format(pname, port),
|
|
||||||
t_initial=t_initial,
|
|
||||||
t_final=t_final)
|
|
||||||
|
|
||||||
def write_delay_measures(self):
|
def write_delay_measures(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -386,27 +451,6 @@ class delay(simulation):
|
||||||
debug.info(1, "Found feasible_period: {0}ns".format(self.period))
|
debug.info(1, "Found feasible_period: {0}ns".format(self.period))
|
||||||
return feasible_delays
|
return feasible_delays
|
||||||
|
|
||||||
|
|
||||||
def parse_values(self, values_names, port, mult = 1.0):
|
|
||||||
"""Parse multiple values in the timing output file. Optional multiplier.
|
|
||||||
Return a dict of the input names and values. Port used for parsing file.
|
|
||||||
"""
|
|
||||||
values = []
|
|
||||||
all_values_floats = True
|
|
||||||
for vname in values_names:
|
|
||||||
#ngspice converts all measure characters to lowercase, not tested on other sims
|
|
||||||
value = parse_spice_list("timing", "{0}{1}".format(vname.lower(), port))
|
|
||||||
#Check if any of the values fail to parse
|
|
||||||
if type(value)!=float:
|
|
||||||
all_values_floats = False
|
|
||||||
values.append(value)
|
|
||||||
|
|
||||||
#Apply Multiplier only if all values are floats. Let other check functions handle this error.
|
|
||||||
if all_values_floats:
|
|
||||||
return {values_names[i]:values[i]*mult for i in range(len(values))}
|
|
||||||
else:
|
|
||||||
return {values_names[i]:values[i] for i in range(len(values))}
|
|
||||||
|
|
||||||
def run_delay_simulation(self):
|
def run_delay_simulation(self):
|
||||||
"""
|
"""
|
||||||
This tries to simulate a period and checks if the result works. If
|
This tries to simulate a period and checks if the result works. If
|
||||||
|
|
@ -427,32 +471,44 @@ class delay(simulation):
|
||||||
#Too much duplicate code here. Try reducing
|
#Too much duplicate code here. Try reducing
|
||||||
for port in self.targ_read_ports:
|
for port in self.targ_read_ports:
|
||||||
debug.info(2, "Check delay values for port {}".format(port))
|
debug.info(2, "Check delay values for port {}".format(port))
|
||||||
delay_names = [mname for mname in self.delay_meas_names]
|
read_port_dict = {}
|
||||||
delays = self.parse_values(delay_names, port, 1e9) # scale delays to ns
|
#Get measurements from output file
|
||||||
if not self.check_valid_delays(delays):
|
for measure in self.read_meas_objs:
|
||||||
return (False,{})
|
read_port_dict[measure.name] = measure.retrieve_measure(port=port)
|
||||||
result[port].update(delays)
|
|
||||||
|
|
||||||
power_names = [mname for mname in self.power_meas_names if 'read' in mname]
|
#Check timing for read ports. Power is only checked if it was read correctly
|
||||||
powers = self.parse_values(power_names, port, 1e3) # scale power to mw
|
if not self.check_valid_delays(read_port_dict):
|
||||||
#Check that power parsing worked.
|
return (False,{})
|
||||||
for name, power in powers.items():
|
if not check_dict_values_is_float(read_port_dict):
|
||||||
if type(power)!=float:
|
debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict),1) #Printing the entire dict looks bad.
|
||||||
debug.error("Failed to Parse Power Values:\n\t\t{0}".format(powers),1) #Printing the entire dict looks bad.
|
|
||||||
result[port].update(powers)
|
result[port].update(read_port_dict)
|
||||||
|
|
||||||
|
bitline_delay_dict = self.evaluate_bitline_delay(port)
|
||||||
|
result[port].update(bitline_delay_dict)
|
||||||
|
|
||||||
for port in self.targ_write_ports:
|
for port in self.targ_write_ports:
|
||||||
power_names = [mname for mname in self.power_meas_names if 'write' in mname]
|
write_port_dict = {}
|
||||||
powers = self.parse_values(power_names, port, 1e3) # scale power to mw
|
for measure in self.write_meas_objs:
|
||||||
#Check that power parsing worked.
|
write_port_dict[measure.name] = measure.retrieve_measure(port=port)
|
||||||
for name, power in powers.items():
|
|
||||||
if type(power)!=float:
|
if not check_dict_values_is_float(write_port_dict):
|
||||||
debug.error("Failed to Parse Power Values:\n\t\t{0}".format(powers),1) #Printing the entire dict looks bad.
|
debug.error("Failed to Measure Write Port Values:\n\t\t{0}".format(write_port_dict),1) #Printing the entire dict looks bad.
|
||||||
result[port].update(powers)
|
result[port].update(write_port_dict)
|
||||||
|
|
||||||
# The delay is from the negative edge for our SRAM
|
# The delay is from the negative edge for our SRAM
|
||||||
return (True,result)
|
return (True,result)
|
||||||
|
|
||||||
|
def evaluate_bitline_delay(self, port):
|
||||||
|
"""Parse and check the bitline delay. One of the measurements is expected to fail which warrants its own function."""
|
||||||
|
bl_delay_meas_dict = {}
|
||||||
|
values_added = 0 #For error checking
|
||||||
|
for measure in self.bitline_delay_objs:
|
||||||
|
bl_delay_val = measure.retrieve_measure(port=port)
|
||||||
|
if type(bl_delay_val) != float or 0 > bl_delay_val or bl_delay_val > self.period/2: #Only add if value is valid, do not error.
|
||||||
|
debug.error("Bitline delay measurement failed: half-period={}, {}={}".format(self.period/2, measure.name, bl_delay_val),1)
|
||||||
|
bl_delay_meas_dict[measure.name] = bl_delay_val
|
||||||
|
return bl_delay_meas_dict
|
||||||
|
|
||||||
def run_power_simulation(self):
|
def run_power_simulation(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -478,13 +534,13 @@ class delay(simulation):
|
||||||
#key=raw_input("press return to continue")
|
#key=raw_input("press return to continue")
|
||||||
return (leakage_power*1e3, trim_leakage_power*1e3)
|
return (leakage_power*1e3, trim_leakage_power*1e3)
|
||||||
|
|
||||||
def check_valid_delays(self, delay_dict):
|
def check_valid_delays(self, result_dict):
|
||||||
""" Check if the measurements are defined and if they are valid. """
|
""" Check if the measurements are defined and if they are valid. """
|
||||||
#Hard coded names currently
|
#Hard coded names currently
|
||||||
delay_hl = delay_dict["delay_hl"]
|
delay_hl = result_dict["delay_hl"]
|
||||||
delay_lh = delay_dict["delay_lh"]
|
delay_lh = result_dict["delay_lh"]
|
||||||
slew_hl = delay_dict["slew_hl"]
|
slew_hl = result_dict["slew_hl"]
|
||||||
slew_lh = delay_dict["slew_lh"]
|
slew_lh = result_dict["slew_lh"]
|
||||||
period_load_slew_str = "period {0} load {1} slew {2}".format(self.period,self.load, self.slew)
|
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
|
# if it failed or the read was longer than a period
|
||||||
|
|
@ -610,9 +666,22 @@ class delay(simulation):
|
||||||
functions in this characterizer besides analyze."""
|
functions in this characterizer besides analyze."""
|
||||||
self.probe_address = probe_address
|
self.probe_address = probe_address
|
||||||
self.probe_data = probe_data
|
self.probe_data = probe_data
|
||||||
|
self.bitline_column = self.get_data_bit_column_number(probe_address, probe_data)
|
||||||
|
self.wordline_row = self.get_address_row_number(probe_address)
|
||||||
self.prepare_netlist()
|
self.prepare_netlist()
|
||||||
|
|
||||||
|
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 get_address_row_number(self, probe_address):
|
||||||
|
"""Calculates wordline row number of data bit under test using address and column mux size"""
|
||||||
|
return int(probe_address[self.sram.col_addr_size:],2)
|
||||||
|
|
||||||
def prepare_netlist(self):
|
def prepare_netlist(self):
|
||||||
""" Prepare a trimmed netlist and regular netlist. """
|
""" Prepare a trimmed netlist and regular netlist. """
|
||||||
|
|
@ -645,6 +714,9 @@ class delay(simulation):
|
||||||
char_sram_data = {}
|
char_sram_data = {}
|
||||||
|
|
||||||
self.set_probe(probe_address, probe_data)
|
self.set_probe(probe_address, probe_data)
|
||||||
|
self.create_signal_names()
|
||||||
|
self.create_measurement_names()
|
||||||
|
self.create_measurement_objects()
|
||||||
|
|
||||||
self.load=max(loads)
|
self.load=max(loads)
|
||||||
self.slew=max(slews)
|
self.slew=max(slews)
|
||||||
|
|
@ -828,13 +900,14 @@ class delay(simulation):
|
||||||
"""
|
"""
|
||||||
if OPTS.num_rw_ports > 1 or OPTS.num_w_ports > 0 and OPTS.num_r_ports > 0:
|
if OPTS.num_rw_ports > 1 or OPTS.num_w_ports > 0 and OPTS.num_r_ports > 0:
|
||||||
debug.warning("Analytical characterization results are not supported for multiport.")
|
debug.warning("Analytical characterization results are not supported for multiport.")
|
||||||
|
self.create_signal_names()
|
||||||
|
self.create_measurement_names()
|
||||||
power = self.analytical_power(slews, loads)
|
power = self.analytical_power(slews, loads)
|
||||||
port_data = self.get_empty_measure_data_dict()
|
port_data = self.get_empty_measure_data_dict()
|
||||||
for slew in slews:
|
for slew in slews:
|
||||||
for load in loads:
|
for load in loads:
|
||||||
self.set_load_slew(load,slew)
|
self.set_load_slew(load,slew)
|
||||||
bank_delay = self.sram.analytical_delay(self.vdd_voltage, self.slew,self.load)
|
bank_delay = self.sram.analytical_delay(self.corner, self.slew,self.load)
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
for mname in self.delay_meas_names+self.power_meas_names:
|
for mname in self.delay_meas_names+self.power_meas_names:
|
||||||
if "power" in mname:
|
if "power" in mname:
|
||||||
|
|
@ -845,9 +918,12 @@ class delay(simulation):
|
||||||
port_data[port][mname].append(bank_delay[port].slew/1e3)
|
port_data[port][mname].append(bank_delay[port].slew/1e3)
|
||||||
else:
|
else:
|
||||||
debug.error("Measurement name not recognized: {}".format(mname),1)
|
debug.error("Measurement name not recognized: {}".format(mname),1)
|
||||||
sram_data = { "min_period": 0,
|
period_margin = 0.1
|
||||||
|
risefall_delay = bank_delay[self.read_ports[0]].delay/1e3
|
||||||
|
sram_data = { "min_period":risefall_delay*2*period_margin,
|
||||||
"leakage_power": power.leakage}
|
"leakage_power": power.leakage}
|
||||||
|
debug.info(2,"SRAM Data:\n{}".format(sram_data))
|
||||||
|
debug.info(2,"Port Data:\n{}".format(port_data))
|
||||||
return (sram_data,port_data)
|
return (sram_data,port_data)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -855,7 +931,7 @@ class delay(simulation):
|
||||||
"""Get the dynamic and leakage power from the SRAM"""
|
"""Get the dynamic and leakage power from the SRAM"""
|
||||||
#slews unused, only last load is used
|
#slews unused, only last load is used
|
||||||
load = loads[-1]
|
load = loads[-1]
|
||||||
power = self.sram.analytical_power(self.process, self.vdd_voltage, self.temperature, load)
|
power = self.sram.analytical_power(self.corner, load)
|
||||||
#convert from nW to mW
|
#convert from nW to mW
|
||||||
power.dynamic /= 1e6
|
power.dynamic /= 1e6
|
||||||
power.leakage /= 1e6
|
power.leakage /= 1e6
|
||||||
|
|
@ -890,7 +966,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def get_empty_measure_data_dict(self):
|
def get_empty_measure_data_dict(self):
|
||||||
"""Make a dict of lists for each type of delay and power measurement to append results to"""
|
"""Make a dict of lists for each type of delay and power measurement to append results to"""
|
||||||
measure_names = self.delay_meas_names + self.power_meas_names
|
measure_names = self.delay_meas_names + self.power_meas_names + self.voltage_when_names + self.bitline_delay_names
|
||||||
#Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
|
#Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
|
||||||
measure_data = [{mname:[] for mname in measure_names} for i in self.all_ports]
|
measure_data = [{mname:[] for mname in measure_names} for i in self.all_ports]
|
||||||
return measure_data
|
return measure_data
|
||||||
|
|
|
||||||
|
|
@ -83,9 +83,11 @@ class lib:
|
||||||
(self.process, self.voltage, self.temperature) = self.corner
|
(self.process, self.voltage, self.temperature) = self.corner
|
||||||
self.lib = open(lib_name, "w")
|
self.lib = open(lib_name, "w")
|
||||||
debug.info(1,"Writing to {0}".format(lib_name))
|
debug.info(1,"Writing to {0}".format(lib_name))
|
||||||
|
self.corner_name = lib_name.replace(self.out_dir,"").replace(".lib","")
|
||||||
self.characterize()
|
self.characterize()
|
||||||
self.lib.close()
|
self.lib.close()
|
||||||
self.parse_info(self.corner,lib_name)
|
self.parse_info(self.corner,lib_name)
|
||||||
|
|
||||||
def characterize(self):
|
def characterize(self):
|
||||||
""" Characterize the current corner. """
|
""" Characterize the current corner. """
|
||||||
|
|
||||||
|
|
@ -325,7 +327,7 @@ class lib:
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
|
|
||||||
|
|
||||||
self.lib.write(" pin(DOUT{}){{\n".format(read_port))
|
self.lib.write(" pin(DOUT{0}[{1}:0]){{\n".format(read_port,self.sram.word_size-1))
|
||||||
self.lib.write(" timing(){ \n")
|
self.lib.write(" timing(){ \n")
|
||||||
self.lib.write(" timing_sense : non_unate; \n")
|
self.lib.write(" timing_sense : non_unate; \n")
|
||||||
self.lib.write(" related_pin : \"clk{0}\"; \n".format(read_port))
|
self.lib.write(" related_pin : \"clk{0}\"; \n".format(read_port))
|
||||||
|
|
@ -358,7 +360,7 @@ class lib:
|
||||||
self.lib.write(" address : ADDR{0}; \n".format(write_port))
|
self.lib.write(" address : ADDR{0}; \n".format(write_port))
|
||||||
self.lib.write(" clocked_on : clk{0}; \n".format(write_port))
|
self.lib.write(" clocked_on : clk{0}; \n".format(write_port))
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
self.lib.write(" pin(DIN{}){{\n".format(write_port))
|
self.lib.write(" pin(DIN{0}[{1}:0]){{\n".format(write_port,self.sram.word_size-1))
|
||||||
self.write_FF_setuphold(write_port)
|
self.write_FF_setuphold(write_port)
|
||||||
self.lib.write(" }\n") # pin
|
self.lib.write(" }\n") # pin
|
||||||
self.lib.write(" }\n") #bus
|
self.lib.write(" }\n") #bus
|
||||||
|
|
@ -378,7 +380,7 @@ class lib:
|
||||||
self.lib.write(" direction : input; \n")
|
self.lib.write(" direction : input; \n")
|
||||||
self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]))
|
self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]))
|
||||||
self.lib.write(" max_transition : {0};\n".format(self.slews[-1]))
|
self.lib.write(" max_transition : {0};\n".format(self.slews[-1]))
|
||||||
self.lib.write(" pin(ADDR{})".format(port))
|
self.lib.write(" pin(ADDR{0}[{1}:0])".format(port,self.sram.addr_size-1))
|
||||||
self.lib.write("{\n")
|
self.lib.write("{\n")
|
||||||
|
|
||||||
self.write_FF_setuphold(port)
|
self.write_FF_setuphold(port)
|
||||||
|
|
@ -481,17 +483,16 @@ class lib:
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
|
|
||||||
def compute_delay(self):
|
def compute_delay(self):
|
||||||
""" Do the analysis if we haven't characterized the SRAM yet """
|
"""Compute SRAM delays for current corner"""
|
||||||
if not hasattr(self,"d"):
|
self.d = delay(self.sram, self.sp_file, self.corner)
|
||||||
self.d = delay(self.sram, self.sp_file, self.corner)
|
if self.use_model:
|
||||||
if self.use_model:
|
char_results = self.d.analytical_delay(self.slews,self.loads)
|
||||||
char_results = self.d.analytical_delay(self.slews,self.loads)
|
self.char_sram_results, self.char_port_results = char_results
|
||||||
self.char_sram_results, self.char_port_results = char_results
|
else:
|
||||||
else:
|
probe_address = "1" * self.sram.addr_size
|
||||||
probe_address = "1" * self.sram.addr_size
|
probe_data = self.sram.word_size - 1
|
||||||
probe_data = self.sram.word_size - 1
|
char_results = self.d.analyze(probe_address, probe_data, self.slews, self.loads)
|
||||||
char_results = self.d.analyze(probe_address, probe_data, self.slews, self.loads)
|
self.char_sram_results, self.char_port_results = char_results
|
||||||
self.char_sram_results, self.char_port_results = char_results
|
|
||||||
|
|
||||||
def compute_setup_hold(self):
|
def compute_setup_hold(self):
|
||||||
""" Do the analysis if we haven't characterized a FF yet """
|
""" Do the analysis if we haven't characterized a FF yet """
|
||||||
|
|
@ -507,9 +508,11 @@ class lib:
|
||||||
def parse_info(self,corner,lib_name):
|
def parse_info(self,corner,lib_name):
|
||||||
""" Copies important characterization data to datasheet.info to be added to datasheet """
|
""" Copies important characterization data to datasheet.info to be added to datasheet """
|
||||||
if OPTS.is_unit_test:
|
if OPTS.is_unit_test:
|
||||||
git_id = 'AAAAAAAAAAAAAAAAAAAA'
|
git_id = 'FFFFFFFFFFFFFFFFFFFF'
|
||||||
|
|
||||||
else:
|
else:
|
||||||
with open(os.devnull, 'wb') as devnull:
|
with open(os.devnull, 'wb') as devnull:
|
||||||
|
# parses the mose recent git commit id - requres git is installed
|
||||||
proc = subprocess.Popen(['git','rev-parse','HEAD'], cwd=os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/', stdout=subprocess.PIPE)
|
proc = subprocess.Popen(['git','rev-parse','HEAD'], cwd=os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/', stdout=subprocess.PIPE)
|
||||||
|
|
||||||
git_id = str(proc.stdout.read())
|
git_id = str(proc.stdout.read())
|
||||||
|
|
@ -518,16 +521,17 @@ class lib:
|
||||||
git_id = git_id[2:-3]
|
git_id = git_id[2:-3]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
# check if git id is valid
|
||||||
if len(git_id) != 40:
|
if len(git_id) != 40:
|
||||||
debug.warning("Failed to retrieve git id")
|
debug.warning("Failed to retrieve git id")
|
||||||
git_id = 'Failed to retruieve'
|
git_id = 'Failed to retruieve'
|
||||||
|
|
||||||
datasheet = open(OPTS.openram_temp +'/datasheet.info', 'a+')
|
datasheet = open(OPTS.openram_temp +'/datasheet.info', 'a+')
|
||||||
|
|
||||||
current_time = datetime.datetime.now()
|
current_time = datetime.date.today()
|
||||||
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},".format(
|
# write static information to be parser later
|
||||||
"sram_{0}_{1}_{2}".format(OPTS.word_size, OPTS.num_words, OPTS.tech_name),
|
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},".format(
|
||||||
|
OPTS.output_name,
|
||||||
OPTS.num_words,
|
OPTS.num_words,
|
||||||
OPTS.num_banks,
|
OPTS.num_banks,
|
||||||
OPTS.num_rw_ports,
|
OPTS.num_rw_ports,
|
||||||
|
|
@ -542,7 +546,8 @@ class lib:
|
||||||
lib_name,
|
lib_name,
|
||||||
OPTS.word_size,
|
OPTS.word_size,
|
||||||
git_id,
|
git_id,
|
||||||
current_time
|
current_time,
|
||||||
|
OPTS.analytical_delay
|
||||||
))
|
))
|
||||||
|
|
||||||
# information of checks
|
# information of checks
|
||||||
|
|
@ -555,7 +560,9 @@ class lib:
|
||||||
LVS = str(total_lvs_errors)
|
LVS = str(total_lvs_errors)
|
||||||
|
|
||||||
datasheet.write("{0},{1},".format(DRC, LVS))
|
datasheet.write("{0},{1},".format(DRC, LVS))
|
||||||
|
# write area
|
||||||
datasheet.write(str(self.sram.width * self.sram.height)+',')
|
datasheet.write(str(self.sram.width * self.sram.height)+',')
|
||||||
|
# write timing information for all ports
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
#DIN timings
|
#DIN timings
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
|
|
@ -652,9 +659,45 @@ class lib:
|
||||||
|
|
||||||
))
|
))
|
||||||
|
|
||||||
|
# write power information
|
||||||
|
for port in self.all_ports:
|
||||||
|
name = ''
|
||||||
|
read_write = ''
|
||||||
|
|
||||||
|
# write dynamic power usage
|
||||||
|
if port in self.read_ports:
|
||||||
|
web_name = " & !WEb{0}".format(port)
|
||||||
|
name = "!CSb{0} & clk{0}{1}".format(port, web_name)
|
||||||
|
read_write = 'Read'
|
||||||
|
|
||||||
|
datasheet.write("{0},{1},{2},{3},".format(
|
||||||
|
"power",
|
||||||
|
name,
|
||||||
|
read_write,
|
||||||
|
|
||||||
|
np.mean(self.char_port_results[port]["read1_power"] + self.char_port_results[port]["read0_power"])/2
|
||||||
|
))
|
||||||
|
|
||||||
|
if port in self.write_ports:
|
||||||
|
web_name = " & WEb{0}".format(port)
|
||||||
|
name = "!CSb{0} & !clk{0}{1}".format(port, web_name)
|
||||||
|
read_write = 'Write'
|
||||||
|
|
||||||
|
datasheet.write("{0},{1},{2},{3},".format(
|
||||||
|
'power',
|
||||||
|
name,
|
||||||
|
read_write,
|
||||||
|
np.mean(self.char_port_results[port]["write1_power"] + self.char_port_results[port]["write0_power"])/2
|
||||||
|
|
||||||
|
))
|
||||||
|
|
||||||
|
# write leakage power
|
||||||
|
control_str = 'CSb0'
|
||||||
|
for i in range(1, self.total_port_num):
|
||||||
|
control_str += ' & CSb{0}'.format(i)
|
||||||
|
|
||||||
|
datasheet.write("{0},{1},{2},".format('leak', control_str, self.char_sram_results["leakage_power"]))
|
||||||
|
|
||||||
|
|
||||||
datasheet.write("END\n")
|
datasheet.write("END\n")
|
||||||
datasheet.close()
|
datasheet.close()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ class logical_effort():
|
||||||
min_inv_cin = 1+beta
|
min_inv_cin = 1+beta
|
||||||
pinv=parameter["min_inv_para_delay"]
|
pinv=parameter["min_inv_para_delay"]
|
||||||
|
|
||||||
def __init__(self, size, cin, cout, parasitic, out_is_rise=True):
|
def __init__(self, name, size, cin, cout, parasitic, out_is_rise=True):
|
||||||
|
self.name = name
|
||||||
self.cin = cin
|
self.cin = cin
|
||||||
self.cout = cout
|
self.cout = cout
|
||||||
self.logical_effort = (self.cin/size)/logical_effort.min_inv_cin
|
self.logical_effort = (self.cin/size)/logical_effort.min_inv_cin
|
||||||
|
|
@ -19,7 +20,12 @@ class logical_effort():
|
||||||
self.is_rise = out_is_rise
|
self.is_rise = out_is_rise
|
||||||
|
|
||||||
def __str__(self):
|
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)
|
return "Name={}, g={}, h={}, p={}*pinv, rise_delay={}".format(self.name,
|
||||||
|
self.logical_effort,
|
||||||
|
self.eletrical_effort,
|
||||||
|
self.parasitic_scale,
|
||||||
|
self.is_rise
|
||||||
|
)
|
||||||
|
|
||||||
def get_stage_effort(self):
|
def get_stage_effort(self):
|
||||||
return self.logical_effort*self.eletrical_effort
|
return self.logical_effort*self.eletrical_effort
|
||||||
|
|
@ -30,6 +36,10 @@ class logical_effort():
|
||||||
def get_stage_delay(self, pinv):
|
def get_stage_delay(self, pinv):
|
||||||
return self.get_stage_effort()+self.get_parasitic_delay(pinv)
|
return self.get_stage_effort()+self.get_parasitic_delay(pinv)
|
||||||
|
|
||||||
|
def calculate_delays(stage_effort_list, pinv):
|
||||||
|
"""Convert stage effort objects to list of delay values"""
|
||||||
|
return [stage.get_stage_delay(pinv) for stage in stage_effort_list]
|
||||||
|
|
||||||
def calculate_relative_delay(stage_effort_list, pinv=parameter["min_inv_para_delay"]):
|
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."""
|
"""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)
|
total_rise_delay, total_fall_delay = calculate_relative_rise_fall_delays(stage_effort_list, pinv)
|
||||||
|
|
@ -40,7 +50,7 @@ def calculate_relative_rise_fall_delays(stage_effort_list, pinv=parameter["min_i
|
||||||
debug.info(2, "Calculating rise/fall relative delays")
|
debug.info(2, "Calculating rise/fall relative delays")
|
||||||
total_rise_delay, total_fall_delay = 0,0
|
total_rise_delay, total_fall_delay = 0,0
|
||||||
for stage in stage_effort_list:
|
for stage in stage_effort_list:
|
||||||
debug.info(3, stage)
|
debug.info(2, stage)
|
||||||
if stage.is_rise:
|
if stage.is_rise:
|
||||||
total_rise_delay += stage.get_stage_delay(pinv)
|
total_rise_delay += stage.get_stage_delay(pinv)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
import debug
|
||||||
|
from tech import drc, parameter, spice
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from .stimuli import *
|
||||||
|
from .charutils import *
|
||||||
|
|
||||||
|
class spice_measurement(ABC):
|
||||||
|
"""Base class for spice stimulus measurements."""
|
||||||
|
def __init__(self, measure_name, measure_scale=None):
|
||||||
|
#Names must be unique for correct spice simulation, but not enforced here.
|
||||||
|
self.name = measure_name
|
||||||
|
self.measure_scale = measure_scale
|
||||||
|
#Some meta values used externally. variables are added here for consistency accross the objects
|
||||||
|
self.meta_str = None
|
||||||
|
self.meta_add_delay = False
|
||||||
|
@abstractmethod
|
||||||
|
def get_measure_function(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_measure_values(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def write_measure(self, stim_obj, input_tuple):
|
||||||
|
measure_func = self.get_measure_function()
|
||||||
|
if measure_func == None:
|
||||||
|
debug.error("Did not set measure function",1)
|
||||||
|
measure_vals = self.get_measure_values(*input_tuple)
|
||||||
|
measure_func(stim_obj, *measure_vals)
|
||||||
|
|
||||||
|
def retrieve_measure(self, port=""):
|
||||||
|
value = parse_spice_list("timing", "{0}{1}".format(self.name.lower(), port))
|
||||||
|
if type(value)!=float or self.measure_scale == None:
|
||||||
|
return value
|
||||||
|
else:
|
||||||
|
return value*self.measure_scale
|
||||||
|
|
||||||
|
class delay_measure(spice_measurement):
|
||||||
|
"""Generates a spice measurement for the delay of 50%-to-50% points of two signals."""
|
||||||
|
|
||||||
|
def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd=0.5, targ_vdd=0.5, measure_scale=None):
|
||||||
|
spice_measurement.__init__(self, measure_name, measure_scale)
|
||||||
|
self.set_meas_constants(trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd)
|
||||||
|
|
||||||
|
def get_measure_function(self):
|
||||||
|
return stimuli.gen_meas_delay
|
||||||
|
|
||||||
|
def set_meas_constants(self, trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd):
|
||||||
|
"""Set the constants for this measurement: signal names, directions, and trigger scales"""
|
||||||
|
self.trig_dir_str = trig_dir_str
|
||||||
|
self.targ_dir_str = targ_dir_str
|
||||||
|
|
||||||
|
self.trig_val_of_vdd = trig_vdd
|
||||||
|
self.targ_val_of_vdd = targ_vdd
|
||||||
|
|
||||||
|
self.trig_name_no_port = trig_name
|
||||||
|
self.targ_name_no_port = targ_name
|
||||||
|
|
||||||
|
#Time delays and ports are variant and needed as inputs when writing the measurement
|
||||||
|
|
||||||
|
def get_measure_values(self, trig_td, targ_td, vdd_voltage, port=None):
|
||||||
|
"""Constructs inputs to stimulus measurement function. Variant values are inputs here."""
|
||||||
|
trig_val = self.trig_val_of_vdd * vdd_voltage
|
||||||
|
targ_val = self.targ_val_of_vdd * vdd_voltage
|
||||||
|
|
||||||
|
if port != None:
|
||||||
|
#For dictionary indexing reasons, the name is formatted differently than the signals
|
||||||
|
meas_name = "{}{}".format(self.name, port)
|
||||||
|
trig_name = self.trig_name_no_port.format(port)
|
||||||
|
targ_name = self.targ_name_no_port.format(port)
|
||||||
|
else:
|
||||||
|
meas_name = self.name
|
||||||
|
trig_name = self.trig_name_no_port
|
||||||
|
targ_name = self.targ_name_no_port
|
||||||
|
|
||||||
|
return (meas_name,trig_name,targ_name,trig_val,targ_val,self.trig_dir_str,self.targ_dir_str,trig_td,targ_td)
|
||||||
|
|
||||||
|
class slew_measure(delay_measure):
|
||||||
|
|
||||||
|
def __init__(self, measure_name, signal_name, slew_dir_str, measure_scale=None):
|
||||||
|
spice_measurement.__init__(self, measure_name, measure_scale)
|
||||||
|
self.set_meas_constants(signal_name, slew_dir_str)
|
||||||
|
|
||||||
|
def set_meas_constants(self, signal_name, slew_dir_str):
|
||||||
|
"""Set the values needed to generate a Spice measurement statement based on the name of the measurement."""
|
||||||
|
self.trig_dir_str = slew_dir_str
|
||||||
|
self.targ_dir_str = slew_dir_str
|
||||||
|
|
||||||
|
if slew_dir_str == "RISE":
|
||||||
|
self.trig_val_of_vdd = 0.1
|
||||||
|
self.targ_val_of_vdd = 0.9
|
||||||
|
elif slew_dir_str == "FALL":
|
||||||
|
self.trig_val_of_vdd = 0.9
|
||||||
|
self.targ_val_of_vdd = 0.1
|
||||||
|
else:
|
||||||
|
debug.error("Unrecognised slew measurement direction={}".format(slew_dir_str),1)
|
||||||
|
|
||||||
|
self.trig_name_no_port = signal_name
|
||||||
|
self.targ_name_no_port = signal_name
|
||||||
|
|
||||||
|
#Time delays and ports are variant and needed as inputs when writing the measurement
|
||||||
|
|
||||||
|
class power_measure(spice_measurement):
|
||||||
|
"""Generates a spice measurement for the average power between two time points."""
|
||||||
|
|
||||||
|
def __init__(self, measure_name, power_type="", measure_scale=None):
|
||||||
|
spice_measurement.__init__(self, measure_name, measure_scale)
|
||||||
|
self.set_meas_constants(power_type)
|
||||||
|
|
||||||
|
def get_measure_function(self):
|
||||||
|
return stimuli.gen_meas_power
|
||||||
|
|
||||||
|
def set_meas_constants(self, power_type):
|
||||||
|
"""Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)"""
|
||||||
|
#Not needed for power simulation
|
||||||
|
self.power_type = power_type #Expected to be "RISE"/"FALL"
|
||||||
|
|
||||||
|
def get_measure_values(self, t_initial, t_final, port=None):
|
||||||
|
"""Constructs inputs to stimulus measurement function. Variant values are inputs here."""
|
||||||
|
if port != None:
|
||||||
|
meas_name = "{}{}".format(self.name, port)
|
||||||
|
else:
|
||||||
|
meas_name = self.name
|
||||||
|
return (meas_name,t_initial,t_final)
|
||||||
|
|
||||||
|
class voltage_when_measure(spice_measurement):
|
||||||
|
"""Generates a spice measurement to measure the voltage of a signal based on the voltage of another."""
|
||||||
|
|
||||||
|
def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, trig_vdd, measure_scale=None):
|
||||||
|
spice_measurement.__init__(self, measure_name, measure_scale)
|
||||||
|
self.set_meas_constants(trig_name, targ_name, trig_dir_str, trig_vdd)
|
||||||
|
|
||||||
|
def get_measure_function(self):
|
||||||
|
return stimuli.gen_meas_find_voltage
|
||||||
|
|
||||||
|
def set_meas_constants(self, trig_name, targ_name, trig_dir_str, trig_vdd):
|
||||||
|
"""Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)"""
|
||||||
|
self.trig_dir_str = trig_dir_str
|
||||||
|
self.trig_val_of_vdd = trig_vdd
|
||||||
|
|
||||||
|
self.trig_name_no_port = trig_name
|
||||||
|
self.targ_name_no_port = targ_name
|
||||||
|
|
||||||
|
def get_measure_values(self, trig_td, vdd_voltage, port=None):
|
||||||
|
"""Constructs inputs to stimulus measurement function. Variant values are inputs here."""
|
||||||
|
|
||||||
|
if port != None:
|
||||||
|
#For dictionary indexing reasons, the name is formatted differently than the signals
|
||||||
|
meas_name = "{}{}".format(self.name, port)
|
||||||
|
trig_name = self.trig_name_no_port.format(port)
|
||||||
|
targ_name = self.targ_name_no_port.format(port)
|
||||||
|
else:
|
||||||
|
meas_name = self.name
|
||||||
|
trig_name = self.trig_name_no_port
|
||||||
|
targ_name = self.targ_name_no_port
|
||||||
|
|
||||||
|
trig_voltage = self.trig_val_of_vdd*vdd_voltage
|
||||||
|
|
||||||
|
return (meas_name,trig_name,targ_name,trig_voltage,self.trig_dir_str,trig_td)
|
||||||
|
|
@ -0,0 +1,348 @@
|
||||||
|
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
|
||||||
|
from .measurements import *
|
||||||
|
|
||||||
|
class model_check(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.create_data_names()
|
||||||
|
|
||||||
|
def create_data_names(self):
|
||||||
|
self.wl_meas_name, self.wl_model_name = "wl_measures", "wl_model"
|
||||||
|
self.sae_meas_name, self.sae_model_name = "sae_measures", "sae_model"
|
||||||
|
self.wl_slew_name, self.sae_slew_name = "wl_slews", "sae_slews"
|
||||||
|
|
||||||
|
def create_measurement_names(self):
|
||||||
|
"""Create measurement names. The names themselves currently define the type of measurement"""
|
||||||
|
#Create delay measurement names
|
||||||
|
wl_en_driver_delay_names = ["delay_wl_en_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())]
|
||||||
|
wl_driver_delay_names = ["delay_wl_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_driver_stages())]
|
||||||
|
sen_driver_delay_names = ["delay_sen_dvr_{}".format(stage) for stage in range(1,self.get_num_sen_driver_stages())]
|
||||||
|
dc_delay_names = ["delay_delay_chain_stage_{}".format(stage) for stage in range(1,self.get_num_delay_stages()+1)]
|
||||||
|
self.wl_delay_meas_names = wl_en_driver_delay_names+["delay_wl_en", "delay_wl_bar"]+wl_driver_delay_names+["delay_wl"]
|
||||||
|
self.rbl_delay_meas_names = ["delay_gated_clk_nand", "delay_delay_chain_in"]+dc_delay_names
|
||||||
|
self.sae_delay_meas_names = ["delay_pre_sen"]+sen_driver_delay_names+["delay_sen"]
|
||||||
|
|
||||||
|
self.delay_chain_indices = (len(self.rbl_delay_meas_names)-len(dc_delay_names), len(self.rbl_delay_meas_names))
|
||||||
|
#Create slew measurement names
|
||||||
|
wl_en_driver_slew_names = ["slew_wl_en_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())]
|
||||||
|
wl_driver_slew_names = ["slew_wl_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_driver_stages())]
|
||||||
|
sen_driver_slew_names = ["slew_sen_dvr_{}".format(stage) for stage in range(1,self.get_num_sen_driver_stages())]
|
||||||
|
dc_slew_names = ["slew_delay_chain_stage_{}".format(stage) for stage in range(1,self.get_num_delay_stages()+1)]
|
||||||
|
self.wl_slew_meas_names = ["slew_wl_gated_clk_bar"]+wl_en_driver_slew_names+["slew_wl_en", "slew_wl_bar"]+wl_driver_slew_names+["slew_wl"]
|
||||||
|
self.rbl_slew_meas_names = ["slew_rbl_gated_clk_bar","slew_gated_clk_nand", "slew_delay_chain_in"]+dc_slew_names
|
||||||
|
self.sae_slew_meas_names = ["slew_replica_bl0", "slew_pre_sen"]+sen_driver_slew_names+["slew_sen"]
|
||||||
|
|
||||||
|
def create_signal_names(self):
|
||||||
|
"""Creates list of the signal names used in the spice file along the wl and sen paths.
|
||||||
|
Names are re-harded coded here; i.e. the names are hardcoded in most of OpenRAM and are
|
||||||
|
replicated here.
|
||||||
|
"""
|
||||||
|
delay.create_signal_names(self)
|
||||||
|
#Signal names are all hardcoded, need to update to make it work for probe address and different configurations.
|
||||||
|
wl_en_driver_signals = ["Xsram.Xcontrol0.Xbuf_wl_en.Zb{}_int".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())]
|
||||||
|
wl_driver_signals = ["Xsram.Xbank0.Xwordline_driver0.Xwl_driver_inv{}.Zb{}_int".format(self.wordline_row, stage) for stage in range(1,self.get_num_wl_driver_stages())]
|
||||||
|
sen_driver_signals = ["Xsram.Xcontrol0.Xbuf_s_en.Zb{}_int".format(stage) for stage in range(1,self.get_num_sen_driver_stages())]
|
||||||
|
delay_chain_signal_names = ["Xsram.Xcontrol0.Xreplica_bitline.Xdelay_chain.dout_{}".format(stage) for stage in range(1,self.get_num_delay_stages())]
|
||||||
|
|
||||||
|
self.wl_signal_names = ["Xsram.Xcontrol0.gated_clk_bar"]+\
|
||||||
|
wl_en_driver_signals+\
|
||||||
|
["Xsram.wl_en0", "Xsram.Xbank0.Xwordline_driver0.wl_bar_{}".format(self.wordline_row)]+\
|
||||||
|
wl_driver_signals+\
|
||||||
|
["Xsram.Xbank0.wl_{}".format(self.wordline_row)]
|
||||||
|
pre_delay_chain_names = ["Xsram.Xcontrol0.gated_clk_bar", "Xsram.Xcontrol0.Xand2_rbl_in.zb_int", "Xsram.Xcontrol0.rbl_in"]
|
||||||
|
self.rbl_en_signal_names = pre_delay_chain_names+\
|
||||||
|
delay_chain_signal_names+\
|
||||||
|
["Xsram.Xcontrol0.Xreplica_bitline.delayed_en"]
|
||||||
|
self.sae_signal_names = ["Xsram.Xcontrol0.Xreplica_bitline.bl0_0", "Xsram.Xcontrol0.pre_s_en"]+\
|
||||||
|
sen_driver_signals+\
|
||||||
|
["Xsram.s_en0"]
|
||||||
|
|
||||||
|
def create_measurement_objects(self):
|
||||||
|
"""Create the measurements used for read and write ports"""
|
||||||
|
self.create_wordline_measurement_objects()
|
||||||
|
self.create_sae_measurement_objects()
|
||||||
|
self.all_measures = self.wl_meas_objs+self.sae_meas_objs
|
||||||
|
|
||||||
|
def create_wordline_measurement_objects(self):
|
||||||
|
"""Create the measurements to measure the wordline path from the gated_clk_bar signal"""
|
||||||
|
self.wl_meas_objs = []
|
||||||
|
trig_dir = "RISE"
|
||||||
|
targ_dir = "FALL"
|
||||||
|
|
||||||
|
for i in range(1, len(self.wl_signal_names)):
|
||||||
|
self.wl_meas_objs.append(delay_measure(self.wl_delay_meas_names[i-1],
|
||||||
|
self.wl_signal_names[i-1],
|
||||||
|
self.wl_signal_names[i],
|
||||||
|
trig_dir,
|
||||||
|
targ_dir,
|
||||||
|
measure_scale=1e9))
|
||||||
|
self.wl_meas_objs.append(slew_measure(self.wl_slew_meas_names[i-1],
|
||||||
|
self.wl_signal_names[i-1],
|
||||||
|
trig_dir,
|
||||||
|
measure_scale=1e9))
|
||||||
|
temp_dir = trig_dir
|
||||||
|
trig_dir = targ_dir
|
||||||
|
targ_dir = temp_dir
|
||||||
|
self.wl_meas_objs.append(slew_measure(self.wl_slew_meas_names[-1], self.wl_signal_names[-1], trig_dir, measure_scale=1e9))
|
||||||
|
|
||||||
|
def create_sae_measurement_objects(self):
|
||||||
|
"""Create the measurements to measure the sense amp enable path from the gated_clk_bar signal. The RBL splits this path into two."""
|
||||||
|
|
||||||
|
self.sae_meas_objs = []
|
||||||
|
trig_dir = "RISE"
|
||||||
|
targ_dir = "FALL"
|
||||||
|
#Add measurements from gated_clk_bar to RBL
|
||||||
|
for i in range(1, len(self.rbl_en_signal_names)):
|
||||||
|
self.sae_meas_objs.append(delay_measure(self.rbl_delay_meas_names[i-1],
|
||||||
|
self.rbl_en_signal_names[i-1],
|
||||||
|
self.rbl_en_signal_names[i],
|
||||||
|
trig_dir,
|
||||||
|
targ_dir,
|
||||||
|
measure_scale=1e9))
|
||||||
|
self.sae_meas_objs.append(slew_measure(self.rbl_slew_meas_names[i-1],
|
||||||
|
self.rbl_en_signal_names[i-1],
|
||||||
|
trig_dir,
|
||||||
|
measure_scale=1e9))
|
||||||
|
temp_dir = trig_dir
|
||||||
|
trig_dir = targ_dir
|
||||||
|
targ_dir = temp_dir
|
||||||
|
self.sae_meas_objs.append(slew_measure(self.rbl_slew_meas_names[-1],
|
||||||
|
self.rbl_en_signal_names[-1],
|
||||||
|
trig_dir,
|
||||||
|
measure_scale=1e9))
|
||||||
|
|
||||||
|
#Add measurements from rbl_out to sae. Trigger directions do not invert from previous stage due to RBL.
|
||||||
|
trig_dir = "FALL"
|
||||||
|
targ_dir = "RISE"
|
||||||
|
#Add measurements from gated_clk_bar to RBL
|
||||||
|
for i in range(1, len(self.sae_signal_names)):
|
||||||
|
self.sae_meas_objs.append(delay_measure(self.sae_delay_meas_names[i-1],
|
||||||
|
self.sae_signal_names[i-1],
|
||||||
|
self.sae_signal_names[i],
|
||||||
|
trig_dir,
|
||||||
|
targ_dir,
|
||||||
|
measure_scale=1e9))
|
||||||
|
self.sae_meas_objs.append(slew_measure(self.sae_slew_meas_names[i-1],
|
||||||
|
self.sae_signal_names[i-1],
|
||||||
|
trig_dir,
|
||||||
|
measure_scale=1e9))
|
||||||
|
temp_dir = trig_dir
|
||||||
|
trig_dir = targ_dir
|
||||||
|
targ_dir = temp_dir
|
||||||
|
self.sae_meas_objs.append(slew_measure(self.sae_slew_meas_names[-1],
|
||||||
|
self.sae_signal_names[-1],
|
||||||
|
trig_dir,
|
||||||
|
measure_scale=1e9))
|
||||||
|
|
||||||
|
def write_delay_measures(self):
|
||||||
|
"""
|
||||||
|
Write the measure statements to quantify the delay and power results for all targeted ports.
|
||||||
|
"""
|
||||||
|
self.sf.write("\n* Measure statements for delay and power\n")
|
||||||
|
|
||||||
|
# Output some comments to aid where cycles start and what is happening
|
||||||
|
for comment in self.cycle_comments:
|
||||||
|
self.sf.write("* {}\n".format(comment))
|
||||||
|
|
||||||
|
for read_port in self.targ_read_ports:
|
||||||
|
self.write_measures_read_port(read_port)
|
||||||
|
|
||||||
|
def get_delay_measure_variants(self, port, measure_obj):
|
||||||
|
"""Get the measurement values that can either vary from simulation to simulation (vdd, address)
|
||||||
|
or port to port (time delays)"""
|
||||||
|
#Return value is intended to match the delay measure format: trig_td, targ_td, vdd, port
|
||||||
|
#Assuming only read 0 for now
|
||||||
|
if not (type(measure_obj) is delay_measure or type(measure_obj) is slew_measure):
|
||||||
|
debug.error("Measurement not recognized by the model checker.",1)
|
||||||
|
meas_cycle_delay = self.cycle_times[self.measure_cycles[port]["read0"]] + self.period/2
|
||||||
|
return (meas_cycle_delay, meas_cycle_delay, self.vdd_voltage, port)
|
||||||
|
|
||||||
|
def write_measures_read_port(self, port):
|
||||||
|
"""
|
||||||
|
Write the measure statements for all nodes along the wordline path.
|
||||||
|
"""
|
||||||
|
# add measure statements for delays/slews
|
||||||
|
for measure in self.all_measures:
|
||||||
|
measure_variant_inp_tuple = self.get_delay_measure_variants(port, measure)
|
||||||
|
measure.write_measure(self.stim, measure_variant_inp_tuple)
|
||||||
|
|
||||||
|
def get_measurement_values(self, meas_objs, port):
|
||||||
|
"""Gets the delays and slews from a specified port from the spice output file and returns them as lists."""
|
||||||
|
delay_meas_list = []
|
||||||
|
slew_meas_list = []
|
||||||
|
for measure in meas_objs:
|
||||||
|
measure_value = measure.retrieve_measure(port=port)
|
||||||
|
if type(measure_value) != float:
|
||||||
|
debug.error("Failed to Measure Value:\n\t\t{}={}".format(measure.name, measure_value),1)
|
||||||
|
if type(measure) is delay_measure:
|
||||||
|
delay_meas_list.append(measure_value)
|
||||||
|
elif type(measure)is slew_measure:
|
||||||
|
slew_meas_list.append(measure_value)
|
||||||
|
else:
|
||||||
|
debug.error("Measurement object not recognized.",1)
|
||||||
|
return delay_meas_list, slew_meas_list
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
wl_delay_result = [[] for i in self.all_ports]
|
||||||
|
wl_slew_result = [[] for i in self.all_ports]
|
||||||
|
sae_delay_result = [[] for i in self.all_ports]
|
||||||
|
sae_slew_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.
|
||||||
|
|
||||||
|
#Retrieve the results from the output file
|
||||||
|
for port in self.targ_read_ports:
|
||||||
|
#Parse and check the voltage measurements
|
||||||
|
wl_delay_result[port], wl_slew_result[port] = self.get_measurement_values(self.wl_meas_objs, port)
|
||||||
|
sae_delay_result[port], sae_slew_result[port] = self.get_measurement_values(self.sae_meas_objs, port)
|
||||||
|
return (True,wl_delay_result, sae_delay_result, wl_slew_result, sae_slew_result)
|
||||||
|
|
||||||
|
def get_model_delays(self, port):
|
||||||
|
"""Get model delays based on port. Currently assumes single RW port."""
|
||||||
|
return self.sram.control_logic_rw.get_wl_sen_delays()
|
||||||
|
|
||||||
|
def get_num_delay_stages(self):
|
||||||
|
"""Gets the number of stages in the delay chain from the control logic"""
|
||||||
|
return len(self.sram.control_logic_rw.replica_bitline.delay_fanout_list)
|
||||||
|
|
||||||
|
def get_num_delay_fanout_list(self):
|
||||||
|
"""Gets the number of stages in the delay chain from the control logic"""
|
||||||
|
return self.sram.control_logic_rw.replica_bitline.delay_fanout_list
|
||||||
|
|
||||||
|
def get_num_delay_stage_fanout(self):
|
||||||
|
"""Gets fanout in each stage in the delay chain. Assumes each stage is the same"""
|
||||||
|
return self.sram.control_logic_rw.replica_bitline.delay_fanout_list[0]
|
||||||
|
|
||||||
|
def get_num_wl_en_driver_stages(self):
|
||||||
|
"""Gets the number of stages in the wl_en driver from the control logic"""
|
||||||
|
return self.sram.control_logic_rw.wl_en_driver.num_stages
|
||||||
|
|
||||||
|
def get_num_sen_driver_stages(self):
|
||||||
|
"""Gets the number of stages in the sen driver from the control logic"""
|
||||||
|
return self.sram.control_logic_rw.s_en_driver.num_stages
|
||||||
|
|
||||||
|
def get_num_wl_driver_stages(self):
|
||||||
|
"""Gets the number of stages in the wordline driver from the control logic"""
|
||||||
|
return self.sram.bank.wordline_driver.inv.num_stages
|
||||||
|
|
||||||
|
def scale_delays(self, delay_list):
|
||||||
|
"""Takes in a list of measured delays and convert it to simple units to easily compare to model values."""
|
||||||
|
converted_values = []
|
||||||
|
#Calculate average
|
||||||
|
total = 0
|
||||||
|
for meas_value in delay_list:
|
||||||
|
total+=meas_value
|
||||||
|
average = total/len(delay_list)
|
||||||
|
|
||||||
|
#Convert values
|
||||||
|
for meas_value in delay_list:
|
||||||
|
converted_values.append(meas_value/average)
|
||||||
|
return converted_values
|
||||||
|
|
||||||
|
def min_max_normalization(self, value_list):
|
||||||
|
"""Re-scales input values on a range from 0-1 where min(list)=0, max(list)=1"""
|
||||||
|
scaled_values = []
|
||||||
|
min_max_diff = max(value_list) - min(value_list)
|
||||||
|
average = sum(value_list)/len(value_list)
|
||||||
|
for value in value_list:
|
||||||
|
scaled_values.append((value-average)/(min_max_diff))
|
||||||
|
return scaled_values
|
||||||
|
|
||||||
|
def calculate_error_l2_norm(self, list_a, list_b):
|
||||||
|
"""Calculates error between two lists using the l2 norm"""
|
||||||
|
error_list = []
|
||||||
|
for val_a, val_b in zip(list_a, list_b):
|
||||||
|
error_list.append((val_a-val_b)**2)
|
||||||
|
return error_list
|
||||||
|
|
||||||
|
def compare_measured_and_model(self, measured_vals, model_vals):
|
||||||
|
"""First scales both inputs into similar ranges and then compares the error between both."""
|
||||||
|
scaled_meas = self.min_max_normalization(measured_vals)
|
||||||
|
debug.info(1, "Scaled measurements:\n{}".format(scaled_meas))
|
||||||
|
scaled_model = self.min_max_normalization(model_vals)
|
||||||
|
debug.info(1, "Scaled model:\n{}".format(scaled_model))
|
||||||
|
errors = self.calculate_error_l2_norm(scaled_meas, scaled_model)
|
||||||
|
debug.info(1, "Errors:\n{}\n".format(errors))
|
||||||
|
|
||||||
|
def analyze(self, probe_address, probe_data, slews, loads):
|
||||||
|
"""Measures entire delay path along the wordline and sense amp enable and compare it to the model delays."""
|
||||||
|
self.load=max(loads)
|
||||||
|
self.slew=max(slews)
|
||||||
|
self.set_probe(probe_address, probe_data)
|
||||||
|
self.create_signal_names()
|
||||||
|
self.create_measurement_names()
|
||||||
|
self.create_measurement_objects()
|
||||||
|
data_dict = {}
|
||||||
|
|
||||||
|
read_port = self.read_ports[0] #only test the first read port
|
||||||
|
self.targ_read_ports = [read_port]
|
||||||
|
self.targ_write_ports = [self.write_ports[0]]
|
||||||
|
debug.info(1,"Model test: corner {}".format(self.corner))
|
||||||
|
(success, wl_delays, sae_delays, wl_slews, sae_slews)=self.run_delay_simulation()
|
||||||
|
debug.check(success, "Model measurements Failed: period={}".format(self.period))
|
||||||
|
wl_model_delays, sae_model_delays = self.get_model_delays(read_port)
|
||||||
|
|
||||||
|
debug.info(1,"Measured Wordline delays (ns):\n\t {}".format(wl_delays[read_port]))
|
||||||
|
debug.info(1,"Wordline model delays:\n\t {}".format(wl_model_delays))
|
||||||
|
debug.info(1,"Measured Wordline slews:\n\t {}".format(wl_slews[read_port]))
|
||||||
|
debug.info(1,"Measured SAE delays (ns):\n\t {}".format(sae_delays[read_port]))
|
||||||
|
debug.info(1,"SAE model delays:\n\t {}".format(sae_model_delays))
|
||||||
|
debug.info(1,"Measured SAE slews:\n\t {}".format(sae_slews[read_port]))
|
||||||
|
|
||||||
|
data_dict[self.wl_meas_name] = wl_delays[read_port]
|
||||||
|
data_dict[self.wl_model_name] = wl_model_delays
|
||||||
|
data_dict[self.sae_meas_name] = sae_delays[read_port]
|
||||||
|
data_dict[self.sae_model_name] = sae_model_delays
|
||||||
|
data_dict[self.wl_slew_name] = wl_slews[read_port]
|
||||||
|
data_dict[self.sae_slew_name] = sae_slews[read_port]
|
||||||
|
|
||||||
|
#Some evaluations of the model and measured values
|
||||||
|
# debug.info(1, "Comparing wordline measurements and model.")
|
||||||
|
# self.compare_measured_and_model(wl_delays[read_port], wl_model_delays)
|
||||||
|
# debug.info(1, "Comparing SAE measurements and model")
|
||||||
|
# self.compare_measured_and_model(sae_delays[read_port], sae_model_delays)
|
||||||
|
|
||||||
|
return data_dict
|
||||||
|
|
||||||
|
def get_all_signal_names(self):
|
||||||
|
"""Returns all signals names as a dict indexed by hardcoded names. Useful for writing the head of the CSV."""
|
||||||
|
name_dict = {}
|
||||||
|
#Signal names are more descriptive than the measurement names, first value trimmed to match size of measurements names.
|
||||||
|
name_dict[self.wl_meas_name] = self.wl_signal_names[1:]
|
||||||
|
name_dict[self.wl_model_name] = name_dict["wl_measures"] #model uses same names as measured.
|
||||||
|
name_dict[self.sae_meas_name] = self.rbl_en_signal_names[1:]+self.sae_signal_names[1:]
|
||||||
|
name_dict[self.sae_model_name] = name_dict["sae_measures"]
|
||||||
|
name_dict[self.wl_slew_name] = self.wl_slew_meas_names
|
||||||
|
name_dict[self.sae_slew_name] = self.rbl_slew_meas_names+self.sae_slew_meas_names
|
||||||
|
return name_dict
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -258,14 +258,15 @@ class stimuli():
|
||||||
|
|
||||||
# UIC is needed for ngspice to converge
|
# UIC is needed for ngspice to converge
|
||||||
self.sf.write(".TRAN {0}p {1}n UIC\n".format(timestep,end_time))
|
self.sf.write(".TRAN {0}p {1}n UIC\n".format(timestep,end_time))
|
||||||
|
self.sf.write(".TEMP {}\n".format(self.temperature))
|
||||||
if OPTS.spice_name == "ngspice":
|
if OPTS.spice_name == "ngspice":
|
||||||
# ngspice sometimes has convergence problems if not using gear method
|
# ngspice sometimes has convergence problems if not using gear method
|
||||||
# which is more accurate, but slower than the default trapezoid method
|
# which is more accurate, but slower than the default trapezoid method
|
||||||
# Do not remove this or it may not converge due to some "pa_00" nodes
|
# Do not remove this or it may not converge due to some "pa_00" nodes
|
||||||
# unless you figure out what these are.
|
# unless you figure out what these are.
|
||||||
self.sf.write(".OPTIONS POST=1 RELTOL={0} PROBE method=gear TEMP={1}\n".format(reltol,self.temperature))
|
self.sf.write(".OPTIONS POST=1 RELTOL={0} PROBE method=gear\n".format(reltol))
|
||||||
else:
|
else:
|
||||||
self.sf.write(".OPTIONS POST=1 RUNLVL={0} PROBE TEMP={1}\n".format(runlvl,self.temperature))
|
self.sf.write(".OPTIONS POST=1 RUNLVL={0} PROBE\n".format(runlvl))
|
||||||
|
|
||||||
# create plots for all signals
|
# create plots for all signals
|
||||||
self.sf.write("* probe is used for hspice/xa, while plot is used in ngspice\n")
|
self.sf.write("* probe is used for hspice/xa, while plot is used in ngspice\n")
|
||||||
|
|
|
||||||
|
After Width: | Height: | Size: 17 KiB |
|
|
@ -19,8 +19,8 @@
|
||||||
padding-top: 11px;
|
padding-top: 11px;
|
||||||
padding-bottom: 11px;
|
padding-bottom: 11px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
background-color: #004184;
|
background-color: #003C6C;
|
||||||
color: #F1B521;
|
color: #FDC700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 42 KiB |
|
|
@ -28,17 +28,17 @@ class datasheet():
|
||||||
# for item in self.description:
|
# for item in self.description:
|
||||||
# self.html += item + ','
|
# self.html += item + ','
|
||||||
self.html += '-->'
|
self.html += '-->'
|
||||||
|
# Add vlsida logo
|
||||||
vlsi_logo = 0
|
vlsi_logo = 0
|
||||||
with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/vlsi_logo.png', "rb") as image_file:
|
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())
|
vlsi_logo = base64.b64encode(image_file.read())
|
||||||
|
|
||||||
|
# Add openram logo
|
||||||
openram_logo = 0
|
openram_logo = 0
|
||||||
with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/openram_logo_placeholder.png', "rb") as image_file:
|
with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/OpenRAM_logo.png', "rb") as image_file:
|
||||||
openram_logo = base64.b64encode(image_file.read())
|
openram_logo = base64.b64encode(image_file.read())
|
||||||
|
|
||||||
self.html += '<a href="https://vlsida.soe.ucsc.edu/"><img src="data:image/png;base64,{0}" alt="VLSIDA"></a>'.format(str(vlsi_logo)[
|
self.html += '<a href="https://vlsida.soe.ucsc.edu/"><img src="data:image/png;base64,{0}" alt="VLSIDA"></a><a href ="https://github.com/VLSIDA/OpenRAM"><img src ="data:image/png;base64,{1}" alt = "OpenRAM"></a>'.format(str(vlsi_logo)[2:-1], str(openram_logo)[2:-1])
|
||||||
2:-1])
|
|
||||||
|
|
||||||
self.html += '<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">' + \
|
self.html += '<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">' + \
|
||||||
self.name + '.html' + '</p>'
|
self.name + '.html' + '</p>'
|
||||||
|
|
@ -49,23 +49,30 @@ class datasheet():
|
||||||
'LVS errors: ' + str(self.LVS) + '</p>'
|
'LVS errors: ' + str(self.LVS) + '</p>'
|
||||||
self.html += '<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">' + \
|
self.html += '<p style="font-size: 18px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">' + \
|
||||||
'Git commit id: ' + str(self.git_id) + '</p>'
|
'Git commit id: ' + str(self.git_id) + '</p>'
|
||||||
|
# print port table
|
||||||
self.html += '<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Ports and Configuration</p>'
|
self.html += '<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Ports and Configuration</p>'
|
||||||
# self.html += in_out(self.io,table_id='data').__html__().replace('<','<').replace('"','"').replace('>',">")
|
|
||||||
self.html += self.io_table.to_html()
|
self.html += self.io_table.to_html()
|
||||||
|
|
||||||
|
# print operating condidition information
|
||||||
self.html += '<p style="font-size: 26px;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 += self.operating_table.to_html()
|
self.html += self.operating_table.to_html()
|
||||||
|
|
||||||
self.html += '<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Timing and Current Data</p>'
|
# check if analytical model is being used
|
||||||
# self.html += timing_and_current_data(self.timing,table_id='data').__html__()
|
self.html += '<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Timing Data</p>'
|
||||||
|
model = ''
|
||||||
|
if self.ANALYTICAL_MODEL == 'True':
|
||||||
|
model = "analytical model: results may not be precise"
|
||||||
|
else:
|
||||||
|
model = "spice characterizer"
|
||||||
|
# display timing data
|
||||||
|
self.html += '<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Using '+model+'</p>'
|
||||||
self.html += self.timing_table.to_html()
|
self.html += self.timing_table.to_html()
|
||||||
|
# display power data
|
||||||
|
self.html += '<p style="font-size: 26px;font-family: Trebuchet MS, Arial, Helvetica, sans-serif;">Power Data</p>'
|
||||||
|
self.html += self.power_table.to_html()
|
||||||
|
# display corner information
|
||||||
self.html += '<p style="font-size: 26px;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 += self.corners_table.to_html()
|
self.html += self.corners_table.to_html()
|
||||||
|
# display deliverables table
|
||||||
self.html += '<p style="font-size: 26px;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 += self.dlv_table.to_html()
|
self.html += self.dlv_table.to_html()
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ This is a script to load data from the characterization and layout processes int
|
||||||
a web friendly html datasheet.
|
a web friendly html datasheet.
|
||||||
"""
|
"""
|
||||||
# TODO:
|
# TODO:
|
||||||
# include power
|
|
||||||
# Diagram generation
|
# Diagram generation
|
||||||
# Improve css
|
# Improve css
|
||||||
|
|
||||||
|
|
@ -16,19 +15,34 @@ import csv
|
||||||
import datasheet
|
import datasheet
|
||||||
import table_gen
|
import table_gen
|
||||||
|
|
||||||
|
# def process_name(corner):
|
||||||
def process_name(corner):
|
# """
|
||||||
"""
|
# Expands the names of the characterization corner types into something human friendly
|
||||||
Expands the names of the characterization corner types into something human friendly
|
# """
|
||||||
"""
|
# if corner == "TS":
|
||||||
if corner == "TT":
|
# return "Typical - Slow"
|
||||||
return "Typical - Typical"
|
# if corner == "TT":
|
||||||
if corner == "SS":
|
# return "Typical - Typical"
|
||||||
return "Slow - Slow"
|
# if corner == "TF":
|
||||||
if corner == "FF":
|
# return "Typical - Fast"
|
||||||
return "Fast - Fast"
|
#
|
||||||
else:
|
# if corner == "SS":
|
||||||
return "custom"
|
# return "Slow - Slow"
|
||||||
|
# if corner == "ST":
|
||||||
|
# return "Slow - Typical"
|
||||||
|
# if corner == "SF":
|
||||||
|
# return "Slow - Fast"
|
||||||
|
#
|
||||||
|
# if corner == "FS":
|
||||||
|
# return "Fast - Slow"
|
||||||
|
# if corner == "FT":
|
||||||
|
# return "Fast - Typical"
|
||||||
|
# if corner == "FF":
|
||||||
|
# return "Fast - Fast"
|
||||||
|
#
|
||||||
|
# else:
|
||||||
|
# return "custom"
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
def parse_characterizer_csv(f, pages):
|
def parse_characterizer_csv(f, pages):
|
||||||
|
|
@ -92,6 +106,9 @@ def parse_characterizer_csv(f, pages):
|
||||||
DATETIME = row[col]
|
DATETIME = row[col]
|
||||||
col += 1
|
col += 1
|
||||||
|
|
||||||
|
ANALYTICAL_MODEL = row[col]
|
||||||
|
col += 1
|
||||||
|
|
||||||
DRC = row[col]
|
DRC = row[col]
|
||||||
col += 1
|
col += 1
|
||||||
|
|
||||||
|
|
@ -100,6 +117,7 @@ def parse_characterizer_csv(f, pages):
|
||||||
|
|
||||||
AREA = row[col]
|
AREA = row[col]
|
||||||
col += 1
|
col += 1
|
||||||
|
|
||||||
for sheet in pages:
|
for sheet in pages:
|
||||||
|
|
||||||
if sheet.name == NAME:
|
if sheet.name == NAME:
|
||||||
|
|
@ -133,7 +151,7 @@ def parse_characterizer_csv(f, pages):
|
||||||
1000/float(MIN_PERIOD)))
|
1000/float(MIN_PERIOD)))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
# check current .lib file produces the slowest timing results
|
||||||
while(True):
|
while(True):
|
||||||
col_start = col
|
col_start = col
|
||||||
if(row[col].startswith('DIN')):
|
if(row[col].startswith('DIN')):
|
||||||
|
|
@ -147,31 +165,31 @@ def parse_characterizer_csv(f, pages):
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('setup falling'):
|
if item[0].endswith('setup falling'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('hold rising'):
|
if item[0].endswith('hold rising'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('hold falling'):
|
if item[0].endswith('hold falling'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
col += 1
|
col += 1
|
||||||
|
|
||||||
|
|
@ -186,31 +204,31 @@ def parse_characterizer_csv(f, pages):
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('cell fall'):
|
if item[0].endswith('cell fall'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('rise transition'):
|
if item[0].endswith('rise transition'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('fall transition'):
|
if item[0].endswith('fall transition'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
col += 1
|
col += 1
|
||||||
|
|
||||||
|
|
@ -225,31 +243,31 @@ def parse_characterizer_csv(f, pages):
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('setup falling'):
|
if item[0].endswith('setup falling'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('hold rising'):
|
if item[0].endswith('hold rising'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('hold falling'):
|
if item[0].endswith('hold falling'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
col += 1
|
col += 1
|
||||||
|
|
||||||
|
|
@ -264,31 +282,31 @@ def parse_characterizer_csv(f, pages):
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('setup falling'):
|
if item[0].endswith('setup falling'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('hold rising'):
|
if item[0].endswith('hold rising'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('hold falling'):
|
if item[0].endswith('hold falling'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
col += 1
|
col += 1
|
||||||
|
|
||||||
|
|
@ -303,31 +321,31 @@ def parse_characterizer_csv(f, pages):
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('setup falling'):
|
if item[0].endswith('setup falling'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('hold rising'):
|
if item[0].endswith('hold rising'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
elif item[0].endswith('hold falling'):
|
if item[0].endswith('hold falling'):
|
||||||
if float(row[col+1]) < float(item[1]):
|
if float(row[col+1]) < float(item[1]):
|
||||||
item[1] = row[col+1]
|
item[1] = row[col+1]
|
||||||
if float(row[col+2]) > float(item[2]):
|
if float(row[col+2]) > float(item[2]):
|
||||||
item[2] = row[col+2]
|
item[2] = row[col+2]
|
||||||
|
|
||||||
col += 2
|
col += 2
|
||||||
|
|
||||||
col += 1
|
col += 1
|
||||||
|
|
||||||
|
|
@ -336,8 +354,36 @@ def parse_characterizer_csv(f, pages):
|
||||||
sheet.description.append(str(element))
|
sheet.description.append(str(element))
|
||||||
break
|
break
|
||||||
|
|
||||||
new_sheet.corners_table.add_row([PROC, process_name(
|
#check if new power is worse the previous
|
||||||
PROC), VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')])
|
while(True):
|
||||||
|
col_start = col
|
||||||
|
if row[col] == 'power':
|
||||||
|
for item in sheet.power_table.rows:
|
||||||
|
if item[0].startswith(row[col+1]):
|
||||||
|
if item[2].startswith('{0} Rising'.format(row[col+2])):
|
||||||
|
if float(item[2]) < float(row[col+3]):
|
||||||
|
item[2] = row[col+3]
|
||||||
|
if item[2].startswith('{0} Falling'.format(row[col+2])):
|
||||||
|
if float(item[2]) < float(row[col+3]):
|
||||||
|
item[2] = row[col+3]
|
||||||
|
col += 4
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
# check if new leakge is worse the previous
|
||||||
|
while(True):
|
||||||
|
col_start = col
|
||||||
|
if row[col] == 'leak':
|
||||||
|
for item in sheet.power_table.rows:
|
||||||
|
if item[0].startswith(row[col+1]):
|
||||||
|
if float(item[2]) < float(row[col+2]):
|
||||||
|
item[2] = row[col+2]
|
||||||
|
col += 3
|
||||||
|
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
# add new corner information
|
||||||
|
new_sheet.corners_table.add_row(
|
||||||
|
[PROC, VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')])
|
||||||
new_sheet.dlv_table.add_row(
|
new_sheet.dlv_table.add_row(
|
||||||
['.lib', 'Synthesis models', '<a href="file://{0}">{1}</a>'.format(LIB_NAME, LIB_NAME.replace(OUT_DIR, ''))])
|
['.lib', 'Synthesis models', '<a href="file://{0}">{1}</a>'.format(LIB_NAME, LIB_NAME.replace(OUT_DIR, ''))])
|
||||||
|
|
||||||
|
|
@ -351,14 +397,15 @@ def parse_characterizer_csv(f, pages):
|
||||||
new_sheet.time = DATETIME
|
new_sheet.time = DATETIME
|
||||||
new_sheet.DRC = DRC
|
new_sheet.DRC = DRC
|
||||||
new_sheet.LVS = LVS
|
new_sheet.LVS = LVS
|
||||||
|
new_sheet.ANALYTICAL_MODEL = ANALYTICAL_MODEL
|
||||||
new_sheet.description = [NAME, NUM_WORDS, NUM_BANKS, NUM_RW_PORTS, NUM_W_PORTS,
|
new_sheet.description = [NAME, NUM_WORDS, NUM_BANKS, NUM_RW_PORTS, NUM_W_PORTS,
|
||||||
NUM_R_PORTS, TECH_NAME, MIN_PERIOD, WORD_SIZE, ORIGIN_ID, DATETIME]
|
NUM_R_PORTS, TECH_NAME, MIN_PERIOD, WORD_SIZE, ORIGIN_ID, DATETIME]
|
||||||
|
|
||||||
new_sheet.corners_table = table_gen.table_gen("corners")
|
new_sheet.corners_table = table_gen.table_gen("corners")
|
||||||
new_sheet.corners_table.add_row(
|
new_sheet.corners_table.add_row(
|
||||||
['Corner Name', 'Process', 'Power Supply', 'Temperature', 'Library Name Suffix'])
|
['Transistor Type', 'Power Supply', 'Temperature', 'Corner Name'])
|
||||||
new_sheet.corners_table.add_row([PROC, process_name(
|
new_sheet.corners_table.add_row(
|
||||||
PROC), VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')])
|
[PROC, VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')])
|
||||||
new_sheet.operating_table = table_gen.table_gen(
|
new_sheet.operating_table = table_gen.table_gen(
|
||||||
"operating_table")
|
"operating_table")
|
||||||
new_sheet.operating_table.add_row(
|
new_sheet.operating_table.add_row(
|
||||||
|
|
@ -375,9 +422,13 @@ def parse_characterizer_csv(f, pages):
|
||||||
# failed to provide non-zero MIN_PERIOD
|
# failed to provide non-zero MIN_PERIOD
|
||||||
new_sheet.operating_table.add_row(
|
new_sheet.operating_table.add_row(
|
||||||
['Operating Frequency (F)', '', '', "not available in netlist only", 'MHz'])
|
['Operating Frequency (F)', '', '', "not available in netlist only", 'MHz'])
|
||||||
|
new_sheet.power_table = table_gen.table_gen("power")
|
||||||
|
new_sheet.power_table.add_row(
|
||||||
|
['Pins', 'Mode', 'Power', 'Units'])
|
||||||
new_sheet.timing_table = table_gen.table_gen("timing")
|
new_sheet.timing_table = table_gen.table_gen("timing")
|
||||||
new_sheet.timing_table.add_row(
|
new_sheet.timing_table.add_row(
|
||||||
['Parameter', 'Min', 'Max', 'Units'])
|
['Parameter', 'Min', 'Max', 'Units'])
|
||||||
|
# parse initial timing information
|
||||||
while(True):
|
while(True):
|
||||||
col_start = col
|
col_start = col
|
||||||
if(row[col].startswith('DIN')):
|
if(row[col].startswith('DIN')):
|
||||||
|
|
@ -504,6 +555,32 @@ def parse_characterizer_csv(f, pages):
|
||||||
for element in row[col_start:col-1]:
|
for element in row[col_start:col-1]:
|
||||||
sheet.description.append(str(element))
|
sheet.description.append(str(element))
|
||||||
break
|
break
|
||||||
|
# parse initial power and leakage information
|
||||||
|
while(True):
|
||||||
|
start = col
|
||||||
|
if(row[col].startswith('power')):
|
||||||
|
new_sheet.power_table.add_row([row[col+1],
|
||||||
|
'{0} Rising'.format(
|
||||||
|
row[col+2]),
|
||||||
|
row[col+3][0:6],
|
||||||
|
'mW']
|
||||||
|
)
|
||||||
|
new_sheet.power_table.add_row([row[col+1],
|
||||||
|
'{0} Falling'.format(
|
||||||
|
row[col+2]),
|
||||||
|
row[col+3][0:6],
|
||||||
|
'mW']
|
||||||
|
)
|
||||||
|
|
||||||
|
col += 4
|
||||||
|
|
||||||
|
elif(row[col].startswith('leak')):
|
||||||
|
new_sheet.power_table.add_row(
|
||||||
|
[row[col+1], 'leakage', row[col+2], 'mW'])
|
||||||
|
col += 3
|
||||||
|
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
new_sheet.dlv_table = table_gen.table_gen("dlv")
|
new_sheet.dlv_table = table_gen.table_gen("dlv")
|
||||||
new_sheet.dlv_table.add_row(['Type', 'Description', 'Link'])
|
new_sheet.dlv_table.add_row(['Type', 'Description', 'Link'])
|
||||||
|
|
@ -537,12 +614,13 @@ def parse_characterizer_csv(f, pages):
|
||||||
new_sheet.io_table.add_row(['NUM_RW_PORTS', NUM_RW_PORTS])
|
new_sheet.io_table.add_row(['NUM_RW_PORTS', NUM_RW_PORTS])
|
||||||
new_sheet.io_table.add_row(['NUM_R_PORTS', NUM_R_PORTS])
|
new_sheet.io_table.add_row(['NUM_R_PORTS', NUM_R_PORTS])
|
||||||
new_sheet.io_table.add_row(['NUM_W_PORTS', NUM_W_PORTS])
|
new_sheet.io_table.add_row(['NUM_W_PORTS', NUM_W_PORTS])
|
||||||
new_sheet.io_table.add_row(['Area', AREA])
|
new_sheet.io_table.add_row(
|
||||||
|
['Area (µm<sup>2</sup>)', str(round(float(AREA)))])
|
||||||
|
|
||||||
|
|
||||||
class datasheet_gen():
|
class datasheet_gen():
|
||||||
def datasheet_write(name):
|
def datasheet_write(name):
|
||||||
|
"""writes the datasheet to a file"""
|
||||||
in_dir = OPTS.openram_temp
|
in_dir = OPTS.openram_temp
|
||||||
|
|
||||||
if not (os.path.isdir(in_dir)):
|
if not (os.path.isdir(in_dir)):
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,29 @@
|
||||||
class table_gen:
|
class table_gen:
|
||||||
def __init__(self,name):
|
"""small library of functions to generate the html tables"""
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.rows = []
|
self.rows = []
|
||||||
self.table_id = 'data'
|
self.table_id = 'data'
|
||||||
|
|
||||||
def add_row(self,row):
|
def add_row(self, row):
|
||||||
|
"""add a row to table_gen object"""
|
||||||
self.rows.append(row)
|
self.rows.append(row)
|
||||||
|
|
||||||
def gen_table_head(self):
|
def gen_table_head(self):
|
||||||
|
"""generate html table header"""
|
||||||
html = ''
|
html = ''
|
||||||
|
|
||||||
html += '<thead>'
|
html += '<thead>'
|
||||||
html += '<tr>'
|
html += '<tr>'
|
||||||
for col in self.rows[0]:
|
for col in self.rows[0]:
|
||||||
html += '<th>' + str(col) + '</th>'
|
html += '<th>' + str(col) + '</th>'
|
||||||
html += '</tr>'
|
html += '</tr>'
|
||||||
html += '</thead>'
|
html += '</thead>'
|
||||||
return html
|
return html
|
||||||
|
|
||||||
def gen_table_body(self):
|
def gen_table_body(self):
|
||||||
|
"""generate html body (used after gen_table_head)"""
|
||||||
html = ''
|
html = ''
|
||||||
|
|
||||||
html += '<tbody>'
|
html += '<tbody>'
|
||||||
|
|
@ -33,7 +38,7 @@ class table_gen:
|
||||||
return html
|
return html
|
||||||
|
|
||||||
def to_html(self):
|
def to_html(self):
|
||||||
|
"""writes table_gen object to inline html"""
|
||||||
html = ''
|
html = ''
|
||||||
html += '<table id= \"'+self.table_id+'\">'
|
html += '<table id= \"'+self.table_id+'\">'
|
||||||
html += self.gen_table_head()
|
html += self.gen_table_head()
|
||||||
|
|
|
||||||
|
|
@ -1,827 +0,0 @@
|
||||||
#!/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 )
|
|
||||||
|
|
@ -48,19 +48,37 @@ def print_raw(str):
|
||||||
|
|
||||||
|
|
||||||
def log(str):
|
def log(str):
|
||||||
if log.create_file:
|
if globals.OPTS.output_name != '':
|
||||||
compile_log = open(globals.OPTS.output_path +
|
if log.create_file:
|
||||||
globals.OPTS.output_name + '.log', "w")
|
# We may have not yet read the config, so we need to ensure
|
||||||
log.create_file = 0
|
# it ends with a /
|
||||||
|
# This is also done in read_config if we change the path
|
||||||
|
# FIXME: There's actually a bug here. The first few lines
|
||||||
|
# could be in one log file and after read_config it could be
|
||||||
|
# in another log file if the path or name changes.
|
||||||
|
if not globals.OPTS.output_path.endswith('/'):
|
||||||
|
globals.OPTS.output_path += "/"
|
||||||
|
compile_log = open(globals.OPTS.output_path +
|
||||||
|
globals.OPTS.output_name + '.log', "w+")
|
||||||
|
log.create_file = 0
|
||||||
|
else:
|
||||||
|
compile_log = open(globals.OPTS.output_path +
|
||||||
|
globals.OPTS.output_name + '.log', "a")
|
||||||
|
|
||||||
|
if len(log.setup_output) != 0:
|
||||||
|
for line in log.setup_output:
|
||||||
|
compile_log.write(line)
|
||||||
|
log.setup_output = []
|
||||||
|
compile_log.write(str + '\n')
|
||||||
else:
|
else:
|
||||||
compile_log = open(globals.OPTS.output_path +
|
log.setup_output.append(str + "\n")
|
||||||
globals.OPTS.output_name + '.log', "a")
|
|
||||||
compile_log.write(str + '\n')
|
|
||||||
|
# use a static list of strings to store messages until the global paths are set up
|
||||||
|
log.setup_output = []
|
||||||
log.create_file = 1
|
log.create_file = 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def info(lev, str):
|
def info(lev, str):
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
if (OPTS.debug_level >= lev):
|
if (OPTS.debug_level >= lev):
|
||||||
|
|
@ -71,5 +89,5 @@ def info(lev, str):
|
||||||
class_name = ""
|
class_name = ""
|
||||||
else:
|
else:
|
||||||
class_name = mod.__name__
|
class_name = mod.__name__
|
||||||
print_raw("[{0}/{1}]: {2}".format(class_name, frm[0].f_code.co_name, str))
|
print_raw("[{0}/{1}]: {2}".format(class_name,
|
||||||
|
frm[0].f_code.co_name, str))
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
word_size = 2
|
word_size = 2
|
||||||
num_words = 16
|
num_words = 16
|
||||||
|
|
||||||
bitcell = "bitcell_1rw_1r"
|
|
||||||
replica_bitcell = "replica_bitcell_1rw_1r"
|
|
||||||
num_rw_ports = 1
|
num_rw_ports = 1
|
||||||
num_r_ports = 1
|
num_r_ports = 1
|
||||||
num_w_ports = 0
|
num_w_ports = 0
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
word_size = 2
|
||||||
|
num_words = 16
|
||||||
|
|
||||||
|
num_rw_ports = 1
|
||||||
|
num_r_ports = 1
|
||||||
|
num_w_ports = 0
|
||||||
|
|
||||||
|
tech_name = "scn4m_subm"
|
||||||
|
process_corners = ["TT"]
|
||||||
|
supply_voltages = [5.0]
|
||||||
|
temperatures = [25]
|
||||||
|
|
||||||
|
output_path = "temp"
|
||||||
|
output_name = "sram_1w_1r_{0}_{1}_{2}".format(word_size,num_words,tech_name)
|
||||||
|
|
||||||
|
drc_name = "magic"
|
||||||
|
lvs_name = "netgen"
|
||||||
|
pex_name = "magic"
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
468eb9a4a038201c2b0004fe6e4ae9b2d37fdd57
|
|
||||||
|
|
@ -133,6 +133,8 @@ def init_openram(config_file, is_unit_test=True):
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
factory.reset()
|
factory.reset()
|
||||||
|
|
||||||
|
setup_bitcell()
|
||||||
|
|
||||||
# Reset the static duplicate name checker for unit tests.
|
# Reset the static duplicate name checker for unit tests.
|
||||||
import hierarchy_design
|
import hierarchy_design
|
||||||
hierarchy_design.hierarchy_design.name_map=[]
|
hierarchy_design.hierarchy_design.name_map=[]
|
||||||
|
|
@ -157,6 +159,46 @@ def init_openram(config_file, is_unit_test=True):
|
||||||
if not CHECKPOINT_OPTS:
|
if not CHECKPOINT_OPTS:
|
||||||
CHECKPOINT_OPTS = copy.copy(OPTS)
|
CHECKPOINT_OPTS = copy.copy(OPTS)
|
||||||
|
|
||||||
|
def setup_bitcell():
|
||||||
|
"""
|
||||||
|
Determine the correct custom or parameterized bitcell for the design.
|
||||||
|
"""
|
||||||
|
global OPTS
|
||||||
|
|
||||||
|
# If we have non-1rw ports,
|
||||||
|
# and the user didn't over-ride the bitcell manually,
|
||||||
|
# figure out the right bitcell to use
|
||||||
|
if (OPTS.bitcell=="bitcell" and OPTS.replica_bitcell=="replica_bitcell"):
|
||||||
|
|
||||||
|
if (OPTS.num_rw_ports==1 and OPTS.num_w_ports==0 and OPTS.num_r_ports==0):
|
||||||
|
OPTS.bitcell = "bitcell"
|
||||||
|
OPTS.replica_bitcell = "replica_bitcell"
|
||||||
|
else:
|
||||||
|
ports = ""
|
||||||
|
if OPTS.num_rw_ports>0:
|
||||||
|
ports += "{}rw_".format(OPTS.num_rw_ports)
|
||||||
|
if OPTS.num_w_ports>0:
|
||||||
|
ports += "{}w_".format(OPTS.num_w_ports)
|
||||||
|
if OPTS.num_r_ports>0:
|
||||||
|
ports += "{}r".format(OPTS.num_r_ports)
|
||||||
|
|
||||||
|
OPTS.bitcell = "bitcell_"+ports
|
||||||
|
OPTS.replica_bitcell = "replica_bitcell_"+ports
|
||||||
|
|
||||||
|
# See if a custom bitcell exists
|
||||||
|
from importlib import find_loader
|
||||||
|
bitcell_loader = find_loader(OPTS.bitcell)
|
||||||
|
replica_bitcell_loader = find_loader(OPTS.replica_bitcell)
|
||||||
|
# Use the pbitcell if we couldn't find a custom bitcell
|
||||||
|
# or its custom replica bitcell
|
||||||
|
if bitcell_loader==None or replica_bitcell_loader==None:
|
||||||
|
# Use the pbitcell (and give a warning if not in unit test mode)
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.replica_bitcell = "replica_pbitcell"
|
||||||
|
if not OPTS.is_unit_test:
|
||||||
|
debug.warning("Using the parameterized bitcell which may have suboptimal density.")
|
||||||
|
|
||||||
|
debug.info(1,"Using bitcell: {}".format(OPTS.bitcell))
|
||||||
|
|
||||||
|
|
||||||
def get_tool(tool_type, preferences, default_name=None):
|
def get_tool(tool_type, preferences, default_name=None):
|
||||||
|
|
@ -253,6 +295,7 @@ def read_config(config_file, is_unit_test=True):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def end_openram():
|
def end_openram():
|
||||||
""" Clean up openram for a proper exit """
|
""" Clean up openram for a proper exit """
|
||||||
cleanup_paths()
|
cleanup_paths()
|
||||||
|
|
@ -417,7 +460,11 @@ def report_status():
|
||||||
debug.error("Tech name must be specified in config file.")
|
debug.error("Tech name must be specified in config file.")
|
||||||
|
|
||||||
debug.print_raw("Technology: {0}".format(OPTS.tech_name))
|
debug.print_raw("Technology: {0}".format(OPTS.tech_name))
|
||||||
debug.print_raw("Total size: {} bits".format(OPTS.word_size*OPTS.num_words*OPTS.num_banks))
|
total_size = OPTS.word_size*OPTS.num_words*OPTS.num_banks
|
||||||
|
debug.print_raw("Total size: {} bits".format(total_size))
|
||||||
|
if total_size>=2**14:
|
||||||
|
debug.warning("Requesting such a large memory size ({0}) will have a large run-time. ".format(total_size) +
|
||||||
|
"Consider using multiple smaller banks.")
|
||||||
debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size,
|
debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size,
|
||||||
OPTS.num_words,
|
OPTS.num_words,
|
||||||
OPTS.num_banks))
|
OPTS.num_banks))
|
||||||
|
|
|
||||||
|
|
@ -1216,26 +1216,30 @@ class bank(design.design):
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, vdd, slew, load):
|
def analytical_delay(self, corner, slew, load):
|
||||||
""" return analytical delay of the bank"""
|
""" return analytical delay of the bank"""
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
decoder_delay = self.row_decoder.analytical_delay(slew, self.wordline_driver.input_load())
|
decoder_delay = self.row_decoder.analytical_delay(corner, slew, self.wordline_driver.input_load())
|
||||||
|
|
||||||
word_driver_delay = self.wordline_driver.analytical_delay(decoder_delay.slew, self.bitcell_array.input_load())
|
word_driver_delay = self.wordline_driver.analytical_delay(corner,
|
||||||
|
decoder_delay.slew,
|
||||||
|
self.bitcell_array.input_load())
|
||||||
|
|
||||||
#FIXME: Array delay is the same for every port.
|
#FIXME: Array delay is the same for every port.
|
||||||
bitcell_array_delay = self.bitcell_array.analytical_delay(word_driver_delay.slew)
|
bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_delay.slew)
|
||||||
|
|
||||||
#This also essentially creates the same delay for each port. Good structure, no substance
|
#This also essentially creates the same delay for each port. Good structure, no substance
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
if self.words_per_row > 1:
|
if self.words_per_row > 1:
|
||||||
column_mux_delay = self.column_mux_array[port].analytical_delay(vdd, bitcell_array_delay.slew,
|
column_mux_delay = self.column_mux_array[port].analytical_delay(corner,
|
||||||
self.sense_amp_array.input_load())
|
bitcell_array_delay.slew,
|
||||||
|
self.sense_amp_array.input_load())
|
||||||
else:
|
else:
|
||||||
column_mux_delay = self.return_delay(delay = 0.0, slew=word_driver_delay.slew)
|
column_mux_delay = self.return_delay(delay = 0.0, slew=word_driver_delay.slew)
|
||||||
|
|
||||||
bl_t_data_out_delay = self.sense_amp_array.analytical_delay(column_mux_delay.slew,
|
bl_t_data_out_delay = self.sense_amp_array.analytical_delay(corner,
|
||||||
|
column_mux_delay.slew,
|
||||||
self.bitcell_array.output_load())
|
self.bitcell_array.output_load())
|
||||||
# output load of bitcell_array is set to be only small part of bl for sense amp.
|
# output load of bitcell_array is set to be only small part of bl for sense amp.
|
||||||
results.append(decoder_delay + word_driver_delay + bitcell_array_delay + column_mux_delay + bl_t_data_out_delay)
|
results.append(decoder_delay + word_driver_delay + bitcell_array_delay + column_mux_delay + bl_t_data_out_delay)
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ class bitcell_array(design.design):
|
||||||
self.add_power_pin(pin_name, pin.center(), 0, pin.layer)
|
self.add_power_pin(pin_name, pin.center(), 0, pin.layer)
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0):
|
def analytical_delay(self, corner, slew, load=0):
|
||||||
from tech import drc
|
from tech import drc
|
||||||
wl_wire = self.gen_wl_wire()
|
wl_wire = self.gen_wl_wire()
|
||||||
wl_wire.return_delay_over_wire(slew)
|
wl_wire.return_delay_over_wire(slew)
|
||||||
|
|
@ -141,25 +141,25 @@ class bitcell_array(design.design):
|
||||||
cell_load = 2 * bl_wire.return_input_cap() # we ingore the wire r
|
cell_load = 2 * bl_wire.return_input_cap() # we ingore the wire r
|
||||||
# hence just use the whole c
|
# hence just use the whole c
|
||||||
bl_swing = 0.1
|
bl_swing = 0.1
|
||||||
cell_delay = self.cell.analytical_delay(wl_to_cell_delay.slew, cell_load, swing = bl_swing)
|
cell_delay = self.cell.analytical_delay(corner, wl_to_cell_delay.slew, cell_load, swing = bl_swing)
|
||||||
|
|
||||||
#we do not consider the delay over the wire for now
|
#we do not consider the delay over the wire for now
|
||||||
return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
|
return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
|
||||||
wl_to_cell_delay.slew)
|
wl_to_cell_delay.slew)
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Power of Bitcell array and bitline in nW."""
|
"""Power of Bitcell array and bitline in nW."""
|
||||||
from tech import drc
|
from tech import drc, parameter
|
||||||
|
|
||||||
# Dynamic Power from Bitline
|
# Dynamic Power from Bitline
|
||||||
bl_wire = self.gen_bl_wire()
|
bl_wire = self.gen_bl_wire()
|
||||||
cell_load = 2 * bl_wire.return_input_cap()
|
cell_load = 2 * bl_wire.return_input_cap()
|
||||||
bl_swing = 0.1 #This should probably be defined in the tech file or input
|
bl_swing = parameter["rbl_height_percentage"]
|
||||||
freq = spice["default_event_rate"]
|
freq = spice["default_event_rate"]
|
||||||
bitline_dynamic = bl_swing*cell_load*vdd*vdd*freq #not sure if calculation is correct
|
bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing)
|
||||||
|
|
||||||
#Calculate the bitcell power which currently only includes leakage
|
#Calculate the bitcell power which currently only includes leakage
|
||||||
cell_power = self.cell.analytical_power(proc, vdd, temp, load)
|
cell_power = self.cell.analytical_power(corner, load)
|
||||||
|
|
||||||
#Leakage power grows with entire array and bitlines.
|
#Leakage power grows with entire array and bitlines.
|
||||||
total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size,
|
total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size,
|
||||||
|
|
|
||||||
|
|
@ -30,13 +30,15 @@ class control_logic(design.design):
|
||||||
self.port_type = port_type
|
self.port_type = port_type
|
||||||
|
|
||||||
self.num_cols = word_size*words_per_row
|
self.num_cols = word_size*words_per_row
|
||||||
self.num_words = num_rows * words_per_row
|
self.num_words = num_rows*words_per_row
|
||||||
|
|
||||||
self.enable_delay_chain_resizing = False
|
self.enable_delay_chain_resizing = True
|
||||||
|
|
||||||
#self.sram=None #disable re-sizing for debugging, FIXME: resizing is not working, needs to be adjusted for new control logic.
|
#Determines how much larger the sen delay should be. Accounts for possible error in model.
|
||||||
self.wl_timing_tolerance = 1 #Determines how much larger the sen delay should be. Accounts for possible error in model.
|
self.wl_timing_tolerance = 1
|
||||||
self.parasitic_inv_delay = parameter["min_inv_para_delay"] #Keeping 0 for now until further testing.
|
self.parasitic_inv_delay = parameter["min_inv_para_delay"]
|
||||||
|
self.wl_stage_efforts = None
|
||||||
|
self.sen_stage_efforts = None
|
||||||
|
|
||||||
if self.port_type == "rw":
|
if self.port_type == "rw":
|
||||||
self.num_control_signals = 2
|
self.num_control_signals = 2
|
||||||
|
|
@ -130,42 +132,60 @@ class control_logic(design.design):
|
||||||
self.add_mod(self.p_en_bar_driver)
|
self.add_mod(self.p_en_bar_driver)
|
||||||
|
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||||
delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
|
from importlib import reload
|
||||||
bitcell_loads = int(math.ceil(self.num_rows / 2.0))
|
self.delay_chain_resized = False
|
||||||
self.replica_bitline = factory.create(module_type="replica_bitline",
|
c = reload(__import__(OPTS.replica_bitline))
|
||||||
delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic,
|
replica_bitline = getattr(c, OPTS.replica_bitline)
|
||||||
bitcell_loads=bitcell_loads)
|
bitcell_loads = int(math.ceil(self.num_rows * parameter["rbl_height_percentage"]))
|
||||||
|
#Use a model to determine the delays with that heuristic
|
||||||
|
if OPTS.use_tech_delay_chain_size: #Use tech parameters if set.
|
||||||
if self.sram != None:
|
fanout_list = parameter["static_fanout_list"]
|
||||||
self.set_sen_wl_delays()
|
debug.info(1, "Using tech parameters to size delay chain: fanout_list={}".format(fanout_list))
|
||||||
|
|
||||||
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 = factory.create(module_type="replica_bitline",
|
self.replica_bitline = factory.create(module_type="replica_bitline",
|
||||||
delay_fanout_list=[delay_fanout]*delay_stages,
|
delay_fanout_list=fanout_list,
|
||||||
bitcell_loads=bitcell_loads)
|
bitcell_loads=bitcell_loads)
|
||||||
|
if self.sram != None: #Calculate model value even for specified sizes
|
||||||
|
self.set_sen_wl_delays()
|
||||||
|
|
||||||
self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing
|
else: #Otherwise, use a heuristic and/or model based sizing.
|
||||||
|
#First use a heuristic
|
||||||
|
delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
|
||||||
|
self.replica_bitline = factory.create(module_type="replica_bitline",
|
||||||
|
delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic,
|
||||||
|
bitcell_loads=bitcell_loads)
|
||||||
|
#Resize if necessary, condition depends on resizing method
|
||||||
|
if self.sram != None and self.enable_delay_chain_resizing and not self.does_sen_rise_fall_timing_match():
|
||||||
|
#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 = factory.create(module_type="replica_bitline",
|
||||||
|
delay_fanout_list=stage_list,
|
||||||
|
bitcell_loads=bitcell_loads)
|
||||||
|
|
||||||
|
#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 = factory.create(module_type="replica_bitline",
|
||||||
|
# delay_fanout_list=[delay_fanout]*delay_stages,
|
||||||
|
# bitcell_loads=bitcell_loads)
|
||||||
|
|
||||||
|
self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing
|
||||||
|
self.delay_chain_resized = True
|
||||||
|
|
||||||
self.add_mod(self.replica_bitline)
|
self.add_mod(self.replica_bitline)
|
||||||
|
|
||||||
def get_heuristic_delay_chain_size(self):
|
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 """
|
"""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
|
#FIXME: The minimum was 2 fanout, now it will not pass DRC unless it is 3. Why?
|
||||||
delay_fanout = 3 # This can be anything >=2
|
delay_fanout = 3 # This can be anything >=3
|
||||||
# Delay stages Must be non-inverting
|
# Model poorly captures delay of the column mux. Be pessismistic for column mux
|
||||||
if self.words_per_row >= 4:
|
if self.words_per_row >= 2:
|
||||||
delay_stages = 8
|
delay_stages = 8
|
||||||
elif self.words_per_row == 2:
|
|
||||||
delay_stages = 6
|
|
||||||
else:
|
else:
|
||||||
delay_stages = 4
|
delay_stages = 2
|
||||||
|
|
||||||
|
#Read ports have a shorter s_en delay. The model is not accurate enough to catch this difference
|
||||||
|
#on certain sram configs.
|
||||||
|
if self.port_type == "r":
|
||||||
|
delay_stages+=2
|
||||||
|
|
||||||
return (delay_stages, delay_fanout)
|
return (delay_stages, delay_fanout)
|
||||||
|
|
||||||
|
|
@ -227,14 +247,25 @@ class control_logic(design.design):
|
||||||
required_delay_rise = self.wl_delay_rise*self.wl_timing_tolerance - (self.sen_delay_rise-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))
|
debug.info(2,"Required delays from chain: fall={}, rise={}".format(required_delay_fall,required_delay_rise))
|
||||||
|
|
||||||
|
#If the fanout is different between rise/fall by this amount. Stage algorithm is made more pessimistic.
|
||||||
|
WARNING_FANOUT_DIFF = 5
|
||||||
|
stages_close = False
|
||||||
#The stages need to be equal (or at least a even number of stages with matching rise/fall delays)
|
#The stages need to be equal (or at least a even number of stages with matching rise/fall delays)
|
||||||
while True:
|
while True:
|
||||||
stages_fall = self.calculate_stages_with_fixed_fanout(required_delay_fall,fanout_fall)
|
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)
|
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))
|
debug.info(1,"Fall stages={}, rise stages={}".format(stages_fall,stages_rise))
|
||||||
|
if abs(stages_fall-stages_rise) == 1 and not stages_close:
|
||||||
|
stages_close = True
|
||||||
|
safe_fanout_rise = fanout_rise
|
||||||
|
safe_fanout_fall = fanout_fall
|
||||||
|
|
||||||
if stages_fall == stages_rise:
|
if stages_fall == stages_rise:
|
||||||
break
|
break
|
||||||
elif abs(stages_fall-stages_rise) == 1:
|
elif abs(stages_fall-stages_rise) == 1 and WARNING_FANOUT_DIFF < abs(fanout_fall-fanout_rise):
|
||||||
|
debug.info(1, "Delay chain fanouts between stages are large. Making chain size larger for safety.")
|
||||||
|
fanout_rise = safe_fanout_rise
|
||||||
|
fanout_fall = safe_fanout_fall
|
||||||
break
|
break
|
||||||
#There should also be a condition to make sure the fanout does not get too large.
|
#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
|
#Otherwise, increase the fanout of delay with the most stages, calculate new stages
|
||||||
|
|
@ -819,8 +850,8 @@ class control_logic(design.design):
|
||||||
def get_delays_to_wl(self):
|
def get_delays_to_wl(self):
|
||||||
"""Get the delay (in delay units) of the clk to a wordline in the bitcell array"""
|
"""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.")
|
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()
|
self.wl_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)
|
clk_to_wl_rise,clk_to_wl_fall = logical_effort.calculate_relative_rise_fall_delays(self.wl_stage_efforts, self.parasitic_inv_delay)
|
||||||
total_delay = clk_to_wl_rise + clk_to_wl_fall
|
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))
|
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
|
return clk_to_wl_rise,clk_to_wl_fall
|
||||||
|
|
@ -849,8 +880,8 @@ class control_logic(design.design):
|
||||||
This does not incorporate the delay of the replica bitline.
|
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.")
|
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()
|
self.sen_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)
|
clk_to_sen_rise, clk_to_sen_fall = logical_effort.calculate_relative_rise_fall_delays(self.sen_stage_efforts, self.parasitic_inv_delay)
|
||||||
total_delay = clk_to_sen_rise + clk_to_sen_fall
|
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))
|
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
|
return clk_to_sen_rise, clk_to_sen_fall
|
||||||
|
|
@ -882,3 +913,11 @@ class control_logic(design.design):
|
||||||
|
|
||||||
return stage_effort_list
|
return stage_effort_list
|
||||||
|
|
||||||
|
def get_wl_sen_delays(self):
|
||||||
|
"""Gets a list of the stages and delays in order of their path."""
|
||||||
|
if self.sen_stage_efforts == None or self.wl_stage_efforts == None:
|
||||||
|
debug.error("Model delays not calculated for SRAM.", 1)
|
||||||
|
wl_delays = logical_effort.calculate_delays(self.wl_stage_efforts, self.parasitic_inv_delay)
|
||||||
|
sen_delays = logical_effort.calculate_delays(self.sen_stage_efforts, self.parasitic_inv_delay)
|
||||||
|
return wl_delays, sen_delays
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,11 @@ class dff(design.design):
|
||||||
self.height = dff.height
|
self.height = dff.height
|
||||||
self.pin_map = dff.pin_map
|
self.pin_map = dff.pin_map
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Returns dynamic and leakage power. Results in nW"""
|
"""Returns dynamic and leakage power. Results in nW"""
|
||||||
c_eff = self.calculate_effective_capacitance(load)
|
c_eff = self.calculate_effective_capacitance(load)
|
||||||
f = spice["default_event_rate"]
|
freq = spice["default_event_rate"]
|
||||||
power_dyn = c_eff*vdd*vdd*f
|
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
|
||||||
power_leak = spice["msflop_leakage"]
|
power_leak = spice["msflop_leakage"]
|
||||||
|
|
||||||
total_power = self.return_power(power_dyn, power_leak)
|
total_power = self.return_power(power_dyn, power_leak)
|
||||||
|
|
@ -39,7 +39,7 @@ class dff(design.design):
|
||||||
transition_prob = spice["flop_transition_prob"]
|
transition_prob = spice["flop_transition_prob"]
|
||||||
return transition_prob*(c_load + c_para)
|
return transition_prob*(c_load + c_para)
|
||||||
|
|
||||||
def analytical_delay(self, slew, load = 0.0):
|
def analytical_delay(self, corner, slew, load = 0.0):
|
||||||
# dont know how to calculate this now, use constant in tech file
|
# dont know how to calculate this now, use constant in tech file
|
||||||
result = self.return_delay(spice["dff_delay"], spice["dff_slew"])
|
result = self.return_delay(spice["dff_delay"], spice["dff_slew"])
|
||||||
return result
|
return result
|
||||||
|
|
|
||||||
|
|
@ -154,8 +154,8 @@ class dff_array(design.design):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
return self.dff.analytical_delay(slew=slew, load=load)
|
return self.dff.analytical_delay(corner, slew=slew, load=load)
|
||||||
|
|
||||||
def get_clk_cin(self):
|
def get_clk_cin(self):
|
||||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
|
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
|
||||||
|
|
|
||||||
|
|
@ -172,11 +172,11 @@ class dff_buf(design.design):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
""" Calculate the analytical delay of DFF-> INV -> INV """
|
""" Calculate the analytical delay of DFF-> INV -> INV """
|
||||||
dff_delay=self.dff.analytical_delay(slew=slew, load=self.inv1.input_load())
|
dff_delay=self.dff.analytical_delay(corner, slew=slew, load=self.inv1.input_load())
|
||||||
inv1_delay = self.inv1.analytical_delay(slew=dff_delay.slew, load=self.inv2.input_load())
|
inv1_delay = self.inv1.analytical_delay(corner, slew=dff_delay.slew, load=self.inv2.input_load())
|
||||||
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
|
inv2_delay = self.inv2.analytical_delay(corner, slew=inv1_delay.slew, load=load)
|
||||||
return dff_delay + inv1_delay + inv2_delay
|
return dff_delay + inv1_delay + inv2_delay
|
||||||
|
|
||||||
def get_clk_cin(self):
|
def get_clk_cin(self):
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ class dff_buf_array(design.design):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
return self.dff.analytical_delay(slew=slew, load=load)
|
return self.dff.analytical_delay(slew=slew, load=load)
|
||||||
|
|
||||||
def get_clk_cin(self):
|
def get_clk_cin(self):
|
||||||
|
|
|
||||||
|
|
@ -145,10 +145,10 @@ class dff_inv(design.design):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
""" Calculate the analytical delay of DFF-> INV -> INV """
|
""" Calculate the analytical delay of DFF-> INV -> INV """
|
||||||
dff_delay=self.dff.analytical_delay(slew=slew, load=self.inv1.input_load())
|
dff_delay=self.dff.analytical_delay(corner, slew=slew, load=self.inv1.input_load())
|
||||||
inv1_delay = self.inv1.analytical_delay(slew=dff_delay.slew, load=load)
|
inv1_delay = self.inv1.analytical_delay(corner, slew=dff_delay.slew, load=load)
|
||||||
return dff_delay + inv1_delay
|
return dff_delay + inv1_delay
|
||||||
|
|
||||||
def get_clk_cin(self):
|
def get_clk_cin(self):
|
||||||
|
|
|
||||||
|
|
@ -185,8 +185,8 @@ class dff_inv_array(design.design):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
return self.dff.analytical_delay(slew=slew, load=load)
|
return self.dff.analytical_delay(corner, slew=slew, load=load)
|
||||||
|
|
||||||
def get_clk_cin(self):
|
def get_clk_cin(self):
|
||||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
|
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
|
||||||
|
|
|
||||||
|
|
@ -594,7 +594,7 @@ class hierarchical_decoder(design.design):
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load = 0.0):
|
def analytical_delay(self, corner, slew, load = 0.0):
|
||||||
# A -> out
|
# A -> out
|
||||||
if self.determine_predecodes(self.num_inputs)[1]==0:
|
if self.determine_predecodes(self.num_inputs)[1]==0:
|
||||||
pre = self.pre2_4
|
pre = self.pre2_4
|
||||||
|
|
@ -602,15 +602,15 @@ class hierarchical_decoder(design.design):
|
||||||
else:
|
else:
|
||||||
pre = self.pre3_8
|
pre = self.pre3_8
|
||||||
nand = self.nand3
|
nand = self.nand3
|
||||||
a_t_out_delay = pre.analytical_delay(slew=slew,load = nand.input_load())
|
a_t_out_delay = pre.analytical_delay(corner, slew=slew,load = nand.input_load())
|
||||||
|
|
||||||
# out -> z
|
# out -> z
|
||||||
out_t_z_delay = nand.analytical_delay(slew= a_t_out_delay.slew,
|
out_t_z_delay = nand.analytical_delay(corner, slew= a_t_out_delay.slew,
|
||||||
load = self.inv.input_load())
|
load = self.inv.input_load())
|
||||||
result = a_t_out_delay + out_t_z_delay
|
result = a_t_out_delay + out_t_z_delay
|
||||||
|
|
||||||
# Z -> decode_out
|
# Z -> decode_out
|
||||||
z_t_decodeout_delay = self.inv.analytical_delay(slew = out_t_z_delay.slew , load = load)
|
z_t_decodeout_delay = self.inv.analytical_delay(corner, slew = out_t_z_delay.slew , load = load)
|
||||||
result = result + z_t_decodeout_delay
|
result = result + z_t_decodeout_delay
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,15 +51,15 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||||
return combination
|
return combination
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load = 0.0 ):
|
def analytical_delay(self, corner, slew, load = 0.0 ):
|
||||||
# in -> inbar
|
# in -> inbar
|
||||||
a_t_b_delay = self.inv.analytical_delay(slew=slew, load=self.nand.input_load())
|
a_t_b_delay = self.inv.analytical_delay(corner, slew=slew, load=self.nand.input_load())
|
||||||
|
|
||||||
# inbar -> z
|
# inbar -> z
|
||||||
b_t_z_delay = self.nand.analytical_delay(slew=a_t_b_delay.slew, load=self.inv.input_load())
|
b_t_z_delay = self.nand.analytical_delay(corner, slew=a_t_b_delay.slew, load=self.inv.input_load())
|
||||||
|
|
||||||
# Z -> out
|
# Z -> out
|
||||||
a_t_out_delay = self.inv.analytical_delay(slew=b_t_z_delay.slew, load=load)
|
a_t_out_delay = self.inv.analytical_delay(corner, slew=b_t_z_delay.slew, load=load)
|
||||||
|
|
||||||
return a_t_b_delay + b_t_z_delay + a_t_out_delay
|
return a_t_b_delay + b_t_z_delay + a_t_out_delay
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,15 +60,15 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
||||||
return combination
|
return combination
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load = 0.0 ):
|
def analytical_delay(self, corner, slew, load = 0.0 ):
|
||||||
# A -> Abar
|
# A -> Abar
|
||||||
a_t_b_delay = self.inv.analytical_delay(slew=slew, load=self.nand.input_load())
|
a_t_b_delay = self.inv.analytical_delay(corner, slew=slew, load=self.nand.input_load())
|
||||||
|
|
||||||
# Abar -> z
|
# Abar -> z
|
||||||
b_t_z_delay = self.nand.analytical_delay(slew=a_t_b_delay.slew, load=self.inv.input_load())
|
b_t_z_delay = self.nand.analytical_delay(corner, slew=a_t_b_delay.slew, load=self.inv.input_load())
|
||||||
|
|
||||||
# Z -> out
|
# Z -> out
|
||||||
a_t_out_delay = self.inv.analytical_delay(slew=b_t_z_delay.slew, load=load)
|
a_t_out_delay = self.inv.analytical_delay(corner, slew=b_t_z_delay.slew, load=load)
|
||||||
|
|
||||||
return a_t_b_delay + b_t_z_delay + a_t_out_delay
|
return a_t_b_delay + b_t_z_delay + a_t_out_delay
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -816,19 +816,19 @@ class multibank(design.design):
|
||||||
offset=in_pin + self.m2m3_via_offset,
|
offset=in_pin + self.m2m3_via_offset,
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
def analytical_delay(self, slew, load):
|
def analytical_delay(self, corner, slew, load):
|
||||||
""" return analytical delay of the bank"""
|
""" return analytical delay of the bank"""
|
||||||
decoder_delay = self.row_decoder.analytical_delay(slew, self.wordline_driver.input_load())
|
decoder_delay = self.row_decoder.analytical_delay(corner, slew, self.wordline_driver.input_load())
|
||||||
|
|
||||||
word_driver_delay = self.wordline_driver.analytical_delay(decoder_delay.slew, self.bitcell_array.input_load())
|
word_driver_delay = self.wordline_driver.analytical_delay(corner, decoder_delay.slew, self.bitcell_array.input_load())
|
||||||
|
|
||||||
bitcell_array_delay = self.bitcell_array.analytical_delay(word_driver_delay.slew)
|
bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_delay.slew)
|
||||||
|
|
||||||
bl_t_data_out_delay = self.sense_amp_array.analytical_delay(bitcell_array_delay.slew,
|
bl_t_data_out_delay = self.sense_amp_array.analytical_delay(corner, bitcell_array_delay.slew,
|
||||||
self.bitcell_array.output_load())
|
self.bitcell_array.output_load())
|
||||||
# output load of bitcell_array is set to be only small part of bl for sense amp.
|
# output load of bitcell_array is set to be only small part of bl for sense amp.
|
||||||
|
|
||||||
data_t_DATA_delay = self.tri_gate_array.analytical_delay(bl_t_data_out_delay.slew, load)
|
data_t_DATA_delay = self.tri_gate_array.analytical_delay(corner, bl_t_data_out_delay.slew, load)
|
||||||
|
|
||||||
result = decoder_delay + word_driver_delay + bitcell_array_delay + bl_t_data_out_delay + data_t_DATA_delay
|
result = decoder_delay + word_driver_delay + bitcell_array_delay + bl_t_data_out_delay + data_t_DATA_delay
|
||||||
return result
|
return result
|
||||||
|
|
|
||||||
|
|
@ -31,14 +31,14 @@ class sense_amp(design.design):
|
||||||
bitline_pmos_size = 8 #FIXME: This should be set somewhere and referenced. Probably in tech file.
|
bitline_pmos_size = 8 #FIXME: This should be set somewhere and referenced. Probably in tech file.
|
||||||
return spice["min_tx_drain_c"]*(bitline_pmos_size/parameter["min_tx_size"])#ff
|
return spice["min_tx_drain_c"]*(bitline_pmos_size/parameter["min_tx_size"])#ff
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
from tech import spice
|
from tech import spice
|
||||||
r = spice["min_tx_r"]/(10)
|
r = spice["min_tx_r"]/(10)
|
||||||
c_para = spice["min_tx_drain_c"]
|
c_para = spice["min_tx_drain_c"]
|
||||||
result = self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)
|
result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
|
||||||
return self.return_delay(result.delay, result.slew)
|
return self.return_delay(result.delay, result.slew)
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Returns dynamic and leakage power. Results in nW"""
|
"""Returns dynamic and leakage power. Results in nW"""
|
||||||
#Power in this module currently not defined. Returns 0 nW (leakage and dynamic).
|
#Power in this module currently not defined. Returns 0 nW (leakage and dynamic).
|
||||||
total_power = self.return_power()
|
total_power = self.return_power()
|
||||||
|
|
@ -48,4 +48,5 @@ class sense_amp(design.design):
|
||||||
"""Get the relative capacitance of sense amp enable gate cin"""
|
"""Get the relative capacitance of sense amp enable gate cin"""
|
||||||
pmos_cin = parameter["sa_en_pmos_size"]/drc("minwidth_tx")
|
pmos_cin = parameter["sa_en_pmos_size"]/drc("minwidth_tx")
|
||||||
nmos_cin = parameter["sa_en_nmos_size"]/drc("minwidth_tx")
|
nmos_cin = parameter["sa_en_nmos_size"]/drc("minwidth_tx")
|
||||||
|
#sen is connected to 2 pmos isolation TX and 1 nmos per sense amp.
|
||||||
return 2*pmos_cin + nmos_cin
|
return 2*pmos_cin + nmos_cin
|
||||||
|
|
@ -136,10 +136,10 @@ class sense_amp_array(design.design):
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
return self.amp.input_load()
|
return self.amp.input_load()
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
return self.amp.analytical_delay(slew=slew, load=load)
|
return self.amp.analytical_delay(corner, slew=slew, load=load)
|
||||||
|
|
||||||
def get_en_cin(self):
|
def get_en_cin(self):
|
||||||
"""Get the relative capacitance of all the sense amp enable connections in the array"""
|
"""Get the relative capacitance of all the sense amp enable connections in the array"""
|
||||||
sense_amp_en_cin = self.amp.get_en_cin()
|
sense_amp_en_cin = self.amp.get_en_cin()
|
||||||
return sense_amp_en_cin * self.words_per_row
|
return sense_amp_en_cin * self.word_size
|
||||||
|
|
|
||||||
|
|
@ -216,13 +216,14 @@ class single_level_column_mux_array(design.design):
|
||||||
offset= br_out_offset,
|
offset= br_out_offset,
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
def analytical_delay(self, vdd, slew, load=0.0):
|
def analytical_delay(self, corner, vdd, slew, load=0.0):
|
||||||
from tech import spice, parameter
|
from tech import spice, parameter
|
||||||
|
proc,vdd,temp = corner
|
||||||
r = spice["min_tx_r"]/(self.mux.ptx_width/parameter["min_tx_size"])
|
r = spice["min_tx_r"]/(self.mux.ptx_width/parameter["min_tx_size"])
|
||||||
#Drains of mux transistors make up capacitance.
|
#Drains of mux transistors make up capacitance.
|
||||||
c_para = spice["min_tx_drain_c"]*(self.mux.ptx_width/parameter["min_tx_size"])*self.words_per_row#ff
|
c_para = spice["min_tx_drain_c"]*(self.mux.ptx_width/parameter["min_tx_size"])*self.words_per_row#ff
|
||||||
volt_swing = spice["v_threshold_typical"]/vdd
|
volt_swing = spice["v_threshold_typical"]/vdd
|
||||||
|
|
||||||
result = self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew, swing = volt_swing)
|
result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = volt_swing)
|
||||||
return self.return_delay(result.delay, result.slew)
|
return self.return_delay(result.delay, result.slew)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,13 @@ class tri_gate(design.design):
|
||||||
self.height = tri_gate.height
|
self.height = tri_gate.height
|
||||||
self.pin_map = tri_gate.pin_map
|
self.pin_map = tri_gate.pin_map
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
from tech import spice
|
from tech import spice
|
||||||
r = spice["min_tx_r"]
|
r = spice["min_tx_r"]
|
||||||
c_para = spice["min_tx_drain_c"]
|
c_para = spice["min_tx_drain_c"]
|
||||||
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)
|
return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Returns dynamic and leakage power. Results in nW"""
|
"""Returns dynamic and leakage power. Results in nW"""
|
||||||
#Power in this module currently not defined. Returns 0 nW (leakage and dynamic).
|
#Power in this module currently not defined. Returns 0 nW (leakage and dynamic).
|
||||||
total_power = self.return_power()
|
total_power = self.return_power()
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,6 @@ class tri_gate_array(design.design):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
return self.tri.analytical_delay(slew = slew, load = load)
|
return self.tri.analytical_delay(corner, slew = slew, load = load)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -210,12 +210,12 @@ class wordline_driver(design.design):
|
||||||
end=wl_offset-vector(self.m1_width,0))
|
end=wl_offset-vector(self.m1_width,0))
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0):
|
def analytical_delay(self, corner, slew, load=0):
|
||||||
# decode -> net
|
# decode -> net
|
||||||
decode_t_net = self.nand2.analytical_delay(slew, self.inv.input_load())
|
decode_t_net = self.nand2.analytical_delay(corner, slew, self.inv.input_load())
|
||||||
|
|
||||||
# net -> wl
|
# net -> wl
|
||||||
net_t_wl = self.inv.analytical_delay(decode_t_net.slew, load)
|
net_t_wl = self.inv.analytical_delay(corner, decode_t_net.slew, load)
|
||||||
|
|
||||||
return decode_t_net + net_t_wl
|
return decode_t_net + net_t_wl
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,9 @@ class options(optparse.Values):
|
||||||
# You can manually specify banks, but it is better to auto-detect it.
|
# You can manually specify banks, but it is better to auto-detect it.
|
||||||
num_banks = 1
|
num_banks = 1
|
||||||
|
|
||||||
|
#Uses the delay chain size in the tech.py file rather automatic sizing.
|
||||||
|
use_tech_delay_chain_size = False
|
||||||
|
|
||||||
# These are the default modules that can be over-riden
|
# These are the default modules that can be over-riden
|
||||||
bank_select = "bank_select"
|
bank_select = "bank_select"
|
||||||
bitcell_array = "bitcell_array"
|
bitcell_array = "bitcell_array"
|
||||||
|
|
|
||||||
|
|
@ -107,10 +107,10 @@ class pand2(pgate.pgate):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
""" Calculate the analytical delay of DFF-> INV -> INV """
|
""" Calculate the analytical delay of DFF-> INV -> INV """
|
||||||
nand_delay = selfnand.analytical_delay(slew=slew, load=self.inv.input_load())
|
nand_delay = self.nand.analytical_delay(corner, slew=slew, load=self.inv.input_load())
|
||||||
inv_delay = self.inv.analytical_delay(slew=nand_delay.slew, load=load)
|
inv_delay = self.inv.analytical_delay(corner, slew=nand_delay.slew, load=load)
|
||||||
return nand_delay + inv_delay
|
return nand_delay + inv_delay
|
||||||
|
|
||||||
def get_stage_efforts(self, external_cout, inp_is_rise=False):
|
def get_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||||
|
|
|
||||||
|
|
@ -110,10 +110,10 @@ class pbuf(pgate.pgate):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
""" Calculate the analytical delay of DFF-> INV -> INV """
|
""" Calculate the analytical delay of DFF-> INV -> INV """
|
||||||
inv1_delay = self.inv1.analytical_delay(slew=slew, load=self.inv2.input_load())
|
inv1_delay = self.inv1.analytical_delay(corner, slew=slew, load=self.inv2.input_load())
|
||||||
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
|
inv2_delay = self.inv2.analytical_delay(corner, slew=inv1_delay.slew, load=load)
|
||||||
return inv1_delay + inv2_delay
|
return inv1_delay + inv2_delay
|
||||||
|
|
||||||
def get_stage_efforts(self, external_cout, inp_is_rise=False):
|
def get_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ class pdriver(pgate.pgate):
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
return self.inv_list[0].input_load()
|
return self.inv_list[0].input_load()
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
"""Calculate the analytical delay of INV1 -> ... -> INVn"""
|
"""Calculate the analytical delay of INV1 -> ... -> INVn"""
|
||||||
|
|
||||||
cout_list = []
|
cout_list = []
|
||||||
|
|
@ -184,7 +184,7 @@ class pdriver(pgate.pgate):
|
||||||
|
|
||||||
delays = []
|
delays = []
|
||||||
for inv,cout in zip(self.inv_list,cout_list):
|
for inv,cout in zip(self.inv_list,cout_list):
|
||||||
delays.append(inv.analytical_delay(slew=input_slew, load=cout))
|
delays.append(inv.analytical_delay(corner, slew=input_slew, load=cout))
|
||||||
input_slew = delays[-1].slew
|
input_slew = delays[-1].slew
|
||||||
|
|
||||||
delay = delays[0]
|
delay = delays[0]
|
||||||
|
|
@ -196,17 +196,16 @@ class pdriver(pgate.pgate):
|
||||||
|
|
||||||
def get_stage_efforts(self, external_cout, inp_is_rise=False):
|
def get_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||||
"""Get the stage efforts of the A -> Z path"""
|
"""Get the stage efforts of the A -> Z path"""
|
||||||
|
cout_list = []
|
||||||
cout_list = {}
|
|
||||||
for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]):
|
for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]):
|
||||||
cout_list[prev_inv]=inv.get_cin()
|
cout_list.append(inv.get_cin())
|
||||||
|
|
||||||
cout_list[self.inv_list[-1]]=external_cout
|
cout_list.append(external_cout)
|
||||||
|
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
last_inp_is_rise = inp_is_rise
|
last_inp_is_rise = inp_is_rise
|
||||||
for inv in self.inv_list:
|
for inv,cout in zip(self.inv_list,cout_list):
|
||||||
stage = inv.get_stage_effort(cout_list[inv], last_inp_is_rise)
|
stage = inv.get_stage_effort(cout, last_inp_is_rise)
|
||||||
stage_effort_list.append(stage)
|
stage_effort_list.append(stage)
|
||||||
last_inp_is_rise = stage.is_rise
|
last_inp_is_rise = stage.is_rise
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -261,16 +261,16 @@ class pinv(pgate.pgate):
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
||||||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
||||||
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)
|
return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Returns dynamic and leakage power. Results in nW"""
|
"""Returns dynamic and leakage power. Results in nW"""
|
||||||
c_eff = self.calculate_effective_capacitance(load)
|
c_eff = self.calculate_effective_capacitance(load)
|
||||||
freq = spice["default_event_rate"]
|
freq = spice["default_event_rate"]
|
||||||
power_dyn = c_eff*vdd*vdd*freq
|
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
|
||||||
power_leak = spice["inv_leakage"]
|
power_leak = spice["inv_leakage"]
|
||||||
|
|
||||||
total_power = self.return_power(power_dyn, power_leak)
|
total_power = self.return_power(power_dyn, power_leak)
|
||||||
|
|
@ -292,4 +292,4 @@ class pinv(pgate.pgate):
|
||||||
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
||||||
"""
|
"""
|
||||||
parasitic_delay = 1
|
parasitic_delay = 1
|
||||||
return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
|
return logical_effort.logical_effort(self.name, self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
|
||||||
|
|
|
||||||
|
|
@ -177,10 +177,10 @@ class pinvbuf(design.design):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
""" Calculate the analytical delay of DFF-> INV -> INV """
|
""" Calculate the analytical delay of DFF-> INV -> INV """
|
||||||
inv1_delay = self.inv1.analytical_delay(slew=slew, load=self.inv2.input_load())
|
inv1_delay = self.inv1.analytical_delay(corner, slew=slew, load=self.inv2.input_load())
|
||||||
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
|
inv2_delay = self.inv2.analytical_delay(corner, slew=inv1_delay.slew, load=load)
|
||||||
return inv1_delay + inv2_delay
|
return inv1_delay + inv2_delay
|
||||||
|
|
||||||
def determine_clk_buf_stage_efforts(self, external_cout, inp_is_rise=False):
|
def determine_clk_buf_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||||
|
|
|
||||||
|
|
@ -227,16 +227,16 @@ class pnand2(pgate.pgate):
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
||||||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
||||||
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)
|
return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Returns dynamic and leakage power. Results in nW"""
|
"""Returns dynamic and leakage power. Results in nW"""
|
||||||
c_eff = self.calculate_effective_capacitance(load)
|
c_eff = self.calculate_effective_capacitance(load)
|
||||||
freq = spice["default_event_rate"]
|
freq = spice["default_event_rate"]
|
||||||
power_dyn = c_eff*vdd*vdd*freq
|
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
|
||||||
power_leak = spice["nand2_leakage"]
|
power_leak = spice["nand2_leakage"]
|
||||||
|
|
||||||
total_power = self.return_power(power_dyn, power_leak)
|
total_power = self.return_power(power_dyn, power_leak)
|
||||||
|
|
@ -258,4 +258,4 @@ class pnand2(pgate.pgate):
|
||||||
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
||||||
"""
|
"""
|
||||||
parasitic_delay = 2
|
parasitic_delay = 2
|
||||||
return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
|
return logical_effort.logical_effort(self.name, self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import debug
|
||||||
from tech import drc, parameter, spice
|
from tech import drc, parameter, spice
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
import logical_effort
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
||||||
class pnand3(pgate.pgate):
|
class pnand3(pgate.pgate):
|
||||||
|
|
@ -239,16 +240,16 @@ class pnand3(pgate.pgate):
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
||||||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
||||||
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)
|
return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Returns dynamic and leakage power. Results in nW"""
|
"""Returns dynamic and leakage power. Results in nW"""
|
||||||
c_eff = self.calculate_effective_capacitance(load)
|
c_eff = self.calculate_effective_capacitance(load)
|
||||||
freq = spice["default_event_rate"]
|
freq = spice["default_event_rate"]
|
||||||
power_dyn = c_eff*vdd*vdd*freq
|
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
|
||||||
power_leak = spice["nand3_leakage"]
|
power_leak = spice["nand3_leakage"]
|
||||||
|
|
||||||
total_power = self.return_power(power_dyn, power_leak)
|
total_power = self.return_power(power_dyn, power_leak)
|
||||||
|
|
@ -270,4 +271,4 @@ class pnand3(pgate.pgate):
|
||||||
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
|
||||||
"""
|
"""
|
||||||
parasitic_delay = 3
|
parasitic_delay = 3
|
||||||
return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
|
return logical_effort.logical_effort(self.name, self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
|
||||||
|
|
|
||||||
|
|
@ -212,16 +212,16 @@ class pnor2(pgate.pgate):
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, corner, slew, load=0.0):
|
||||||
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
||||||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
||||||
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)
|
return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Returns dynamic and leakage power. Results in nW"""
|
"""Returns dynamic and leakage power. Results in nW"""
|
||||||
c_eff = self.calculate_effective_capacitance(load)
|
c_eff = self.calculate_effective_capacitance(load)
|
||||||
freq = spice["default_event_rate"]
|
freq = spice["default_event_rate"]
|
||||||
power_dyn = c_eff*vdd*vdd*freq
|
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
|
||||||
power_leak = spice["nor2_leakage"]
|
power_leak = spice["nor2_leakage"]
|
||||||
|
|
||||||
total_power = self.return_power(power_dyn, power_leak)
|
total_power = self.return_power(power_dyn, power_leak)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
import pstats
|
|
||||||
p = pstats.Stats('profile.dat')
|
|
||||||
p.strip_dirs()
|
|
||||||
p.sort_stats('cumulative')
|
|
||||||
p.print_stats(50)
|
|
||||||
|
|
@ -499,9 +499,9 @@ class sram_base(design, verilog, lef):
|
||||||
sp.close()
|
sp.close()
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, vdd, slew,load):
|
def analytical_delay(self, corner, slew,load):
|
||||||
""" LH and HL are the same in analytical model. """
|
""" LH and HL are the same in analytical model. """
|
||||||
return self.bank.analytical_delay(vdd,slew,load)
|
return self.bank.analytical_delay(corner,slew,load)
|
||||||
|
|
||||||
def determine_wordline_stage_efforts(self, inp_is_rise=True):
|
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"""
|
"""Get the all the stage efforts for each stage in the path from clk_buf to a wordline"""
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,13 @@ from sram_factory import factory
|
||||||
class sram_config:
|
class sram_config:
|
||||||
""" This is a structure that is used to hold the SRAM configuration options. """
|
""" This is a structure that is used to hold the SRAM configuration options. """
|
||||||
|
|
||||||
def __init__(self, word_size, num_words, num_banks=1):
|
def __init__(self, word_size, num_words, num_banks=1, words_per_row=None):
|
||||||
self.word_size = word_size
|
self.word_size = word_size
|
||||||
self.num_words = num_words
|
self.num_words = num_words
|
||||||
self.num_banks = num_banks
|
self.num_banks = num_banks
|
||||||
|
|
||||||
# This will get over-written when we determine the organization
|
# This will get over-written when we determine the organization
|
||||||
self.words_per_row = None
|
self.words_per_row = words_per_row
|
||||||
|
|
||||||
self.compute_sizes()
|
self.compute_sizes()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,17 +36,21 @@ class control_logic_test(openram_test):
|
||||||
|
|
||||||
# Check port specific control logic
|
# Check port specific control logic
|
||||||
OPTS.num_rw_ports = 1
|
OPTS.num_rw_ports = 1
|
||||||
OPTS.num_w_ports = 1
|
OPTS.num_w_ports = 0
|
||||||
OPTS.num_r_ports = 1
|
OPTS.num_r_ports = 0
|
||||||
|
|
||||||
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
||||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="rw")
|
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="rw")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
OPTS.num_rw_ports = 0
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
||||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="w")
|
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="w")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
|
debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
|
||||||
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="r")
|
a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="r")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Run a regression test on a 1 bank SRAM
|
||||||
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from testutils import header,openram_test
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
import debug
|
||||||
|
|
||||||
|
#@unittest.skip("SKIPPING 20_psram_1bank_2mux_1w_1r_test, odd supply routing error")
|
||||||
|
class psram_1bank_2mux_1w_1r_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
|
from sram import sram
|
||||||
|
from sram_config import sram_config
|
||||||
|
OPTS.bitcell = "bitcell_1w_1r"
|
||||||
|
OPTS.replica_bitcell="replica_bitcell_1w_1r"
|
||||||
|
|
||||||
|
OPTS.num_rw_ports = 0
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
|
||||||
|
c = sram_config(word_size=4,
|
||||||
|
num_words=32,
|
||||||
|
num_banks=1)
|
||||||
|
c.num_words=32
|
||||||
|
c.words_per_row=2
|
||||||
|
c.recompute_sizes()
|
||||||
|
debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
|
||||||
|
OPTS.num_r_ports,
|
||||||
|
OPTS.num_w_ports,
|
||||||
|
c.word_size,
|
||||||
|
c.num_words,
|
||||||
|
c.words_per_row,
|
||||||
|
c.num_banks))
|
||||||
|
a = sram(c, "sram")
|
||||||
|
self.local_check(a, final_verification=True)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# run the test from the command line
|
||||||
|
if __name__ == "__main__":
|
||||||
|
(OPTS, args) = globals.parse_args()
|
||||||
|
del sys.argv[1:]
|
||||||
|
header(__file__, OPTS.tech_name)
|
||||||
|
unittest.main()
|
||||||
|
|
@ -23,7 +23,7 @@ class timing_sram_test(openram_test):
|
||||||
from importlib import reload
|
from importlib import reload
|
||||||
import characterizer
|
import characterizer
|
||||||
reload(characterizer)
|
reload(characterizer)
|
||||||
from characterizer import delay, bitline_delay
|
from characterizer import delay
|
||||||
from sram import sram
|
from sram import sram
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
c = sram_config(word_size=1,
|
c = sram_config(word_size=1,
|
||||||
|
|
@ -43,37 +43,44 @@ class timing_sram_test(openram_test):
|
||||||
|
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
d = delay(s.s, tempspice, corner)
|
d = delay(s.s, tempspice, corner)
|
||||||
bl = bitline_delay(s.s, tempspice, corner)
|
|
||||||
import tech
|
import tech
|
||||||
loads = [tech.spice["msflop_in_cap"]*4]
|
loads = [tech.spice["msflop_in_cap"]*4]
|
||||||
slews = [tech.spice["rise_time"]*2]
|
slews = [tech.spice["rise_time"]*2]
|
||||||
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
|
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
|
#Combine info about port into all data
|
||||||
data.update(port_data[0])
|
data.update(port_data[0])
|
||||||
|
|
||||||
if OPTS.tech_name == "freepdk45":
|
if OPTS.tech_name == "freepdk45":
|
||||||
golden_data = {'delay_hl': [0.2152017],
|
golden_data = {'delay_bl': [0.1980959],
|
||||||
'delay_lh': [0.2152017],
|
'delay_br': [0.1946091],
|
||||||
'leakage_power': 0.0022907,
|
'delay_hl': [0.2121267],
|
||||||
'min_period': 0.488,
|
'delay_lh': [0.2121267],
|
||||||
'read0_power': [0.47437749999999995],
|
'leakage_power': 0.0023761999999999998,
|
||||||
'read1_power': [0.45026109999999997],
|
'min_period': 0.43,
|
||||||
'slew_hl': [0.0846786],
|
'read0_power': [0.5139368],
|
||||||
'slew_lh': [0.0846786],
|
'read1_power': [0.48940979999999995],
|
||||||
'write0_power': [0.40809259999999997],
|
'slew_hl': [0.0516745],
|
||||||
'write1_power': [0.4078904]}
|
'slew_lh': [0.0516745],
|
||||||
|
'volt_bl': [0.5374525],
|
||||||
|
'volt_br': [1.1058],
|
||||||
|
'write0_power': [0.46267169999999996],
|
||||||
|
'write1_power': [0.4670826]}
|
||||||
elif OPTS.tech_name == "scn4m_subm":
|
elif OPTS.tech_name == "scn4m_subm":
|
||||||
golden_data = {'delay_hl': [1.4333000000000002],
|
golden_data = {'delay_bl': [1.1029],
|
||||||
'delay_lh': [1.4333000000000002],
|
'delay_br': [0.9656455999999999],
|
||||||
'leakage_power': 0.0271847,
|
'delay_hl': [1.288],
|
||||||
'min_period': 2.891,
|
'delay_lh': [1.288],
|
||||||
'read0_power': [15.714200000000002],
|
'leakage_power': 0.0273896,
|
||||||
'read1_power': [14.9848],
|
'min_period': 2.578,
|
||||||
'slew_hl': [0.6819276999999999],
|
'read0_power': [16.9996],
|
||||||
'slew_lh': [0.6819276999999999],
|
'read1_power': [16.2616],
|
||||||
'write0_power': [13.9658],
|
'slew_hl': [0.47891700000000004],
|
||||||
'write1_power': [14.8422]}
|
'slew_lh': [0.47891700000000004],
|
||||||
|
'volt_bl': [4.2155],
|
||||||
|
'volt_br': [5.8142],
|
||||||
|
'write0_power': [16.0656],
|
||||||
|
'write1_power': [16.2616]}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.assertTrue(False) # other techs fail
|
self.assertTrue(False) # other techs fail
|
||||||
# Check if no too many or too few results
|
# Check if no too many or too few results
|
||||||
|
|
|
||||||
|
|
@ -51,27 +51,36 @@ class timing_sram_test(openram_test):
|
||||||
data.update(port_data[0])
|
data.update(port_data[0])
|
||||||
|
|
||||||
if OPTS.tech_name == "freepdk45":
|
if OPTS.tech_name == "freepdk45":
|
||||||
golden_data = {'delay_hl': [0.221699],
|
golden_data = {'delay_bl': [0.2003652],
|
||||||
'delay_lh': [0.221699],
|
'delay_br': [0.198698],
|
||||||
'leakage_power': 0.001467648,
|
'delay_hl': [0.2108836],
|
||||||
'min_period': 0.605,
|
'delay_lh': [0.2108836],
|
||||||
'read0_power': [0.3879335],
|
'leakage_power': 0.001564799,
|
||||||
'read1_power': [0.3662724],
|
'min_period': 0.508,
|
||||||
'slew_hl': [0.08562444999999999],
|
'read0_power': [0.43916689999999997],
|
||||||
'slew_lh': [0.08562444999999999],
|
'read1_power': [0.4198608],
|
||||||
'write0_power': [0.3362456],
|
'slew_hl': [0.0455126],
|
||||||
'write1_power': [0.3372035]}
|
'slew_lh': [0.0455126],
|
||||||
|
'volt_bl': [0.6472883],
|
||||||
|
'volt_br': [1.114024],
|
||||||
|
'write0_power': [0.40681890000000004],
|
||||||
|
'write1_power': [0.4198608]}
|
||||||
elif OPTS.tech_name == "scn4m_subm":
|
elif OPTS.tech_name == "scn4m_subm":
|
||||||
golden_data = {'delay_hl': [1.7951730000000001],
|
golden_data = {'delay_bl': [1.3937359999999999],
|
||||||
'delay_lh': [1.7951730000000001],
|
'delay_br': [1.2596429999999998],
|
||||||
'leakage_power': 0.001669513,
|
'delay_hl': [1.5747600000000002],
|
||||||
'min_period': 3.594,
|
'delay_lh': [1.5747600000000002],
|
||||||
'read0_power': [17.03022],
|
'leakage_power': 0.00195795,
|
||||||
'read1_power': [16.55897],
|
'min_period': 3.281,
|
||||||
'slew_hl': [0.7079951],
|
'read0_power': [14.92874],
|
||||||
'slew_lh': [0.7079951],
|
'read1_power': [14.369810000000001],
|
||||||
'write0_power': [15.16726],
|
'slew_hl': [0.49631959999999997],
|
||||||
'write1_power': [16.13527]}
|
'slew_lh': [0.49631959999999997],
|
||||||
|
'volt_bl': [4.132618],
|
||||||
|
'volt_br': [5.573099],
|
||||||
|
'write0_power': [13.79953],
|
||||||
|
'write1_power': [14.369810000000001]}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.assertTrue(False) # other techs fail
|
self.assertTrue(False) # other techs fail
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Check the .lib file for an SRAM
|
||||||
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from testutils import header,openram_test
|
||||||
|
import sys,os,re
|
||||||
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class model_corners_lib_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
|
|
||||||
|
from characterizer import lib
|
||||||
|
from sram import sram
|
||||||
|
from sram_config import sram_config
|
||||||
|
c = sram_config(word_size=2,
|
||||||
|
num_words=16,
|
||||||
|
num_banks=1)
|
||||||
|
c.words_per_row=1
|
||||||
|
c.recompute_sizes()
|
||||||
|
debug.info(1, "Testing analytical timing for sample 2 bit, 16 words SRAM with 1 bank")
|
||||||
|
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||||
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
|
s.sp_write(tempspice)
|
||||||
|
|
||||||
|
#Set the corners. Lib will create a power set of the lists.
|
||||||
|
if OPTS.tech_name == "scn4m_subm":
|
||||||
|
OPTS.process_corners = ["TT", "SS", "FF"]
|
||||||
|
OPTS.supply_voltages = [5.0]
|
||||||
|
OPTS.temperatures = [25]
|
||||||
|
elif OPTS.tech_name == "freepdk45":
|
||||||
|
OPTS.process_corners = ["TT", "SS", "FF"]
|
||||||
|
OPTS.supply_voltages = [1.0]
|
||||||
|
OPTS.temperatures = [25]
|
||||||
|
|
||||||
|
lib(out_dir=OPTS.openram_temp, sram=s.s, sp_file=tempspice, use_model=True)
|
||||||
|
|
||||||
|
# get all of the .lib files generated
|
||||||
|
files = os.listdir(OPTS.openram_temp)
|
||||||
|
nametest = re.compile("\.lib$", re.IGNORECASE)
|
||||||
|
lib_files = filter(nametest.search, files)
|
||||||
|
|
||||||
|
# and compare them with the golden model
|
||||||
|
for filename in lib_files:
|
||||||
|
newname = filename.replace(".lib","_analytical.lib")
|
||||||
|
libname = "{0}/{1}".format(OPTS.openram_temp,filename)
|
||||||
|
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),newname)
|
||||||
|
self.assertTrue(self.isapproxdiff(libname,golden,0.15))
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# run the test from the command line
|
||||||
|
if __name__ == "__main__":
|
||||||
|
(OPTS, args) = globals.parse_args()
|
||||||
|
del sys.argv[1:]
|
||||||
|
header(__file__, OPTS.tech_name)
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Run a regression test on various srams
|
||||||
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from testutils import header,openram_test
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class delay_model_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
|
OPTS.spice_name="hspice"
|
||||||
|
OPTS.analytical_delay = False
|
||||||
|
OPTS.netlist_only = True
|
||||||
|
OPTS.trim_netlist = False
|
||||||
|
debug.info(1, "Trimming disabled for this test. Simulation could be slow.")
|
||||||
|
|
||||||
|
# This is a hack to reload the characterizer __init__ with the spice version
|
||||||
|
from importlib import reload
|
||||||
|
import characterizer
|
||||||
|
reload(characterizer)
|
||||||
|
|
||||||
|
from characterizer import model_check
|
||||||
|
from sram import sram
|
||||||
|
from sram_config import sram_config
|
||||||
|
c = sram_config(word_size=4,
|
||||||
|
num_words=16,
|
||||||
|
num_banks=1)
|
||||||
|
c.words_per_row=1
|
||||||
|
c.recompute_sizes()
|
||||||
|
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
||||||
|
s = sram(c, name="sram1")
|
||||||
|
|
||||||
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
|
s.sp_write(tempspice)
|
||||||
|
|
||||||
|
probe_address = "1" * s.s.addr_size
|
||||||
|
probe_data = s.s.word_size - 1
|
||||||
|
debug.info(1, "Probe address {0} probe data bit {1}".format(probe_address, probe_data))
|
||||||
|
|
||||||
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
|
mc = model_check(s.s, tempspice, corner)
|
||||||
|
import tech
|
||||||
|
loads = [tech.spice["msflop_in_cap"]*4]
|
||||||
|
slews = [tech.spice["rise_time"]*2]
|
||||||
|
sram_data = mc.analyze(probe_address, probe_data, slews, loads)
|
||||||
|
#Combine info about port into all data
|
||||||
|
|
||||||
|
#debug.info(1,"Data:\n{}".format(wl_data))
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# run the test from the command line
|
||||||
|
if __name__ == "__main__":
|
||||||
|
(OPTS, args) = globals.parse_args()
|
||||||
|
del sys.argv[1:]
|
||||||
|
header(__file__, OPTS.tech_name)
|
||||||
|
unittest.main()
|
||||||
|
|
@ -0,0 +1,321 @@
|
||||||
|
library (sram_2_16_1_freepdk45_FF_1p0V_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 : 1.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 : 1.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.00125, 0.005, 0.04");
|
||||||
|
index_2("0.052275, 0.2091, 1.6728");
|
||||||
|
}
|
||||||
|
|
||||||
|
lu_table_template(CONSTRAINT_TABLE){
|
||||||
|
variable_1 : related_pin_transition;
|
||||||
|
variable_2 : constrained_pin_transition;
|
||||||
|
index_1("0.00125, 0.005, 0.04");
|
||||||
|
index_2("0.00125, 0.005, 0.04");
|
||||||
|
}
|
||||||
|
|
||||||
|
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_1_freepdk45){
|
||||||
|
memory(){
|
||||||
|
type : ram;
|
||||||
|
address_width : 4;
|
||||||
|
word_width : 2;
|
||||||
|
}
|
||||||
|
interface_timing : true;
|
||||||
|
dont_use : true;
|
||||||
|
map_only : true;
|
||||||
|
dont_touch : true;
|
||||||
|
area : 1124.88;
|
||||||
|
|
||||||
|
leakage_power () {
|
||||||
|
when : "CSb0";
|
||||||
|
value : 0.000167;
|
||||||
|
}
|
||||||
|
cell_leakage_power : 0;
|
||||||
|
bus(DIN0){
|
||||||
|
bus_type : DATA;
|
||||||
|
direction : input;
|
||||||
|
capacitance : 0.2091;
|
||||||
|
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 : 1.6728;
|
||||||
|
min_capacitance : 0.052275;
|
||||||
|
memory_read(){
|
||||||
|
address : ADDR0;
|
||||||
|
}
|
||||||
|
pin(DOUT0[1:0]){
|
||||||
|
timing(){
|
||||||
|
timing_sense : non_unate;
|
||||||
|
related_pin : "clk0";
|
||||||
|
timing_type : falling_edge;
|
||||||
|
cell_rise(CELL_TABLE) {
|
||||||
|
values("0.088, 0.088, 0.088",\
|
||||||
|
"0.088, 0.088, 0.088",\
|
||||||
|
"0.088, 0.088, 0.088");
|
||||||
|
}
|
||||||
|
cell_fall(CELL_TABLE) {
|
||||||
|
values("0.088, 0.088, 0.088",\
|
||||||
|
"0.088, 0.088, 0.088",\
|
||||||
|
"0.088, 0.088, 0.088");
|
||||||
|
}
|
||||||
|
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 : 0.2091;
|
||||||
|
max_transition : 0.04;
|
||||||
|
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 : 0.2091;
|
||||||
|
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 : 0.2091;
|
||||||
|
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 : 0.2091;
|
||||||
|
internal_power(){
|
||||||
|
when : "!CSb0 & clk0 & !WEb0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("0.033101244168888884");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("0.033101244168888884");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal_power(){
|
||||||
|
when : "!CSb0 & !clk0 & WEb0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("0.033101244168888884");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("0.033101244168888884");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.009");
|
||||||
|
}
|
||||||
|
fall_constraint(scalar) {
|
||||||
|
values("0.009");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timing(){
|
||||||
|
timing_type :"minimum_period";
|
||||||
|
related_pin : clk0;
|
||||||
|
rise_constraint(scalar) {
|
||||||
|
values("0.018");
|
||||||
|
}
|
||||||
|
fall_constraint(scalar) {
|
||||||
|
values("0.018");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,321 @@
|
||||||
|
library (sram_2_16_1_freepdk45_SS_1p0V_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 : 1.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 : 1.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.00125, 0.005, 0.04");
|
||||||
|
index_2("0.052275, 0.2091, 1.6728");
|
||||||
|
}
|
||||||
|
|
||||||
|
lu_table_template(CONSTRAINT_TABLE){
|
||||||
|
variable_1 : related_pin_transition;
|
||||||
|
variable_2 : constrained_pin_transition;
|
||||||
|
index_1("0.00125, 0.005, 0.04");
|
||||||
|
index_2("0.00125, 0.005, 0.04");
|
||||||
|
}
|
||||||
|
|
||||||
|
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_1_freepdk45){
|
||||||
|
memory(){
|
||||||
|
type : ram;
|
||||||
|
address_width : 4;
|
||||||
|
word_width : 2;
|
||||||
|
}
|
||||||
|
interface_timing : true;
|
||||||
|
dont_use : true;
|
||||||
|
map_only : true;
|
||||||
|
dont_touch : true;
|
||||||
|
area : 1124.88;
|
||||||
|
|
||||||
|
leakage_power () {
|
||||||
|
when : "CSb0";
|
||||||
|
value : 0.000167;
|
||||||
|
}
|
||||||
|
cell_leakage_power : 0;
|
||||||
|
bus(DIN0){
|
||||||
|
bus_type : DATA;
|
||||||
|
direction : input;
|
||||||
|
capacitance : 0.2091;
|
||||||
|
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 : 1.6728;
|
||||||
|
min_capacitance : 0.052275;
|
||||||
|
memory_read(){
|
||||||
|
address : ADDR0;
|
||||||
|
}
|
||||||
|
pin(DOUT0[1:0]){
|
||||||
|
timing(){
|
||||||
|
timing_sense : non_unate;
|
||||||
|
related_pin : "clk0";
|
||||||
|
timing_type : falling_edge;
|
||||||
|
cell_rise(CELL_TABLE) {
|
||||||
|
values("0.107, 0.107, 0.107",\
|
||||||
|
"0.107, 0.107, 0.107",\
|
||||||
|
"0.107, 0.107, 0.107");
|
||||||
|
}
|
||||||
|
cell_fall(CELL_TABLE) {
|
||||||
|
values("0.107, 0.107, 0.107",\
|
||||||
|
"0.107, 0.107, 0.107",\
|
||||||
|
"0.107, 0.107, 0.107");
|
||||||
|
}
|
||||||
|
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 : 0.2091;
|
||||||
|
max_transition : 0.04;
|
||||||
|
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 : 0.2091;
|
||||||
|
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 : 0.2091;
|
||||||
|
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 : 0.2091;
|
||||||
|
internal_power(){
|
||||||
|
when : "!CSb0 & clk0 & !WEb0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("0.033101244168888884");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("0.033101244168888884");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal_power(){
|
||||||
|
when : "!CSb0 & !clk0 & WEb0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("0.033101244168888884");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("0.033101244168888884");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.0105");
|
||||||
|
}
|
||||||
|
fall_constraint(scalar) {
|
||||||
|
values("0.0105");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timing(){
|
||||||
|
timing_type :"minimum_period";
|
||||||
|
related_pin : clk0;
|
||||||
|
rise_constraint(scalar) {
|
||||||
|
values("0.021");
|
||||||
|
}
|
||||||
|
fall_constraint(scalar) {
|
||||||
|
values("0.021");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -93,7 +93,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
address : ADDR0;
|
address : ADDR0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
}
|
}
|
||||||
pin(DIN0){
|
pin(DIN0[1:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -132,7 +132,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : ADDR0;
|
address : ADDR0;
|
||||||
}
|
}
|
||||||
pin(DOUT0){
|
pin(DOUT0[1:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_sense : non_unate;
|
timing_sense : non_unate;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -166,7 +166,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.2091;
|
||||||
max_transition : 0.04;
|
max_transition : 0.04;
|
||||||
pin(ADDR0){
|
pin(ADDR0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
address : ADDR0;
|
address : ADDR0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
}
|
}
|
||||||
pin(DIN0){
|
pin(DIN0[1:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -132,7 +132,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : ADDR0;
|
address : ADDR0;
|
||||||
}
|
}
|
||||||
pin(DOUT0){
|
pin(DOUT0[1:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_sense : non_unate;
|
timing_sense : non_unate;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -166,7 +166,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.2091;
|
||||||
max_transition : 0.04;
|
max_transition : 0.04;
|
||||||
pin(ADDR0){
|
pin(ADDR0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
address : ADDR0;
|
address : ADDR0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
}
|
}
|
||||||
pin(DIN0){
|
pin(DIN0[1:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -132,7 +132,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : ADDR0;
|
address : ADDR0;
|
||||||
}
|
}
|
||||||
pin(DOUT0){
|
pin(DOUT0[1:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_sense : non_unate;
|
timing_sense : non_unate;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -166,7 +166,7 @@ cell (sram_2_16_1_freepdk45){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 0.2091;
|
capacitance : 0.2091;
|
||||||
max_transition : 0.04;
|
max_transition : 0.04;
|
||||||
pin(ADDR0){
|
pin(ADDR0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,321 @@
|
||||||
|
library (sram_2_16_1_scn4m_subm_FF_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_1_scn4m_subm){
|
||||||
|
memory(){
|
||||||
|
type : ram;
|
||||||
|
address_width : 4;
|
||||||
|
word_width : 2;
|
||||||
|
}
|
||||||
|
interface_timing : true;
|
||||||
|
dont_use : true;
|
||||||
|
map_only : true;
|
||||||
|
dont_touch : true;
|
||||||
|
area : 73068.14000000001;
|
||||||
|
|
||||||
|
leakage_power () {
|
||||||
|
when : "CSb0";
|
||||||
|
value : 0.000167;
|
||||||
|
}
|
||||||
|
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 : falling_edge;
|
||||||
|
cell_rise(CELL_TABLE) {
|
||||||
|
values("0.241, 0.241, 0.241",\
|
||||||
|
"0.241, 0.241, 0.241",\
|
||||||
|
"0.241, 0.241, 0.241");
|
||||||
|
}
|
||||||
|
cell_fall(CELL_TABLE) {
|
||||||
|
values("0.241, 0.241, 0.241",\
|
||||||
|
"0.241, 0.241, 0.241",\
|
||||||
|
"0.241, 0.241, 0.241");
|
||||||
|
}
|
||||||
|
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("4.99880645");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("4.99880645");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal_power(){
|
||||||
|
when : "!CSb0 & !clk0 & WEb0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("4.99880645");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("4.99880645");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.024");
|
||||||
|
}
|
||||||
|
fall_constraint(scalar) {
|
||||||
|
values("0.024");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timing(){
|
||||||
|
timing_type :"minimum_period";
|
||||||
|
related_pin : clk0;
|
||||||
|
rise_constraint(scalar) {
|
||||||
|
values("0.048");
|
||||||
|
}
|
||||||
|
fall_constraint(scalar) {
|
||||||
|
values("0.048");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,321 @@
|
||||||
|
library (sram_2_16_1_scn4m_subm_SS_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_1_scn4m_subm){
|
||||||
|
memory(){
|
||||||
|
type : ram;
|
||||||
|
address_width : 4;
|
||||||
|
word_width : 2;
|
||||||
|
}
|
||||||
|
interface_timing : true;
|
||||||
|
dont_use : true;
|
||||||
|
map_only : true;
|
||||||
|
dont_touch : true;
|
||||||
|
area : 73068.14000000001;
|
||||||
|
|
||||||
|
leakage_power () {
|
||||||
|
when : "CSb0";
|
||||||
|
value : 0.000167;
|
||||||
|
}
|
||||||
|
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 : falling_edge;
|
||||||
|
cell_rise(CELL_TABLE) {
|
||||||
|
values("0.294, 0.294, 0.294",\
|
||||||
|
"0.294, 0.294, 0.294",\
|
||||||
|
"0.294, 0.294, 0.294");
|
||||||
|
}
|
||||||
|
cell_fall(CELL_TABLE) {
|
||||||
|
values("0.294, 0.294, 0.294",\
|
||||||
|
"0.294, 0.294, 0.294",\
|
||||||
|
"0.294, 0.294, 0.294");
|
||||||
|
}
|
||||||
|
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("4.99880645");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("4.99880645");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal_power(){
|
||||||
|
when : "!CSb0 & !clk0 & WEb0";
|
||||||
|
rise_power(scalar){
|
||||||
|
values("4.99880645");
|
||||||
|
}
|
||||||
|
fall_power(scalar){
|
||||||
|
values("4.99880645");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.0295");
|
||||||
|
}
|
||||||
|
fall_constraint(scalar) {
|
||||||
|
values("0.0295");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timing(){
|
||||||
|
timing_type :"minimum_period";
|
||||||
|
related_pin : clk0;
|
||||||
|
rise_constraint(scalar) {
|
||||||
|
values("0.059");
|
||||||
|
}
|
||||||
|
fall_constraint(scalar) {
|
||||||
|
values("0.059");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -93,7 +93,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
address : ADDR0;
|
address : ADDR0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
}
|
}
|
||||||
pin(DIN0){
|
pin(DIN0[1:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -132,7 +132,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : ADDR0;
|
address : ADDR0;
|
||||||
}
|
}
|
||||||
pin(DOUT0){
|
pin(DOUT0[1:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_sense : non_unate;
|
timing_sense : non_unate;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -166,7 +166,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 9.8242;
|
||||||
max_transition : 0.4;
|
max_transition : 0.4;
|
||||||
pin(ADDR0){
|
pin(ADDR0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
address : ADDR0;
|
address : ADDR0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
}
|
}
|
||||||
pin(DIN0){
|
pin(DIN0[1:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -132,7 +132,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : ADDR0;
|
address : ADDR0;
|
||||||
}
|
}
|
||||||
pin(DOUT0){
|
pin(DOUT0[1:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_sense : non_unate;
|
timing_sense : non_unate;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -166,7 +166,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 9.8242;
|
||||||
max_transition : 0.4;
|
max_transition : 0.4;
|
||||||
pin(ADDR0){
|
pin(ADDR0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
address : ADDR0;
|
address : ADDR0;
|
||||||
clocked_on : clk0;
|
clocked_on : clk0;
|
||||||
}
|
}
|
||||||
pin(DIN0){
|
pin(DIN0[1:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -132,7 +132,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
memory_read(){
|
memory_read(){
|
||||||
address : ADDR0;
|
address : ADDR0;
|
||||||
}
|
}
|
||||||
pin(DOUT0){
|
pin(DOUT0[1:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_sense : non_unate;
|
timing_sense : non_unate;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
@ -166,7 +166,7 @@ cell (sram_2_16_1_scn4m_subm){
|
||||||
direction : input;
|
direction : input;
|
||||||
capacitance : 9.8242;
|
capacitance : 9.8242;
|
||||||
max_transition : 0.4;
|
max_transition : 0.4;
|
||||||
pin(ADDR0){
|
pin(ADDR0[3:0]){
|
||||||
timing(){
|
timing(){
|
||||||
timing_type : setup_rising;
|
timing_type : setup_rising;
|
||||||
related_pin : "clk0";
|
related_pin : "clk0";
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ class openram_test(unittest.TestCase):
|
||||||
|
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,w.name)
|
||||||
w.gds_write(tempgds)
|
w.gds_write(tempgds)
|
||||||
import verify
|
import verify
|
||||||
|
|
||||||
|
|
@ -21,14 +21,15 @@ class openram_test(unittest.TestCase):
|
||||||
if result != 0:
|
if result != 0:
|
||||||
self.fail("DRC failed: {}".format(w.name))
|
self.fail("DRC failed: {}".format(w.name))
|
||||||
|
|
||||||
self.cleanup()
|
if OPTS.purge_temp:
|
||||||
|
self.cleanup()
|
||||||
|
|
||||||
def local_check(self, a, final_verification=False):
|
def local_check(self, a, final_verification=False):
|
||||||
|
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name)
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,a.name)
|
||||||
|
|
||||||
a.sp_write(tempspice)
|
a.sp_write(tempspice)
|
||||||
# cannot write gds in netlist_only mode
|
# cannot write gds in netlist_only mode
|
||||||
|
|
@ -36,7 +37,7 @@ class openram_test(unittest.TestCase):
|
||||||
a.gds_write(tempgds)
|
a.gds_write(tempgds)
|
||||||
|
|
||||||
import verify
|
import verify
|
||||||
result=verify.run_drc(a.name, tempgds)
|
result=verify.run_drc(a.name, tempgds, extract=True, final_verification=final_verification)
|
||||||
if result != 0:
|
if result != 0:
|
||||||
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
|
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
|
||||||
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
|
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
|
||||||
|
|
@ -44,7 +45,7 @@ class openram_test(unittest.TestCase):
|
||||||
self.fail("DRC failed: {}".format(a.name))
|
self.fail("DRC failed: {}".format(a.name))
|
||||||
|
|
||||||
|
|
||||||
result=verify.run_lvs(a.name, tempgds, tempspice, final_verification)
|
result=verify.run_lvs(a.name, tempgds, tempspice, final_verification=final_verification)
|
||||||
if result != 0:
|
if result != 0:
|
||||||
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
|
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
|
||||||
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
|
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
|
||||||
|
|
@ -54,6 +55,7 @@ class openram_test(unittest.TestCase):
|
||||||
if OPTS.purge_temp:
|
if OPTS.purge_temp:
|
||||||
self.cleanup()
|
self.cleanup()
|
||||||
|
|
||||||
|
|
||||||
def find_feasible_test_period(self, delay_obj, sram, load, slew):
|
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.
|
"""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.
|
Only determines the feasible period for a single port and assumes that for all ports for performance.
|
||||||
|
|
@ -62,6 +64,9 @@ class openram_test(unittest.TestCase):
|
||||||
delay_obj.set_load_slew(load, slew)
|
delay_obj.set_load_slew(load, slew)
|
||||||
delay_obj.set_probe(probe_address="1"*sram.addr_size, probe_data=(sram.word_size-1))
|
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.
|
test_port = delay_obj.read_ports[0] #Only test one port, assumes other ports have similar period.
|
||||||
|
delay_obj.create_signal_names()
|
||||||
|
delay_obj.create_measurement_names()
|
||||||
|
delay_obj.create_measurement_objects()
|
||||||
delay_obj.find_feasible_period_one_port(test_port)
|
delay_obj.find_feasible_period_one_port(test_port)
|
||||||
return delay_obj.period
|
return delay_obj.period
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ num_drc_runs = 0
|
||||||
num_lvs_runs = 0
|
num_lvs_runs = 0
|
||||||
num_pex_runs = 0
|
num_pex_runs = 0
|
||||||
|
|
||||||
def run_drc(name, gds_name):
|
def run_drc(name, gds_name, final_verification=False):
|
||||||
"""Run DRC check on a given top-level name which is
|
"""Run DRC check on a given top-level name which is
|
||||||
implemented in gds_name."""
|
implemented in gds_name."""
|
||||||
|
|
||||||
|
|
@ -93,7 +93,7 @@ def run_drc(name, gds_name):
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
def run_lvs(name, gds_name, sp_name):
|
def run_lvs(name, gds_name, sp_name, final_verification=False):
|
||||||
"""Run LVS check on a given top-level name which is
|
"""Run LVS check on a given top-level name which is
|
||||||
implemented in gds_name and sp_name. """
|
implemented in gds_name and sp_name. """
|
||||||
|
|
||||||
|
|
@ -178,7 +178,7 @@ def run_lvs(name, gds_name, sp_name):
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
def run_pex(name, gds_name, sp_name, output=None):
|
def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
|
||||||
"""Run pex on a given top-level name which is
|
"""Run pex on a given top-level name which is
|
||||||
implemented in gds_name and sp_name. """
|
implemented in gds_name and sp_name. """
|
||||||
debug.error("PEX extraction not implemented with Assura.",-1)
|
debug.error("PEX extraction not implemented with Assura.",-1)
|
||||||
|
|
|
||||||
|
|
@ -126,9 +126,9 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False):
|
||||||
f.close()
|
f.close()
|
||||||
# those lines should be the last 3
|
# those lines should be the last 3
|
||||||
results = results[-3:]
|
results = results[-3:]
|
||||||
geometries = int(re.split("\W+", results[0])[5])
|
geometries = int(re.split(r'\W+', results[0])[5])
|
||||||
rulechecks = int(re.split("\W+", results[1])[4])
|
rulechecks = int(re.split(r'\W+', results[1])[4])
|
||||||
errors = int(re.split("\W+", results[2])[5])
|
errors = int(re.split(r'\W+', results[2])[5])
|
||||||
|
|
||||||
# always display this summary
|
# always display this summary
|
||||||
if errors > 0:
|
if errors > 0:
|
||||||
|
|
@ -227,7 +227,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
|
||||||
incorrect = list(filter(test.search, results))
|
incorrect = list(filter(test.search, results))
|
||||||
|
|
||||||
# Errors begin with "Error:"
|
# Errors begin with "Error:"
|
||||||
test = re.compile("\s+Error:")
|
test = re.compile(r'\s+Error:')
|
||||||
errors = list(filter(test.search, results))
|
errors = list(filter(test.search, results))
|
||||||
for e in errors:
|
for e in errors:
|
||||||
debug.error(e.strip("\n"))
|
debug.error(e.strip("\n"))
|
||||||
|
|
@ -282,7 +282,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
|
||||||
return total_errors
|
return total_errors
|
||||||
|
|
||||||
|
|
||||||
def run_pex(cell_name, gds_name, sp_name, output=None):
|
def run_pex(cell_name, gds_name, sp_name, output=None, final_verification=False):
|
||||||
"""Run pex on a given top-level name which is
|
"""Run pex on a given top-level name which is
|
||||||
implemented in gds_name and sp_name. """
|
implemented in gds_name and sp_name. """
|
||||||
|
|
||||||
|
|
@ -363,7 +363,7 @@ def correct_port(name, output_file_name, ref_file_name):
|
||||||
pex_file.seek(match_index_start)
|
pex_file.seek(match_index_start)
|
||||||
rest_text = pex_file.read()
|
rest_text = pex_file.read()
|
||||||
# locate the end of circuit definition line
|
# locate the end of circuit definition line
|
||||||
match = re.search("\* \n", rest_text)
|
match = re.search(r'\* \n', rest_text)
|
||||||
match_index_end = match.start()
|
match_index_end = match.start()
|
||||||
# store the unchanged part of pex file in memory
|
# store the unchanged part of pex file in memory
|
||||||
pex_file.seek(0)
|
pex_file.seek(0)
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,10 @@ def write_magic_script(cell_name, gds_name, extract=False, final_verification=Fa
|
||||||
#f.write("load {}_new\n".format(cell_name))
|
#f.write("load {}_new\n".format(cell_name))
|
||||||
#f.write("cellname rename {0}_new {0}\n".format(cell_name))
|
#f.write("cellname rename {0}_new {0}\n".format(cell_name))
|
||||||
#f.write("load {}\n".format(cell_name))
|
#f.write("load {}\n".format(cell_name))
|
||||||
|
f.write("cellname delete \\(UNNAMED\\)\n")
|
||||||
f.write("writeall force\n")
|
f.write("writeall force\n")
|
||||||
|
f.write("select top cell\n")
|
||||||
|
f.write("expand\n")
|
||||||
f.write("drc check\n")
|
f.write("drc check\n")
|
||||||
f.write("drc catchup\n")
|
f.write("drc catchup\n")
|
||||||
f.write("drc count total\n")
|
f.write("drc count total\n")
|
||||||
|
|
@ -55,14 +58,26 @@ def write_magic_script(cell_name, gds_name, extract=False, final_verification=Fa
|
||||||
else:
|
else:
|
||||||
pre = ""
|
pre = ""
|
||||||
if final_verification:
|
if final_verification:
|
||||||
f.write(pre+"extract unique\n")
|
f.write(pre+"extract unique all\n".format(cell_name))
|
||||||
f.write(pre+"extract\n")
|
f.write(pre+"extract\n".format(cell_name))
|
||||||
|
#f.write(pre+"ext2spice hierarchy on\n")
|
||||||
|
#f.write(pre+"ext2spice scale off\n")
|
||||||
|
# lvs exists in 8.2.79, but be backword compatible for now
|
||||||
|
#f.write(pre+"ext2spice lvs\n")
|
||||||
f.write(pre+"ext2spice hierarchy on\n")
|
f.write(pre+"ext2spice hierarchy on\n")
|
||||||
|
f.write(pre+"ext2spice format ngspice\n")
|
||||||
|
f.write(pre+"ext2spice cthresh infinite\n")
|
||||||
|
f.write(pre+"ext2spice rthresh infinite\n")
|
||||||
|
f.write(pre+"ext2spice renumber off\n")
|
||||||
f.write(pre+"ext2spice scale off\n")
|
f.write(pre+"ext2spice scale off\n")
|
||||||
|
f.write(pre+"ext2spice blackbox on\n")
|
||||||
|
f.write(pre+"ext2spice subcircuit top auto\n")
|
||||||
|
f.write(pre+"ext2spice global off\n")
|
||||||
|
|
||||||
# Can choose hspice, ngspice, or spice3,
|
# Can choose hspice, ngspice, or spice3,
|
||||||
# but they all seem compatible enough.
|
# but they all seem compatible enough.
|
||||||
#f.write(pre+"ext2spice format ngspice\n")
|
#f.write(pre+"ext2spice format ngspice\n")
|
||||||
f.write(pre+"ext2spice\n")
|
f.write(pre+"ext2spice {}\n".format(cell_name))
|
||||||
f.write("quit -noprompt\n")
|
f.write("quit -noprompt\n")
|
||||||
f.write("EOF\n")
|
f.write("EOF\n")
|
||||||
|
|
||||||
|
|
@ -136,15 +151,20 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
|
||||||
# etc.
|
# etc.
|
||||||
try:
|
try:
|
||||||
f = open(outfile, "r")
|
f = open(outfile, "r")
|
||||||
except:
|
except FileNotFoundError:
|
||||||
debug.error("Unable to retrieve DRC results file. Is magic set up?",1)
|
debug.error("Unable to load DRC results file from {}. Is magic set up?".format(outfile),1)
|
||||||
|
|
||||||
results = f.readlines()
|
results = f.readlines()
|
||||||
f.close()
|
f.close()
|
||||||
|
errors=1
|
||||||
# those lines should be the last 3
|
# those lines should be the last 3
|
||||||
for line in results:
|
for line in results:
|
||||||
if "Total DRC errors found:" in line:
|
if "Total DRC errors found:" in line:
|
||||||
errors = int(re.split(": ", line)[1])
|
errors = int(re.split(": ", line)[1])
|
||||||
break
|
break
|
||||||
|
else:
|
||||||
|
debug.error("Unable to find the total error line in Magic output.",1)
|
||||||
|
|
||||||
|
|
||||||
# always display this summary
|
# always display this summary
|
||||||
if errors > 0:
|
if errors > 0:
|
||||||
|
|
@ -185,7 +205,11 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
|
||||||
total_errors = 0
|
total_errors = 0
|
||||||
|
|
||||||
# check the result for these lines in the summary:
|
# check the result for these lines in the summary:
|
||||||
f = open(resultsfile, "r")
|
try:
|
||||||
|
f = open(resultsfile, "r")
|
||||||
|
except FileNotFoundError:
|
||||||
|
debug.error("Unable to load LVS results from {}".format(resultsfile),1)
|
||||||
|
|
||||||
results = f.readlines()
|
results = f.readlines()
|
||||||
f.close()
|
f.close()
|
||||||
# Look for the results after the final "Subcircuit summary:"
|
# Look for the results after the final "Subcircuit summary:"
|
||||||
|
|
@ -235,7 +259,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
|
||||||
return total_errors
|
return total_errors
|
||||||
|
|
||||||
|
|
||||||
def run_pex(name, gds_name, sp_name, output=None):
|
def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
|
||||||
"""Run pex on a given top-level name which is
|
"""Run pex on a given top-level name which is
|
||||||
implemented in gds_name and sp_name. """
|
implemented in gds_name and sp_name. """
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ drc_warned = False
|
||||||
lvs_warned = False
|
lvs_warned = False
|
||||||
pex_warned = False
|
pex_warned = False
|
||||||
|
|
||||||
def run_drc(cell_name, gds_name, extract=False):
|
def run_drc(cell_name, gds_name, extract=False, final_verification=False):
|
||||||
global drc_warned
|
global drc_warned
|
||||||
if not drc_warned:
|
if not drc_warned:
|
||||||
debug.warning("DRC unable to run.")
|
debug.warning("DRC unable to run.")
|
||||||
|
|
@ -25,7 +25,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
|
||||||
# Since we warned, return a failing test.
|
# Since we warned, return a failing test.
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def run_pex(name, gds_name, sp_name, output=None):
|
def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
|
||||||
global pex_warned
|
global pex_warned
|
||||||
if not pex_warned:
|
if not pex_warned:
|
||||||
debug.warning("PEX unable to run.")
|
debug.warning("PEX unable to run.")
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
all: openram_manual.tex
|
|
||||||
pdflatex openram_manual
|
|
||||||
bib:
|
|
||||||
bibtex openram_manual
|
|
||||||
clean:
|
|
||||||
rm -f openram_manual.pdf *.aux *.bbl *.blq *.dvi *.log *.lot *.toc *.lof *.blg
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
\section{Internal Control Signals}
|
|
||||||
\label{sec:control}
|
|
||||||
|
|
||||||
This section not needed... All information is in Section~\ref{sec:timing} (Timing).
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
\section{Debug Framework}
|
|
||||||
\label{sec:debug}
|
|
||||||
|
|
||||||
All output in OpenRAM should use the shared debug framework. This is
|
|
||||||
still under development but is in a usable state. It is going to be
|
|
||||||
replaced with the Python Logging framework which is quite simple.
|
|
||||||
|
|
||||||
All of the debug framework is contained in debug.py and is based
|
|
||||||
around the concept of a ``debug level'' which is a single global
|
|
||||||
variable in this file. This level is, by default, 0 which will output
|
|
||||||
normal minimal output. The general guidelines for debug output are:
|
|
||||||
\begin{itemize}
|
|
||||||
\item 0 Normal output
|
|
||||||
\item 1 Verbose output
|
|
||||||
\item 2 Detailed output
|
|
||||||
\item 3+ Excessively detailed output
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
The debug level can be adjusted on the command line when arguments are parsed using the ``-v'' flag. Adding more ``-v'' flags will increase the debug level as in the following examples:
|
|
||||||
\begin{verbatim}
|
|
||||||
python tests/01_library_drc_test.py -vv
|
|
||||||
python openram.py 4 16 -v -v
|
|
||||||
\end{verbatim}
|
|
||||||
which each put the program in debug level 2 (detailed output).
|
|
||||||
|
|
||||||
Since every module may output a lot of information in the higher debug
|
|
||||||
levels, the output format is standardized to allow easy searching via
|
|
||||||
grep or other command-line tools. The standard output formatting is
|
|
||||||
used through three interface functions:
|
|
||||||
\begin{itemize}
|
|
||||||
\item debug.info(int, msg)
|
|
||||||
\item debug.warning(msg)
|
|
||||||
\item debug.error(msg)
|
|
||||||
\end{itemize}
|
|
||||||
The msg string in each case can be any string format including data or
|
|
||||||
other useful debug information. The string should also contain
|
|
||||||
information to make it human understandable. {\bf It should not just be
|
|
||||||
a number!} The warning and error messages are independent of debug
|
|
||||||
levels while the info message will only print the message if the
|
|
||||||
current debug level is above the parameter value.
|
|
||||||
|
|
||||||
The output format of the debug info messages are:
|
|
||||||
\begin{verbatim}
|
|
||||||
[ module ]: msg
|
|
||||||
\end{verbatim}
|
|
||||||
where module is the calling module name and msg is the string
|
|
||||||
provided. This enables a grep command to get the relevant lines. The
|
|
||||||
warning and error messages include the file name and line number of
|
|
||||||
the warning/error.
|
|
||||||
|
Before Width: | Height: | Size: 47 KiB |
|
|
@ -1,747 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="744.09448819"
|
|
||||||
height="1052.3622047"
|
|
||||||
id="svg2"
|
|
||||||
sodipodi:version="0.32"
|
|
||||||
inkscape:version="0.46"
|
|
||||||
sodipodi:docname="Logic Diagram.svg"
|
|
||||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
|
||||||
<defs
|
|
||||||
id="defs4">
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient4867">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#cccccc;stop-opacity:1;"
|
|
||||||
offset="0"
|
|
||||||
id="stop4869" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#cccccc;stop-opacity:0;"
|
|
||||||
offset="1"
|
|
||||||
id="stop4871" />
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient3807">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#cccccc;stop-opacity:1;"
|
|
||||||
offset="0"
|
|
||||||
id="stop3809" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#cccccc;stop-opacity:0;"
|
|
||||||
offset="1"
|
|
||||||
id="stop3811" />
|
|
||||||
</linearGradient>
|
|
||||||
<marker
|
|
||||||
inkscape:stockid="Arrow1Lstart"
|
|
||||||
orient="auto"
|
|
||||||
refY="0.0"
|
|
||||||
refX="0.0"
|
|
||||||
id="Arrow1Lstart"
|
|
||||||
style="overflow:visible">
|
|
||||||
<path
|
|
||||||
id="path3831"
|
|
||||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
|
||||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
|
|
||||||
transform="scale(0.8) translate(12.5,0)" />
|
|
||||||
</marker>
|
|
||||||
<marker
|
|
||||||
inkscape:stockid="Arrow1Lend"
|
|
||||||
orient="auto"
|
|
||||||
refY="0.0"
|
|
||||||
refX="0.0"
|
|
||||||
id="Arrow1Lend"
|
|
||||||
style="overflow:visible;">
|
|
||||||
<path
|
|
||||||
id="path3834"
|
|
||||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
|
||||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
|
|
||||||
transform="scale(0.8) rotate(180) translate(12.5,0)" />
|
|
||||||
</marker>
|
|
||||||
<inkscape:perspective
|
|
||||||
sodipodi:type="inkscape:persp3d"
|
|
||||||
inkscape:vp_x="0 : 526.18109 : 1"
|
|
||||||
inkscape:vp_y="0 : 1000 : 0"
|
|
||||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
|
||||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
|
||||||
id="perspective10" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient3807"
|
|
||||||
id="linearGradient3813"
|
|
||||||
x1="199.69901"
|
|
||||||
y1="218.7489"
|
|
||||||
x2="199.43983"
|
|
||||||
y2="217.65218"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
gradientTransform="translate(0,116)" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient3807"
|
|
||||||
id="linearGradient3819"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
x1="199.69901"
|
|
||||||
y1="218.7489"
|
|
||||||
x2="199.43983"
|
|
||||||
y2="217.65218"
|
|
||||||
gradientTransform="translate(0,-691.72632)" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient4867"
|
|
||||||
id="linearGradient4873"
|
|
||||||
x1="394.20999"
|
|
||||||
y1="489.94479"
|
|
||||||
x2="393.62537"
|
|
||||||
y2="490.3624"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
gradientTransform="translate(0,100)" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient4867"
|
|
||||||
id="linearGradient4879"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
x1="394.20999"
|
|
||||||
y1="489.94479"
|
|
||||||
x2="393.62537"
|
|
||||||
y2="490.3624"
|
|
||||||
gradientTransform="translate(-1019.8693,100)" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient4867"
|
|
||||||
id="linearGradient4885"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
x1="394.20999"
|
|
||||||
y1="489.94479"
|
|
||||||
x2="393.62537"
|
|
||||||
y2="490.3624"
|
|
||||||
gradientTransform="translate(0,100)" />
|
|
||||||
</defs>
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
gridtolerance="10000"
|
|
||||||
guidetolerance="10"
|
|
||||||
objecttolerance="10"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="16.932823"
|
|
||||||
inkscape:cx="504.04531"
|
|
||||||
inkscape:cy="492.15828"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:window-width="1600"
|
|
||||||
inkscape:window-height="1132"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
showguides="true"
|
|
||||||
inkscape:guide-bbox="true" />
|
|
||||||
<metadata
|
|
||||||
id="metadata7">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1">
|
|
||||||
<rect
|
|
||||||
style="fill:url(#linearGradient3813);fill-opacity:1"
|
|
||||||
id="rect2383"
|
|
||||||
width="165.71428"
|
|
||||||
height="94.646927"
|
|
||||||
x="133.76231"
|
|
||||||
y="309.66827" />
|
|
||||||
<rect
|
|
||||||
style="fill:#cccccc"
|
|
||||||
id="rect2385"
|
|
||||||
width="208.57143"
|
|
||||||
height="188.57143"
|
|
||||||
x="406.00479"
|
|
||||||
y="309.50024" />
|
|
||||||
<rect
|
|
||||||
style="fill:#cccccc"
|
|
||||||
id="rect2387"
|
|
||||||
width="208.38266"
|
|
||||||
height="62.857143"
|
|
||||||
x="405.96155"
|
|
||||||
y="70.725639" />
|
|
||||||
<rect
|
|
||||||
style="fill:url(#linearGradient4873);fill-opacity:1"
|
|
||||||
id="rect2389"
|
|
||||||
width="138.24103"
|
|
||||||
height="54.285713"
|
|
||||||
x="371.81412"
|
|
||||||
y="558.85974" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:23.82649612px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="452.81046"
|
|
||||||
y="105.8875"
|
|
||||||
id="text2399"
|
|
||||||
transform="scale(0.9927707,1.0072819)"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2401"
|
|
||||||
x="452.81046"
|
|
||||||
y="105.8875">Precharge</tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="478.94641"
|
|
||||||
y="410.42963"
|
|
||||||
id="text2403"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2405"
|
|
||||||
x="478.94641"
|
|
||||||
y="410.42963">Array</tspan></text>
|
|
||||||
<rect
|
|
||||||
style="fill:#cccccc"
|
|
||||||
id="rect2429"
|
|
||||||
width="277.14285"
|
|
||||||
height="54.285713"
|
|
||||||
x="371.49484"
|
|
||||||
y="672.11481" />
|
|
||||||
<rect
|
|
||||||
style="fill:#cccccc"
|
|
||||||
id="rect2431"
|
|
||||||
width="277.14285"
|
|
||||||
height="54.285713"
|
|
||||||
x="372.53488"
|
|
||||||
y="794.2793" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="439.30377"
|
|
||||||
y="708.78662"
|
|
||||||
id="text2437"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2439"
|
|
||||||
x="439.30377"
|
|
||||||
y="708.78662">Sense Amp</tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="428.77615"
|
|
||||||
y="828.11359"
|
|
||||||
id="text2441"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2443"
|
|
||||||
x="428.77615"
|
|
||||||
y="828.11359">Output Latch</tspan></text>
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1"
|
|
||||||
d="M 510.87523,794.2793 L 510.29735,726.40052"
|
|
||||||
id="path2453"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connection-start="#rect2431"
|
|
||||||
inkscape:connection-end="#rect2429" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00533342px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-opacity:1"
|
|
||||||
d="M 510.37148,613.14813 L 510.36003,672.35929"
|
|
||||||
id="path2455"
|
|
||||||
inkscape:connector-type="polyline" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00327015px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-opacity:1"
|
|
||||||
d="M 297.90384,403.80303 L 406.00315,403.80054"
|
|
||||||
id="path2469"
|
|
||||||
inkscape:connector-type="polyline" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="237.36064"
|
|
||||||
y="462.23129"
|
|
||||||
id="text2497"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2499"
|
|
||||||
x="237.36064"
|
|
||||||
y="462.23129" /></text>
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-opacity:1"
|
|
||||||
d="M 511.49401,848.56501 L 512.51267,919.88151"
|
|
||||||
id="path2521"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connection-start="#rect2431" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="432.52811"
|
|
||||||
y="954.8941"
|
|
||||||
id="text2527"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2529"
|
|
||||||
x="432.52811"
|
|
||||||
y="954.8941">Out to System</tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="322.32162"
|
|
||||||
y="-51.962601"
|
|
||||||
id="text2531"
|
|
||||||
transform="matrix(9.034996e-4,0.9999996,-0.9999996,9.034996e-4,0,0)"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2533"
|
|
||||||
x="322.32162"
|
|
||||||
y="-51.962601">In From System</tspan><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
x="322.32162"
|
|
||||||
y="-21.962603"
|
|
||||||
id="tspan2535" /></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="538.99377"
|
|
||||||
y="516.83362"
|
|
||||||
id="text2832"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2834"
|
|
||||||
x="538.99377"
|
|
||||||
y="516.83362"> Bit Lines</tspan><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
x="538.99377"
|
|
||||||
y="531.83362"
|
|
||||||
id="tspan2938">BL<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2950">0</tspan>,BR<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2948">0</tspan>, BL<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2946">1</tspan>, BR<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2944">1</tspan>, ... BL<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2942">j</tspan> BR<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2940">j </tspan></tspan></text>
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="M 364.52511,382.19547 L 336.74637,425.84777"
|
|
||||||
id="path2836" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="280.00189"
|
|
||||||
y="-339.76331"
|
|
||||||
id="text2838"
|
|
||||||
transform="matrix(3.852356e-3,0.9999926,-0.9999926,3.852356e-3,0,0)"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2840"
|
|
||||||
x="280.00189"
|
|
||||||
y="-339.76331"> Word Lines</tspan><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
x="280.00189"
|
|
||||||
y="-324.76331"
|
|
||||||
id="tspan2930"> W<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2936">0</tspan>, W<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2934">1</tspan>, ..., W<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2932">log(n)</tspan></tspan></text>
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);stroke-opacity:1"
|
|
||||||
d="M 371.888,589.5005 L 309.17124,589.84843"
|
|
||||||
id="path2842"
|
|
||||||
inkscape:connector-type="polyline" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);stroke-opacity:1"
|
|
||||||
d="M 370.94208,702.41208 L 308.22531,702.76001"
|
|
||||||
id="path2854"
|
|
||||||
inkscape:connector-type="polyline" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);stroke-opacity:1"
|
|
||||||
d="M 371.88799,824.43518 L 309.17123,824.78311"
|
|
||||||
id="path2860"
|
|
||||||
inkscape:connector-type="polyline" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="M 491.10498,654.25031 L 526.70018,628.88523"
|
|
||||||
id="path2870" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="320.09518"
|
|
||||||
y="-99.119331"
|
|
||||||
id="text2888"
|
|
||||||
transform="matrix(-1.094382e-2,0.9999401,-0.9999401,-1.094382e-2,0,0)"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2890"
|
|
||||||
x="320.09518"
|
|
||||||
y="-99.119331">A<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2892">0</tspan>, A<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2896">1</tspan>, ... A<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2898">n</tspan></tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="552.88428"
|
|
||||||
y="-299.25662"
|
|
||||||
id="text2902"
|
|
||||||
transform="matrix(-1.094382e-2,0.9999401,-0.9999401,-1.094382e-2,0,0)"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2904"
|
|
||||||
x="552.88428"
|
|
||||||
y="-299.25662">A<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2906">0</tspan>, A<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2908">1</tspan>, ... Ak<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2910" /></tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:37.14432144px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="784.93219"
|
|
||||||
y="-237.72998"
|
|
||||||
id="text2912"
|
|
||||||
transform="matrix(2.6675397e-2,0.8871754,-1.1264084,2.54215e-2,0,0)"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2914"
|
|
||||||
x="784.93219"
|
|
||||||
y="-237.72998"
|
|
||||||
style="font-size:18.57216072px">S<tspan
|
|
||||||
style="font-size:9.28608036px"
|
|
||||||
id="tspan2916">clk</tspan></tspan></text>
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="M 491.47553,766.55443 L 530.65923,741.92468"
|
|
||||||
id="path2922" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="784.55219"
|
|
||||||
y="-372.34665"
|
|
||||||
id="text2924"
|
|
||||||
transform="matrix(-9.6248034e-2,0.9953574,-0.9953574,-9.6248034e-2,0,0)"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2926"
|
|
||||||
x="784.55219"
|
|
||||||
y="-372.34665">clk</tspan><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
x="784.55219"
|
|
||||||
y="-357.34665"
|
|
||||||
id="tspan2928" /></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="727.75165"
|
|
||||||
y="543.27771"
|
|
||||||
id="text2970"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2972"
|
|
||||||
x="727.75165"
|
|
||||||
y="543.27771" /></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="537.27209"
|
|
||||||
y="156.72511"
|
|
||||||
id="text2992"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2994"
|
|
||||||
x="537.27209"
|
|
||||||
y="156.72511"> Bit Lines</tspan><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
x="537.27209"
|
|
||||||
y="171.72511"
|
|
||||||
id="tspan2996">BL<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan2998">0</tspan>,BR<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan3000">0</tspan>, BL<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan3002">1</tspan>, BR<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan3004">1</tspan>, ... BL<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan3006">j</tspan> BR<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan3008">j </tspan></tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="523.96411"
|
|
||||||
y="638.21588"
|
|
||||||
id="text3010"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan3012"
|
|
||||||
x="523.96411"
|
|
||||||
y="638.21588"> Bit Lines</tspan><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
x="523.96411"
|
|
||||||
y="653.21588"
|
|
||||||
id="tspan3014">BL<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan3016">0</tspan>,BR<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan3018">0</tspan>, BL<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan3020">1</tspan>, BR<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan3022">1</tspan>, ... BL<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan3024">j/2^k</tspan> BR<tspan
|
|
||||||
style="font-size:6px"
|
|
||||||
id="tspan3026">j/2^k </tspan></tspan></text>
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-mid:none;marker-end:none;marker-start:url(#Arrow1Lstart)"
|
|
||||||
d="M 404.99504,103.56693 L 342.27828,103.91486"
|
|
||||||
id="path3046"
|
|
||||||
inkscape:connector-type="polyline" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="86.832726"
|
|
||||||
y="-327.60617"
|
|
||||||
id="text3052"
|
|
||||||
transform="matrix(-1.094382e-2,0.9999401,-0.9999401,-1.094382e-2,0,0)"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan3054"
|
|
||||||
x="86.832726"
|
|
||||||
y="-327.60617">Pclk</tspan><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
x="86.832726"
|
|
||||||
y="-312.60617"
|
|
||||||
id="tspan3062" /></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="551.03613"
|
|
||||||
y="753.10077"
|
|
||||||
id="text3064"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan3066"
|
|
||||||
x="551.03613"
|
|
||||||
y="753.10077"
|
|
||||||
style="font-size:12px"> Data</tspan><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
x="551.03613"
|
|
||||||
y="768.10077"
|
|
||||||
id="tspan3068"><tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3111">D</tspan><tspan
|
|
||||||
style="font-size:8px"
|
|
||||||
id="tspan3074">0</tspan><tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3115">, </tspan><tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3109">D</tspan><tspan
|
|
||||||
style="font-size:8px"
|
|
||||||
id="tspan3072">1</tspan><tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3113">, ...,</tspan><tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3107"> D</tspan><tspan
|
|
||||||
style="font-size:8px"
|
|
||||||
id="tspan3070">j/2^k</tspan></tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="543.46613"
|
|
||||||
y="865.92303"
|
|
||||||
id="text3117"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan3119"
|
|
||||||
x="543.46613"
|
|
||||||
y="865.92303"
|
|
||||||
style="font-size:12px"> Data Out</tspan><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
x="543.46613"
|
|
||||||
y="880.92303"
|
|
||||||
id="tspan3121"><tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3123">Do</tspan><tspan
|
|
||||||
style="font-size:8px"
|
|
||||||
id="tspan3125">0</tspan><tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3127">, </tspan><tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3129">Do</tspan><tspan
|
|
||||||
style="font-size:8px"
|
|
||||||
id="tspan3131">1</tspan><tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3133">, ...,</tspan><tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3135"> Do</tspan><tspan
|
|
||||||
style="font-size:8px"
|
|
||||||
id="tspan3137">j/2^k</tspan></tspan></text>
|
|
||||||
<path
|
|
||||||
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke-width:0.40000001000000002;stroke-miterlimit:18.10000038000000089;stroke-dasharray:none"
|
|
||||||
id="path3309"
|
|
||||||
d="M 75.196328,158.6717 C 80.758538,157.28869 86.44734,156.6028 92.133726,155.94035 C 107.05435,154.05138 121.8677,151.43215 136.75528,149.30749 C 147.64996,147.53122 158.58499,146.01225 169.47598,144.21603 C 171.5715,143.74706 173.73538,143.65255 175.84432,143.27807 C 176.90658,143.08945 177.95684,142.73177 179.00742,142.48204 C 180.58421,142.34805 181.98047,141.66528 183.53245,141.39396 L 172.37378,149.88252 C 170.88347,150.29297 169.41362,150.72728 167.88051,150.96244 C 164.844,151.6568 161.73546,151.85357 158.66031,152.32711 C 148.00248,153.81685 137.31827,155.11752 126.69325,156.8396 C 111.66369,159.01206 96.704443,161.62748 81.668664,163.7554 C 75.768122,164.62195 69.820463,165.47786 64.116915,167.27925 L 75.196328,158.6717 z" />
|
|
||||||
<rect
|
|
||||||
y="-498.05804"
|
|
||||||
x="133.76231"
|
|
||||||
height="94.646927"
|
|
||||||
width="165.71428"
|
|
||||||
id="rect3815"
|
|
||||||
style="fill:url(#linearGradient3819);fill-opacity:1"
|
|
||||||
transform="scale(1,-1)" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="170.85649"
|
|
||||||
y="394.76114"
|
|
||||||
id="text2393"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2395"
|
|
||||||
x="170.85649"
|
|
||||||
y="394.76114">Address </tspan><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
x="170.85649"
|
|
||||||
y="424.76114"
|
|
||||||
id="tspan2397">Decoder</tspan></text>
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);stroke-opacity:1"
|
|
||||||
d="M 133.5,403.36218 L 70.75,402.86218"
|
|
||||||
id="path3823" />
|
|
||||||
<rect
|
|
||||||
y="558.85974"
|
|
||||||
x="371.81412"
|
|
||||||
height="54.285713"
|
|
||||||
width="138.24103"
|
|
||||||
id="rect4875"
|
|
||||||
style="fill:url(#linearGradient4885);fill-opacity:1" />
|
|
||||||
<rect
|
|
||||||
style="fill:url(#linearGradient4879);fill-opacity:1"
|
|
||||||
id="rect4877"
|
|
||||||
width="138.24103"
|
|
||||||
height="54.285713"
|
|
||||||
x="-648.05518"
|
|
||||||
y="558.85974"
|
|
||||||
transform="scale(-1,1)" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="439.2803"
|
|
||||||
y="595.7511"
|
|
||||||
id="text2407"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2409"
|
|
||||||
x="439.2803"
|
|
||||||
y="595.7511">Column Mux</tspan></text>
|
|
||||||
<path
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
id="path4881"
|
|
||||||
d="M 510.37147,497.86869 L 510.36004,557.47571"
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00782228px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-opacity:1" />
|
|
||||||
<path
|
|
||||||
id="path4883"
|
|
||||||
d="M 491.10498,538.25031 L 526.70018,512.88523"
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
|
||||||
<rect
|
|
||||||
style="fill:#cccccc"
|
|
||||||
id="rect2427"
|
|
||||||
width="277.14285"
|
|
||||||
height="54.285713"
|
|
||||||
x="372.23978"
|
|
||||||
y="190.47002" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="432.57791"
|
|
||||||
y="225.61827"
|
|
||||||
id="text2433"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2435"
|
|
||||||
x="432.57791"
|
|
||||||
y="225.61827">Write Driver</tspan></text>
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);stroke-opacity:1"
|
|
||||||
d="M 371.40729,219.41404 L 308.69052,219.76197"
|
|
||||||
id="path2848"
|
|
||||||
inkscape:connector-type="polyline" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-opacity:1"
|
|
||||||
d="M 340.99482,208.10497 C 327.752,230.80694 327.752,230.80694 327.752,230.80694"
|
|
||||||
id="path2882" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="167.72096"
|
|
||||||
y="-293.01819"
|
|
||||||
id="text2884"
|
|
||||||
transform="matrix(-2.8547241e-3,0.9999959,-0.9999959,-2.8547241e-3,0,0)"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2886"
|
|
||||||
x="167.72096"
|
|
||||||
y="-293.01819">Enable, Data in</tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:8px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
|
||||||
x="519.95123"
|
|
||||||
y="268.63846"
|
|
||||||
id="text3028"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan3030"
|
|
||||||
x="519.95123"
|
|
||||||
y="268.63846"
|
|
||||||
style="font-size:12px"> Bit Lines</tspan><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
x="519.95123"
|
|
||||||
y="283.63846"
|
|
||||||
id="tspan3084"><tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3103">BL</tspan>0 ,<tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3101">BR</tspan><tspan
|
|
||||||
style="font-size:8px"
|
|
||||||
id="tspan3036">0</tspan>, <tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3099">BL</tspan><tspan
|
|
||||||
style="font-size:8px"
|
|
||||||
id="tspan3038">1</tspan>, <tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3097">BR</tspan><tspan
|
|
||||||
style="font-size:8px"
|
|
||||||
id="tspan3078">1</tspan>, ... <tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3095">BL</tspan><tspan
|
|
||||||
style="font-size:8px"
|
|
||||||
id="tspan3042">j/2^k</tspan><tspan
|
|
||||||
style="font-size:12px"
|
|
||||||
id="tspan3093"> BR</tspan><tspan
|
|
||||||
style="font-size:8px"
|
|
||||||
id="tspan3044">j /2^k</tspan></tspan></text>
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:url(#Arrow1Lend)"
|
|
||||||
d="M 510.33208,133.58278 L 510.65644,190.47002"
|
|
||||||
id="path4910"
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
inkscape:connection-start="#rect2387"
|
|
||||||
inkscape:connection-end="#rect2427" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-type="polyline"
|
|
||||||
id="path6475"
|
|
||||||
d="M 508.33374,244.83566 L 508.65589,308.42732"
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.0536716px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow1Lend);stroke-opacity:1" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="M 491.10498,280.25031 L 526.70018,254.88523"
|
|
||||||
id="path6477" />
|
|
||||||
<path
|
|
||||||
id="path6479"
|
|
||||||
d="M 491.10498,168.25031 L 526.70018,142.88523"
|
|
||||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 29 KiB |
|
|
@ -1,522 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="744.09448819"
|
|
||||||
height="1052.3622047"
|
|
||||||
id="svg6017"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.48.3.1 r9886"
|
|
||||||
sodipodi:docname="cell_6t.svg">
|
|
||||||
<defs
|
|
||||||
id="defs6019" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="1"
|
|
||||||
inkscape:cx="199"
|
|
||||||
inkscape:cy="609.48139"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:window-width="1580"
|
|
||||||
inkscape:window-height="810"
|
|
||||||
inkscape:window-x="143"
|
|
||||||
inkscape:window-y="132"
|
|
||||||
inkscape:window-maximized="0">
|
|
||||||
<inkscape:grid
|
|
||||||
type="xygrid"
|
|
||||||
id="grid6109" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<metadata
|
|
||||||
id="metadata6022">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1">
|
|
||||||
<g
|
|
||||||
id="g6894"
|
|
||||||
transform="translate(20,1.3297774e-6)">
|
|
||||||
<g
|
|
||||||
style="stroke-width:4.11560297;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
id="g6006"
|
|
||||||
transform="matrix(0.51500628,0,0,0.4585435,23.157615,250.95114)">
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:4.11560297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 71.537739,504.66541 77.668961,0 0.20751,-65.01034 96.87868,-0.41421 0,65.42455 77.66896,0"
|
|
||||||
id="path5141"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:4.11560297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 142.12846,439.3006 111.72287,0"
|
|
||||||
id="path5143"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:4.11560297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 149.90664,429.40111 96.16652,0"
|
|
||||||
id="path5145"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
transform="matrix(0.51500333,0,0,0.45312146,186.14808,178.39506)"
|
|
||||||
id="g6011-6" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 230,452.36218 0,60"
|
|
||||||
id="path6181"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
sodipodi:type="arc"
|
|
||||||
style="fill:none"
|
|
||||||
id="path6210"
|
|
||||||
sodipodi:cx="325"
|
|
||||||
sodipodi:cy="417.36218"
|
|
||||||
sodipodi:rx="55"
|
|
||||||
sodipodi:ry="35"
|
|
||||||
d="m 380,417.36218 a 55,35 0 1 1 -110,0 55,35 0 1 1 110,0 z" />
|
|
||||||
<g
|
|
||||||
id="g6948">
|
|
||||||
<g
|
|
||||||
style="stroke-width:3.34598514;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
id="g6006-9"
|
|
||||||
transform="matrix(0,0.51500628,-0.4585435,0,461.41104,285.5198)">
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:3.34598514;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 71.537739,504.66541 77.668961,0 0.20751,-65.01034 96.87868,-0.41421 0,65.42455 77.66896,0"
|
|
||||||
id="path5141-6"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:3.34598514;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 142.12846,439.3006 111.72287,0"
|
|
||||||
id="path5143-42"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:3.34598514;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 149.90664,429.40111 96.16652,0"
|
|
||||||
id="path5145-5"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g>
|
|
||||||
<path
|
|
||||||
transform="translate(-75,10)"
|
|
||||||
d="m 350,377.36218 a 5,5 0 1 1 -10,0 5,5 0 1 1 10,0 z"
|
|
||||||
sodipodi:ry="5"
|
|
||||||
sodipodi:rx="5"
|
|
||||||
sodipodi:cy="377.36218"
|
|
||||||
sodipodi:cx="345"
|
|
||||||
id="path6744"
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:1.626;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
sodipodi:type="arc" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
transform="matrix(0,0.51500628,-0.4585435,0,461.60097,475.41293)"
|
|
||||||
id="g6006-24"
|
|
||||||
style="stroke-width:4.11560297;stroke-miterlimit:4;stroke-dasharray:none">
|
|
||||||
<path
|
|
||||||
sodipodi:nodetypes="cccccc"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path5141-8"
|
|
||||||
d="m 71.537739,504.66541 77.668961,0 0.20751,-65.01034 96.87868,-0.41421 0,65.42455 77.66896,0"
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:4.11560297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path5143-2"
|
|
||||||
d="m 142.12846,439.3006 111.72287,0"
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:4.11560297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path5145-8"
|
|
||||||
d="m 149.90664,429.40111 96.16652,0"
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:4.11560297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
transform="matrix(0,-0.51500628,0.4585435,0,158.39903,679.31144)"
|
|
||||||
id="g6006-3"
|
|
||||||
style="stroke-width:4.11560297;stroke-miterlimit:4;stroke-dasharray:none">
|
|
||||||
<path
|
|
||||||
sodipodi:nodetypes="cccccc"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path5141-2"
|
|
||||||
d="m 71.537739,504.66541 77.668961,0 0.20751,-65.01034 96.87868,-0.41421 0,65.42455 77.66896,0"
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:4.11560297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path5143-8"
|
|
||||||
d="m 142.12846,439.3006 111.72287,0"
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:4.11560297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path5145-3"
|
|
||||||
d="m 149.90664,429.40111 96.16652,0"
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:4.11560297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
transform="matrix(-1,0,0,-1,620,774.72437)"
|
|
||||||
id="g6948-0">
|
|
||||||
<g
|
|
||||||
style="stroke-width:3.34598517;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
id="g6006-9-4"
|
|
||||||
transform="matrix(0,0.51500628,-0.4585435,0,461.41104,285.5198)">
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:3.34598517;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 71.537739,504.66541 77.668961,0 0.20751,-65.01034 96.87868,-0.41421 0,65.42455 77.66896,0"
|
|
||||||
id="path5141-6-8"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:3.34598517;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 142.12846,439.3006 111.72287,0"
|
|
||||||
id="path5143-42-3"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:3.34598517;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 149.90664,429.40111 96.16652,0"
|
|
||||||
id="path5145-5-8"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g>
|
|
||||||
<path
|
|
||||||
transform="translate(-75,10)"
|
|
||||||
d="m 350,377.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
|
||||||
sodipodi:ry="5"
|
|
||||||
sodipodi:rx="5"
|
|
||||||
sodipodi:cy="377.36218"
|
|
||||||
sodipodi:cx="345"
|
|
||||||
id="path6744-9"
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:1.62600005;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
sodipodi:type="arc" />
|
|
||||||
</g>
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 390,512.36218 0,-60"
|
|
||||||
id="path6988"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<g
|
|
||||||
transform="translate(350,1.3297774e-6)"
|
|
||||||
id="g6894-7">
|
|
||||||
<g
|
|
||||||
style="stroke-width:4.11560297;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
id="g6006-5"
|
|
||||||
transform="matrix(0.51500628,0,0,0.4585435,23.157615,250.95114)">
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:4.11560297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 71.537739,504.66541 77.668961,0 0.20751,-65.01034 96.87868,-0.41421 0,65.42455 77.66896,0"
|
|
||||||
id="path5141-3"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:4.11560297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 142.12846,439.3006 111.72287,0"
|
|
||||||
id="path5143-27"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:4.11560297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 149.90664,429.40111 96.16652,0"
|
|
||||||
id="path5145-30"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 190,482.36218 40,0"
|
|
||||||
id="path7020"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 440,482.36218 -50,0"
|
|
||||||
id="path7022"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 230,292.36218 160,0 0,0 0,30"
|
|
||||||
id="path7024"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 230,322.36218 0,-30"
|
|
||||||
id="path7026"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 310,292.36218 0,-30 30,0 -60,0"
|
|
||||||
id="path7028"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 230,642.36218 0,20 160,0 0,-20"
|
|
||||||
id="path7030"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 310,662.36218 0,30 -30,0 60,0"
|
|
||||||
id="path7032"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 290,702.36218 40,0"
|
|
||||||
id="path7034"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 300,712.36218 20,0"
|
|
||||||
id="path7036"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 540,482.36218 0,-150 0,300"
|
|
||||||
id="path7057"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 80,482.36218 0,-150 0,300"
|
|
||||||
id="path7059"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 80,232.36218 460,0"
|
|
||||||
id="path7061"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:1.96486509;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 330,386.34238 0,193.03475"
|
|
||||||
id="path7063"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 230,482.36218 100,0"
|
|
||||||
id="path7067"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:1.9069252;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 290,452.36218 100,0"
|
|
||||||
id="path7069"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 275,387.36218 15,0"
|
|
||||||
id="path7071"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2.26907873;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 345.73333,387.36218 -16.73333,0"
|
|
||||||
id="path7073"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 265,576.36218 24,0"
|
|
||||||
id="path7075"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cc" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2.03967071;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 331.03846,578.36218 24.96154,0"
|
|
||||||
id="path7075-3"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cc" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:1.96486509;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 290,384.84481 0,193.03475"
|
|
||||||
id="path7063-1"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
sodipodi:type="arc"
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
id="path7117-9"
|
|
||||||
sodipodi:cx="108"
|
|
||||||
sodipodi:cy="307.86218"
|
|
||||||
sodipodi:rx="2"
|
|
||||||
sodipodi:ry="2.5"
|
|
||||||
d="m 110,307.86218 a 2,2.5 0 1 1 -4,0 2,2.5 0 1 1 4,0 z"
|
|
||||||
transform="matrix(1.2092203,0,0,0.96737621,158.90421,154.54363)" />
|
|
||||||
<path
|
|
||||||
sodipodi:type="arc"
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
id="path7117-9-7"
|
|
||||||
sodipodi:cx="108"
|
|
||||||
sodipodi:cy="307.86218"
|
|
||||||
sodipodi:rx="2"
|
|
||||||
sodipodi:ry="2.5"
|
|
||||||
d="m 110,307.86218 a 2,2.5 0 1 1 -4,0 2,2.5 0 1 1 4,0 z"
|
|
||||||
transform="matrix(1.2092203,0,0,0.96737621,199.40421,183.54363)" />
|
|
||||||
<path
|
|
||||||
sodipodi:type="arc"
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
id="path7117-9-8"
|
|
||||||
sodipodi:cx="108"
|
|
||||||
sodipodi:cy="307.86218"
|
|
||||||
sodipodi:rx="2"
|
|
||||||
sodipodi:ry="2.5"
|
|
||||||
d="m 110,307.86218 a 2,2.5 0 1 1 -4,0 2,2.5 0 1 1 4,0 z"
|
|
||||||
transform="matrix(1.2092203,0,0,0.96737621,259.40421,185.54363)" />
|
|
||||||
<path
|
|
||||||
sodipodi:type="arc"
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
id="path7117-9-4"
|
|
||||||
sodipodi:cx="108"
|
|
||||||
sodipodi:cy="307.86218"
|
|
||||||
sodipodi:rx="2"
|
|
||||||
sodipodi:ry="2.5"
|
|
||||||
d="m 110,307.86218 a 2,2.5 0 1 1 -4,0 2,2.5 0 1 1 4,0 z"
|
|
||||||
transform="matrix(1.2092203,0,0,0.96737621,179.40421,-6.456369)" />
|
|
||||||
<path
|
|
||||||
sodipodi:type="arc"
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
id="path7117-9-9"
|
|
||||||
sodipodi:cx="108"
|
|
||||||
sodipodi:cy="307.86218"
|
|
||||||
sodipodi:rx="2"
|
|
||||||
sodipodi:ry="2.5"
|
|
||||||
d="m 110,307.86218 a 2,2.5 0 1 1 -4,0 2,2.5 0 1 1 4,0 z"
|
|
||||||
transform="matrix(1.2092203,0,0,0.96737621,179.40421,364.54363)" />
|
|
||||||
<path
|
|
||||||
sodipodi:type="arc"
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
id="path7117-9-71"
|
|
||||||
sodipodi:cx="108"
|
|
||||||
sodipodi:cy="307.86218"
|
|
||||||
sodipodi:rx="2"
|
|
||||||
sodipodi:ry="2.5"
|
|
||||||
d="m 110,307.86218 a 2,2.5 0 1 1 -4,0 2,2.5 0 1 1 4,0 z"
|
|
||||||
transform="matrix(1.2092203,0,0,0.96737621,98.40421,185.54363)" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
d="m 145,446.36218 2,-215"
|
|
||||||
id="path7183"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 475,446.36218 0,-216"
|
|
||||||
id="path7185"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cc" />
|
|
||||||
<path
|
|
||||||
sodipodi:type="arc"
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
id="path7117-9-1"
|
|
||||||
sodipodi:cx="108"
|
|
||||||
sodipodi:cy="307.86218"
|
|
||||||
sodipodi:rx="2"
|
|
||||||
sodipodi:ry="2.5"
|
|
||||||
d="m 110,307.86218 a 2,2.5 0 1 1 -4,0 2,2.5 0 1 1 4,0 z"
|
|
||||||
transform="matrix(1.2092203,0,0,0.96737621,16.404208,-64.456369)" />
|
|
||||||
<path
|
|
||||||
sodipodi:type="arc"
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
id="path7117-9-5"
|
|
||||||
sodipodi:cx="108"
|
|
||||||
sodipodi:cy="307.86218"
|
|
||||||
sodipodi:rx="2"
|
|
||||||
sodipodi:ry="2.5"
|
|
||||||
d="m 110,307.86218 a 2,2.5 0 1 1 -4,0 2,2.5 0 1 1 4,0 z"
|
|
||||||
transform="matrix(1.2092203,0,0,0.96737621,344.40421,-65.456369)" />
|
|
||||||
<path
|
|
||||||
sodipodi:type="arc"
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
id="path7117-9-74"
|
|
||||||
sodipodi:cx="108"
|
|
||||||
sodipodi:cy="307.86218"
|
|
||||||
sodipodi:rx="2"
|
|
||||||
sodipodi:ry="2.5"
|
|
||||||
d="m 110,307.86218 a 2,2.5 0 1 1 -4,0 2,2.5 0 1 1 4,0 z"
|
|
||||||
transform="matrix(1.2092203,0,0,0.96737621,409.40421,184.54363)" />
|
|
||||||
<path
|
|
||||||
sodipodi:type="arc"
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
id="path7117-9-89"
|
|
||||||
sodipodi:cx="108"
|
|
||||||
sodipodi:cy="307.86218"
|
|
||||||
sodipodi:rx="2"
|
|
||||||
sodipodi:ry="2.5"
|
|
||||||
d="m 110,307.86218 a 2,2.5 0 1 1 -4,0 2,2.5 0 1 1 4,0 z"
|
|
||||||
transform="matrix(1.2092203,0,0,0.96737621,-51.595792,184.54363)" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:0.99999998%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
|
||||||
x="350"
|
|
||||||
y="262.36218"
|
|
||||||
id="text7226"
|
|
||||||
sodipodi:linespacing="0.99999998%"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan7228"
|
|
||||||
x="350"
|
|
||||||
y="262.36218"
|
|
||||||
style="line-height:0.99999998%" /></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:16px;font-style:normal;font-weight:normal;line-height:10.00000015%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
|
||||||
x="342"
|
|
||||||
y="270.36218"
|
|
||||||
id="text7230"
|
|
||||||
sodipodi:linespacing="10%"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan7232"
|
|
||||||
x="342"
|
|
||||||
y="270.36218">VDD</tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:16px;font-style:normal;font-weight:normal;line-height:10.00000015%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
|
||||||
x="350"
|
|
||||||
y="691.36218"
|
|
||||||
id="text7234"
|
|
||||||
sodipodi:linespacing="10%"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan7236"
|
|
||||||
x="350"
|
|
||||||
y="691.36218">GND</tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:16px;font-style:normal;font-weight:normal;line-height:10.00000015%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
|
||||||
x="549"
|
|
||||||
y="482.36218"
|
|
||||||
id="text7238"
|
|
||||||
sodipodi:linespacing="10%"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan7240"
|
|
||||||
x="549"
|
|
||||||
y="482.36218">BL_bar</tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:16px;font-style:normal;font-weight:normal;line-height:10.00000015%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
|
||||||
x="48"
|
|
||||||
y="483.36218"
|
|
||||||
id="text7242"
|
|
||||||
sodipodi:linespacing="10%"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan7244"
|
|
||||||
x="48"
|
|
||||||
y="483.36218">BL</tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:16px;font-style:normal;font-weight:normal;line-height:10.00000015%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
|
||||||
x="116"
|
|
||||||
y="229.36218"
|
|
||||||
id="text7246"
|
|
||||||
sodipodi:linespacing="10%"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan7248"
|
|
||||||
x="116"
|
|
||||||
y="229.36218">WL</tspan></text>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 23 KiB |