mirror of https://github.com/VLSIDA/OpenRAM.git
Multibank file generation (messy)
This commit is contained in:
parent
3dd65b1a01
commit
22c01d7f27
|
|
@ -7,7 +7,6 @@
|
|||
#
|
||||
import math
|
||||
from tech import spice
|
||||
from verilog_template import verilog_template
|
||||
|
||||
|
||||
class verilog:
|
||||
|
|
@ -16,13 +15,19 @@ class verilog:
|
|||
This is inherited by the sram_base class.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.template = verilog_template('verilog_template.v')
|
||||
self.template.readTemplate()
|
||||
pass
|
||||
|
||||
def verilog_write(self, verilog_name):
|
||||
""" Write a behavioral Verilog model. """
|
||||
self.vf = open(verilog_name, "w")
|
||||
|
||||
self.vf.write("// OpenRAM SRAM model\n")
|
||||
self.vf.write("// Words: {0}\n".format(self.num_words))
|
||||
self.vf.write("// Word size: {0}\n".format(self.word_size))
|
||||
if self.write_size:
|
||||
self.template.setSectionRepeat('WRITE_SIZE_CMT', 1)
|
||||
self.vf.write("// Write size: {0}\n\n".format(self.write_size))
|
||||
else:
|
||||
self.vf.write("\n")
|
||||
|
||||
try:
|
||||
self.vdd_name = spice["power"]
|
||||
|
|
@ -33,13 +38,16 @@ class verilog:
|
|||
except KeyError:
|
||||
self.gnd_name = "gnd"
|
||||
|
||||
self.template.setTextDict('MODULE_NAME', self.name)
|
||||
self.template.setTextDict('VDD', self.vdd_name)
|
||||
self.template.setTextDict('GND', self.gnd_name)
|
||||
if self.num_banks > 1:
|
||||
self.vf.write("module {0}(\n".format(self.name + '_1bank'))
|
||||
else:
|
||||
self.vf.write("module {0}(\n".format(self.name))
|
||||
self.vf.write("`ifdef USE_POWER_PINS\n")
|
||||
self.vf.write(" {},\n".format(self.vdd_name))
|
||||
self.vf.write(" {},\n".format(self.gnd_name))
|
||||
self.vf.write("`endif\n")
|
||||
|
||||
for port in self.all_ports:
|
||||
self.template.cloneSection("PORTS", "PORTS" + str(port))
|
||||
|
||||
if port in self.readwrite_ports:
|
||||
self.vf.write("// Port {0}: RW\n".format(port))
|
||||
elif port in self.read_ports:
|
||||
|
|
@ -129,10 +137,6 @@ class verilog:
|
|||
self.vf.write(" reg [ADDR_WIDTH-1:0] addr{0}_reg;\n".format(port))
|
||||
if port in self.write_ports:
|
||||
self.vf.write(" reg [DATA_WIDTH-1:0] din{0}_reg;\n".format(port))
|
||||
self.vf.write("`ifdef USE_POWER_PINS\n")
|
||||
self.vf.write(" {},\n".format(self.vdd_name))
|
||||
self.vf.write(" {},\n".format(self.gnd_name))
|
||||
self.vf.write("`endif\n")
|
||||
if port in self.read_ports:
|
||||
self.vf.write(" reg [DATA_WIDTH-1:0] dout{0};\n".format(port))
|
||||
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ class bank(design.design):
|
|||
# The local control signals are gated when we have bank select logic,
|
||||
# so this prefix will be added to all of the input signals to create
|
||||
# the internal gated signals.
|
||||
if self.num_banks>1:
|
||||
self.prefix="gated_"
|
||||
else:
|
||||
#if self.num_banks>1:
|
||||
# self.prefix="gated_"
|
||||
#else:
|
||||
self.prefix=""
|
||||
|
||||
self.create_netlist()
|
||||
|
|
@ -98,9 +98,9 @@ class bank(design.design):
|
|||
|
||||
# For more than one bank, we have a bank select and name
|
||||
# the signals gated_*.
|
||||
if self.num_banks > 1:
|
||||
for port in self.all_ports:
|
||||
self.add_pin("bank_sel{}".format(port), "INPUT")
|
||||
#if self.num_banks > 1:
|
||||
# for port in self.all_ports:
|
||||
# self.add_pin("bank_sel{}".format(port), "INPUT")
|
||||
for port in self.read_ports:
|
||||
self.add_pin("s_en{0}".format(port), "INPUT")
|
||||
for port in self.all_ports:
|
||||
|
|
@ -128,8 +128,8 @@ class bank(design.design):
|
|||
self.route_port_address(port)
|
||||
self.route_column_address_lines(port)
|
||||
self.route_control_lines(port)
|
||||
if self.num_banks > 1:
|
||||
self.route_bank_select(port)
|
||||
#if self.num_banks > 1:
|
||||
# self.route_bank_select(port)
|
||||
|
||||
self.route_supplies()
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ class bank(design.design):
|
|||
self.create_port_data()
|
||||
self.create_port_address()
|
||||
self.create_column_decoder()
|
||||
self.create_bank_select()
|
||||
#self.create_bank_select()
|
||||
|
||||
def compute_instance_offsets(self):
|
||||
"""
|
||||
|
|
@ -252,8 +252,8 @@ class bank(design.design):
|
|||
y_offset = min(self.column_decoder_offsets[port].y, self.port_data[port].column_mux_offset.y)
|
||||
else:
|
||||
y_offset = self.port_address_offsets[port].y
|
||||
if self.num_banks > 1:
|
||||
y_offset += self.bank_select.height + drc("well_to_well")
|
||||
#if self.num_banks > 1:
|
||||
# y_offset += self.bank_select.height + drc("well_to_well")
|
||||
self.bank_select_offsets[port] = vector(-x_offset, -y_offset)
|
||||
|
||||
def compute_instance_port1_offsets(self):
|
||||
|
|
@ -311,20 +311,24 @@ class bank(design.design):
|
|||
self.place_port_address(self.port_address_offsets)
|
||||
|
||||
self.place_column_decoder(self.column_decoder_offsets)
|
||||
self.place_bank_select(self.bank_select_offsets)
|
||||
#self.place_bank_select(self.bank_select_offsets)
|
||||
|
||||
def compute_sizes(self):
|
||||
""" Computes the required sizes to create the bank """
|
||||
|
||||
|
||||
self.num_words_per_bank = self.num_words / self.num_banks
|
||||
self.num_bits_per_bank = self.word_size * self.num_words_per_bank
|
||||
|
||||
self.num_cols = int(self.words_per_row * self.word_size)
|
||||
self.num_rows_temp = int(self.num_words / self.words_per_row)
|
||||
self.num_rows_temp = int(self.num_words_per_bank / self.words_per_row)
|
||||
self.num_rows = self.num_rows_temp + self.num_spare_rows
|
||||
|
||||
self.row_addr_size = ceil(log(self.num_rows, 2))
|
||||
self.col_addr_size = int(log(self.words_per_row, 2))
|
||||
self.addr_size = self.col_addr_size + self.row_addr_size
|
||||
|
||||
debug.check(self.num_rows_temp * self.num_cols==self.word_size * self.num_words,
|
||||
debug.check(self.num_rows_temp * self.num_cols * self.num_banks ==self.word_size * self.num_words,
|
||||
"Invalid bank sizes.")
|
||||
debug.check(self.addr_size==self.col_addr_size + self.row_addr_size,
|
||||
"Invalid address break down.")
|
||||
|
|
@ -351,9 +355,9 @@ class bank(design.design):
|
|||
# These will be outputs of the gaters if this is multibank, if not, normal signals.
|
||||
self.control_signals = []
|
||||
for port in self.all_ports:
|
||||
if self.num_banks > 1:
|
||||
self.control_signals.append(["gated_" + str for str in self.input_control_signals[port]])
|
||||
else:
|
||||
#if self.num_banks > 1:
|
||||
# self.control_signals.append(["gated_" + str for str in self.input_control_signals[port]])
|
||||
#else:
|
||||
self.control_signals.append(self.input_control_signals[port])
|
||||
|
||||
|
||||
|
|
@ -406,8 +410,8 @@ class bank(design.design):
|
|||
bit_offsets=self.bit_offsets)
|
||||
self.port_data.append(temp_pre)
|
||||
|
||||
if(self.num_banks > 1):
|
||||
self.bank_select = factory.create(module_type="bank_select")
|
||||
#if(self.num_banks > 1):
|
||||
# self.bank_select = factory.create(module_type="bank_select")
|
||||
|
||||
def create_bitcell_array(self):
|
||||
""" Creating Bitcell Array """
|
||||
|
|
@ -577,7 +581,7 @@ class bank(design.design):
|
|||
def create_bank_select(self):
|
||||
""" Create the bank select logic. """
|
||||
|
||||
if not self.num_banks > 1:
|
||||
if not self.num_banks < 2:
|
||||
return
|
||||
|
||||
self.bank_select_inst = [None] * len(self.all_ports)
|
||||
|
|
@ -595,7 +599,7 @@ class bank(design.design):
|
|||
def place_bank_select(self, offsets):
|
||||
""" Place the bank select logic. """
|
||||
|
||||
if not self.num_banks > 1:
|
||||
if not self.num_banks < 2:
|
||||
return
|
||||
|
||||
debug.check(len(offsets)>=len(self.all_ports),
|
||||
|
|
@ -694,7 +698,8 @@ class bank(design.design):
|
|||
names=self.control_signals[0],
|
||||
length=control_bus_length,
|
||||
vertical=True,
|
||||
make_pins=(self.num_banks==1),
|
||||
#make_pins=(self.num_banks==1),
|
||||
make_pins=(True),
|
||||
pitch=self.m3_pitch)
|
||||
|
||||
self.copy_layout_pin(self.port_address_inst[0], "wl_en", self.prefix + "wl_en0")
|
||||
|
|
@ -711,7 +716,8 @@ class bank(design.design):
|
|||
names=list(reversed(self.control_signals[1])),
|
||||
length=control_bus_length,
|
||||
vertical=True,
|
||||
make_pins=(self.num_banks==1),
|
||||
#make_pins=(self.num_banks==1),
|
||||
make_pins=(True),
|
||||
pitch=self.m3_pitch)
|
||||
|
||||
self.copy_layout_pin(self.port_address_inst[1], "wl_en", self.prefix + "wl_en1")
|
||||
|
|
|
|||
|
|
@ -41,11 +41,6 @@ class sram():
|
|||
|
||||
self.s = sram(name, sram_config)
|
||||
|
||||
if self.num_banks != 1:
|
||||
from sram_multibank import sram_multibank
|
||||
mb = sram_multibank(s)
|
||||
mb.verilog_write()
|
||||
|
||||
self.s.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.s.create_layout()
|
||||
|
|
@ -83,7 +78,11 @@ class sram():
|
|||
shutil.move(unique_name, name)
|
||||
|
||||
def verilog_write(self, name):
|
||||
self.s.verilog_write(name)
|
||||
self.s.verilog_write(name + '_1bank.v')
|
||||
if self.num_banks != 1:
|
||||
from sram_multibank import sram_multibank
|
||||
mb = sram_multibank(self.s)
|
||||
mb.verilog_write(name + '.v')
|
||||
|
||||
def extended_config_write(self, name):
|
||||
"""Dump config file with all options.
|
||||
|
|
@ -184,7 +183,7 @@ class sram():
|
|||
|
||||
# Write a verilog model
|
||||
start_time = datetime.datetime.now()
|
||||
vname = OPTS.output_path + self.s.name + ".v"
|
||||
vname = OPTS.output_path + self.s.name
|
||||
debug.print_raw("Verilog: Writing to {0}".format(vname))
|
||||
self.verilog_write(vname)
|
||||
print_time("Verilog", datetime.datetime.now(), start_time)
|
||||
|
|
|
|||
|
|
@ -6,19 +6,780 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
from vector import vector
|
||||
from sram_base import sram_base
|
||||
from contact import m2_via
|
||||
from channel_route import channel_route
|
||||
from router_tech import router_tech
|
||||
from globals import OPTS
|
||||
from globals import OPTS, print_time
|
||||
import datetime
|
||||
import debug
|
||||
from math import log, ceil
|
||||
from importlib import reload
|
||||
from design import design
|
||||
from verilog import verilog
|
||||
from lef import lef
|
||||
from sram_factory import factory
|
||||
from tech import spice
|
||||
|
||||
|
||||
class sram_1bank(sram_base):
|
||||
class sram_1bank(design, verilog, lef):
|
||||
"""
|
||||
Procedures specific to a one bank SRAM.
|
||||
"""
|
||||
def __init__(self, name, sram_config):
|
||||
sram_base.__init__(self, name, sram_config)
|
||||
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)
|
||||
|
||||
self.bank_insts = []
|
||||
|
||||
if self.write_size:
|
||||
self.num_wmasks = int(ceil(self.word_size / self.write_size))
|
||||
else:
|
||||
self.num_wmasks = 0
|
||||
|
||||
if not self.num_spare_cols:
|
||||
self.num_spare_cols = 0
|
||||
|
||||
try:
|
||||
from tech import power_grid
|
||||
self.supply_stack = power_grid
|
||||
except ImportError:
|
||||
# if no power_grid is specified by tech we use sensible defaults
|
||||
# Route a M3/M4 grid
|
||||
self.supply_stack = self.m3_stack
|
||||
|
||||
def add_pins(self):
|
||||
""" Add pins for entire SRAM. """
|
||||
|
||||
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")
|
||||
|
||||
# These are used to create the physical pins
|
||||
self.control_logic_inputs = []
|
||||
self.control_logic_outputs = []
|
||||
for port in self.all_ports:
|
||||
if port in self.readwrite_ports:
|
||||
self.control_logic_inputs.append(self.control_logic_rw.get_inputs())
|
||||
self.control_logic_outputs.append(self.control_logic_rw.get_outputs())
|
||||
elif port in self.write_ports:
|
||||
self.control_logic_inputs.append(self.control_logic_w.get_inputs())
|
||||
self.control_logic_outputs.append(self.control_logic_w.get_outputs())
|
||||
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:
|
||||
self.add_pin("web{}".format(port), "INPUT")
|
||||
for port in self.all_ports:
|
||||
self.add_pin("clk{}".format(port), "INPUT")
|
||||
# add the optional write mask pins
|
||||
for port in self.write_ports:
|
||||
for bit in range(self.num_wmasks):
|
||||
self.add_pin("wmask{0}[{1}]".format(port, bit), "INPUT")
|
||||
if self.num_spare_cols == 1:
|
||||
self.add_pin("spare_wen{0}".format(port), "INPUT")
|
||||
else:
|
||||
for bit in range(self.num_spare_cols):
|
||||
self.add_pin("spare_wen{0}[{1}]".format(port, bit), "INPUT")
|
||||
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")
|
||||
|
||||
# Standard supply and ground names
|
||||
try:
|
||||
self.vdd_name = spice["power"]
|
||||
except KeyError:
|
||||
self.vdd_name = "vdd"
|
||||
try:
|
||||
self.gnd_name = spice["ground"]
|
||||
except KeyError:
|
||||
self.gnd_name = "gnd"
|
||||
|
||||
self.add_pin(self.vdd_name, "POWER")
|
||||
self.add_pin(self.gnd_name, "GROUND")
|
||||
self.ext_supplies = [self.vdd_name, self.gnd_name]
|
||||
self.ext_supply = {"vdd" : self.vdd_name, "gnd" : self.gnd_name}
|
||||
|
||||
def add_global_pex_labels(self):
|
||||
"""
|
||||
Add pex labels at the sram level for spice analysis
|
||||
"""
|
||||
|
||||
|
||||
|
||||
# add pex labels for bitcells
|
||||
for bank_num in range(len(self.bank_insts)):
|
||||
bank = self.bank_insts[bank_num]
|
||||
pex_data = bank.reverse_transformation_bitcell(self.bitcell.name)
|
||||
|
||||
bank_offset = pex_data[0] # offset bank relative to sram
|
||||
Q_offset = pex_data[1] # offset of storage relative to bank
|
||||
Q_bar_offset = pex_data[2] # offset of storage relative to bank
|
||||
bl_offsets = pex_data[3]
|
||||
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]]
|
||||
Q_bar = [bank_offset[cell][0] + Q_bar_offset[cell][0],
|
||||
bank_offset[cell][1] + Q_bar_offset[cell][1]]
|
||||
OPTS.words_per_row = self.words_per_row
|
||||
row = int(cell % (OPTS.num_words / self.words_per_row))
|
||||
col = int(cell / (OPTS.num_words))
|
||||
self.add_layout_pin_rect_center("bitcell_Q_b{}_r{}_c{}".format(bank_num,
|
||||
row,
|
||||
col),
|
||||
storage_layer_name,
|
||||
Q)
|
||||
self.add_layout_pin_rect_center("bitcell_Q_bar_b{}_r{}_c{}".format(bank_num,
|
||||
row,
|
||||
col),
|
||||
storage_layer_name,
|
||||
Q_bar)
|
||||
|
||||
for cell in range(len(bl_offsets)):
|
||||
col = bl_meta[cell][0][2]
|
||||
for bitline in range(len(bl_offsets[cell])):
|
||||
bitline_location = [float(bank_offset[cell][0]) + bl_offsets[cell][bitline][0],
|
||||
float(bank_offset[cell][1]) + bl_offsets[cell][bitline][1]]
|
||||
bl.append([bitline_location, bl_meta[cell][bitline][3], col])
|
||||
|
||||
for cell in range(len(br_offsets)):
|
||||
col = br_meta[cell][0][2]
|
||||
for bitline in range(len(br_offsets[cell])):
|
||||
bitline_location = [float(bank_offset[cell][0]) + br_offsets[cell][bitline][0],
|
||||
float(bank_offset[cell][1]) + br_offsets[cell][bitline][1]]
|
||||
br.append([bitline_location, br_meta[cell][bitline][3], col])
|
||||
|
||||
for i in range(len(bl)):
|
||||
self.add_layout_pin_rect_center("bl{0}_{1}".format(bl[i][1], bl[i][2]),
|
||||
bitline_layer_name, bl[i][0])
|
||||
|
||||
for i in range(len(br)):
|
||||
self.add_layout_pin_rect_center("br{0}_{1}".format(br[i][1], br[i][2]),
|
||||
bitline_layer_name, br[i][0])
|
||||
|
||||
# add pex labels for control logic
|
||||
for i in range(len(self.control_logic_insts)):
|
||||
instance = self.control_logic_insts[i]
|
||||
control_logic_offset = instance.offset
|
||||
for output in instance.mod.output_list:
|
||||
pin = instance.mod.get_pin(output)
|
||||
pin.transform([0, 0], instance.mirror, instance.rotate)
|
||||
offset = [control_logic_offset[0] + pin.center()[0],
|
||||
control_logic_offset[1] + pin.center()[1]]
|
||||
self.add_layout_pin_rect_center("{0}{1}".format(pin.name, i),
|
||||
storage_layer_name,
|
||||
offset)
|
||||
|
||||
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()
|
||||
self.place_instances()
|
||||
if not OPTS.is_unit_test:
|
||||
print_time("Placement", datetime.datetime.now(), start_time)
|
||||
|
||||
start_time = datetime.datetime.now()
|
||||
self.route_layout()
|
||||
|
||||
if not OPTS.is_unit_test:
|
||||
print_time("Routing", datetime.datetime.now(), start_time)
|
||||
|
||||
self.add_lvs_correspondence_points()
|
||||
|
||||
self.offset_all_coordinates()
|
||||
|
||||
highest_coord = self.find_highest_coords()
|
||||
self.width = highest_coord[0]
|
||||
self.height = highest_coord[1]
|
||||
if OPTS.use_pex and OPTS.pex_exe[0] != "calibre":
|
||||
debug.info(2, "adding global pex labels")
|
||||
self.add_global_pex_labels()
|
||||
self.add_boundary(ll=vector(0, 0),
|
||||
ur=vector(self.width, self.height))
|
||||
|
||||
start_time = datetime.datetime.now()
|
||||
if not OPTS.is_unit_test:
|
||||
# We only enable final verification if we have routed the design
|
||||
# Only run this if not a unit test, because unit test will also verify it.
|
||||
self.DRC_LVS(final_verification=OPTS.route_supplies, force_check=OPTS.check_lvsdrc)
|
||||
print_time("Verification", datetime.datetime.now(), start_time)
|
||||
|
||||
def create_modules(self):
|
||||
debug.error("Must override pure virtual function.", -1)
|
||||
|
||||
def route_supplies(self, bbox=None):
|
||||
""" Route the supply grid and connect the pins to them. """
|
||||
|
||||
# Copy the pins to the top level
|
||||
# This will either be used to route or left unconnected.
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
for inst in self.insts:
|
||||
self.copy_power_pins(inst, pin_name, self.ext_supply[pin_name])
|
||||
|
||||
if not OPTS.route_supplies:
|
||||
# Do not route the power supply (leave as must-connect pins)
|
||||
return
|
||||
elif OPTS.route_supplies == "grid":
|
||||
from supply_grid_router import supply_grid_router as router
|
||||
else:
|
||||
from supply_tree_router import supply_tree_router as router
|
||||
rtr=router(layers=self.supply_stack,
|
||||
design=self,
|
||||
bbox=bbox,
|
||||
pin_type=OPTS.supply_pin_type)
|
||||
|
||||
rtr.route()
|
||||
|
||||
if OPTS.supply_pin_type in ["left", "right", "top", "bottom", "ring"]:
|
||||
# Find the lowest leftest pin for vdd and gnd
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
# Copy the pin shape(s) to rectangles
|
||||
for pin in self.get_pins(pin_name):
|
||||
self.add_rect(pin.layer,
|
||||
pin.ll(),
|
||||
pin.width(),
|
||||
pin.height())
|
||||
|
||||
# Remove the pin shape(s)
|
||||
self.remove_layout_pin(pin_name)
|
||||
|
||||
# Get new pins
|
||||
pins = rtr.get_new_pins(pin_name)
|
||||
for pin in pins:
|
||||
self.add_layout_pin(self.ext_supply[pin_name],
|
||||
pin.layer,
|
||||
pin.ll(),
|
||||
pin.width(),
|
||||
pin.height())
|
||||
|
||||
elif OPTS.route_supplies and OPTS.supply_pin_type == "single":
|
||||
# Update these as we may have routed outside the region (perimeter pins)
|
||||
lowest_coord = self.find_lowest_coords()
|
||||
|
||||
# Find the lowest leftest pin for vdd and gnd
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
# Copy the pin shape(s) to rectangles
|
||||
for pin in self.get_pins(pin_name):
|
||||
self.add_rect(pin.layer,
|
||||
pin.ll(),
|
||||
pin.width(),
|
||||
pin.height())
|
||||
|
||||
# Remove the pin shape(s)
|
||||
self.remove_layout_pin(pin_name)
|
||||
|
||||
# Get the lowest, leftest pin
|
||||
pin = rtr.get_ll_pin(pin_name)
|
||||
|
||||
pin_width = 2 * getattr(self, "{}_width".format(pin.layer))
|
||||
|
||||
# Add it as an IO pin to the perimeter
|
||||
route_width = pin.rx() - lowest_coord.x
|
||||
pin_offset = vector(lowest_coord.x, pin.by())
|
||||
self.add_rect(pin.layer,
|
||||
pin_offset,
|
||||
route_width,
|
||||
pin.height())
|
||||
|
||||
self.add_layout_pin(self.ext_supply[pin_name],
|
||||
pin.layer,
|
||||
pin_offset,
|
||||
pin_width,
|
||||
pin.height())
|
||||
else:
|
||||
# Grid is left with many top level pins
|
||||
pass
|
||||
|
||||
def route_escape_pins(self, bbox):
|
||||
"""
|
||||
Add the top-level pins for a single bank SRAM with control.
|
||||
"""
|
||||
|
||||
# List of pin to new pin name
|
||||
pins_to_route = []
|
||||
for port in self.all_ports:
|
||||
# Connect the control pins as inputs
|
||||
for signal in self.control_logic_inputs[port]:
|
||||
if signal.startswith("rbl"):
|
||||
continue
|
||||
if signal=="clk":
|
||||
pins_to_route.append("{0}{1}".format(signal, port))
|
||||
else:
|
||||
pins_to_route.append("{0}{1}".format(signal, port))
|
||||
|
||||
if port in self.write_ports:
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
pins_to_route.append("din{0}[{1}]".format(port, bit))
|
||||
|
||||
if port in self.readwrite_ports or port in self.read_ports:
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
pins_to_route.append("dout{0}[{1}]".format(port, bit))
|
||||
|
||||
for bit in range(self.col_addr_size):
|
||||
pins_to_route.append("addr{0}[{1}]".format(port, bit))
|
||||
|
||||
for bit in range(self.row_addr_size):
|
||||
pins_to_route.append("addr{0}[{1}]".format(port, bit + self.col_addr_size))
|
||||
|
||||
if port in self.write_ports:
|
||||
if self.write_size:
|
||||
for bit in range(self.num_wmasks):
|
||||
pins_to_route.append("wmask{0}[{1}]".format(port, bit))
|
||||
|
||||
if port in self.write_ports:
|
||||
if self.num_spare_cols == 1:
|
||||
pins_to_route.append("spare_wen{0}".format(port))
|
||||
else:
|
||||
for bit in range(self.num_spare_cols):
|
||||
pins_to_route.append("spare_wen{0}[{1}]".format(port, bit))
|
||||
|
||||
from signal_escape_router import signal_escape_router as router
|
||||
rtr=router(layers=self.m3_stack,
|
||||
design=self,
|
||||
bbox=bbox)
|
||||
rtr.escape_route(pins_to_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 + 1# + log(self.num_banks, 2) + 1
|
||||
# data bus size
|
||||
self.num_horizontal_line = self.word_size
|
||||
|
||||
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
|
||||
# The order of the control signals on the control bus:
|
||||
self.control_bus_names = []
|
||||
for port in self.all_ports:
|
||||
self.control_bus_names[port] = ["clk_buf{}".format(port)]
|
||||
wen = "w_en{}".format(port)
|
||||
sen = "s_en{}".format(port)
|
||||
pen = "p_en_bar{}".format(port)
|
||||
if self.port_id[port] == "r":
|
||||
self.control_bus_names[port].extend([sen, pen])
|
||||
elif self.port_id[port] == "w":
|
||||
self.control_bus_names[port].extend([wen, pen])
|
||||
else:
|
||||
self.control_bus_names[port].extend([sen, wen, pen])
|
||||
self.vert_control_bus_positions = self.create_vertical_bus(layer="m2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=self.vertical_bus_offset,
|
||||
names=self.control_bus_names[port],
|
||||
length=self.vertical_bus_height)
|
||||
|
||||
self.addr_bus_names=["A{0}[{1}]".format(port, i) for i in range(self.addr_size)]
|
||||
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="m2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=self.addr_bus_offset,
|
||||
names=self.addr_bus_names,
|
||||
length=self.addr_bus_height))
|
||||
|
||||
self.bank_sel_bus_names = ["bank_sel{0}_{1}".format(port, i) for i in range(1)]#range(self.num_banks)]
|
||||
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="m2",
|
||||
pitch=self.m2_pitch,
|
||||
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",
|
||||
pitch=self.m3_pitch,
|
||||
offset=self.data_bus_offset,
|
||||
names=self.data_bus_names,
|
||||
length=self.data_bus_width)
|
||||
|
||||
# Horizontal control logic bus
|
||||
# vdd/gnd in bus go along whole SRAM
|
||||
# FIXME: Fatten these wires?
|
||||
self.horz_control_bus_positions = self.create_horizontal_bus(layer="m1",
|
||||
pitch=self.m1_pitch,
|
||||
offset=self.supply_bus_offset,
|
||||
names=["vdd"],
|
||||
length=self.supply_bus_width)
|
||||
# The gnd rail must not be the entire width since we protrude the right-most vdd rail up for
|
||||
# the decoder in 4-bank SRAMs
|
||||
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="m1",
|
||||
pitch=self.m1_pitch,
|
||||
offset=self.supply_bus_offset + vector(0, self.m1_pitch),
|
||||
names=["gnd"],
|
||||
length=self.supply_bus_width))
|
||||
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="m1",
|
||||
pitch=self.m1_pitch,
|
||||
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
|
||||
self.msb_address = dff_buf_array(name="msb_address",
|
||||
rows=1,
|
||||
columns=self.num_banks / 2)
|
||||
|
||||
if self.num_banks>2:
|
||||
self.msb_decoder = self.bank.decoder.pre2_4
|
||||
|
||||
def add_modules(self):
|
||||
self.bitcell = factory.create(module_type=OPTS.bitcell)
|
||||
self.dff = factory.create(module_type="dff")
|
||||
|
||||
# Create the bank module (up to four are instantiated)
|
||||
self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank")
|
||||
|
||||
self.num_spare_cols = self.bank.num_spare_cols
|
||||
|
||||
# Create the address and control flops (but not the clk)
|
||||
self.row_addr_dff = factory.create("dff_array", module_name="row_addr_dff", rows=self.row_addr_size, columns=1)
|
||||
|
||||
if self.col_addr_size > 0:
|
||||
self.col_addr_dff = factory.create("dff_array", module_name="col_addr_dff", rows=1, columns=self.col_addr_size)
|
||||
else:
|
||||
self.col_addr_dff = None
|
||||
|
||||
self.data_dff = factory.create("dff_array", module_name="data_dff", rows=1, columns=self.word_size + self.num_spare_cols)
|
||||
|
||||
if self.write_size:
|
||||
self.wmask_dff = factory.create("dff_array", module_name="wmask_dff", rows=1, columns=self.num_wmasks)
|
||||
|
||||
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)
|
||||
|
||||
# Create bank decoder
|
||||
# if(self.num_banks > 1):
|
||||
# self.add_multi_bank_modules()
|
||||
|
||||
self.bank_count = 0
|
||||
|
||||
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,
|
||||
words_per_row=self.words_per_row,
|
||||
word_size=self.word_size,
|
||||
spare_columns=self.num_spare_cols,
|
||||
sram=self,
|
||||
port_type="rw")
|
||||
if len(self.writeonly_ports) > 0:
|
||||
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
|
||||
words_per_row=self.words_per_row,
|
||||
word_size=self.word_size,
|
||||
spare_columns=self.num_spare_cols,
|
||||
sram=self,
|
||||
port_type="w")
|
||||
if len(self.readonly_ports) > 0:
|
||||
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
|
||||
words_per_row=self.words_per_row,
|
||||
word_size=self.word_size,
|
||||
spare_columns=self.num_spare_cols,
|
||||
sram=self,
|
||||
port_type="r")
|
||||
|
||||
def create_bank(self, bank_num):
|
||||
""" Create a bank """
|
||||
self.bank_insts.append(self.add_inst(name="bank{0}".format(bank_num),
|
||||
mod=self.bank))
|
||||
|
||||
temp = []
|
||||
for port in self.read_ports:
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
temp.append("dout{0}[{1}]".format(port, bit))
|
||||
for port in self.all_ports:
|
||||
temp.append("rbl_bl{0}".format(port))
|
||||
for port in self.write_ports:
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
temp.append("bank_din{0}_{1}".format(port, bit))
|
||||
for port in self.all_ports:
|
||||
for bit in range(self.bank_addr_size):
|
||||
temp.append("a{0}_{1}".format(port, bit))
|
||||
# if(self.num_banks > 1):
|
||||
# for port in self.all_ports:
|
||||
# temp.append("bank_sel{0}_{1}".format(port, bank_num))
|
||||
for port in self.read_ports:
|
||||
temp.append("s_en{0}".format(port))
|
||||
for port in self.all_ports:
|
||||
temp.append("p_en_bar{0}".format(port))
|
||||
for port in self.write_ports:
|
||||
temp.append("w_en{0}".format(port))
|
||||
for bit in range(self.num_wmasks):
|
||||
temp.append("bank_wmask{0}_{1}".format(port, bit))
|
||||
for bit in range(self.num_spare_cols):
|
||||
temp.append("bank_spare_wen{0}_{1}".format(port, bit))
|
||||
for port in self.all_ports:
|
||||
temp.append("wl_en{0}".format(port))
|
||||
temp.extend(self.ext_supplies)
|
||||
self.connect_inst(temp)
|
||||
|
||||
return self.bank_insts[-1]
|
||||
|
||||
def place_bank(self, bank_inst, position, x_flip, y_flip):
|
||||
""" Place a bank at the given position with orientations """
|
||||
|
||||
# x_flip == 1 --> no flip in x_axis
|
||||
# x_flip == -1 --> flip in x_axis
|
||||
# y_flip == 1 --> no flip in y_axis
|
||||
# y_flip == -1 --> flip in y_axis
|
||||
|
||||
# x_flip and y_flip are used for position translation
|
||||
|
||||
if x_flip == -1 and y_flip == -1:
|
||||
bank_rotation = 180
|
||||
else:
|
||||
bank_rotation = 0
|
||||
|
||||
if x_flip == y_flip:
|
||||
bank_mirror = "R0"
|
||||
elif x_flip == -1:
|
||||
bank_mirror = "MX"
|
||||
elif y_flip == -1:
|
||||
bank_mirror = "MY"
|
||||
else:
|
||||
bank_mirror = "R0"
|
||||
|
||||
bank_inst.place(offset=position,
|
||||
mirror=bank_mirror,
|
||||
rotate=bank_rotation)
|
||||
|
||||
return bank_inst
|
||||
|
||||
def create_row_addr_dff(self):
|
||||
""" Add all address flops for the main decoder """
|
||||
insts = []
|
||||
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 = []
|
||||
for bit in range(self.row_addr_size):
|
||||
inputs.append("addr{}[{}]".format(port, bit + self.col_addr_size))
|
||||
outputs.append("a{}_{}".format(port, bit + self.col_addr_size))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
||||
|
||||
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 = []
|
||||
for bit in range(self.col_addr_size):
|
||||
inputs.append("addr{}[{}]".format(port, bit))
|
||||
outputs.append("a{}_{}".format(port, bit))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
||||
|
||||
return insts
|
||||
|
||||
def create_data_dff(self):
|
||||
""" Add and place all data flops """
|
||||
insts = []
|
||||
for port in self.all_ports:
|
||||
if port in self.write_ports:
|
||||
insts.append(self.add_inst(name="data_dff{}".format(port),
|
||||
mod=self.data_dff))
|
||||
else:
|
||||
insts.append(None)
|
||||
continue
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
inputs.append("din{}[{}]".format(port, bit))
|
||||
outputs.append("bank_din{}_{}".format(port, bit))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
||||
|
||||
return insts
|
||||
|
||||
def create_wmask_dff(self):
|
||||
""" Add and place all wmask flops """
|
||||
insts = []
|
||||
for port in self.all_ports:
|
||||
if port in self.write_ports:
|
||||
insts.append(self.add_inst(name="wmask_dff{}".format(port),
|
||||
mod=self.wmask_dff))
|
||||
else:
|
||||
insts.append(None)
|
||||
continue
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
for bit in range(self.num_wmasks):
|
||||
inputs.append("wmask{}[{}]".format(port, bit))
|
||||
outputs.append("bank_wmask{}_{}".format(port, bit))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
||||
|
||||
return insts
|
||||
|
||||
def create_spare_wen_dff(self):
|
||||
""" Add all spare write enable flops """
|
||||
insts = []
|
||||
for port in self.all_ports:
|
||||
if port in self.write_ports:
|
||||
insts.append(self.add_inst(name="spare_wen_dff{}".format(port),
|
||||
mod=self.spare_wen_dff))
|
||||
else:
|
||||
insts.append(None)
|
||||
continue
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
for bit in range(self.num_spare_cols):
|
||||
inputs.append("spare_wen{}[{}]".format(port, bit))
|
||||
outputs.append("bank_spare_wen{}_{}".format(port, bit))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
|
||||
|
||||
return insts
|
||||
|
||||
def create_control_logic(self):
|
||||
""" Add control logic instances """
|
||||
|
||||
insts = []
|
||||
for port in self.all_ports:
|
||||
if port in self.readwrite_ports:
|
||||
mod = self.control_logic_rw
|
||||
elif port in self.write_ports:
|
||||
mod = self.control_logic_w
|
||||
else:
|
||||
mod = self.control_logic_r
|
||||
|
||||
insts.append(self.add_inst(name="control{}".format(port), mod=mod))
|
||||
|
||||
# Inputs
|
||||
temp = ["csb{}".format(port)]
|
||||
if port in self.readwrite_ports:
|
||||
temp.append("web{}".format(port))
|
||||
temp.append("clk{}".format(port))
|
||||
temp.append("rbl_bl{}".format(port))
|
||||
|
||||
# Outputs
|
||||
if port in self.read_ports:
|
||||
temp.append("s_en{}".format(port))
|
||||
if port in self.write_ports:
|
||||
temp.append("w_en{}".format(port))
|
||||
temp.append("p_en_bar{}".format(port))
|
||||
temp.extend(["wl_en{}".format(port), "clk_buf{}".format(port)] + self.ext_supplies)
|
||||
self.connect_inst(temp)
|
||||
|
||||
return insts
|
||||
|
||||
def sp_write(self, sp_name, lvs=False, trim=False):
|
||||
# Write the entire spice of the object to the file
|
||||
############################################################
|
||||
# Spice circuit
|
||||
############################################################
|
||||
sp = open(sp_name, 'w')
|
||||
|
||||
sp.write("**************************************************\n")
|
||||
sp.write("* OpenRAM generated memory.\n")
|
||||
sp.write("* Words: {}\n".format(self.num_words))
|
||||
sp.write("* Data bits: {}\n".format(self.word_size))
|
||||
sp.write("* Banks: {}\n".format(self.num_banks))
|
||||
sp.write("* Column mux: {}:1\n".format(self.words_per_row))
|
||||
sp.write("* Trimmed: {}\n".format(trim))
|
||||
sp.write("* LVS: {}\n".format(lvs))
|
||||
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"],
|
||||
# spice["gnd_name"]))
|
||||
usedMODS = list()
|
||||
self.sp_write_file(sp, usedMODS, lvs=lvs, trim=trim)
|
||||
del usedMODS
|
||||
sp.close()
|
||||
|
||||
def graph_exclude_bits(self, targ_row, targ_col):
|
||||
"""
|
||||
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()
|
||||
|
||||
def graph_exclude_column_mux(self, column_include_num, port):
|
||||
"""
|
||||
Excludes all columns muxes unrelated to the target bit being simulated.
|
||||
"""
|
||||
self.bank.graph_exclude_column_mux(column_include_num, port)
|
||||
|
||||
def graph_clear_column_mux(self, port):
|
||||
"""
|
||||
Clear mux exclusions to allow different bit tests.
|
||||
"""
|
||||
self.bank.graph_clear_column_mux(port)
|
||||
|
||||
def create_modules(self):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -121,7 +121,8 @@ class sram_config:
|
|||
self.row_addr_size = ceil(log(self.num_rows, 2))
|
||||
self.col_addr_size = int(log(self.words_per_row, 2))
|
||||
self.bank_addr_size = self.col_addr_size + self.row_addr_size
|
||||
self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2))
|
||||
#self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2))
|
||||
self.addr_size = self.bank_addr_size
|
||||
debug.info(1, "Row addr size: {}".format(self.row_addr_size)
|
||||
+ " Col addr size: {}".format(self.col_addr_size)
|
||||
+ " Bank addr size: {}".format(self.bank_addr_size))
|
||||
|
|
|
|||
|
|
@ -1,27 +1,32 @@
|
|||
from template import template
|
||||
from globals import OPTS
|
||||
import os
|
||||
from math import ceil, log
|
||||
|
||||
|
||||
class sram_multibank:
|
||||
|
||||
def __init__(self, sram):
|
||||
dict = {
|
||||
rw_ports = [i for i in sram.all_ports if i in sram.read_ports and i in sram.write_ports]
|
||||
r_ports = [i for i in sram.all_ports if i in sram.read_ports and i not in sram.write_ports]
|
||||
w_ports = [i for i in sram.all_ports if i not in sram.read_ports and i in sram.write_ports]
|
||||
self.dict = {
|
||||
'module_name': OPTS.output_name,
|
||||
'bank_module_name': OPTS.output_name + '_1bank',
|
||||
'vdd': 'vdd',
|
||||
'gnd': 'gnd',
|
||||
'ports': sram.all_ports,
|
||||
'rw_ports': sram.readwrite_ports,
|
||||
'r_ports': sram.read_ports,
|
||||
'w_ports': sram.write_ports,
|
||||
'banks': sram.banks,
|
||||
'rw_ports': rw_ports,
|
||||
'r_ports': r_ports,
|
||||
'w_ports': w_ports,
|
||||
'banks': list(range(sram.num_banks)),
|
||||
'data_width': sram.word_size,
|
||||
'addr_width': sram.addr_size,
|
||||
'bank_sel': list(range(sram.num_banks)),
|
||||
'addr_width': sram.addr_size + ceil(log(sram.num_banks, 2)),
|
||||
'bank_sel': ceil(log(sram.num_banks, 2)),
|
||||
'num_wmask': sram.num_wmasks
|
||||
}
|
||||
|
||||
def verilog_write():
|
||||
t = template('../sram/sram_multibank_template.v', dict)
|
||||
t.write(OPTS.output_name + '.v')
|
||||
|
||||
def verilog_write(self, name):
|
||||
template_filename = os.path.join(os.path.abspath(os.environ["OPENRAM_HOME"]), "sram/sram_multibank_template.v")
|
||||
t = template(template_filename, self.dict)
|
||||
t.write(name)
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ module {{ module_name }} (
|
|||
end
|
||||
{% endfor %}
|
||||
|
||||
{% for port in ports %}
|
||||
{% for port in rw_ports %}
|
||||
always @(*) begin
|
||||
{% for bank in banks %}
|
||||
csb{{ port }}_bank{{ bank }} = 1'b1;
|
||||
|
|
@ -143,4 +143,35 @@ module {{ module_name }} (
|
|||
end
|
||||
{% endfor %}
|
||||
|
||||
{% for port in w_ports %}
|
||||
always @(*) begin
|
||||
{% for bank in banks %}
|
||||
csb{{ port }}_bank{{ bank }} = 1'b1;
|
||||
web{{ port }}_bank{{ bank }} = 1'b1;
|
||||
{% endfor %}
|
||||
case (addr{{ port }}[ADDR_WIDTH - 1 : ADDR_WIDTH - BANK_SEL])
|
||||
{% for bank in banks %}
|
||||
{{ bank }}: begin
|
||||
web{{ port }}_bank{{ bank }} = web{{ port }};
|
||||
csb{{ port }}_bank{{ bank }} = csb{{ port }};
|
||||
end
|
||||
{% endfor %}
|
||||
endcase
|
||||
end
|
||||
{% endfor %}
|
||||
|
||||
{% for port in r_ports %}
|
||||
always @(*) begin
|
||||
{% for bank in banks %}
|
||||
csb{{ port }}_bank{{ bank }} = 1'b1;
|
||||
{% endfor %}
|
||||
case (addr{{ port }}[ADDR_WIDTH - 1 : ADDR_WIDTH - BANK_SEL])
|
||||
{% for bank in banks %}
|
||||
{{ bank }}: begin
|
||||
csb{{ port }}_bank{{ bank }} = csb{{ port }};
|
||||
end
|
||||
{% endfor %}
|
||||
endcase
|
||||
end
|
||||
{% endfor %}
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import re
|
||||
|
||||
|
||||
class baseSection:
|
||||
children = []
|
||||
|
||||
|
|
@ -7,6 +8,7 @@ class baseSection:
|
|||
for c in self.children:
|
||||
c.expand(dict, fd)
|
||||
|
||||
|
||||
class loopSection(baseSection):
|
||||
|
||||
def __init__(self, var, key):
|
||||
|
|
@ -22,12 +24,13 @@ class loopSection(baseSection):
|
|||
if self.var in dict:
|
||||
del dict[self.var]
|
||||
|
||||
|
||||
class textSection(baseSection):
|
||||
|
||||
def __init__(self, text):
|
||||
self.text = text
|
||||
|
||||
def expand(self, dict):
|
||||
def expand(self, dict, fd):
|
||||
var_re = re.compile('\{\{ (\S*) \}\}')
|
||||
vars = var_re.finditer(self.text)
|
||||
newText = self.text
|
||||
|
|
@ -35,6 +38,7 @@ class textSection(baseSection):
|
|||
newText = newText.replace('{{ ' + var.group(1) + ' }}', str(dict[var.group(1)]))
|
||||
print(newText, end='', file=fd)
|
||||
|
||||
|
||||
class template:
|
||||
|
||||
def __init__(self, template, dict):
|
||||
|
|
@ -69,4 +73,3 @@ class template:
|
|||
self.readTemplate()
|
||||
self.baseSectionSection.expand(self.dict, fd)
|
||||
fd.close()
|
||||
|
||||
Loading…
Reference in New Issue