mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-09-03 08:27:11 +02:00
Merged with dev
This commit is contained in:
+27
-8
@@ -6,7 +6,10 @@
|
||||
# All rights reserved.
|
||||
#
|
||||
import datetime
|
||||
import os
|
||||
import debug
|
||||
import verify
|
||||
from characterizer import functional
|
||||
from globals import OPTS, print_time
|
||||
|
||||
|
||||
@@ -38,7 +41,7 @@ class sram():
|
||||
start_time = datetime.datetime.now()
|
||||
|
||||
self.name = name
|
||||
|
||||
|
||||
if self.num_banks == 1:
|
||||
from sram_1bank import sram_1bank as sram
|
||||
elif self.num_banks == 2:
|
||||
@@ -50,16 +53,16 @@ class sram():
|
||||
self.s.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.s.create_layout()
|
||||
|
||||
|
||||
if not OPTS.is_unit_test:
|
||||
print_time("SRAM creation", datetime.datetime.now(), start_time)
|
||||
|
||||
|
||||
def sp_write(self, name):
|
||||
self.s.sp_write(name)
|
||||
|
||||
def lvs_write(self, name):
|
||||
self.s.lvs_write(name)
|
||||
|
||||
|
||||
def lef_write(self, name):
|
||||
self.s.lef_write(name)
|
||||
|
||||
@@ -70,7 +73,7 @@ class sram():
|
||||
self.s.verilog_write(name)
|
||||
|
||||
def extended_config_write(self, name):
|
||||
"""Dump config file with all options.
|
||||
"""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)))
|
||||
@@ -80,7 +83,7 @@ class sram():
|
||||
else:
|
||||
f.write(str(var_name) + " = " + str(var_value)+ "\n")
|
||||
f.close()
|
||||
|
||||
|
||||
def save(self):
|
||||
""" Save all the output files while reporting time to do it as well. """
|
||||
|
||||
@@ -90,6 +93,11 @@ class sram():
|
||||
gdsname = OPTS.output_path + self.s.name + ".gds"
|
||||
debug.print_raw("GDS: Writing to {0}".format(gdsname))
|
||||
self.gds_write(gdsname)
|
||||
verify.write_drc_script(cell_name=self.s.name,
|
||||
gds_name=os.path.basename(gdsname),
|
||||
extract=True,
|
||||
final_verification=True,
|
||||
output_path=OPTS.output_path)
|
||||
print_time("GDS", datetime.datetime.now(), start_time)
|
||||
|
||||
# Create a LEF physical model
|
||||
@@ -104,6 +112,10 @@ class sram():
|
||||
spname = OPTS.output_path + self.s.name + ".sp"
|
||||
debug.print_raw("SP: Writing to {0}".format(spname))
|
||||
self.sp_write(spname)
|
||||
functional(self.s,
|
||||
os.path.basename(spname),
|
||||
cycles=200,
|
||||
output_path=OPTS.output_path)
|
||||
print_time("Spice writing", datetime.datetime.now(), start_time)
|
||||
|
||||
# Save the LVS file
|
||||
@@ -111,11 +123,16 @@ class sram():
|
||||
lvsname = OPTS.output_path + self.s.name + ".lvs.sp"
|
||||
debug.print_raw("LVS: Writing to {0}".format(lvsname))
|
||||
self.lvs_write(lvsname)
|
||||
if not OPTS.netlist_only:
|
||||
verify.write_lvs_script(cell_name=self.s.name,
|
||||
gds_name=os.path.basename(gdsname),
|
||||
sp_name=os.path.basename(lvsname),
|
||||
final_verification=True,
|
||||
output_path=OPTS.output_path)
|
||||
print_time("LVS writing", datetime.datetime.now(), start_time)
|
||||
|
||||
|
||||
# Save the extracted spice file
|
||||
if OPTS.use_pex:
|
||||
import verify
|
||||
start_time = datetime.datetime.now()
|
||||
# Output the extracted design if requested
|
||||
pexname = OPTS.output_path + self.s.name + ".pex.sp"
|
||||
@@ -127,6 +144,8 @@ class sram():
|
||||
# Use generated spice file for characterization
|
||||
sp_file = spname
|
||||
|
||||
# Save a functional simulation file
|
||||
|
||||
# Characterize the design
|
||||
start_time = datetime.datetime.now()
|
||||
from characterizer import lib
|
||||
|
||||
+35
-35
@@ -19,13 +19,13 @@ class sram_1bank(sram_base):
|
||||
"""
|
||||
def __init__(self, name, sram_config):
|
||||
sram_base.__init__(self, name, sram_config)
|
||||
|
||||
|
||||
def create_modules(self):
|
||||
"""
|
||||
This adds the modules for a single bank SRAM with control
|
||||
logic.
|
||||
"""
|
||||
|
||||
|
||||
self.bank_inst=self.create_bank(0)
|
||||
|
||||
self.control_logic_insts = self.create_control_logic()
|
||||
@@ -51,7 +51,7 @@ class sram_1bank(sram_base):
|
||||
This places the instances for a single bank SRAM with control
|
||||
logic and up to 2 ports.
|
||||
"""
|
||||
|
||||
|
||||
# No orientation or offset
|
||||
self.place_bank(self.bank_inst, [0, 0], 1, 1)
|
||||
|
||||
@@ -129,10 +129,10 @@ class sram_1bank(sram_base):
|
||||
y_offset = self.bank.bank_array_ll.y
|
||||
self.row_addr_pos[port] = vector(x_offset, y_offset)
|
||||
self.row_addr_dff_insts[port].place(self.row_addr_pos[port], mirror="XY")
|
||||
|
||||
|
||||
def place_control(self):
|
||||
port = 0
|
||||
|
||||
|
||||
# This includes 2 M2 pitches for the row addr clock line.
|
||||
# The delay line is aligned with the bitcell array while the control logic is aligned with the port_data
|
||||
# using the control_logic_center value.
|
||||
@@ -171,7 +171,7 @@ class sram_1bank(sram_base):
|
||||
x_offset = self.col_addr_dff_insts[port].rx()
|
||||
else:
|
||||
self.col_addr_pos[port] = vector(x_offset, 0)
|
||||
|
||||
|
||||
if port in self.write_ports:
|
||||
if self.write_size:
|
||||
# Add the write mask flops below the write mask AND array.
|
||||
@@ -201,7 +201,7 @@ class sram_1bank(sram_base):
|
||||
|
||||
if len(self.all_ports) > 1:
|
||||
port = 1
|
||||
|
||||
|
||||
# Add the col address flops below the bank to the right of the control logic
|
||||
x_offset = self.control_logic_insts[port].lx() - 2 * self.dff.width
|
||||
# Place it a data bus below the x-axis, but at least as high as the control logic to not block
|
||||
@@ -215,7 +215,7 @@ class sram_1bank(sram_base):
|
||||
x_offset = self.col_addr_dff_insts[port].lx()
|
||||
else:
|
||||
self.col_addr_pos[port] = vector(x_offset, y_offset)
|
||||
|
||||
|
||||
if port in self.write_ports:
|
||||
# Add spare write enable flops to the right of the data flops since the spare
|
||||
# columns will be on the left
|
||||
@@ -248,7 +248,7 @@ class sram_1bank(sram_base):
|
||||
highest_coord = self.find_highest_coords()
|
||||
lowest_coord = self.find_lowest_coords()
|
||||
bbox = [lowest_coord, highest_coord]
|
||||
|
||||
|
||||
for port in self.all_ports:
|
||||
# Depending on the port, use the bottom/top or left/right sides
|
||||
# Port 0 is left/bottom
|
||||
@@ -296,7 +296,7 @@ class sram_1bank(sram_base):
|
||||
self.copy_layout_pin(self.data_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"din{0}[{1}]".format(port, bit))
|
||||
|
||||
|
||||
# Data output pins go to BOTTOM/TOP
|
||||
if port in self.readwrite_ports and OPTS.perimeter_pins:
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
@@ -319,8 +319,8 @@ class sram_1bank(sram_base):
|
||||
self.copy_layout_pin(self.bank_inst,
|
||||
"dout{0}_{1}".format(port, bit),
|
||||
"dout{0}[{1}]".format(port, bit))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Lower address bits go to BOTTOM/TOP
|
||||
for bit in range(self.col_addr_size):
|
||||
@@ -333,7 +333,7 @@ class sram_1bank(sram_base):
|
||||
self.copy_layout_pin(self.col_addr_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"addr{0}[{1}]".format(port, bit))
|
||||
|
||||
|
||||
# Upper address bits go to LEFT/RIGHT
|
||||
for bit in range(self.row_addr_size):
|
||||
if OPTS.perimeter_pins:
|
||||
@@ -345,7 +345,7 @@ class sram_1bank(sram_base):
|
||||
self.copy_layout_pin(self.row_addr_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"addr{0}[{1}]".format(port, bit + self.col_addr_size))
|
||||
|
||||
|
||||
# Write mask pins go to BOTTOM/TOP
|
||||
if port in self.write_ports:
|
||||
if self.write_size:
|
||||
@@ -379,20 +379,20 @@ class sram_1bank(sram_base):
|
||||
self.add_layout_pins()
|
||||
|
||||
self.route_clk()
|
||||
|
||||
|
||||
self.route_control_logic()
|
||||
|
||||
|
||||
self.route_row_addr_dff()
|
||||
|
||||
def route_dffs(self, add_routes=True):
|
||||
|
||||
|
||||
for port in self.all_ports:
|
||||
self.route_dff(port, add_routes)
|
||||
|
||||
def route_dff(self, port, add_routes):
|
||||
|
||||
route_map = []
|
||||
|
||||
|
||||
# column mux dff is routed on it's own since it is to the far end
|
||||
# decoder inputs are min pitch M2, so need to use lower layer stack
|
||||
if self.col_addr_size > 0:
|
||||
@@ -408,7 +408,7 @@ class sram_1bank(sram_base):
|
||||
else:
|
||||
offset = vector(0,
|
||||
self.bank.height + 2 * self.m1_space)
|
||||
|
||||
|
||||
cr = channel_route.channel_route(netlist=route_map,
|
||||
offset=offset,
|
||||
layer_stack=self.m1_stack,
|
||||
@@ -420,7 +420,7 @@ class sram_1bank(sram_base):
|
||||
self.col_addr_bus_size[port] = cr.height
|
||||
|
||||
route_map = []
|
||||
|
||||
|
||||
# wmask dff
|
||||
if self.num_wmasks > 0 and port in self.write_ports:
|
||||
dff_names = ["dout_{}".format(x) for x in range(self.num_wmasks)]
|
||||
@@ -436,7 +436,7 @@ class sram_1bank(sram_base):
|
||||
bank_names = ["din{0}_{1}".format(port, x) for x in range(self.word_size + self.num_spare_cols)]
|
||||
bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
|
||||
route_map.extend(list(zip(bank_pins, dff_pins)))
|
||||
|
||||
|
||||
if port in self.readwrite_ports and OPTS.perimeter_pins:
|
||||
# outputs from sense amp
|
||||
# These are the output pins which had their pin placed on the perimeter, so route from the
|
||||
@@ -454,14 +454,14 @@ class sram_1bank(sram_base):
|
||||
bank_names = ["bank_spare_wen{0}_{1}".format(port, x) for x in range(self.num_spare_cols)]
|
||||
bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
|
||||
route_map.extend(list(zip(bank_pins, dff_pins)))
|
||||
|
||||
|
||||
if len(route_map) > 0:
|
||||
|
||||
|
||||
if self.num_wmasks > 0 and port in self.write_ports:
|
||||
layer_stack = self.m3_stack
|
||||
else:
|
||||
layer_stack = self.m1_stack
|
||||
|
||||
|
||||
if port == 0:
|
||||
offset = vector(self.control_logic_insts[port].rx() + self.dff.width,
|
||||
- self.data_bus_size[port] + 2 * self.m1_pitch)
|
||||
@@ -486,7 +486,7 @@ class sram_1bank(sram_base):
|
||||
self.connect_inst([])
|
||||
else:
|
||||
self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap
|
||||
|
||||
|
||||
def route_clk(self):
|
||||
""" Route the clock network """
|
||||
|
||||
@@ -497,7 +497,7 @@ class sram_1bank(sram_base):
|
||||
# are clk_buf and clk_buf_bar
|
||||
control_clk_buf_pin = self.control_logic_insts[port].get_pin("clk_buf")
|
||||
control_clk_buf_pos = control_clk_buf_pin.center()
|
||||
|
||||
|
||||
# This uses a metal2 track to the right (for port0) of the control/row addr DFF
|
||||
# to route vertically. For port1, it is to the left.
|
||||
row_addr_clk_pin = self.row_addr_dff_insts[port].get_pin("clk")
|
||||
@@ -518,11 +518,11 @@ class sram_1bank(sram_base):
|
||||
self.add_via_stack_center(from_layer=control_clk_buf_pin.layer,
|
||||
to_layer="m2",
|
||||
offset=clk_steiner_pos)
|
||||
|
||||
|
||||
# Note, the via to the control logic is taken care of above
|
||||
self.add_wire(self.m2_stack[::-1],
|
||||
[row_addr_clk_pos, mid1_pos, clk_steiner_pos])
|
||||
|
||||
|
||||
if self.col_addr_dff:
|
||||
dff_clk_pin = self.col_addr_dff_insts[port].get_pin("clk")
|
||||
dff_clk_pos = dff_clk_pin.center()
|
||||
@@ -567,9 +567,9 @@ class sram_1bank(sram_base):
|
||||
self.add_via_stack_center(from_layer=dest_pin.layer,
|
||||
to_layer="m2",
|
||||
offset=dest_pin.center())
|
||||
|
||||
|
||||
def route_row_addr_dff(self):
|
||||
"""
|
||||
"""
|
||||
Connect the output of the row flops to the bank pins
|
||||
"""
|
||||
for port in self.all_ports:
|
||||
@@ -602,7 +602,7 @@ class sram_1bank(sram_base):
|
||||
self.add_label(text=n,
|
||||
layer=pin.layer,
|
||||
offset=pin.center())
|
||||
|
||||
|
||||
def graph_exclude_data_dff(self):
|
||||
"""
|
||||
Removes data dff and wmask dff (if applicable) from search graph.
|
||||
@@ -616,7 +616,7 @@ class sram_1bank(sram_base):
|
||||
if self.num_spare_cols:
|
||||
for inst in self.spare_wen_dff_insts:
|
||||
self.graph_inst_exclude.add(inst)
|
||||
|
||||
|
||||
def graph_exclude_addr_dff(self):
|
||||
"""
|
||||
Removes data dff from search graph.
|
||||
@@ -624,7 +624,7 @@ class sram_1bank(sram_base):
|
||||
# Address is considered not part of the critical path, subjectively removed
|
||||
for inst in self.row_addr_dff_insts:
|
||||
self.graph_inst_exclude.add(inst)
|
||||
|
||||
|
||||
if self.col_addr_dff:
|
||||
for inst in self.col_addr_dff_insts:
|
||||
self.graph_inst_exclude.add(inst)
|
||||
@@ -636,7 +636,7 @@ class sram_1bank(sram_base):
|
||||
# Insts located in control logic, exclusion function called here
|
||||
for inst in self.control_logic_insts:
|
||||
inst.mod.graph_exclude_dffs()
|
||||
|
||||
|
||||
def get_cell_name(self, inst_name, row, col):
|
||||
"""
|
||||
Gets the spice name of the target bitcell.
|
||||
@@ -645,6 +645,6 @@ class sram_1bank(sram_base):
|
||||
if inst_name.find("x") != 0:
|
||||
inst_name = "x" + inst_name
|
||||
return self.bank_inst.mod.get_cell_name(inst_name + ".x" + self.bank_inst.name, row, col)
|
||||
|
||||
|
||||
def get_bank_num(self, inst_name, row, col):
|
||||
return 0
|
||||
|
||||
+27
-27
@@ -32,11 +32,11 @@ class sram_2bank(sram_base):
|
||||
# In 2 bank SRAM, the height is determined by the control bus which is higher than the msb address
|
||||
self.vertical_bus_height = self.bank.height + 2*self.bank_to_bus_distance + self.data_bus_height + self.control_bus_height
|
||||
# The address bus extends down through the power rails, but control and bank_sel bus don't
|
||||
self.addr_bus_height = self.vertical_bus_height
|
||||
|
||||
self.addr_bus_height = self.vertical_bus_height
|
||||
|
||||
self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 0)
|
||||
self.data_bus_offset = vector(0, self.bank.height + self.bank_to_bus_distance)
|
||||
self.supply_bus_offset = vector(0, self.data_bus_offset.y + self.data_bus_height)
|
||||
self.supply_bus_offset = vector(0, self.data_bus_offset.y + self.data_bus_height)
|
||||
self.control_bus_offset = vector(0, self.supply_bus_offset.y + self.supply_bus_height)
|
||||
self.bank_sel_bus_offset = self.vertical_bus_offset + vector(self.m2_pitch*self.control_size,0)
|
||||
self.addr_bus_offset = self.bank_sel_bus_offset.scale(1,0) + vector(self.m2_pitch*self.num_banks,0)
|
||||
@@ -49,14 +49,14 @@ class sram_2bank(sram_base):
|
||||
self.msb_address_position = vector(self.bank_inst[1].lx() + 3*self.supply_rail_pitch,
|
||||
self.supply_bus_offset.y + self.supply_bus_height \
|
||||
+ 2*self.m1_pitch + self.msb_address.width)
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
""" Adds the modules and the buses to the top level """
|
||||
|
||||
self.compute_bus_sizes()
|
||||
|
||||
self.add_banks()
|
||||
|
||||
|
||||
self.compute_bank_offsets()
|
||||
|
||||
self.add_busses()
|
||||
@@ -90,7 +90,7 @@ class sram_2bank(sram_base):
|
||||
rotate=270)
|
||||
self.msb_bank_sel_addr = "addr[{}]".format(self.addr_size-1)
|
||||
self.connect_inst([self.msb_bank_sel_addr,"bank_sel[1]","bank_sel[0]","clk_buf", "vdd", "gnd"])
|
||||
|
||||
|
||||
|
||||
def route_shared_banks(self):
|
||||
""" Route the shared signals for two and four bank configurations. """
|
||||
@@ -98,7 +98,7 @@ class sram_2bank(sram_base):
|
||||
# create the input control pins
|
||||
for n in self.control_logic_inputs + ["clk"]:
|
||||
self.copy_layout_pin(self.control_logic_inst, n)
|
||||
|
||||
|
||||
# connect the control logic to the control bus
|
||||
for n in self.control_logic_outputs + ["vdd", "gnd"]:
|
||||
pins = self.control_logic_inst.get_pins(n)
|
||||
@@ -109,7 +109,7 @@ class sram_2bank(sram_base):
|
||||
rail_pos = vector(pin_pos.x,self.horz_control_bus_positions[n].y)
|
||||
self.add_path("m2",[pin_pos,rail_pos])
|
||||
self.add_via_center(self.m1_stack,rail_pos)
|
||||
|
||||
|
||||
# connect the control logic cross bar
|
||||
for n in self.control_logic_outputs:
|
||||
cross_pos = vector(self.vert_control_bus_positions[n].x,self.horz_control_bus_positions[n].y)
|
||||
@@ -125,7 +125,7 @@ class sram_2bank(sram_base):
|
||||
|
||||
def route_single_msb_address(self):
|
||||
""" Route one MSB address bit for 2-bank SRAM """
|
||||
|
||||
|
||||
# connect the bank MSB flop supplies
|
||||
vdd_pins = self.msb_address_inst.get_pins("vdd")
|
||||
for vdd_pin in vdd_pins:
|
||||
@@ -133,11 +133,11 @@ class sram_2bank(sram_base):
|
||||
vdd_pos = vdd_pin.bc()
|
||||
down_pos = vdd_pos - vector(0,self.m1_pitch)
|
||||
rail_pos = vector(vdd_pos.x,self.horz_control_bus_positions["vdd"].y)
|
||||
self.add_path("m1",[vdd_pos,down_pos])
|
||||
self.add_via_center(self.m1_stack,down_pos,rotate=90)
|
||||
self.add_path("m1",[vdd_pos,down_pos])
|
||||
self.add_via_center(self.m1_stack,down_pos,rotate=90)
|
||||
self.add_path("m2",[down_pos,rail_pos])
|
||||
self.add_via_center(self.m1_stack,rail_pos)
|
||||
|
||||
|
||||
gnd_pins = self.msb_address_inst.get_pins("gnd")
|
||||
# Only add the ground connection to the lowest metal2 rail in the flop array
|
||||
# FIXME: SCMOS doesn't have a vertical rail in the cell, or we could use those
|
||||
@@ -149,9 +149,9 @@ class sram_2bank(sram_base):
|
||||
gnd_pos = gnd_pin.ur()
|
||||
rail_pos = vector(gnd_pos.x,self.horz_control_bus_positions["gnd"].y)
|
||||
self.add_path("m2",[gnd_pos,rail_pos])
|
||||
self.add_via_center(self.m1_stack,rail_pos)
|
||||
|
||||
# connect the MSB flop to the address input bus
|
||||
self.add_via_center(self.m1_stack,rail_pos)
|
||||
|
||||
# connect the MSB flop to the address input bus
|
||||
msb_pins = self.msb_address_inst.get_pins("din[0]")
|
||||
for msb_pin in msb_pins:
|
||||
if msb_pin.layer == "m3":
|
||||
@@ -170,7 +170,7 @@ class sram_2bank(sram_base):
|
||||
self.add_path("m2",[msb_out_pos,out_extend_right_pos,out_extend_up_pos])
|
||||
self.add_wire(("m3","via2","m2"),[out_extend_right_pos,out_extend_up_pos,rail_pos])
|
||||
self.add_via_center(self.m2_stack,rail_pos)
|
||||
|
||||
|
||||
# Connect the output to select 1
|
||||
msb_out_pin = self.msb_address_inst.get_pin("dout[0]")
|
||||
msb_out_pos = msb_out_pin.rc()
|
||||
@@ -180,21 +180,21 @@ class sram_2bank(sram_base):
|
||||
self.add_path("m2",[msb_out_pos,out_extend_right_pos,out_extend_down_pos])
|
||||
self.add_wire(("m3","via2","m2"),[out_extend_right_pos,out_extend_down_pos,rail_pos])
|
||||
self.add_via_center(self.m2_stack,rail_pos)
|
||||
|
||||
|
||||
# Connect clk
|
||||
clk_pin = self.msb_address_inst.get_pin("clk")
|
||||
clk_pos = clk_pin.bc()
|
||||
rail_pos = self.horz_control_bus_positions["clk_buf"]
|
||||
bend_pos = vector(clk_pos.x,self.horz_control_bus_positions["clk_buf"].y)
|
||||
self.add_path("m1",[clk_pos,bend_pos,rail_pos])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def route(self):
|
||||
""" Route all of the signals for the two bank SRAM. """
|
||||
|
||||
self.route_shared_banks()
|
||||
|
||||
|
||||
# connect the horizontal control bus to the vertical bus
|
||||
# connect the data output to the data bus
|
||||
for n in self.data_bus_names:
|
||||
@@ -220,21 +220,21 @@ class sram_2bank(sram_base):
|
||||
self.add_via_center(self.m2_stack,rail_pos)
|
||||
|
||||
|
||||
|
||||
|
||||
def add_lvs_correspondence_points(self):
|
||||
"""
|
||||
This adds some points for easier debugging if LVS goes wrong.
|
||||
"""
|
||||
This adds some points for easier debugging if LVS goes wrong.
|
||||
These should probably be turned off by default though, since extraction
|
||||
will show these as ports in the extracted netlist.
|
||||
"""
|
||||
|
||||
|
||||
if self.num_banks==1: return
|
||||
|
||||
|
||||
for n in self.control_bus_names:
|
||||
self.add_label(text=n,
|
||||
layer="m2",
|
||||
layer="m2",
|
||||
offset=self.vert_control_bus_positions[n])
|
||||
for n in self.bank_sel_bus_names:
|
||||
self.add_label(text=n,
|
||||
layer="m2",
|
||||
layer="m2",
|
||||
offset=self.vert_control_bus_positions[n])
|
||||
|
||||
+41
-41
@@ -26,7 +26,7 @@ class sram_base(design, verilog, lef):
|
||||
design.__init__(self, name)
|
||||
lef.__init__(self, ["m1", "m2", "m3", "m4"])
|
||||
verilog.__init__(self)
|
||||
|
||||
|
||||
self.sram_config = sram_config
|
||||
sram_config.set_local_config(self)
|
||||
|
||||
@@ -46,7 +46,7 @@ class sram_base(design, verilog, lef):
|
||||
for port in self.write_ports:
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
self.add_pin("din{0}[{1}]".format(port, bit), "INPUT")
|
||||
|
||||
|
||||
for port in self.all_ports:
|
||||
for bit in range(self.addr_size):
|
||||
self.add_pin("addr{0}[{1}]".format(port, bit), "INPUT")
|
||||
@@ -64,7 +64,7 @@ class sram_base(design, verilog, lef):
|
||||
else:
|
||||
self.control_logic_inputs.append(self.control_logic_r.get_inputs())
|
||||
self.control_logic_outputs.append(self.control_logic_r.get_outputs())
|
||||
|
||||
|
||||
for port in self.all_ports:
|
||||
self.add_pin("csb{}".format(port), "INPUT")
|
||||
for port in self.readwrite_ports:
|
||||
@@ -80,7 +80,7 @@ class sram_base(design, verilog, lef):
|
||||
for port in self.read_ports:
|
||||
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")
|
||||
|
||||
@@ -89,7 +89,7 @@ class sram_base(design, verilog, lef):
|
||||
Add pex labels at the sram level for spice analysis
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
# add pex labels for bitcells
|
||||
for bank_num in range(len(self.bank_insts)):
|
||||
@@ -103,13 +103,13 @@ class sram_base(design, verilog, lef):
|
||||
br_offsets = pex_data[4]
|
||||
bl_meta = pex_data[5]
|
||||
br_meta = pex_data[6]
|
||||
|
||||
|
||||
bl = []
|
||||
br = []
|
||||
|
||||
storage_layer_name = "m1"
|
||||
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]]
|
||||
@@ -166,21 +166,21 @@ class sram_base(design, verilog, lef):
|
||||
|
||||
def create_netlist(self):
|
||||
""" Netlist creation """
|
||||
|
||||
|
||||
start_time = datetime.datetime.now()
|
||||
|
||||
|
||||
# Must create the control logic before pins to get the pins
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_modules()
|
||||
|
||||
|
||||
# This is for the lib file if we don't create layout
|
||||
self.width=0
|
||||
self.height=0
|
||||
|
||||
|
||||
if not OPTS.is_unit_test:
|
||||
print_time("Submodules", datetime.datetime.now(), start_time)
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
""" Layout creation """
|
||||
start_time = datetime.datetime.now()
|
||||
@@ -195,7 +195,7 @@ class sram_base(design, verilog, lef):
|
||||
print_time("Routing", datetime.datetime.now(), start_time)
|
||||
|
||||
self.add_lvs_correspondence_points()
|
||||
|
||||
|
||||
self.offset_all_coordinates()
|
||||
|
||||
highest_coord = self.find_highest_coords()
|
||||
@@ -214,7 +214,7 @@ class sram_base(design, verilog, lef):
|
||||
|
||||
def create_modules(self):
|
||||
debug.error("Must override pure virtual function.", -1)
|
||||
|
||||
|
||||
def route_supplies(self):
|
||||
""" Route the supply grid and connect the pins to them. """
|
||||
|
||||
@@ -244,10 +244,10 @@ class sram_base(design, verilog, lef):
|
||||
from supply_grid_router import supply_grid_router as router
|
||||
rtr=router(grid_stack, self)
|
||||
rtr.route()
|
||||
|
||||
|
||||
def compute_bus_sizes(self):
|
||||
""" Compute the independent bus widths shared between two and four bank SRAMs """
|
||||
|
||||
|
||||
# address size + control signals + one-hot bank select signals
|
||||
self.num_vertical_line = self.addr_size + self.control_size + log(self.num_banks, 2) + 1
|
||||
# data bus size
|
||||
@@ -255,20 +255,20 @@ class sram_base(design, verilog, lef):
|
||||
|
||||
self.vertical_bus_width = self.m2_pitch * self.num_vertical_line
|
||||
# vertical bus height depends on 2 or 4 banks
|
||||
|
||||
|
||||
self.data_bus_height = self.m3_pitch * self.num_horizontal_line
|
||||
self.data_bus_width = 2 * (self.bank.width + self.bank_to_bus_distance) + self.vertical_bus_width
|
||||
|
||||
|
||||
self.control_bus_height = self.m1_pitch * (self.control_size + 2)
|
||||
self.control_bus_width = self.bank.width + self.bank_to_bus_distance + self.vertical_bus_width
|
||||
|
||||
|
||||
self.supply_bus_height = self.m1_pitch * 2 # 2 for vdd/gnd placed with control bus
|
||||
self.supply_bus_width = self.data_bus_width
|
||||
|
||||
# Sanity check to ensure we can fit the control logic above a single bank (0.9 is a hack really)
|
||||
debug.check(self.bank.width + self.vertical_bus_width > 0.9 * self.control_logic.width,
|
||||
"Bank is too small compared to control logic.")
|
||||
|
||||
|
||||
def add_busses(self):
|
||||
""" Add the horizontal and vertical busses """
|
||||
# Vertical bus
|
||||
@@ -304,7 +304,7 @@ class sram_base(design, verilog, lef):
|
||||
offset=self.bank_sel_bus_offset,
|
||||
names=self.bank_sel_bus_names,
|
||||
length=self.vertical_bus_height))
|
||||
|
||||
|
||||
# Horizontal data bus
|
||||
self.data_bus_names = ["DATA{0}[{1}]".format(port, i) for i in range(self.word_size)]
|
||||
self.data_bus_positions = self.create_horizontal_pin_bus(layer="m3",
|
||||
@@ -333,7 +333,7 @@ class sram_base(design, verilog, lef):
|
||||
offset=self.control_bus_offset,
|
||||
names=self.control_bus_names[port],
|
||||
length=self.control_bus_width))
|
||||
|
||||
|
||||
def add_multi_bank_modules(self):
|
||||
""" Create the multibank address flops and bank decoder """
|
||||
from dff_buf_array import dff_buf_array
|
||||
@@ -345,7 +345,7 @@ class sram_base(design, verilog, lef):
|
||||
if self.num_banks>2:
|
||||
self.msb_decoder = self.bank.decoder.pre2_4
|
||||
self.add_mod(self.msb_decoder)
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
self.bitcell = factory.create(module_type=OPTS.bitcell)
|
||||
self.dff = factory.create(module_type="dff")
|
||||
@@ -370,7 +370,7 @@ class sram_base(design, verilog, lef):
|
||||
if self.num_spare_cols:
|
||||
self.spare_wen_dff = factory.create("dff_array", module_name="spare_wen_dff", rows=1, columns=self.num_spare_cols)
|
||||
self.add_mod(self.spare_wen_dff)
|
||||
|
||||
|
||||
# Create the bank module (up to four are instantiated)
|
||||
self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank")
|
||||
self.add_mod(self.bank)
|
||||
@@ -383,7 +383,7 @@ class sram_base(design, verilog, lef):
|
||||
|
||||
c = reload(__import__(OPTS.control_logic))
|
||||
self.mod_control_logic = getattr(c, OPTS.control_logic)
|
||||
|
||||
|
||||
# Create the control logic module for each port type
|
||||
if len(self.readwrite_ports)>0:
|
||||
self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
|
||||
@@ -470,7 +470,7 @@ class sram_base(design, verilog, lef):
|
||||
bank_mirror = "MY"
|
||||
else:
|
||||
bank_mirror = "R0"
|
||||
|
||||
|
||||
bank_inst.place(offset=position,
|
||||
mirror=bank_mirror,
|
||||
rotate=bank_rotation)
|
||||
@@ -483,7 +483,7 @@ class sram_base(design, verilog, lef):
|
||||
for port in self.all_ports:
|
||||
insts.append(self.add_inst(name="row_address{}".format(port),
|
||||
mod=self.row_addr_dff))
|
||||
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
@@ -492,16 +492,16 @@ class sram_base(design, verilog, lef):
|
||||
outputs.append("a{}[{}]".format(port, bit + self.col_addr_size))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
|
||||
|
||||
|
||||
return insts
|
||||
|
||||
|
||||
def create_col_addr_dff(self):
|
||||
""" Add and place all address flops for the column decoder """
|
||||
insts = []
|
||||
for port in self.all_ports:
|
||||
insts.append(self.add_inst(name="col_address{}".format(port),
|
||||
mod=self.col_addr_dff))
|
||||
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
@@ -510,7 +510,7 @@ class sram_base(design, verilog, lef):
|
||||
outputs.append("a{}[{}]".format(port, bit))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
|
||||
|
||||
|
||||
return insts
|
||||
|
||||
def create_data_dff(self):
|
||||
@@ -523,7 +523,7 @@ class sram_base(design, verilog, lef):
|
||||
else:
|
||||
insts.append(None)
|
||||
continue
|
||||
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
@@ -532,7 +532,7 @@ class sram_base(design, verilog, lef):
|
||||
outputs.append("bank_din{}[{}]".format(port, bit))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
|
||||
|
||||
|
||||
return insts
|
||||
|
||||
def create_wmask_dff(self):
|
||||
@@ -556,7 +556,7 @@ class sram_base(design, verilog, lef):
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
|
||||
|
||||
return insts
|
||||
|
||||
|
||||
def create_spare_wen_dff(self):
|
||||
""" Add all spare write enable flops """
|
||||
insts = []
|
||||
@@ -578,7 +578,7 @@ class sram_base(design, verilog, lef):
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
|
||||
|
||||
return insts
|
||||
|
||||
|
||||
def create_control_logic(self):
|
||||
""" Add control logic instances """
|
||||
|
||||
@@ -590,7 +590,7 @@ class sram_base(design, verilog, lef):
|
||||
mod = self.control_logic_w
|
||||
else:
|
||||
mod = self.control_logic_r
|
||||
|
||||
|
||||
insts.append(self.add_inst(name="control{}".format(port), mod=mod))
|
||||
|
||||
# Inputs
|
||||
@@ -608,9 +608,9 @@ class sram_base(design, verilog, lef):
|
||||
temp.append("p_en_bar{}".format(port))
|
||||
temp.extend(["wl_en{}".format(port), "clk_buf{}".format(port), "vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
return insts
|
||||
|
||||
|
||||
def sp_write(self, sp_name, lvs_netlist=False):
|
||||
# Write the entire spice of the object to the file
|
||||
############################################################
|
||||
@@ -626,7 +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"],
|
||||
@@ -644,9 +644,9 @@ class sram_base(design, verilog, lef):
|
||||
Excludes bits in column from being added to graph except target
|
||||
"""
|
||||
self.bank.graph_exclude_bits(targ_row, targ_col)
|
||||
|
||||
|
||||
def clear_exclude_bits(self):
|
||||
"""
|
||||
"""
|
||||
Clears the bit exclusions
|
||||
"""
|
||||
self.bank.clear_exclude_bits()
|
||||
|
||||
@@ -13,7 +13,7 @@ from sram_factory import factory
|
||||
|
||||
class sram_config:
|
||||
""" This is a structure that is used to hold the SRAM configuration options. """
|
||||
|
||||
|
||||
def __init__(self, word_size, num_words, write_size=None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=0):
|
||||
self.word_size = word_size
|
||||
self.num_words = num_words
|
||||
@@ -29,7 +29,7 @@ class sram_config:
|
||||
|
||||
def set_local_config(self, module):
|
||||
""" Copy all of the member variables to the given module for convenience """
|
||||
|
||||
|
||||
members = [attr for attr in dir(self) if not callable(getattr(self, attr)) and not attr.startswith("__")]
|
||||
|
||||
# Copy all the variables to the local module
|
||||
@@ -39,14 +39,14 @@ class sram_config:
|
||||
def compute_sizes(self):
|
||||
""" Computes the organization of the memory using bitcell size by trying to make it square."""
|
||||
|
||||
bitcell = factory.create(module_type="bitcell")
|
||||
|
||||
bitcell = factory.create(module_type=OPTS.bitcell)
|
||||
|
||||
debug.check(self.num_banks in [1, 2, 4],
|
||||
"Valid number of banks are 1 , 2 and 4.")
|
||||
|
||||
self.num_words_per_bank = self.num_words / self.num_banks
|
||||
self.num_bits_per_bank = self.word_size * self.num_words_per_bank
|
||||
|
||||
|
||||
# If this was hard coded, don't dynamically compute it!
|
||||
if not self.words_per_row:
|
||||
# Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry)
|
||||
@@ -64,18 +64,18 @@ class sram_config:
|
||||
self.recompute_sizes()
|
||||
|
||||
def recompute_sizes(self):
|
||||
"""
|
||||
Calculate the auxiliary values assuming fixed number of words per row.
|
||||
This can be called multiple times from the unit test when we reconfigure an
|
||||
"""
|
||||
Calculate the auxiliary values assuming fixed number of words per row.
|
||||
This can be called multiple times from the unit test when we reconfigure an
|
||||
SRAM for testing.
|
||||
"""
|
||||
|
||||
debug.info(1, "Recomputing with words per row: {}".format(self.words_per_row))
|
||||
|
||||
|
||||
# If the banks changed
|
||||
self.num_words_per_bank = self.num_words / self.num_banks
|
||||
self.num_bits_per_bank = self.word_size * self.num_words_per_bank
|
||||
|
||||
|
||||
# Fix the number of columns and rows
|
||||
self.num_cols = int(self.words_per_row * self.word_size)
|
||||
self.num_rows_temp = int(self.num_words_per_bank / self.words_per_row)
|
||||
@@ -116,11 +116,11 @@ class sram_config:
|
||||
debug.check(tentative_num_rows * words_per_row <= 4096,
|
||||
"Number of words exceeds 2048")
|
||||
return int(words_per_row * tentative_num_rows / 512)
|
||||
|
||||
|
||||
# Recompute the words per row given a hard min
|
||||
if (not OPTS.is_unit_test and tentative_num_rows < 16):
|
||||
debug.check(tentative_num_rows * words_per_row >= 16,
|
||||
"Minimum number of rows is 16, but given {0}".format(tentative_num_rows))
|
||||
return int(words_per_row * tentative_num_rows / 16)
|
||||
|
||||
|
||||
return words_per_row
|
||||
|
||||
Reference in New Issue
Block a user