Add custom cell custom port order code. Update setup/hold to use it.

This commit is contained in:
mrg 2020-11-17 11:12:59 -08:00
parent 80333ffacb
commit baae28194b
6 changed files with 83 additions and 28 deletions

View File

@ -22,7 +22,11 @@ class _cell:
self._port_map = {x: x for x in port_order}
# Update mapping of names
self._original_port_order = port_order
self._port_order = port_order
# Create an index array
self._port_indices = [self._port_order.index(x) for x in self._original_port_order]
# Update ordered name list
self._port_names = [self._port_map[x] for x in self._port_order]
@ -49,7 +53,13 @@ class _cell:
self._port_names = [self._port_map[x] for x in self._port_order]
# Update ordered type list in the new order
self._port_types = [self._port_types_map[x] for x in self._port_order]
# Update the index array
self._port_indices = [self._port_order.index(x) for x in self._original_port_order]
@property
def port_indices(self):
return self._port_indices
@property
def port_map(self):
return self._port_map

View File

@ -39,6 +39,7 @@ class design(hierarchy_design):
# that they matched here
debug.check(prop.port_names == self.pins,
"Custom cell pin names do not match spice file:\n{0} vs {1}".format(prop.port_names, self.pins))
self.add_pin_indices(prop.port_indices)
self.add_pin_names(prop.port_map)
self.add_pin_types(prop.port_types)

View File

@ -62,14 +62,7 @@ class layout():
self.pwr_grid_layer = power_grid[0]
except ImportError:
self.pwr_grid_layer = "m3"
def add_pin_names(self, pin_dict):
"""
Create a mapping from internal pin names to external pin names.
"""
self.pin_names = pin_dict
############################################################
# GDS layout
############################################################
@ -325,11 +318,8 @@ class layout():
"""
Return the pin or list of pins
"""
if text in self.pin_names:
name = self.pin_names[text]
else:
name = text
name = self.get_pin_name(text)
try:
if len(self.pin_map[name]) > 1:
debug.error("Should use a pin iterator since more than one pin {}".format(text), -1)
@ -345,16 +335,42 @@ class layout():
"""
Return a pin list (instead of a single pin)
"""
if text in self.pin_names:
name = self.pin_names[text]
else:
name = text
name = self.get_pin_name(text)
if name in self.pin_map.keys():
return self.pin_map[name]
else:
return set()
def add_pin_names(self, pin_dict):
"""
Create a mapping from internal pin names to external pin names.
"""
self.pin_names = pin_dict
self.original_pin_names = {y: x for (x, y) in self.pin_names.items()}
def get_pin_name(self, text):
""" Return the custom cell pin name """
if text in self.pin_names:
return self.pin_names[text]
else:
return text
def get_original_pin_names(self):
""" Return the internal cell pin name """
# This uses the hierarchy_spice pins (in order)
return [self.get_original_pin_name(x) for x in self.pins]
def get_original_pin_name(self, text):
""" Return the internal cell pin names in custom port order """
if text in self.original_pin_names:
return self.original_pin_names[text]
else:
return text
def get_pin_names(self):
"""
Return a pin list of all pins

View File

@ -35,11 +35,13 @@ class spice():
self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
# Holds subckts/mods for this module
self.mods = []
# Holds the pins for this module
# Holds the pins for this module (in order)
self.pins = []
# The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND
# for each instance, this is the set of nets/nodes that map to the pins for this instance
self.pin_type = {}
# An (optional) list of indices to reorder the pins to match the spice.
self.pin_indices = []
# THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the
# Spice format)
self.conns = []
@ -95,10 +97,25 @@ class spice():
else:
debug.error("Mismatch in type and pin list lengths.", -1)
def add_pin_indices(self, index_list):
"""
Add pin indices for all the cell's pins.
"""
self.pin_indices = index_list
def get_ordered_inputs(self, input_list):
"""
Return the inputs reordered to match the pins.
"""
if not self.pin_indices:
return input_list
new_list = [input_list[x] for x in self.pin_indices]
return new_list
def add_pin_types(self, type_list):
"""
Add pin types for all the cell's pins.
Typically, should only be used for handmade cells.
"""
# This only works if self.pins == bitcell.pin_names
if len(type_list) != len(self.pins):
@ -107,7 +124,7 @@ class spice():
\n Module names={}\
".format(self.name, self.pins, type_list), 1)
self.pin_type = {pin: type for pin, type in zip(self.pins, type_list)}
def get_pin_type(self, name):
""" Returns the type of the signal pin. """
pin_type = self.pin_type[name]
@ -159,19 +176,26 @@ class spice():
self.mods.append(mod)
def connect_inst(self, args, check=True):
"""Connects the pins of the last instance added
"""
Connects the pins of the last instance added
It is preferred to use the function with the check to find if
there is a problem. The check option can be set to false
where we dynamically generate groups of connections after a
group of modules are generated."""
group of modules are generated.
"""
num_pins = len(self.insts[-1].mod.pins)
num_args = len(args)
# Order the arguments if the hard cell has a custom port order
ordered_args = self.get_ordered_inputs(args)
if (check and num_pins != num_args):
if num_pins < num_args:
mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins)
arg_pins = args
arg_pins = ordered_args
else:
arg_pins = args + [""] * (num_pins - num_args)
arg_pins = ordered_args + [""] * (num_pins - num_args)
mod_pins = self.insts[-1].mod.pins
modpins_string = "\n".join(["{0} -> {1}".format(arg, mod) for (arg, mod) in zip(arg_pins, mod_pins)])
@ -180,8 +204,9 @@ class spice():
modpins_string),
1)
self.conns.append(args)
self.conns.append(ordered_args)
# This checks if we don't have enough instance port connections for the number of insts
if check and (len(self.insts)!=len(self.conns)):
insts_string=pformat(self.insts)
conns_string=pformat(self.conns)

View File

@ -5,9 +5,9 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import debug
import math
class verilog:
"""
Create a behavioral Verilog file for simulation.
@ -16,7 +16,7 @@ class verilog:
def __init__(self):
pass
def verilog_write(self,verilog_name):
def verilog_write(self, verilog_name):
""" Write a behavioral Verilog model. """
self.vf = open(verilog_name, "w")
@ -220,6 +220,9 @@ class verilog:
self.vf.write(" dout{0} <= #(DELAY) mem[addr{0}_reg];\n".format(port))
self.vf.write(" end\n")
self.vf.write(" always @(csb{0})\n".format(port))
self.vf.write(" dout{0} = 0)\n".format(port))
def add_address_check(self, wport, rport):
""" Output a warning if the two addresses match """
# If the rport is actually reading... and addresses match.

View File

@ -48,7 +48,7 @@ class setup_hold():
# instantiate the master-slave d-flip-flop
self.sf.write("\n* Instantiation of the Master-Slave D-flip-flop\n")
self.stim.inst_model(pins=self.dff.get_ordered_inputs(self.dff.pins),
self.stim.inst_model(pins=self.dff.get_original_pin_names(),
model_name=self.dff.cell_name)
self.write_data(mode=mode,