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} self._port_map = {x: x for x in port_order}
# Update mapping of names # Update mapping of names
self._original_port_order = port_order
self._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 # Update ordered name list
self._port_names = [self._port_map[x] for x in self._port_order] 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] self._port_names = [self._port_map[x] for x in self._port_order]
# Update ordered type list in the new order # Update ordered type list in the new order
self._port_types = [self._port_types_map[x] for x in self._port_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 @property
def port_map(self): def port_map(self):
return self._port_map return self._port_map

View File

@ -39,6 +39,7 @@ class design(hierarchy_design):
# that they matched here # that they matched here
debug.check(prop.port_names == self.pins, 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)) "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_names(prop.port_map)
self.add_pin_types(prop.port_types) self.add_pin_types(prop.port_types)

View File

@ -62,14 +62,7 @@ class layout():
self.pwr_grid_layer = power_grid[0] self.pwr_grid_layer = power_grid[0]
except ImportError: except ImportError:
self.pwr_grid_layer = "m3" 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 # GDS layout
############################################################ ############################################################
@ -325,11 +318,8 @@ class layout():
""" """
Return the pin or list of pins Return the pin or list of pins
""" """
if text in self.pin_names: name = self.get_pin_name(text)
name = self.pin_names[text]
else:
name = text
try: try:
if len(self.pin_map[name]) > 1: if len(self.pin_map[name]) > 1:
debug.error("Should use a pin iterator since more than one pin {}".format(text), -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) Return a pin list (instead of a single pin)
""" """
if text in self.pin_names: name = self.get_pin_name(text)
name = self.pin_names[text]
else:
name = text
if name in self.pin_map.keys(): if name in self.pin_map.keys():
return self.pin_map[name] return self.pin_map[name]
else: else:
return set() 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): def get_pin_names(self):
""" """
Return a pin list of all pins Return a pin list of all pins

View File

@ -35,11 +35,13 @@ class spice():
self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND"] self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
# Holds subckts/mods for this module # Holds subckts/mods for this module
self.mods = [] self.mods = []
# Holds the pins for this module # Holds the pins for this module (in order)
self.pins = [] self.pins = []
# The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND # 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 # for each instance, this is the set of nets/nodes that map to the pins for this instance
self.pin_type = {} 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 # THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the
# Spice format) # Spice format)
self.conns = [] self.conns = []
@ -95,10 +97,25 @@ class spice():
else: else:
debug.error("Mismatch in type and pin list lengths.", -1) 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): def add_pin_types(self, type_list):
""" """
Add pin types for all the cell's pins. 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 # This only works if self.pins == bitcell.pin_names
if len(type_list) != len(self.pins): if len(type_list) != len(self.pins):
@ -107,7 +124,7 @@ class spice():
\n Module names={}\ \n Module names={}\
".format(self.name, self.pins, type_list), 1) ".format(self.name, self.pins, type_list), 1)
self.pin_type = {pin: type for pin, type in zip(self.pins, type_list)} self.pin_type = {pin: type for pin, type in zip(self.pins, type_list)}
def get_pin_type(self, name): def get_pin_type(self, name):
""" Returns the type of the signal pin. """ """ Returns the type of the signal pin. """
pin_type = self.pin_type[name] pin_type = self.pin_type[name]
@ -159,19 +176,26 @@ class spice():
self.mods.append(mod) self.mods.append(mod)
def connect_inst(self, args, check=True): 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 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 there is a problem. The check option can be set to false
where we dynamically generate groups of connections after a 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_pins = len(self.insts[-1].mod.pins)
num_args = len(args) 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 (check and num_pins != num_args):
if num_pins < num_args: if num_pins < num_args:
mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins) mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins)
arg_pins = args arg_pins = ordered_args
else: else:
arg_pins = args + [""] * (num_pins - num_args) arg_pins = ordered_args + [""] * (num_pins - num_args)
mod_pins = self.insts[-1].mod.pins 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)]) 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), modpins_string),
1) 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)): if check and (len(self.insts)!=len(self.conns)):
insts_string=pformat(self.insts) insts_string=pformat(self.insts)
conns_string=pformat(self.conns) conns_string=pformat(self.conns)

View File

@ -5,9 +5,9 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import debug
import math import math
class verilog: class verilog:
""" """
Create a behavioral Verilog file for simulation. Create a behavioral Verilog file for simulation.
@ -16,7 +16,7 @@ class verilog:
def __init__(self): def __init__(self):
pass pass
def verilog_write(self,verilog_name): def verilog_write(self, verilog_name):
""" Write a behavioral Verilog model. """ """ Write a behavioral Verilog model. """
self.vf = open(verilog_name, "w") 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(" dout{0} <= #(DELAY) mem[addr{0}_reg];\n".format(port))
self.vf.write(" end\n") 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): def add_address_check(self, wport, rport):
""" Output a warning if the two addresses match """ """ Output a warning if the two addresses match """
# If the rport is actually reading... and 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 # instantiate the master-slave d-flip-flop
self.sf.write("\n* Instantiation of the Master-Slave D-flip-flop\n") 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) model_name=self.dff.cell_name)
self.write_data(mode=mode, self.write_data(mode=mode,