mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-08-29 17:39:02 +02:00
Merge master branch into router
This commit is contained in:
@@ -384,12 +384,17 @@ class delay():
|
||||
if (min_period0 == None) or (delay0 == None):
|
||||
return None
|
||||
debug.info(1, "Min Period for high_to_low transistion: {0}n with a delay of {1}".format(min_period0, delay0))
|
||||
data = {"min_period1": min_period1, # period in ns
|
||||
read_power=ch.convert_to_float(ch.parse_output("timing", "power_read"))
|
||||
write_power=ch.convert_to_float(ch.parse_output("timing", "power_write"))
|
||||
|
||||
data = {"min_period1": min_period1, # period in ns
|
||||
"delay1": delay1, # delay in s
|
||||
"min_period0": min_period0,
|
||||
"delay0": delay0
|
||||
"delay0": delay0,
|
||||
"read_power": read_power,
|
||||
"write_power": write_power
|
||||
}
|
||||
return data
|
||||
return data
|
||||
|
||||
|
||||
def obtain_cycle_times(self, slow_period, fast_period):
|
||||
|
||||
@@ -63,6 +63,8 @@ class lib:
|
||||
|
||||
data = self.d.analyze(probe_address, probe_data)
|
||||
for i in data.keys():
|
||||
if i == "read_power" or i == "write_power":
|
||||
continue
|
||||
data[i] = ch.round_time(data[i])
|
||||
|
||||
|
||||
@@ -82,7 +84,7 @@ class lib:
|
||||
self.lib.write(" current_unit : \"1mA\" ;\n")
|
||||
self.lib.write(" resistance_unit : \"1kohm\" ;\n")
|
||||
self.lib.write(" capacitive_load_unit(1 ,fF) ;\n")
|
||||
self.lib.write(" leakage_power_unit : \"1uW\" ;\n")
|
||||
self.lib.write(" leakage_power_unit : \"1mW\" ;\n")
|
||||
self.lib.write(" pulling_resistance_unit :\"1kohm\" ;\n")
|
||||
self.lib.write(" operating_conditions(TT){\n")
|
||||
self.lib.write(" voltage : {0} ;\n".format(tech.spice["supply_voltage"]))
|
||||
@@ -144,6 +146,13 @@ class lib:
|
||||
self.lib.write(" index_1 (\"0.5\");\n")
|
||||
self.lib.write(" }\n\n")
|
||||
|
||||
CONS2 = ["INPUT_BY_TRANS_FOR_CLOCK" , "INPUT_BY_TRANS_FOR_SIGNAL"]
|
||||
for i in CONS2:
|
||||
self.lib.write(" power_lut_template({0})".format(i))
|
||||
self.lib.write("{\n")
|
||||
self.lib.write(" variable_1 : input_transition_time;\n")
|
||||
self.lib.write(" index_1 (\"0.5\");\n")
|
||||
self.lib.write(" }\n\n")
|
||||
|
||||
def write_bus(self):
|
||||
""" Adds format of DATA and ADDR bus."""
|
||||
@@ -201,17 +210,36 @@ class lib:
|
||||
self.lib.write(" pin(DATA[{0}:0])".format(self.word_size - 1))
|
||||
self.lib.write("{\n")
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" three_state : \"OEb & !clk\"; \n")
|
||||
self.lib.write(" three_state : \"!OEb & !clk\"; \n")
|
||||
|
||||
self.lib.write(" memory_write(){ \n")
|
||||
self.lib.write(" address : ADDR; \n")
|
||||
self.lib.write(" clocked_on : clk; \n")
|
||||
self.lib.write(" }\n")
|
||||
self.write_timing(times)
|
||||
self.lib.write(" internal_power(){\n")
|
||||
self.lib.write(" when : \"OEb & !clk\"; \n")
|
||||
self.lib.write(" rise_power(INPUT_BY_TRANS_FOR_SIGNAL){\n")
|
||||
self.lib.write(" values(\"{0}\");\n".format(data["write_power"]* 1e3))
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" fall_power(INPUT_BY_TRANS_FOR_SIGNAL){\n")
|
||||
self.lib.write(" values(\"{0}\");\n".format(data["write_power"]* 1e3))
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" }\n")
|
||||
self.write_timing(times)
|
||||
|
||||
self.lib.write(" memory_read(){ \n")
|
||||
self.lib.write(" address : ADDR; \n")
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" timing(){ \n")
|
||||
self.lib.write(" internal_power(){\n")
|
||||
self.lib.write(" when : \"!OEb & !clk\"; \n")
|
||||
self.lib.write(" rise_power(INPUT_BY_TRANS_FOR_SIGNAL){\n")
|
||||
self.lib.write(" values(\"{0}\");\n".format(data["read_power"]* 1e3))
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" fall_power(INPUT_BY_TRANS_FOR_SIGNAL){\n")
|
||||
self.lib.write(" values(\"{0}\");\n".format(data["read_power"]* 1e3))
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" timing(){ \n")
|
||||
self.lib.write(" timing_sense : non_unate; \n")
|
||||
self.lib.write(" related_pin : \"clk\"; \n")
|
||||
self.lib.write(" timing_type : rising_edge; \n")
|
||||
@@ -267,26 +295,26 @@ class lib:
|
||||
self.lib.write(" clock : true;\n")
|
||||
self.lib.write(" direction : input; \n")
|
||||
self.lib.write(" capacitance : {0}; \n".format(tech.spice["FF_in_cap"]))
|
||||
self.lib.write(" min_pulse_width_high : {0} ; \n".format(ch.round_time(data["min_period1"])))
|
||||
self.lib.write(" min_pulse_width_low : {0} ; \n".format(ch.round_time(data["min_period0"])))
|
||||
min_pulse_width = (ch.round_time(data["min_period1"]) + ch.round_time(data["min_period0"]))/2.0
|
||||
min_period = ch.round_time(data["min_period1"]) + ch.round_time(data["min_period0"])
|
||||
self.lib.write(" timing(){ \n")
|
||||
self.lib.write(" timing_type :\"min_pulse_width\"; \n")
|
||||
self.lib.write(" related_pin : clk; \n")
|
||||
self.lib.write(" rise_constraint(CLK_TRAN) {\n")
|
||||
self.lib.write(" values(\"0\"); \n")
|
||||
self.lib.write(" values(\"{0}\"); \n".format(min_pulse_width))
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" fall_constraint(CLK_TRAN) {\n")
|
||||
self.lib.write(" values(\"0\"); \n")
|
||||
self.lib.write(" values(\"{0}\"); \n".format(min_pulse_width))
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" timing(){ \n")
|
||||
self.lib.write(" timing_type :\"minimum_period\"; \n")
|
||||
self.lib.write(" related_pin : clk; \n")
|
||||
self.lib.write(" rise_constraint(CLK_TRAN) {\n")
|
||||
self.lib.write(" values(\"0\"); \n")
|
||||
self.lib.write(" values(\"{0}\"); \n".format(min_period))
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" fall_constraint(CLK_TRAN) {\n")
|
||||
self.lib.write(" values(\"0\"); \n")
|
||||
self.lib.write(" values(\"{0}\"); \n".format(min_period))
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" }\n")
|
||||
|
||||
+8
-10
@@ -1,10 +1,8 @@
|
||||
"""
|
||||
This provides a set of useful generic types for the gdsMill interface.
|
||||
"""
|
||||
|
||||
import tech
|
||||
import debug
|
||||
from utils import snap_to_grid
|
||||
from vector import vector
|
||||
|
||||
class geometry:
|
||||
@@ -38,7 +36,7 @@ class instance(geometry):
|
||||
self.mod = mod
|
||||
self.gds = mod.gds
|
||||
self.rotate = rotate
|
||||
self.offset = vector(snap_to_grid(offset))
|
||||
self.offset = vector(offset).snap_to_grid()
|
||||
self.mirror = mirror
|
||||
|
||||
debug.info(3, "creating instance: " + self.name)
|
||||
@@ -72,7 +70,7 @@ class path(geometry):
|
||||
self.name = "path"
|
||||
self.layerNumber = layerNumber
|
||||
self.coordinates = map(lambda x: [x[0], x[1]], coordinates)
|
||||
self.coordinates = snap_to_grid(self.coordinates)
|
||||
self.coordinates = vector(self.coordinates).snap_to_grid()
|
||||
self.path_width = path_width
|
||||
|
||||
# FIXME figure out the width/height. This type of path is not
|
||||
@@ -105,7 +103,7 @@ class label(geometry):
|
||||
self.name = "label"
|
||||
self.text = text
|
||||
self.layerNumber = layerNumber
|
||||
self.offset = vector(snap_to_grid(offset))
|
||||
self.offset = vector(offset).snap_to_grid()
|
||||
self.zoom = zoom
|
||||
self.size = 0
|
||||
|
||||
@@ -137,10 +135,10 @@ class rectangle(geometry):
|
||||
geometry.__init__(self)
|
||||
self.name = "rect"
|
||||
self.layerNumber = layerNumber
|
||||
self.offset = vector(snap_to_grid(offset))
|
||||
self.size = snap_to_grid([width, height])
|
||||
self.width = self.size[0]
|
||||
self.height = self.size[1]
|
||||
self.offset = vector(offset).snap_to_grid()
|
||||
self.size = vector(width, height).snap_to_grid()
|
||||
self.width = self.size.x
|
||||
self.height = self.size.y
|
||||
|
||||
debug.info(3, "creating rectangle (" + str(self.layerNumber) + "): "
|
||||
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
|
||||
@@ -148,7 +146,7 @@ class rectangle(geometry):
|
||||
|
||||
def gds_write_file(self, newLayout):
|
||||
"""Writes the rectangular shape to GDS"""
|
||||
debug.info(3, "writing rectangle (" + str(self.layerNumber) + "): "
|
||||
debug.info(3, "writing rectangle (" + str(self.layerNumber) + "):"
|
||||
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
|
||||
newLayout.addBox(layerNumber=self.layerNumber,
|
||||
purposeNumber=0,
|
||||
|
||||
@@ -3,8 +3,6 @@ import design
|
||||
import math
|
||||
from tech import drc
|
||||
from contact import contact
|
||||
from nand_2 import nand_2
|
||||
from nand_3 import nand_3
|
||||
from pinv import pinv
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
@@ -41,14 +39,8 @@ class hierarchical_predecode(design.design):
|
||||
beta=2,
|
||||
height=self.bitcell_height)
|
||||
self.add_mod(self.inv)
|
||||
if self.number_of_inputs ==2:
|
||||
self.nand = nand_2(name="a_nand_2",
|
||||
nmos_width=self.nmos_width,
|
||||
height=self.bitcell_height)
|
||||
elif self.number_of_inputs ==3:
|
||||
self.nand = nand_3(name="a_nand_3",
|
||||
nmos_width=self.nmos_width,
|
||||
height=self.bitcell_height)
|
||||
# create_nand redefine in sub class based on number of inputs
|
||||
self.create_nand()
|
||||
self.add_mod(self.nand)
|
||||
|
||||
def set_up_constrain(self):
|
||||
@@ -75,12 +67,8 @@ class hierarchical_predecode(design.design):
|
||||
self.gap_between_rail_offset = self.gap_between_rails + drc["minwidth_metal2"]
|
||||
|
||||
self.rails_x_offset = []
|
||||
if self.number_of_inputs == 2:
|
||||
self.rail_height = (self.number_of_outputs * self.nand.height
|
||||
- (self.number_of_outputs - 1) * drc["minwidth_metal2"])
|
||||
elif self.number_of_inputs == 3:
|
||||
self.rail_height = (self.number_of_outputs * self.nand.height
|
||||
- 1.5 * drc["minwidth_metal2"])
|
||||
# set_rail_height redefine in sub class
|
||||
self.set_rail_height()
|
||||
# Creating the left hand side metal2 rails for input connections
|
||||
for hrail_1 in range(self.number_of_inputs):
|
||||
xoffset_1 = (self.metal2_extend_contact
|
||||
@@ -100,10 +88,7 @@ class hierarchical_predecode(design.design):
|
||||
|
||||
def update_size(self):
|
||||
self.width = self.x_off_inv_2 + self.inv.width
|
||||
if self.number_of_inputs ==2:
|
||||
self.height = 4 * self.nand.height
|
||||
elif self.number_of_inputs ==3:
|
||||
self.height = 8 * self.nand.height
|
||||
self.set_height()
|
||||
self.size = vector(self.width, self.height)
|
||||
correct =vector(0, 0.5 * drc["minwidth_metal1"])
|
||||
self.vdd_position = self.size - correct - vector(0, self.inv.height)
|
||||
@@ -142,10 +127,8 @@ class hierarchical_predecode(design.design):
|
||||
|
||||
def add_nand(self,connections):
|
||||
for nand_input in range(self.number_of_outputs):
|
||||
if self.number_of_inputs ==2:
|
||||
name = "Xpre2x4_nand[{0}]".format(nand_input)
|
||||
elif self.number_of_inputs ==3:
|
||||
name = "Xpre3x8_nand[{0}]".format(nand_input)
|
||||
inout = str(self.number_of_inputs)+"x"+str(self.number_of_outputs)
|
||||
name = "Xpre"+inout+"_nand[{0}]".format(nand_input)
|
||||
if (nand_input % 2 == 0):
|
||||
y_off = nand_input * (self.nand.height)
|
||||
mirror = "R0"
|
||||
@@ -167,30 +150,135 @@ class hierarchical_predecode(design.design):
|
||||
self.connect_inst(connections[nand_input])
|
||||
|
||||
def route(self):
|
||||
# route sub funtions need to be redfined in sub class
|
||||
self.route_input_inverters()
|
||||
self.route_nand_to_rails()
|
||||
self.route_vdd_gnd_from_rails_to_gates()
|
||||
|
||||
def route_input_inverters_input(self,inv_rout,inv_in_offset):
|
||||
def route_input_inverters(self):
|
||||
# All conections of the inputs inverters [Inputs, outputs, vdd, gnd]
|
||||
output_shift = self.set_output_shift()
|
||||
for inv_rout in range(self.number_of_inputs):
|
||||
setup = self.setup_route_input_inverter(inv_rout,output_shift)
|
||||
y_dir,inv_in_offset,inv_out_offset,inv_vdd_offset,inv_gnd_offset = setup
|
||||
#add output
|
||||
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
||||
output_metal = self.cal_input_inverters_output(setup,output_shift,inv_rout)
|
||||
offset1,offset2=output_metal[0]
|
||||
offset3,offset4=output_metal[1]
|
||||
self.add_rect(layer="metal1",
|
||||
offset=offset1,
|
||||
width=drc["minwidth_metal1"],
|
||||
height=offset2.y - offset1.y)
|
||||
self.add_rect(layer="metal1",
|
||||
offset=offset3,
|
||||
width=offset4.x - offset3.x,
|
||||
height=drc["minwidth_metal1"])
|
||||
off_via = [self.rails_x_offset[inv_rout + self.number_of_inputs+2] + self.gap_between_rails,
|
||||
inv_vdd_offset.y- self.via_shift - correct]
|
||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
||||
offset=off_via,
|
||||
rotate=90)
|
||||
#route input
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[self.rails_x_offset[inv_rout],
|
||||
inv_in_offset.y],
|
||||
width=inv_in_offset.x - self.rails_x_offset[inv_rout] + drc["minwidth_metal2"],
|
||||
height=drc["minwidth_metal1"])
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
offset=[self.rails_x_offset[inv_rout] + self.gap_between_rails,
|
||||
inv_in_offset.y - self.via_shift],
|
||||
rotate=90)
|
||||
# route vdd
|
||||
self.add_rect(layer="metal1",
|
||||
offset=inv_vdd_offset,
|
||||
width=self.rails_x_offset[self.number_of_inputs] - inv_vdd_offset.x + drc["minwidth_metal2"],
|
||||
height=drc["minwidth_metal1"])
|
||||
# route gnd
|
||||
self.add_rect(layer="metal1",
|
||||
offset=inv_gnd_offset,
|
||||
width=self.rails_x_offset[self.number_of_inputs+1] - inv_gnd_offset.x + drc["minwidth_metal2"],
|
||||
height=drc["minwidth_metal1"])
|
||||
|
||||
def setup_route_input_inverter(self, inv_rout, output_shift):
|
||||
# add Inputs, vdd, gnd of the inputs inverters
|
||||
if (inv_rout % 2 == 0):
|
||||
base_offset=[self.x_off_inv_1, inv_rout * self.inv.height ]
|
||||
y_dir = 1
|
||||
else:
|
||||
base_offset=[self.x_off_inv_1, 2 * self.inv.height - drc["minwidth_metal1"]]
|
||||
y_dir = -1
|
||||
inv_out_offset = base_offset+self.inv.Z_position.scale(1,y_dir)
|
||||
inv_in_offset = base_offset+self.inv.A_position.scale(1,y_dir)
|
||||
inv_vdd_offset = base_offset+self.inv.vdd_position.scale(1,y_dir)
|
||||
inv_gnd_offset = base_offset+self.inv.gnd_position.scale(1,y_dir)
|
||||
#return info to create output of the input inverter
|
||||
return [y_dir,inv_in_offset,inv_out_offset,inv_vdd_offset,inv_gnd_offset]
|
||||
|
||||
def route_nand_to_rails(self):
|
||||
# This 2D array defines the connection mapping
|
||||
nand_input_line_combination = self.get_nand_input_line_combination()
|
||||
for k in range(self.number_of_outputs):
|
||||
# create x offset list
|
||||
index_lst= nand_input_line_combination[k]
|
||||
line_x_offset = []
|
||||
for index in index_lst:
|
||||
line_x_offset.append(self.rails_x_offset[index])
|
||||
# create y offset list
|
||||
yoffset_nand_in, correct= self.create_y_offsets(k)
|
||||
# connect based on the two list
|
||||
for i in range(self.number_of_inputs):
|
||||
x_offset = line_x_offset[i]
|
||||
y_offset = yoffset_nand_in[i]
|
||||
# Connecting the i-th input of Nand3 gate
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[x_offset, y_offset],
|
||||
width=self.x_off_nand - x_offset,
|
||||
height=drc["minwidth_metal1"])
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
offset=[x_offset+ self.gap_between_rails,
|
||||
y_offset - self.via_shift - correct[i]],
|
||||
rotate=90)
|
||||
# Extended of the top NAND2 to the left hand side input rails
|
||||
if(k == self.number_of_outputs - 1):
|
||||
x_offset = self.rails_x_offset[i]
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[x_offset, y_offset],
|
||||
width=self.x_off_nand - x_offset,
|
||||
height=drc["minwidth_metal1"])
|
||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
||||
offset=[x_offset + self.gap_between_rails,
|
||||
y_offset - self.via_shift],
|
||||
rotate=90)
|
||||
|
||||
def route_vdd_gnd_from_rails_to_gates(self):
|
||||
via_correct = self.get_via_correct()
|
||||
for k in range(self.number_of_outputs):
|
||||
power_line_index = self.number_of_inputs + 1 - (k%2)
|
||||
yoffset = k * self.inv.height - 0.5 * drc["minwidth_metal1"]
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[self.rails_x_offset[power_line_index],
|
||||
yoffset],
|
||||
width=self.x_off_nand - self.rails_x_offset[power_line_index],
|
||||
height=drc["minwidth_metal1"])
|
||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
||||
offset=[self.rails_x_offset[power_line_index] + self.gap_between_rails,
|
||||
yoffset - via_correct.y],
|
||||
rotate=90)
|
||||
|
||||
yoffset = (self.number_of_outputs * self.inv.height
|
||||
- 0.5 * drc["minwidth_metal1"])
|
||||
v_metal = self.get_vertical_metal()
|
||||
via_y = self.get_via_y()
|
||||
index = self.number_of_inputs + 1
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[self.rails_x_offset[inv_rout],
|
||||
inv_in_offset.y],
|
||||
width=inv_in_offset.x - self.rails_x_offset[inv_rout] + drc["minwidth_metal2"],
|
||||
offset=[self.rails_x_offset[index], yoffset],
|
||||
width=self.x_off_nand - self.rails_x_offset[index],
|
||||
height=drc["minwidth_metal1"])
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
offset=[self.rails_x_offset[inv_rout] + self.gap_between_rails,
|
||||
inv_in_offset.y - self.via_shift],
|
||||
self.add_rect(layer=v_metal,
|
||||
offset=[self.rails_x_offset[index], self.rail_height],
|
||||
width=drc["minwidth_"+v_metal],
|
||||
height=yoffset - self.rail_height)
|
||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
||||
offset=[self.rails_x_offset[index] + self.gap_between_rails,
|
||||
via_y] - via_correct,
|
||||
rotate=90)
|
||||
|
||||
def route_input_inverters_vdd(self,inv_vdd_offset):
|
||||
self.add_rect(layer="metal1",
|
||||
offset=inv_vdd_offset,
|
||||
width=self.rails_x_offset[self.number_of_inputs] - inv_vdd_offset.x + drc["minwidth_metal2"],
|
||||
height=drc["minwidth_metal1"])
|
||||
|
||||
def route_input_inverters_gnd(self,inv_gnd_offset):
|
||||
self.add_rect(layer="metal1",
|
||||
offset=inv_gnd_offset,
|
||||
width=self.rails_x_offset[self.number_of_inputs+1] - inv_gnd_offset.x + drc["minwidth_metal2"],
|
||||
height=drc["minwidth_metal1"])
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from tech import drc
|
||||
import debug
|
||||
import design
|
||||
from nand_2 import nand_2
|
||||
from vector import vector
|
||||
from hierarchical_predecode import hierarchical_predecode
|
||||
|
||||
@@ -8,7 +9,6 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||
"""
|
||||
Pre 2x4 decoder used in hierarchical_decoder.
|
||||
"""
|
||||
|
||||
def __init__(self, nmos_width, cellname):
|
||||
hierarchical_predecode.__init__(self, nmos_width, cellname, 2)
|
||||
|
||||
@@ -18,6 +18,15 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||
self.create_layout()
|
||||
self.route()
|
||||
|
||||
def create_nand(self):
|
||||
self.nand = nand_2(name="a_nand_2",
|
||||
nmos_width=self.nmos_width,
|
||||
height=self.bitcell_height)
|
||||
|
||||
def set_rail_height(self):
|
||||
self.rail_height = (self.number_of_outputs * self.nand.height
|
||||
- (self.number_of_outputs - 1) * drc["minwidth_metal2"])
|
||||
|
||||
def create_layout(self):
|
||||
self.create_rails()
|
||||
self.add_inv2x4()
|
||||
@@ -28,6 +37,9 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||
["B[0]", "B[1]", "Z[0]", "vdd", "gnd"]]
|
||||
self.add_nand(connections)
|
||||
|
||||
def set_height(self):
|
||||
self.height = 4 * self.nand.height
|
||||
|
||||
def add_inv2x4(self):
|
||||
self.A_positions = []
|
||||
for inv_2x4 in range(self.number_of_inputs):
|
||||
@@ -51,109 +63,48 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||
"B[{0}]".format(inv_2x4),
|
||||
"vdd", "gnd"])
|
||||
|
||||
def route_input_inverters(self):
|
||||
# All conections of the inputs inverters [Inputs, outputs, vdd, gnd]
|
||||
output_shift = 2 * drc["minwidth_metal1"]
|
||||
for inv_rout in range(self.number_of_inputs):
|
||||
if (inv_rout % 2 == 0):
|
||||
y_dir= 1
|
||||
else:
|
||||
y_dir= -1
|
||||
base = vector(self.x_off_inv_1,
|
||||
(1-y_dir) * (self.inv.height - 0.5 * drc["minwidth_metal1"]))
|
||||
inv_out_offset = base + self.inv.Z_position.scale(1,y_dir)
|
||||
inv_in_offset = base + self.inv.A_position.scale(1,y_dir)
|
||||
inv_vdd_offset = base + self.inv.vdd_position.scale(1,y_dir)
|
||||
inv_gnd_offset = base + self.inv.gnd_position.scale(1,y_dir)
|
||||
out_y_mirrored = inv_vdd_offset.y+ output_shift + drc["minwidth_metal1"]
|
||||
out_offset = [inv_out_offset.x,
|
||||
inv_out_offset.y* (1 + y_dir) / 2
|
||||
+ out_y_mirrored * (1 - y_dir) / 2]
|
||||
# output connection
|
||||
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
||||
off_via = [self.rails_x_offset[inv_rout + 4] + self.gap_between_rails,
|
||||
inv_vdd_offset.y- self.via_shift - correct]
|
||||
self.add_rect(layer="metal1",
|
||||
offset=out_offset,
|
||||
width=drc["minwidth_metal1"],
|
||||
height=(inv_vdd_offset.y- inv_out_offset.y) * y_dir - output_shift)
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[inv_out_offset.x,
|
||||
inv_vdd_offset.y- correct],
|
||||
width=self.rails_x_offset[inv_rout + 4] - inv_out_offset.x+ drc["minwidth_metal2"],
|
||||
height=drc["minwidth_metal1"])
|
||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
||||
offset=off_via,
|
||||
rotate=90)
|
||||
self.route_input_inverters_input(inv_rout,inv_in_offset)
|
||||
self.route_input_inverters_vdd(inv_vdd_offset)
|
||||
self.route_input_inverters_gnd(inv_gnd_offset)
|
||||
def cal_input_inverters_output(self,setup,output_shift,inv_rout):
|
||||
y_dir,inv_in_offset,inv_out_offset,inv_vdd_offset,inv_gnd_offset = setup
|
||||
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
||||
out_offset = vector(inv_out_offset)
|
||||
if y_dir == -1:
|
||||
out_offset.y = inv_vdd_offset.y + output_shift + drc["minwidth_metal1"]
|
||||
|
||||
def route_nand_to_rails(self):
|
||||
# This 2D array defines the connection mapping
|
||||
nand2_input_line_combination = [[4, 5], [6, 5], [4, 7], [6, 7]]
|
||||
for k in range(self.number_of_outputs):
|
||||
# create x offset list
|
||||
x_index = nand2_input_line_combination[k]
|
||||
line_x_offset = [self.rails_x_offset[x_index[0]],
|
||||
self.rails_x_offset[x_index[1]]]
|
||||
# create y offset list
|
||||
if (k % 2 == 0):
|
||||
y_off = k * (self.nand.height)
|
||||
direct = 1
|
||||
else:
|
||||
y_off = (k + 1) * (self.nand.height) - drc["minwidth_metal1"]
|
||||
direct = - 1
|
||||
list_connect = [y_off + direct * self.nand.A_position.y,
|
||||
y_off + direct * self.nand.B_position.y]
|
||||
# connect based on the two list
|
||||
for connect in list_connect:
|
||||
x_offset = line_x_offset[list_connect.index(connect)]
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[x_offset, connect],
|
||||
width=self.x_off_nand - x_offset,
|
||||
height=drc["minwidth_metal1"])
|
||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
||||
offset=[x_offset + self.gap_between_rails,
|
||||
connect - self.via_shift],
|
||||
rotate=90)
|
||||
# Extended of the top NAND2 to the left hand side input rails
|
||||
if(k == self.number_of_outputs - 1):
|
||||
x_offset = self.rails_x_offset[list_connect.index(connect)]
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[x_offset, connect],
|
||||
width=self.x_off_nand - x_offset,
|
||||
height=drc["minwidth_metal1"])
|
||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
||||
offset=[x_offset + self.gap_between_rails,
|
||||
connect - self.via_shift],
|
||||
rotate=90)
|
||||
vertical1 = out_offset
|
||||
vertical2 = vertical1 + vector(0,
|
||||
(inv_vdd_offset.y - inv_out_offset.y) * y_dir
|
||||
- output_shift)
|
||||
horizontal1 = vector(inv_out_offset.x,
|
||||
inv_vdd_offset.y - correct)
|
||||
horizontal2 = horizontal1 + vector(self.rails_x_offset[inv_rout + 4] - inv_out_offset.x+ drc["minwidth_metal2"],
|
||||
0)
|
||||
return [[vertical1,vertical2],[horizontal1,horizontal2]]
|
||||
|
||||
def route_vdd_gnd_from_rails_to_gates(self):
|
||||
for k in range(self.number_of_outputs):
|
||||
power_line_index = 3 - (k%2)
|
||||
yoffset = k * self.inv.height - 0.5 * drc["minwidth_metal1"]
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[self.rails_x_offset[power_line_index],
|
||||
yoffset],
|
||||
width=self.x_off_nand - self.rails_x_offset[power_line_index],
|
||||
height=drc["minwidth_metal1"])
|
||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
||||
offset=[self.rails_x_offset[power_line_index] + self.gap_between_rails,
|
||||
yoffset - self.via_shift],
|
||||
rotate=90)
|
||||
|
||||
yoffset = (self.number_of_outputs * self.inv.height
|
||||
- 0.5 * drc["minwidth_metal1"])
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[self.rails_x_offset[3], yoffset],
|
||||
width=self.x_off_nand - self.rails_x_offset[3],
|
||||
height=drc["minwidth_metal1"])
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[self.rails_x_offset[3], self.rail_height],
|
||||
width=drc["minwidth_metal1"],
|
||||
height=yoffset - self.rail_height)
|
||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
||||
offset=[self.rails_x_offset[3] + self.gap_between_rails,
|
||||
self.rail_height - self.via_shift],
|
||||
rotate=90)
|
||||
def set_output_shift(self):
|
||||
return 2 * drc["minwidth_metal1"]
|
||||
|
||||
def get_nand_input_line_combination(self):
|
||||
combination = [[4, 5], [6, 5], [4, 7], [6, 7]]
|
||||
return combination
|
||||
|
||||
def create_y_offsets(self,k):
|
||||
# create y offset list
|
||||
if (k % 2 == 0):
|
||||
y_off = k * (self.nand.height)
|
||||
direct = 1
|
||||
else:
|
||||
y_off = (k + 1) * (self.nand.height) - drc["minwidth_metal1"]
|
||||
direct = - 1
|
||||
correct =[0,0]
|
||||
yoffset_nand_in = [y_off + direct * self.nand.A_position.y,
|
||||
y_off + direct * self.nand.B_position.y]
|
||||
return yoffset_nand_in, correct
|
||||
|
||||
def get_via_correct(self):
|
||||
return vector(0, self.via_shift)
|
||||
|
||||
def get_vertical_metal(self):
|
||||
return "metal1"
|
||||
|
||||
def get_via_y(self):
|
||||
return self.rail_height
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from tech import drc
|
||||
import debug
|
||||
import design
|
||||
from nand_3 import nand_3
|
||||
from vector import vector
|
||||
from hierarchical_predecode import hierarchical_predecode
|
||||
|
||||
@@ -18,6 +19,14 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
||||
self.create_layout()
|
||||
self.route()
|
||||
|
||||
def create_nand(self):
|
||||
self.nand = nand_3(name="a_nand_3",
|
||||
nmos_width=self.nmos_width,
|
||||
height=self.bitcell_height)
|
||||
|
||||
def set_rail_height(self):
|
||||
self.rail_height = (self.number_of_outputs * self.nand.height
|
||||
- 1.5 * drc["minwidth_metal2"])
|
||||
def create_layout(self):
|
||||
self.create_rails()
|
||||
self.add_output_inverters()
|
||||
@@ -31,111 +40,53 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
||||
["B[0]", "B[1]", "B[2]", "Z[0]", "vdd", "gnd"]]
|
||||
self.add_nand(connections)
|
||||
|
||||
def route_input_inverters(self):
|
||||
# All conections of the inputs inverters [Inputs, outputs, vdd, gnd]
|
||||
for inv_rout in range(self.number_of_inputs):
|
||||
output_shift = 1.5 * drc["minwidth_metal1"]
|
||||
def set_height(self):
|
||||
self.height = 8 * self.nand.height
|
||||
|
||||
if (inv_rout % 2 == 0):
|
||||
base_offset=[self.x_off_inv_1, inv_rout * self.inv.height ]
|
||||
y_dir = 1
|
||||
else:
|
||||
base_offset=[self.x_off_inv_1, 2 * self.inv.height - drc["minwidth_metal1"]]
|
||||
y_dir = -1
|
||||
inv_out_offset = base_offset+self.inv.Z_position.scale(1,y_dir)
|
||||
inv_in_offset = base_offset+self.inv.A_position.scale(1,y_dir)
|
||||
inv_vdd_offset = base_offset+self.inv.vdd_position.scale(1,y_dir)
|
||||
inv_gnd_offset = base_offset+self.inv.gnd_position.scale(1,y_dir)
|
||||
# output connection
|
||||
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
||||
off_via = [self.rails_x_offset[inv_rout + 5] + self.gap_between_rails,
|
||||
inv_vdd_offset.y - self.via_shift - correct]
|
||||
path1 = inv_out_offset + vector(0.5*drc["minwidth_metal1"],
|
||||
- 1.5*drc["minwidth_metal1"] - correct)
|
||||
path2 = vector(path1.x,
|
||||
inv_vdd_offset.y + 0.5 * drc["minwidth_metal1"] - correct)
|
||||
path3 = vector(self.rails_x_offset[inv_rout + 5] + drc["minwidth_metal2"],
|
||||
path2.y)
|
||||
self.add_path("metal1", [path1,path2,path3])
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
offset=off_via,
|
||||
rotate=90)
|
||||
self.route_input_inverters_input(inv_rout,inv_in_offset)
|
||||
self.route_input_inverters_vdd(inv_vdd_offset)
|
||||
self.route_input_inverters_gnd(inv_gnd_offset)
|
||||
def cal_input_inverters_output(self,setup,output_shift,inv_rout):
|
||||
y_dir,inv_in_offset,inv_out_offset,inv_vdd_offset,inv_gnd_offset = setup
|
||||
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
||||
|
||||
def route_nand_to_rails(self):
|
||||
# This 2D array defines the connection mapping of the Nand3 gates to
|
||||
# the rail
|
||||
nand3_input_line_combination = [[5, 6, 7], [5, 6, 10],
|
||||
[5, 9, 7], [5, 9, 10],
|
||||
[8, 6, 7], [8, 6, 10],
|
||||
[8, 9, 7], [8, 9, 10]]
|
||||
for k in range(self.number_of_outputs):
|
||||
index_lst = nand3_input_line_combination[k]
|
||||
line_x_offset = []
|
||||
for index in index_lst:
|
||||
line_x_offset.append(self.rails_x_offset[index])
|
||||
out_offset = inv_out_offset + vector(0, output_shift + correct)
|
||||
vertical1 = out_offset
|
||||
vertical2 = (vertical1.scale(1, 0) + inv_vdd_offset.scale(0, 1)
|
||||
+ vector(0, - correct))
|
||||
horizontal1 = vertical1
|
||||
horizontal2 = vector(self.rails_x_offset[inv_rout + 5] + drc["minwidth_metal2"],
|
||||
vertical2.y)
|
||||
return [[vertical1,vertical2],[horizontal1,horizontal2]]
|
||||
|
||||
if (k % 2 == 0):
|
||||
y_off = k * (self.nand.height)
|
||||
y_dir =1
|
||||
correct = [0,0,self.contact_shift]
|
||||
else:
|
||||
y_off = 2 * self.inv.height - drc["minwidth_metal1"] + (k - 1) * (self.nand.height)
|
||||
y_dir = -1
|
||||
correct = [0,self.contact_shift,0]
|
||||
yoffset_nand_in = [y_off + y_dir*self.nand.A_position[1],
|
||||
y_off + y_dir*self.nand.B_position[1],
|
||||
y_off + y_dir*self.nand.C_position[1]]
|
||||
def set_output_shift(self):
|
||||
return 1.5 * drc["minwidth_metal1"]
|
||||
|
||||
for i in range(self.number_of_inputs):
|
||||
# Connecting the i-th input of Nand3 gate
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[line_x_offset[i], yoffset_nand_in[i]],
|
||||
width=self.x_off_nand - line_x_offset[i],
|
||||
height=drc["minwidth_metal1"])
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
offset=[line_x_offset[i]+ self.gap_between_rails,
|
||||
yoffset_nand_in[i] - self.via_shift - correct[i]],
|
||||
rotate=90)
|
||||
#Extended of the top NAND2 to the left hand side input rails
|
||||
if(k == self.number_of_outputs - 1):
|
||||
for i in range(self.number_of_inputs):
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[self.rails_x_offset[i], yoffset_nand_in[i]],
|
||||
width=self.x_off_nand - self.rails_x_offset[i],
|
||||
height=drc["minwidth_metal1"])
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
offset=[self.rails_x_offset[i] + self.gap_between_rails,
|
||||
yoffset_nand_in[i] - self.via_shift],
|
||||
rotate=90)
|
||||
def get_nand_input_line_combination(self):
|
||||
combination = [[5, 6, 7], [5, 6, 10],
|
||||
[5, 9, 7], [5, 9, 10],
|
||||
[8, 6, 7], [8, 6, 10],
|
||||
[8, 9, 7], [8, 9, 10]]
|
||||
return combination
|
||||
|
||||
def route_vdd_gnd_from_rails_to_gates(self):
|
||||
for k in range(self.number_of_outputs):
|
||||
power_line_index = 4 - (k%2)
|
||||
yoffset = k * self.inv.height - 0.5 * drc["minwidth_metal1"]
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[self.rails_x_offset[power_line_index], yoffset],
|
||||
width=self.x_off_nand - self.rails_x_offset[power_line_index],
|
||||
height=drc["minwidth_metal1"])
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
offset=[self.rails_x_offset[power_line_index] + self.gap_between_rails,
|
||||
yoffset - self.via_shift - self.contact_shift],
|
||||
rotate=90)
|
||||
def create_y_offsets(self,k):
|
||||
if (k % 2 == 0):
|
||||
y_off = k * (self.nand.height)
|
||||
y_dir =1
|
||||
correct = [0,0,self.contact_shift]
|
||||
else:
|
||||
y_off = 2 * self.inv.height - drc["minwidth_metal1"] + (k - 1) * (self.nand.height)
|
||||
y_dir = -1
|
||||
correct = [0,self.contact_shift,0]
|
||||
yoffset_nand_in = [y_off + y_dir*self.nand.A_position[1],
|
||||
y_off + y_dir*self.nand.B_position[1],
|
||||
y_off + y_dir*self.nand.C_position[1]]
|
||||
return yoffset_nand_in, correct
|
||||
|
||||
def get_via_correct(self):
|
||||
return vector(0, self.via_shift+self.contact_shift)
|
||||
|
||||
def get_vertical_metal(self):
|
||||
return "metal2"
|
||||
|
||||
def get_via_y(self):
|
||||
yoffset = (self.number_of_outputs * self.inv.height
|
||||
- 0.5 * drc["minwidth_metal1"])
|
||||
self.add_rect(layer="metal1",
|
||||
offset=[self.rails_x_offset[4], yoffset],
|
||||
width=self.x_off_nand - self.rails_x_offset[4],
|
||||
height=drc["minwidth_metal1"])
|
||||
|
||||
self.add_rect(layer="metal2",
|
||||
offset=[self.rails_x_offset[4], self.rail_height],
|
||||
width=drc["minwidth_metal2"],
|
||||
height=yoffset - self.rail_height)
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
offset=[self.rails_x_offset[4] + self.gap_between_rails - self.via_shift,
|
||||
yoffset - self.via_shift - self.contact_shift],
|
||||
rotate=90)
|
||||
return yoffset
|
||||
|
||||
@@ -5,7 +5,6 @@ import debug
|
||||
from tech import drc, GDS
|
||||
from tech import layer as techlayer
|
||||
import os
|
||||
from utils import snap_to_grid
|
||||
from vector import vector
|
||||
|
||||
class layout:
|
||||
@@ -96,9 +95,9 @@ class layout:
|
||||
"""Translates all 2d cartesian coordinates in a layout given
|
||||
the (x,y) offset"""
|
||||
for obj in self.objs:
|
||||
obj.offset = vector(snap_to_grid(obj.offset - coordinate))
|
||||
obj.offset = vector(obj.offset - coordinate)
|
||||
for inst in self.insts:
|
||||
inst.offset = vector(snap_to_grid(inst.offset - coordinate))
|
||||
inst.offset = vector(inst.offset - coordinate)
|
||||
|
||||
# FIXME: Make name optional and pick a random one if not specified
|
||||
def add_inst(self, name, mod, offset=[0,0], mirror="R0",rotate=0):
|
||||
|
||||
@@ -4,7 +4,7 @@ Check the .lib file for an SRAM
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header,isdiff
|
||||
from testutils import header,isapproxdiff
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
@@ -40,7 +40,8 @@ class lib_test(unittest.TestCase):
|
||||
|
||||
# let's diff the result with a golden model
|
||||
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
|
||||
self.assertEqual(isdiff(libname,golden),True)
|
||||
# Randomly decided 10% difference between spice simulators is ok.
|
||||
self.assertEqual(isapproxdiff(libname,golden,0.10),True)
|
||||
|
||||
os.system("rm {0}".format(libname))
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ library (sram_2_16_1_freepdk45_lib){
|
||||
current_unit : "1mA" ;
|
||||
resistance_unit : "1kohm" ;
|
||||
capacitive_load_unit(1 ,fF) ;
|
||||
leakage_power_unit : "1uW" ;
|
||||
leakage_power_unit : "1mW" ;
|
||||
pulling_resistance_unit :"1kohm" ;
|
||||
operating_conditions(TT){
|
||||
voltage : 1.0 ;
|
||||
@@ -69,6 +69,16 @@ library (sram_2_16_1_freepdk45_lib){
|
||||
index_1 ("0.5");
|
||||
}
|
||||
|
||||
power_lut_template(INPUT_BY_TRANS_FOR_CLOCK){
|
||||
variable_1 : input_transition_time;
|
||||
index_1 ("0.5");
|
||||
}
|
||||
|
||||
power_lut_template(INPUT_BY_TRANS_FOR_SIGNAL){
|
||||
variable_1 : input_transition_time;
|
||||
index_1 ("0.5");
|
||||
}
|
||||
|
||||
default_operating_conditions : TT;
|
||||
|
||||
|
||||
@@ -106,11 +116,20 @@ cell (sram_2_16_1_freepdk45){
|
||||
max_capacitance : 0.62166;
|
||||
pin(DATA[1:0]){
|
||||
}
|
||||
three_state : "OEb & !clk";
|
||||
three_state : "!OEb & !clk";
|
||||
memory_write(){
|
||||
address : ADDR;
|
||||
clocked_on : clk;
|
||||
}
|
||||
internal_power(){
|
||||
when : "OEb & !clk";
|
||||
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
|
||||
values("0.66109");
|
||||
}
|
||||
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
|
||||
values("0.66109");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk";
|
||||
@@ -134,6 +153,15 @@ cell (sram_2_16_1_freepdk45){
|
||||
memory_read(){
|
||||
address : ADDR;
|
||||
}
|
||||
internal_power(){
|
||||
when : "!OEb & !clk";
|
||||
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
|
||||
values("0.027754");
|
||||
}
|
||||
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
|
||||
values("0.027754");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_sense : non_unate;
|
||||
related_pin : "clk";
|
||||
@@ -262,26 +290,24 @@ cell (sram_2_16_1_freepdk45){
|
||||
clock : true;
|
||||
direction : input;
|
||||
capacitance : 0.2091;
|
||||
min_pulse_width_high : 0.081 ;
|
||||
min_pulse_width_low : 0.267 ;
|
||||
timing(){
|
||||
timing_type :"min_pulse_width";
|
||||
related_pin : clk;
|
||||
rise_constraint(CLK_TRAN) {
|
||||
values("0");
|
||||
values("0.174");
|
||||
}
|
||||
fall_constraint(CLK_TRAN) {
|
||||
values("0");
|
||||
values("0.174");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"minimum_period";
|
||||
related_pin : clk;
|
||||
rise_constraint(CLK_TRAN) {
|
||||
values("0");
|
||||
values("0.348");
|
||||
}
|
||||
fall_constraint(CLK_TRAN) {
|
||||
values("0");
|
||||
values("0.348");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ library (sram_2_16_1_scn3me_subm_lib){
|
||||
current_unit : "1mA" ;
|
||||
resistance_unit : "1kohm" ;
|
||||
capacitive_load_unit(1 ,fF) ;
|
||||
leakage_power_unit : "1uW" ;
|
||||
leakage_power_unit : "1mW" ;
|
||||
pulling_resistance_unit :"1kohm" ;
|
||||
operating_conditions(TT){
|
||||
voltage : 5.0 ;
|
||||
@@ -69,6 +69,16 @@ library (sram_2_16_1_scn3me_subm_lib){
|
||||
index_1 ("0.5");
|
||||
}
|
||||
|
||||
power_lut_template(INPUT_BY_TRANS_FOR_CLOCK){
|
||||
variable_1 : input_transition_time;
|
||||
index_1 ("0.5");
|
||||
}
|
||||
|
||||
power_lut_template(INPUT_BY_TRANS_FOR_SIGNAL){
|
||||
variable_1 : input_transition_time;
|
||||
index_1 ("0.5");
|
||||
}
|
||||
|
||||
default_operating_conditions : TT;
|
||||
|
||||
|
||||
@@ -106,11 +116,20 @@ cell (sram_2_16_1_scn3me_subm){
|
||||
max_capacitance : 11.3222;
|
||||
pin(DATA[1:0]){
|
||||
}
|
||||
three_state : "OEb & !clk";
|
||||
three_state : "!OEb & !clk";
|
||||
memory_write(){
|
||||
address : ADDR;
|
||||
clocked_on : clk;
|
||||
}
|
||||
internal_power(){
|
||||
when : "OEb & !clk";
|
||||
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
|
||||
values("15.6576");
|
||||
}
|
||||
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
|
||||
values("15.6576");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk";
|
||||
@@ -134,6 +153,15 @@ cell (sram_2_16_1_scn3me_subm){
|
||||
memory_read(){
|
||||
address : ADDR;
|
||||
}
|
||||
internal_power(){
|
||||
when : "!OEb & !clk";
|
||||
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
|
||||
values("6.2822");
|
||||
}
|
||||
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
|
||||
values("6.2822");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_sense : non_unate;
|
||||
related_pin : "clk";
|
||||
@@ -262,26 +290,24 @@ cell (sram_2_16_1_scn3me_subm){
|
||||
clock : true;
|
||||
direction : input;
|
||||
capacitance : 9.8242;
|
||||
min_pulse_width_high : 1.658 ;
|
||||
min_pulse_width_low : 3.428 ;
|
||||
timing(){
|
||||
timing_type :"min_pulse_width";
|
||||
related_pin : clk;
|
||||
rise_constraint(CLK_TRAN) {
|
||||
values("0");
|
||||
values("2.543");
|
||||
}
|
||||
fall_constraint(CLK_TRAN) {
|
||||
values("0");
|
||||
values("2.543");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"minimum_period";
|
||||
related_pin : clk;
|
||||
rise_constraint(CLK_TRAN) {
|
||||
values("0");
|
||||
values("5.086");
|
||||
}
|
||||
fall_constraint(CLK_TRAN) {
|
||||
values("0");
|
||||
values("5.086");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
|
||||
def isclose(value1,value2,error_tolerance=1e-2):
|
||||
""" This is used to compare relative values. """
|
||||
import debug
|
||||
@@ -11,6 +10,79 @@ def isclose(value1,value2,error_tolerance=1e-2):
|
||||
debug.info(2,"CLOSE {0} {1} relative diff={2}".format(value1,value2,relative_diff))
|
||||
return (check)
|
||||
|
||||
def relative_compare(value1,value2,error_tolerance):
|
||||
""" This is used to compare relative values. """
|
||||
if (value1==value2): # if we don't need a relative comparison!
|
||||
return True
|
||||
return (abs(value1 - value2) / max(value1,value2) <= error_tolerance)
|
||||
|
||||
def isapproxdiff(f1, f2, error_tolerance=0.001):
|
||||
"""Compare two files.
|
||||
|
||||
Arguments:
|
||||
|
||||
f1 -- First file name
|
||||
|
||||
f2 -- Second file name
|
||||
|
||||
Return value:
|
||||
|
||||
True if the files are the same, False otherwise.
|
||||
|
||||
"""
|
||||
import re
|
||||
import debug
|
||||
|
||||
with open(f1, 'rb') as fp1, open(f2, 'rb') as fp2:
|
||||
while True:
|
||||
b1 = fp1.readline()
|
||||
b2 = fp2.readline()
|
||||
#print "b1:",b1,
|
||||
#print "b2:",b2,
|
||||
|
||||
# 1. Find all of the floats using a regex
|
||||
numeric_const_pattern = r"""
|
||||
[-+]? # optional sign
|
||||
(?:
|
||||
(?: \d* \. \d+ ) # .1 .12 .123 etc 9.1 etc 98.1 etc
|
||||
|
|
||||
(?: \d+ \.? ) # 1. 12. 123. etc 1 12 123 etc
|
||||
)
|
||||
# followed by optional exponent part if desired
|
||||
(?: [Ee] [+-]? \d+ ) ?
|
||||
"""
|
||||
rx = re.compile(numeric_const_pattern, re.VERBOSE)
|
||||
b1_floats=rx.findall(b1)
|
||||
b2_floats=rx.findall(b2)
|
||||
debug.info(3,"b1_floats: "+str(b1_floats))
|
||||
debug.info(3,"b2_floats: "+str(b2_floats))
|
||||
|
||||
# 2. Remove the floats from the string
|
||||
for f in b1_floats:
|
||||
b1=b1.replace(str(f),"")
|
||||
for f in b2_floats:
|
||||
b2=b2.replace(str(f),"")
|
||||
#print "b1:",b1,
|
||||
#print "b2:",b2,
|
||||
|
||||
# 3. Check if remaining string matches
|
||||
if b1 != b2:
|
||||
debug.info(2,"Line: {0}\n!=\nLine: {1}".format(b1,b2))
|
||||
return False
|
||||
|
||||
# 4. Now compare that the floats match
|
||||
if len(b1_floats)!=len(b2_floats):
|
||||
debug.info(2,"Len {0} != {1}".format(len(b1_floats),len(b2_floats)))
|
||||
return False
|
||||
for (f1,f2) in zip(b1_floats,b2_floats):
|
||||
if not relative_compare(float(f1),float(f2),error_tolerance):
|
||||
debug.info(2, "Float {0} != {1}".format(f1,f2))
|
||||
return False
|
||||
|
||||
if not b1:
|
||||
return True
|
||||
|
||||
|
||||
def isdiff(file1,file2):
|
||||
""" This is used to compare two files and display the diff if they are different.. """
|
||||
import debug
|
||||
|
||||
+4
-1
@@ -5,6 +5,7 @@ import globals
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
<<<<<<< HEAD
|
||||
def snap_to_grid(offset):
|
||||
"""
|
||||
Changes the coodrinate to match the grid settings
|
||||
@@ -25,10 +26,12 @@ def gds_pin_center(gdsPin):
|
||||
"""
|
||||
This returns the center of a pin shape
|
||||
"""
|
||||
=======
|
||||
def gdsPinToOffset(gdsPin):
|
||||
>>>>>>> master
|
||||
boundary = gdsPin[2]
|
||||
return [0.5 * (boundary[0] + boundary[2]), 0.5 * (boundary[1] + boundary[3])]
|
||||
|
||||
|
||||
def auto_measure_libcell(pin_list, name, units, layer):
|
||||
"""
|
||||
Open a GDS file and find the pins in pin_list as text on a given layer.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import debug
|
||||
import math
|
||||
import tech
|
||||
|
||||
class vector():
|
||||
"""
|
||||
@@ -83,6 +84,21 @@ class vector():
|
||||
"""
|
||||
return vector(other[0]- self.x, other[1] - self.y)
|
||||
|
||||
def snap_to_grid(self):
|
||||
self.x = self.snap_offset_to_grid(self.x)
|
||||
self.y = self.snap_offset_to_grid(self.y)
|
||||
return self
|
||||
|
||||
def snap_offset_to_grid(self, offset):
|
||||
"""
|
||||
Changes the coodrinate to match the grid settings
|
||||
"""
|
||||
grid = tech.drc["grid"]
|
||||
# this gets the nearest integer value
|
||||
off_in_grid = int(round(round((offset / grid), 2), 0))
|
||||
offset = off_in_grid * grid
|
||||
return offset
|
||||
|
||||
def rotate(self):
|
||||
""" pass a copy of rotated vector, without altering the vector! """
|
||||
return vector(self.y,self.x)
|
||||
|
||||
Reference in New Issue
Block a user