PEP8 cleanup. Un-hard-code bitcell layers. Remove dead variable.

This commit is contained in:
mrg 2020-10-01 11:10:18 -07:00
parent 18c8ad265e
commit b32c123dab
7 changed files with 168 additions and 473 deletions

View File

@ -51,23 +51,21 @@ class simulation():
self.load = tech.spice["dff_in_cap"] * 4
self.v_high = self.vdd_voltage - tech.spice["nom_threshold"]
self.v_low = tech.spice["nom_threshold"]
self.v_low = tech.spice["nom_threshold"]
self.gnd_voltage = 0
def create_signal_names(self):
self.addr_name = "a"
self.din_name = "din"
self.dout_name = "dout"
self.pins = self.gen_pin_names(port_signal_names=(self.addr_name,self.din_name,self.dout_name),
port_info=(len(self.all_ports),self.write_ports,self.read_ports),
self.pins = self.gen_pin_names(port_signal_names=(self.addr_name, self.din_name, self.dout_name),
port_info=(len(self.all_ports), self.write_ports, self.read_ports),
abits=self.addr_size,
dbits=self.word_size + self.num_spare_cols)
debug.check(len(self.sram.pins) == len(self.pins),
"Number of pins generated for characterization \
do not match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(self.sram.pins,
self.pins))
#This is TODO once multiport control has been finalized.
#self.control_name = "CSB"
self.pins))
def set_stimulus_variables(self):
# Clock signals
@ -96,7 +94,7 @@ class simulation():
def add_control_one_port(self, port, op):
"""Appends control signals for operation to a given port"""
#Determine values to write to port
# Determine values to write to port
web_val = 1
csb_val = 1
if op == "read":
@ -406,7 +404,9 @@ class simulation():
return pin_names
def add_graph_exclusions(self):
"""Exclude portions of SRAM from timing graph which are not relevant"""
"""
Exclude portions of SRAM from timing graph which are not relevant
"""
# other initializations can only be done during analysis when a bit has been selected
# for testing.
@ -417,7 +417,9 @@ class simulation():
self.sram.bank.bitcell_array.graph_exclude_replica_col_bits()
def set_internal_spice_names(self):
"""Sets important names for characterization such as Sense amp enable and internal bit nets."""
"""
Sets important names for characterization such as Sense amp enable and internal bit nets.
"""
port = self.read_ports[0]
if not OPTS.use_pex:
@ -458,11 +460,10 @@ class simulation():
self.sen_name = self.get_sen_name(self.graph.all_paths)
debug.info(2, "s_en name = {}".format(self.sen_name))
self.bl_name = "bl{0}_{1}".format(port, OPTS.word_size - 1)
self.br_name = "br{0}_{1}".format(port, OPTS.word_size - 1)
debug.info(2, "bl name={}, br name={}".format(self.bl_name, self.br_name))
debug.info(2, "bl name={}, br name={}".format(self.bl_name, self.br_name))
def get_sen_name(self, paths, assumed_port=None):
"""
@ -481,7 +482,9 @@ class simulation():
return sen_name
def create_graph(self):
"""Creates timing graph to generate the timing paths for the SRAM output."""
"""
Creates timing graph to generate the timing paths for the SRAM output.
"""
self.sram.clear_exclude_bits() # Removes previous bit exclusions
self.sram.graph_exclude_bits(self.wordline_row, self.bitline_column)
@ -492,7 +495,9 @@ class simulation():
self.sram.build_graph(self.graph, self.sram_instance_name, self.pins)
def get_bl_name_search_exclusions(self):
"""Gets the mods as a set which should be excluded while searching for name."""
"""
Gets the mods as a set which should be excluded while searching for name.
"""
# Exclude the RBL as it contains bitcells which are not in the main bitcell array
# so it makes the search awkward
@ -519,7 +524,9 @@ class simulation():
return path_net_name
def get_bl_name(self, paths, port):
"""Gets the signal name associated with the bitlines in the bank."""
"""
Gets the signal name associated with the bitlines in the bank.
"""
cell_mod = factory.create(module_type=OPTS.bitcell)
cell_bl = cell_mod.get_bl_name(port)

View File

@ -67,7 +67,7 @@ class sram():
"""Dump config file with all options.
Include defaults and anything changed by input config."""
f = open(name, "w")
var_dict = dict((name, getattr(OPTS, name)) for name in dir(OPTS) if not name.startswith('__') and not callable(getattr(OPTS, name)))
var_dict = dict((name, getattr(OPTS, name)) for name in dir(OPTS) if not name.startswith('__') and not callable(getattr(OPTS, name)))
for var_name, var_value in var_dict.items():
if isinstance(var_value, str):
f.write(str(var_name) + " = " + "\"" + str(var_value) + "\"\n")
@ -156,4 +156,4 @@ class sram():
oname = OPTS.output_path + OPTS.output_name + "_extended.py"
debug.print_raw("Extended Config: Writing to {0}".format(oname))
self.extended_config_write(oname)
print_time("Extended Config", datetime.datetime.now(), start_time)
print_time("Extended Config", datetime.datetime.now(), start_time)

View File

@ -15,9 +15,6 @@ from design import design
from verilog import verilog
from lef import lef
from sram_factory import factory
from tech import drc
import numpy as np
import logical_effort
class sram_base(design, verilog, lef):
@ -43,9 +40,6 @@ class sram_base(design, verilog, lef):
if not self.num_spare_cols:
self.num_spare_cols = 0
# For logical effort delay calculations.
self.all_mods_except_control_done = False
def add_pins(self):
""" Add pins for entire SRAM. """
@ -87,14 +81,16 @@ class sram_base(design, verilog, lef):
for bit in range(self.word_size + self.num_spare_cols):
self.add_pin("dout{0}[{1}]".format(port, bit), "OUTPUT")
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_global_pex_labels(self):
"""
Add pex labels at the sram level for spice analysis
"""
# add pex labels for bitcells
for bank_num in range(len(self.bank_insts)):
bank = self.bank_insts[bank_num]
@ -111,47 +107,62 @@ class sram_base(design, verilog, lef):
bl = []
br = []
storage_layer_name = "m1"
bitline_layer_name = "m2"
storage_layer_name = self.bitcell.get_pin("Q").layer
bitline_layer_name = self.bitcell.get_pin("bl").layer
for cell in range(len(bank_offset)):
Q = [bank_offset[cell][0] + Q_offset[cell][0], bank_offset[cell][1] + Q_offset[cell][1]]
Q_bar = [bank_offset[cell][0] + Q_bar_offset[cell][0], bank_offset[cell][1] + Q_bar_offset[cell][1]]
Q = [bank_offset[cell][0] + Q_offset[cell][0],
bank_offset[cell][1] + Q_offset[cell][1]]
Q_bar = [bank_offset[cell][0] + Q_bar_offset[cell][0],
bank_offset[cell][1] + Q_bar_offset[cell][1]]
OPTS.words_per_row = self.words_per_row
self.add_layout_pin_rect_center("bitcell_Q_b{}_r{}_c{}".format(bank_num, int(cell % (OPTS.num_words / self.words_per_row)), int(cell / (OPTS.num_words))) , storage_layer_name, Q)
self.add_layout_pin_rect_center("bitcell_Q_bar_b{}_r{}_c{}".format(bank_num, int(cell % (OPTS.num_words / self.words_per_row)), int(cell / (OPTS.num_words))), storage_layer_name, Q_bar)
row = int(cell % (OPTS.num_words / self.words_per_row))
col = int(cell / (OPTS.num_words))
self.add_layout_pin_rect_center("bitcell_Q_b{}_r{}_c{}".format(bank_num,
row,
col),
storage_layer_name,
Q)
self.add_layout_pin_rect_center("bitcell_Q_bar_b{}_r{}_c{}".format(bank_num,
row,
col),
storage_layer_name,
Q_bar)
for cell in range(len(bl_offsets)):
col = bl_meta[cell][0][2]
for bitline in range(len(bl_offsets[cell])):
bitline_location = [float(bank_offset[cell][0]) + bl_offsets[cell][bitline][0], float(bank_offset[cell][1]) + bl_offsets[cell][bitline][1]]
bitline_location = [float(bank_offset[cell][0]) + bl_offsets[cell][bitline][0],
float(bank_offset[cell][1]) + bl_offsets[cell][bitline][1]]
bl.append([bitline_location, bl_meta[cell][bitline][3], col])
for cell in range(len(br_offsets)):
col = br_meta[cell][0][2]
for bitline in range(len(br_offsets[cell])):
bitline_location = [float(bank_offset[cell][0]) + br_offsets[cell][bitline][0], float(bank_offset[cell][1]) + br_offsets[cell][bitline][1]]
br.append([bitline_location, br_meta[cell][bitline][3], col])
bitline_location = [float(bank_offset[cell][0]) + br_offsets[cell][bitline][0],
float(bank_offset[cell][1]) + br_offsets[cell][bitline][1]]
br.append([bitline_location, br_meta[cell][bitline][3], col])
for i in range(len(bl)):
self.add_layout_pin_rect_center("bl{0}_{1}".format(bl[i][1], bl[i][2]), bitline_layer_name, bl[i][0])
self.add_layout_pin_rect_center("bl{0}_{1}".format(bl[i][1], bl[i][2]),
bitline_layer_name, bl[i][0])
for i in range(len(br)):
self.add_layout_pin_rect_center("br{0}_{1}".format(br[i][1], br[i][2]), bitline_layer_name, br[i][0])
self.add_layout_pin_rect_center("br{0}_{1}".format(br[i][1], br[i][2]),
bitline_layer_name, br[i][0])
# add pex labels for control logic
for i in range (len(self.control_logic_insts)):
for i in range(len(self.control_logic_insts)):
instance = self.control_logic_insts[i]
control_logic_offset = instance.offset
for output in instance.mod.output_list:
pin = instance.mod.get_pin(output)
pin.transform([0,0], instance.mirror, instance.rotate)
offset = [control_logic_offset[0] + pin.center()[0], control_logic_offset[1] + pin.center()[1]]
self.add_layout_pin_rect_center("{0}{1}".format(pin.name,i), storage_layer_name, offset)
pin.transform([0, 0], instance.mirror, instance.rotate)
offset = [control_logic_offset[0] + pin.center()[0],
control_logic_offset[1] + pin.center()[1]]
self.add_layout_pin_rect_center("{0}{1}".format(pin.name, i),
storage_layer_name,
offset)
def create_netlist(self):
""" Netlist creation """
@ -370,10 +381,6 @@ class sram_base(design, verilog, lef):
self.bank_count = 0
# The control logic can resize itself based on the other modules.
# Requires all other modules added before control logic.
self.all_mods_except_control_done = True
c = reload(__import__(OPTS.control_logic))
self.mod_control_logic = getattr(c, OPTS.control_logic)
@ -619,6 +626,7 @@ class sram_base(design, verilog, lef):
sp.write("* Column mux: {}:1\n".format(self.words_per_row))
sp.write("**************************************************\n")
# This causes unit test mismatch
# sp.write("* Created: {0}\n".format(datetime.datetime.now()))
# sp.write("* User: {0}\n".format(getpass.getuser()))
# sp.write(".global {0} {1}\n".format(spice["vdd_name"],

View File

@ -9,8 +9,8 @@ Run regression tests/pex test on an extracted pinv to ensure pex functionality
with HSPICE.
"""
import unittest
from testutils import header,openram_test
import sys,os
from testutils import header, openram_test
import sys, os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
@ -35,43 +35,43 @@ class hspice_pex_pinv_test(openram_test):
# generate the pinv
prev_purge_value = OPTS.purge_temp
OPTS.purge_temp = False # force set purge to false to save the sp file
# force set purge to false to save the sp file
OPTS.purge_temp = False
debug.info(2, "Checking 1x size inverter")
tx = pinv.pinv(name="pinv", size=1)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,tx.name)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp, tx.name)
tx.gds_write(tempgds)
tempsp = "{0}{1}.sp".format(OPTS.openram_temp,tx.name)
tempsp = "{0}{1}.sp".format(OPTS.openram_temp, tx.name)
tx.sp_write(tempsp)
# make sure that the library simulation is successful\
sp_delay = self.simulate_delay(test_module = tempsp,
top_level_name = tx.name)
if sp_delay is "Failed":
# make sure that the library simulation is successful
sp_delay = self.simulate_delay(test_module=tempsp,
top_level_name=tx.name)
if sp_delay == "Failed":
self.fail('Library Spice module did not behave as expected')
# now generate its pex file
pex_file = self.run_pex(tx)
OPTS.purge_temp = prev_purge_value # restore the old purge value
OPTS.purge_temp = prev_purge_value # restore the old purge value
# generate simulation for pex, make sure the simulation is successful
pex_delay = self.simulate_delay(test_module = pex_file,
top_level_name = tx.name)
pex_delay = self.simulate_delay(test_module=pex_file,
top_level_name=tx.name)
# make sure the extracted spice simulated
if pex_delay is "Failed":
if pex_delay == "Failed":
self.fail('Pex file did not behave as expected')
# if pex data is bigger than original spice file then result is ok
# However this may not always be true depending on the netlist provided
# comment out for now
#debug.info(2,"pex_delay: {0}".format(pex_delay))
#debug.info(2,"sp_delay: {0}".format(sp_delay))
# debug.info(2,"pex_delay: {0}".format(pex_delay))
# debug.info(2,"sp_delay: {0}".format(sp_delay))
#assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\
#.format(pex_delay,sp_delay)
# assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\
# .format(pex_delay,sp_delay)
globals.end_openram()
def simulate_delay(self, test_module, top_level_name):
from characterizer import charutils
from charutils import parse_spice_list
# setup simulation
sim_file = OPTS.openram_temp + "stim.sp"
@ -87,43 +87,43 @@ class hspice_pex_pinv_test(openram_test):
from characterizer import measurements, stimuli
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
sim_file = open(sim_file, "w")
simulation = stimuli(sim_file,corner)
simulation = stimuli(sim_file, corner)
# library files
simulation.write_include(cir_file)
# supply voltages
simulation.gen_constant(sig_name ="vdd",
v_val = tech.spice["nom_supply_voltage"])
simulation.gen_constant(sig_name = "gnd",
v_val = "0v")
simulation.gen_constant(sig_name="vdd",
v_val=tech.spice["nom_supply_voltage"])
simulation.gen_constant(sig_name="gnd",
v_val="0v")
run_time = tech.spice["feasible_period"] * 4
# input voltage
clk_period = tech.spice["feasible_period"]
simulation.gen_pwl(sig_name ="input",
clk_times = [clk_period,clk_period],
data_values = [1,0],
period = clk_period,
slew = 0.001*tech.spice["feasible_period"],
setup = 0)
simulation.gen_pwl(sig_name="input",
clk_times=[clk_period, clk_period],
data_values=[1, 0],
period=clk_period,
slew=0.001 * tech.spice["feasible_period"],
setup=0)
# instantiation of simulated pinv
simulation.inst_model(pins = ["input", "output", "vdd", "gnd"],
model_name = top_module_name)
simulation.inst_model(pins=["input", "output", "vdd", "gnd"],
model_name=top_module_name)
# delay measurement
delay_measure = measurements.delay_measure(measure_name = "pinv_delay",
trig_name = "input",
targ_name = "output",
trig_dir_str = "FALL",
targ_dir_str = "RISE",
has_port = False)
delay_measure = measurements.delay_measure(measure_name="pinv_delay",
trig_name="input",
targ_name="output",
trig_dir_str="FALL",
targ_dir_str="RISE",
has_port=False)
trig_td = trag_td = 0.01 * run_time
rest_info = trig_td,trag_td,tech.spice["nom_supply_voltage"]
rest_info = trig_td, trag_td, tech.spice["nom_supply_voltage"]
delay_measure.write_measure(simulation, rest_info)
simulation.write_control(end_time = run_time)
simulation.write_control(end_time=run_time)
sim_file.close()
return simulation

View File

@ -34,43 +34,43 @@ class ngspice_pex_pinv_test(openram_test):
# generate the pinv module
prev_purge_value = OPTS.purge_temp
OPTS.purge_temp = False # force set purge to false to save the sp file
OPTS.purge_temp = False # force set purge to false to save the sp file
debug.info(2, "Checking 1x size inverter")
tx = pinv.pinv(name="pinv", size=1)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,tx.name)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp, tx.name)
tx.gds_write(tempgds)
tempsp = "{0}{1}.sp".format(OPTS.openram_temp,tx.name)
tempsp = "{0}{1}.sp".format(OPTS.openram_temp, tx.name)
tx.sp_write(tempsp)
# make sure that the library simulation is successful
sp_delay = self.simulate_delay(test_module = tempsp,
top_level_name = tx.name)
if sp_delay is "Failed":
sp_delay = self.simulate_delay(test_module=tempsp,
top_level_name=tx.name)
if sp_delay == "Failed":
self.fail('Library Spice module did not behave as expected')
# now generate its pex file
pex_file = self.run_pex(tx)
OPTS.purge_temp = prev_purge_value # restore the old purge value
# restore the old purge value
OPTS.purge_temp = prev_purge_value
# generate simulation for pex, make sure the simulation is successful
pex_delay = self.simulate_delay(test_module = pex_file,
top_level_name = tx.name)
pex_delay = self.simulate_delay(test_module=pex_file,
top_level_name=tx.name)
# make sure the extracted spice simulated
if pex_delay is "Failed":
if pex_delay == "Failed":
self.fail('Pex file did not behave as expected')
# if pex data is bigger than original spice file then result is ok
# However this may not always be true depending on the netlist provided
# comment out for now
#debug.info(2,"pex_delay: {0}".format(pex_delay))
#debug.info(2,"sp_delay: {0}".format(sp_delay))
# debug.info(2,"pex_delay: {0}".format(pex_delay))
# debug.info(2,"sp_delay: {0}".format(sp_delay))
#assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\
#.format(pex_delay,sp_delay)
# assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\
# .format(pex_delay,sp_delay)
globals.end_openram()
def simulate_delay(self, test_module, top_level_name):
from characterizer import charutils
from charutils import parse_spice_list
# setup simulation
sim_file = OPTS.openram_temp + "stim.sp"
@ -86,47 +86,46 @@ class ngspice_pex_pinv_test(openram_test):
from characterizer import measurements, stimuli
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
sim_file = open(sim_file, "w")
simulation = stimuli(sim_file,corner)
simulation = stimuli(sim_file, corner)
# library files
simulation.write_include(cir_file)
# supply voltages
simulation.gen_constant(sig_name ="vdd",
v_val = tech.spice["nom_supply_voltage"])
simulation.gen_constant(sig_name="vdd",
v_val=tech.spice["nom_supply_voltage"])
# The scn4m_subm and ngspice combination will have a gnd source error:
# "Fatal error: instance vgnd is a shorted VSRC"
# However, remove gnd power for all techa pass for this test
# simulation.gen_constant(sig_name = "gnd",
# v_val = "0v")
run_time = tech.spice["feasible_period"] * 4
# input voltage
clk_period = tech.spice["feasible_period"]
simulation.gen_pwl(sig_name ="input",
clk_times = [clk_period,clk_period],
data_values = [1,0],
period = clk_period,
slew = 0.001*tech.spice["feasible_period"],
setup = 0)
simulation.gen_pwl(sig_name="input",
clk_times=[clk_period, clk_period],
data_values=[1, 0],
period=clk_period,
slew=0.001 * tech.spice["feasible_period"],
setup=0)
# instantiation of simulated pinv
simulation.inst_model(pins = ["input", "output", "vdd", "gnd"],
model_name = top_module_name)
simulation.inst_model(pins=["input", "output", "vdd", "gnd"],
model_name=top_module_name)
# delay measurement
delay_measure = measurements.delay_measure(measure_name = "pinv_delay",
trig_name = "input",
targ_name = "output",
trig_dir_str = "FALL",
targ_dir_str = "RISE",
has_port = False)
delay_measure = measurements.delay_measure(measure_name="pinv_delay",
trig_name="input",
targ_name="output",
trig_dir_str="FALL",
targ_dir_str="RISE",
has_port=False)
trig_td = trag_td = 0.01 * run_time
rest_info = trig_td,trag_td,tech.spice["nom_supply_voltage"]
rest_info = trig_td, trag_td, tech.spice["nom_supply_voltage"]
delay_measure.write_measure(simulation, rest_info)
simulation.write_control(end_time = run_time)
simulation.write_control(end_time=run_time)
sim_file.close()
return simulation

View File

@ -1,319 +0,0 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys,os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING 26_pex_test")
class sram_func_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.use_pex = True
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import setup_hold
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
self.func_test(bank_num=1)
self.func_test(bank_num=2)
self.func_test(bank_num=4)
globals.end_openram()
def func_test(self, bank_num):
import sram
import tech
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
s = sram.sram(word_size=OPTS.word_size,
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="test_sram1")
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
s.sp_write(tempspice)
s.gds_write(tempgds)
self.assertFalse(verify.run_drc(s.name, tempgds))
self.assertFalse(verify.run_lvs(s.name, tempgds, tempspice))
self.assertFalse(verify.run_pex(s.name, tempgds,
tempspice, output=OPTS.openram_temp + "temp_pex.sp"))
import sp_file
stimulus_file = OPTS.openram_temp + "stimulus.sp"
a_stimulus = sp_file.sp_file(stimulus_file)
self.write_stimulus(a_stimulus)
simulator_file = OPTS.openram_temp + "simulator.sp"
a_simulator = sp_file.sp_file(simulator_file)
self.write_simulator(a_simulator)
result_file = OPTS.openram_temp + "result"
import os
if OPTS.spice_name == "hspice":
cmd = "hspice -mt 2 -i {0} > {1} ".format(
simulator_file, result_file)
else:
cmd = "ngspice -b -i {0} > {1} ".format(
simulator_file, result_file)
os.system(cmd)
import re
sp_result = open(result_file, "r")
contents = sp_result.read()
key = "vr1"
val = re.search(
r"{0}(\s*)=(\s*)(\d*(.).*)(\s*)(from)".format(key), contents)
val = val.group(3)
value1 = float(self.convert_voltage_unit(val))
key = "vr2"
val = re.search(
r"{0}(\s*)=(\s*)(\d*(.).*)(\s*)(from)".format(key), contents)
val = val.group(3)
value2 = float(self.convert_voltage_unit(val))
self.assertTrue(round(value1) > 0.5 * tech.spice["supply_voltage"])
self.assertTrue(round(value2) < 0.5 * tech.spice["supply_voltage"])
def convert_voltage_unit(self, string):
newstring = ""
for letter in string:
if letter == "m":
letter = "10e-3"
elif letter == "u":
letter = "10e-6"
else:
letter = letter
newstring = str(newstring) + str(letter)
return newstring
def convert_time_unit(self, string):
newstring = ""
for letter in string:
if letter == "f":
letter = "10e-15"
elif letter == "p":
letter = "10e-12"
elif letter == "n":
letter = "10e-9"
elif letter == "u":
letter = "10e-6"
elif letter == "m":
letter = "10e-3"
else:
letter = letter
newstring = str(newstring) + str(letter)
return newstring
def write_simulator(self, sim_file):
sim_file.write("\n")
import tech
time_step = tech.spice["clock_period"]
for model in tech.spice["fet_models"]:
sim_file.write(".inc " + str(model) + "\n")
sim_file.write(".inc stimulus.sp\n")
sim_file.write(".inc temp_pex.sp\n")
sim_file.write(".options post runlvl=6\n")
sim_file.write("\n")
sim_file.write(
"Xsource DATA[0] ADDR[0] ADDR[1] ADDR[2] ADDR[3] CSb WEb WEb_inv OEb clk vdd vss source\n")
sim_file.write(
"Xsram DATA[0] ADDR[0] ADDR[1] ADDR[2] ADDR[3] CSb WEb OEb clk vdd vss test_sram1\n")
sim_file.write("\n")
sim_file.write(".MEASURE TRAN vr1 AVG V(DATA[0]) FROM ={0}ns TO ={1}ns\n".format(
4.5 * tech.spice["clock_period"], 5 * tech.spice["clock_period"]))
sim_file.write(".MEASURE TRAN vr2 AVG V(DATA[0]) FROM ={0}ns TO ={1}ns\n".format(
9.5 * tech.spice["clock_period"], 10 * tech.spice["clock_period"]))
sim_file.write("\n")
if OPTS.spice_name in ["hspice","xa"]:
sim_file.write(".probe v(x*.*)\n")
sim_file.write(".tran 0.1ns {0}ns\n".format(
10 * tech.spice["clock_period"]))
sim_file.write(".end\n")
else:
sim_file.write(
".meas tran DELAY1.0 TRIG v(clk) VAL=0.5 RISE=6 TARG v(DATA[0]) VAL=0.5 TD=0.5n RISE=1\n")
sim_file.write(".tran 0.1ns {0}ns\n".format(
10 * tech.spice["clock_period"]))
sim_file.write(".control\n")
sim_file.write("run\n")
#sim_file.write("plot CSb WEb OEb \n")
#sim_file.write("plot clk DATA0 \n")
sim_file.write("quit\n")
sim_file.write(".endc\n")
sim_file.write(".end\n")
sim_file.file.close()
def write_stimulus(self, sti_file):
import tech
import sp_file
sti_file.write(
".subckt source DATA[0] ADDR[0] ADDR[1] ADDR[2] ADDR[3] CSb WEb WEb_inv OEb clk vdd vss\n")
time_step = tech.spice["clock_period"]
clk = sp_file.PWL(name="clk", port=["clk", "0"])
for i in range(0, 11):
clk.write_pulse(i * time_step, time_step, "UP")
clk.write_to_sp(sti_file)
WEB_inv = sp_file.PWL(name="WEb_inv", port=["WEb_inv", "0"])
WEB = sp_file.PWL(name="WEB", port=["WEb", "0"])
OEb = sp_file.PWL(name="OEb", port=["OEb", "0"])
CSb = sp_file.PWL(name="CSb", port=["CSb", "0"])
# write
CSb.write_pulse(0.75 * time_step, time_step, "DN")
WEB.write_pulse(0.75 * time_step, time_step, "DN")
WEB_inv.write_pulse(0.75 * time_step, time_step, "UP")
CSb.write_pulse(1.75 * time_step, time_step, "DN")
WEB.write_pulse(1.75 * time_step, time_step, "DN")
WEB_inv.write_pulse(1.75 * time_step, time_step, "UP")
# read
OEb.write_pulse(3.75 * time_step, time_step, "DN")
CSb.write_pulse(3.75 * time_step, time_step, "DN")
# write
CSb.write_pulse(5.75 * time_step, time_step, "DN")
WEB.write_pulse(5.75 * time_step, time_step, "DN")
WEB_inv.write_pulse(5.75 * time_step, time_step, "UP")
CSb.write_pulse(6.75 * time_step, time_step, "DN")
WEB.write_pulse(6.75 * time_step, time_step, "DN")
WEB_inv.write_pulse(6.75 * time_step, time_step, "UP")
# read
OEb.write_pulse(8.75 * time_step, time_step, "DN")
CSb.write_pulse(8.75 * time_step, time_step, "DN")
CSb.write_to_sp(sti_file)
WEB.write_to_sp(sti_file)
WEB_inv.write_to_sp(sti_file)
OEb.write_to_sp(sti_file)
sti_file.write("VA[0] A[0] 0 PWL(0n {0} {1}n {0} {2}n 0 {3}n 0 {4}n {0})\n".format(tech.spice["supply_voltage"], 8.875 * tech.spice[
"clock_period"], 13.875 * tech.spice["clock_period"], 14.5 * tech.spice["clock_period"], 14.501 * tech.spice["clock_period"]))
sti_file.write("VA[1] A[1] 0 PWL(0n {0} {1}n {0} {2}n 0 {3}n 0 {4}n {0})\n".format(tech.spice["supply_voltage"], 8.875 * tech.spice[
"clock_period"], 13.875 * tech.spice["clock_period"], 14.5 * tech.spice["clock_period"], 14.501 * tech.spice["clock_period"]))
sti_file.write("VA[2] A[2] 0 PWL(0n {0} {1}n {0} {2}n 0 {3}n 0 {4}n {0})\n".format(tech.spice["supply_voltage"], 8.875 * tech.spice[
"clock_period"], 13.875 * tech.spice["clock_period"], 14.5 * tech.spice["clock_period"], 14.501 * tech.spice["clock_period"]))
sti_file.write("VA[3] A[3] 0 PWL(0n {0} {1}n {0} {2}n 0 {3}n 0 {4}n {0})\n".format(tech.spice["supply_voltage"], 8.875 * tech.spice[
"clock_period"], 13.875 * tech.spice["clock_period"], 14.5 * tech.spice["clock_period"], 14.501 * tech.spice["clock_period"]))
sti_file.write(
"xA[0]_buff A[0] ADDR[0]_inv ADDR[0] vdd vss test_buf\n")
sti_file.write(
"xA[1]_buff A[1] ADDR[1]_inv ADDR[1] vdd vss test_buf\n")
sti_file.write(
"xA[2]_buff A[2] ADDR[2]_inv ADDR[2] vdd vss test_buf\n")
sti_file.write(
"xA[3]_buff A[3] ADDR[3]_inv ADDR[3] vdd vss test_buf\n")
VD_0 = sp_file.PWL(name="VD[0]", port=["D[0]", "0"])
VD_0.write_pulse(0, 5 * time_step, "S1")
VD_0.write_pulse(5 * time_step, 5 * time_step, "S0")
VD_0.write_to_sp(sti_file)
sti_file.write(
"xD[0]_buff D[0] DATA[0]_inv DATA[0]s vdd vss test_buf\n")
sti_file.write(
"xD[0]_gate DATA[0]s WEb WEb_inv DATA[0] vdd vss tran_gate\n")
sti_file.write("mp[0]_gate_vdd vdd write_v DATA[0] vdd " + str(tech.spice["pmos"]) +
" w=" + str(2 * tech.parameter["min_tx_size"]) + "u" +
" l=" + str(tech.drc["minlength_channel"]) + "u" +
"\n")
sti_file.write("mn[0]_gate_vss vss write_g DATA[0] vss " + str(tech.spice["nmos"]) +
" w=" + str(tech.parameter["min_tx_size"]) + "u" +
" l=" + str(tech.drc["minlength_channel"]) + "u" +
"\n")
Vwrite_v = sp_file.PWL(name="write_v", port=["write_vs", "0"])
Vwrite_v.write_pulse(0, 0.5 * time_step, "S1")
Vwrite_v.write_pulse(7.5 * time_step, time_step, "DN")
Vwrite_v.write_to_sp(sti_file)
sti_file.write(
"xwrite_v write_vs write_v_inv write_v vdd vss test_buf\n")
Vwrite_g = sp_file.PWL(name="write_g", port=["write_gs", "0"])
Vwrite_g.write_pulse(0, 0.5 * time_step, "S0")
Vwrite_g.write_pulse(3 * time_step, time_step, "UP")
Vwrite_g.write_to_sp(sti_file)
sti_file.write(
"xwrite_g write_gs write_g_inv write_g vdd vss test_buf\n")
sti_file.write("Vdd vdd 0 DC " +
str(tech.spice["supply_voltage"]) + "\n")
sti_file.write("Vvss vss 0 DC 0\n")
sti_file.write(".ENDS source\n")
sti_file.write("\n")
sti_file.write(".SUBCKT tran_gate in gate gate_inv out vdd vss\n")
sti_file.write("mp0 in gate out vdd " + str(tech.spice["pmos"]) +
" w=" + str(2 * tech.parameter["min_tx_size"]) + "u" +
" l=" + str(tech.drc["minlength_channel"]) + "u" +
"\n")
sti_file.write("mn0 in gate_inv out vss " + str(tech.spice["nmos"]) +
" w=" + str(tech.parameter["min_tx_size"]) + "u" +
" l=" + str(tech.drc["minlength_channel"]) + "u" +
"\n")
sti_file.write(".ENDS tran_gate\n")
sti_file.write("\n")
sti_file.write(".SUBCKT test_buf in out_inv out_buf vdd vss\n")
sti_file.write("mpinv1 out_inv in vdd vdd " + str(tech.spice["pmos"]) +
" w=" + str(2 * tech.parameter["min_tx_size"]) + "u" +
" l=" + str(tech.drc["minlength_channel"]) + "u" +
"\n")
sti_file.write("mninv1 out_inv in vss vss " + str(tech.spice["nmos"]) +
" w=" + str(tech.parameter["min_tx_size"]) + "u" +
" l=" + str(tech.drc["minlength_channel"]) + "u" +
"\n")
sti_file.write("mpinv2 out_buf out_inv vdd vdd " + str(tech.spice["pmos"]) +
" w=" + str(2 * tech.parameter["min_tx_size"]) + "u" +
" l=" + str(tech.drc["minlength_channel"]) + "u" +
"\n")
sti_file.write("mninv2 out_buf out_inv vss vss " + str(tech.spice["nmos"]) +
" w=" + str(tech.parameter["min_tx_size"]) + "u" +
" l=" + str(tech.drc["minlength_channel"]) + "u" +
"\n")
sti_file.write(".ENDS test_buf\n")
sti_file.write("\n")
sti_file.file.close()
# 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(testRunner=debugTestRunner())

View File

@ -295,11 +295,8 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
global num_pex_runs
num_pex_runs += 1
#debug.warning("PEX using magic not implemented.")
#return 1
os.chdir(OPTS.openram_temp)
from tech import drc
if output == None:
output = name + ".pex.netlist"
@ -312,17 +309,11 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
# pex_fix did run the pex using a script while dev orignial method
# use batch mode.
# the dev old code using batch mode does not run and is split into functions
#pex_runset = write_batch_pex_rule(gds_name,name,sp_name,output)
pex_runset = write_script_pex_rule(gds_name,name,output)
pex_runset = write_script_pex_rule(gds_name, name, output)
errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name)
outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name)
# bash mode command from dev branch
#batch_cmd = "{0} -gui -pex {1}pex_runset -batch 2> {2} 1> {3}".format(OPTS.pex_exe,
# OPTS.openram_temp,
# errfile,
# outfile)
script_cmd = "{0} 2> {1} 1> {2}".format(pex_runset,
errfile,
outfile)
@ -334,8 +325,8 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
pex_nelist = open(output, 'r')
s = pex_nelist.read()
pex_nelist.close()
s = s.replace('pfet','p')
s = s.replace('nfet','n')
s = s.replace('pfet', 'p')
s = s.replace('nfet', 'n')
f = open(output, 'w')
f.write(s)
f.close()
@ -345,12 +336,13 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
results = f.readlines()
f.close()
out_errors = find_error(results)
debug.check(os.path.isfile(output),"Couldn't find PEX extracted output.")
debug.check(os.path.isfile(output), "Couldn't find PEX extracted output.")
correct_port(name,output,sp_name)
correct_port(name, output, sp_name)
return out_errors
def write_batch_pex_rule(gds_name,name,sp_name,output):
def write_batch_pex_rule(gds_name, name, sp_name, output):
"""
The dev branch old batch mode runset
2. magic can perform extraction with the following:
@ -394,7 +386,8 @@ def write_batch_pex_rule(gds_name,name,sp_name,output):
f.close()
return file
def write_script_pex_rule(gds_name,cell_name,output):
def write_script_pex_rule(gds_name, cell_name, output):
global OPTS
run_file = OPTS.openram_temp + "run_pex.sh"
f = open(run_file, "w")
@ -412,23 +405,24 @@ def write_script_pex_rule(gds_name,cell_name,output):
pre = "#"
else:
pre = ""
f.write(pre+"extract\n".format(cell_name))
f.write(pre+"ext2spice hierarchy off\n")
f.write(pre+"ext2spice format ngspice\n")
f.write(pre+"ext2spice renumber off\n")
f.write(pre+"ext2spice scale off\n")
f.write(pre+"ext2spice blackbox on\n")
f.write(pre+"ext2spice subcircuit top on\n")
f.write(pre+"ext2spice global off\n")
f.write(pre+"ext2spice {}\n".format(cell_name))
f.write(pre + "extract\n")
f.write(pre + "ext2spice hierarchy off\n")
f.write(pre + "ext2spice format ngspice\n")
f.write(pre + "ext2spice renumber off\n")
f.write(pre + "ext2spice scale off\n")
f.write(pre + "ext2spice blackbox on\n")
f.write(pre + "ext2spice subcircuit top on\n")
f.write(pre + "ext2spice global off\n")
f.write(pre + "ext2spice {}\n".format(cell_name))
f.write("quit -noprompt\n")
f.write("eof\n")
f.write("mv {0}.spice {1}\n".format(cell_name,output))
f.write("mv {0}.spice {1}\n".format(cell_name, output))
f.close()
os.system("chmod u+x {}".format(run_file))
return run_file
def find_error(results):
# Errors begin with "ERROR:"
test = re.compile("ERROR:")
@ -438,6 +432,7 @@ def find_error(results):
out_errors = len(stdouterrors)
return out_errors
def correct_port(name, output_file_name, ref_file_name):
pex_file = open(output_file_name, "r")
contents = pex_file.read()
@ -456,9 +451,9 @@ def correct_port(name, output_file_name, ref_file_name):
for bank in range(OPTS.num_banks):
for bank in range(OPTS.num_banks):
row = int(OPTS.num_words / OPTS.words_per_row) - 1
col = int(OPTS.word_size * OPTS.words_per_row) - 1
bitcell_list += "bitcell_Q_b{0}_r{1}_c{2} ".format(bank,row,col)
bitcell_list += "bitcell_Q_bar_b{0}_r{1}_c{2} ".format(bank,row,col)
col = int(OPTS.word_size * OPTS.words_per_row) - 1
bitcell_list += "bitcell_Q_b{0}_r{1}_c{2} ".format(bank, row, col)
bitcell_list += "bitcell_Q_bar_b{0}_r{1}_c{2} ".format(bank, row, col)
for col in range(OPTS.word_size * OPTS.words_per_row):
for port in range(OPTS.num_r_ports + OPTS.num_w_ports + OPTS.num_rw_ports):
bitcell_list += "bl{0}_{1} ".format(bank, col)
@ -484,13 +479,18 @@ def correct_port(name, output_file_name, ref_file_name):
# write the new pex file with info in the memory
output_file = open(output_file_name, "w")
output_file.write(part1)
output_file.write(circuit_title+'\n')
output_file.write(circuit_title + '\n')
output_file.write(part2)
output_file.close()
def print_drc_stats():
debug.info(1,"DRC runs: {0}".format(num_drc_runs))
debug.info(1, "DRC runs: {0}".format(num_drc_runs))
def print_lvs_stats():
debug.info(1,"LVS runs: {0}".format(num_lvs_runs))
debug.info(1, "LVS runs: {0}".format(num_lvs_runs))
def print_pex_stats():
debug.info(1,"PEX runs: {0}".format(num_pex_runs))
debug.info(1, "PEX runs: {0}".format(num_pex_runs))