2019-04-26 21:21:50 +02:00
|
|
|
# See LICENSE for licensing information.
|
|
|
|
|
#
|
2019-06-14 17:43:41 +02:00
|
|
|
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
|
|
|
|
# of Regents for the Oklahoma Agricultural and Mechanical College
|
|
|
|
|
# (acting for and on behalf of Oklahoma State University)
|
|
|
|
|
# All rights reserved.
|
2019-04-26 21:21:50 +02:00
|
|
|
#
|
2018-09-04 19:47:24 +02:00
|
|
|
import debug
|
|
|
|
|
from math import log,sqrt,ceil
|
|
|
|
|
from importlib import reload
|
2018-08-31 21:03:28 +02:00
|
|
|
from globals import OPTS
|
2019-01-17 01:15:38 +01:00
|
|
|
from sram_factory import factory
|
2018-08-31 21:03:28 +02:00
|
|
|
|
|
|
|
|
class sram_config:
|
|
|
|
|
""" This is a structure that is used to hold the SRAM configuration options. """
|
|
|
|
|
|
2020-07-13 21:37:56 +02:00
|
|
|
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):
|
2018-08-31 21:03:28 +02:00
|
|
|
self.word_size = word_size
|
|
|
|
|
self.num_words = num_words
|
2019-06-29 00:43:09 +02:00
|
|
|
self.write_size = write_size
|
2018-08-31 21:03:28 +02:00
|
|
|
self.num_banks = num_banks
|
2019-12-08 14:24:39 +01:00
|
|
|
self.num_spare_rows = num_spare_rows
|
2020-04-14 05:09:10 +02:00
|
|
|
self.num_spare_cols = num_spare_cols
|
2018-08-31 21:03:28 +02:00
|
|
|
|
|
|
|
|
# This will get over-written when we determine the organization
|
2019-01-30 20:43:47 +01:00
|
|
|
self.words_per_row = words_per_row
|
2018-08-31 21:03:28 +02:00
|
|
|
|
2020-04-14 05:09:10 +02:00
|
|
|
self.compute_sizes()
|
2018-08-31 21:03:28 +02:00
|
|
|
|
|
|
|
|
def set_local_config(self, module):
|
2018-09-04 19:47:24 +02:00
|
|
|
""" 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
|
|
|
|
|
for member in members:
|
|
|
|
|
setattr(module,member,getattr(self,member))
|
|
|
|
|
|
|
|
|
|
def compute_sizes(self):
|
|
|
|
|
""" Computes the organization of the memory using bitcell size by trying to make it square."""
|
|
|
|
|
|
2019-07-05 17:18:58 +02:00
|
|
|
bitcell = factory.create(module_type="bitcell")
|
2018-08-31 21:03:28 +02:00
|
|
|
|
|
|
|
|
|
2018-09-04 19:47:24 +02:00
|
|
|
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)
|
2019-07-05 17:18:58 +02:00
|
|
|
self.bank_area = bitcell.width*bitcell.height*self.num_bits_per_bank
|
2018-09-04 19:47:24 +02:00
|
|
|
self.bank_side_length = sqrt(self.bank_area)
|
|
|
|
|
|
|
|
|
|
# Estimate the words per row given the height of the bitcell and the square side length
|
2019-07-05 17:18:58 +02:00
|
|
|
self.tentative_num_cols = int(self.bank_side_length/bitcell.width)
|
2018-09-04 19:47:24 +02:00
|
|
|
self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size)
|
|
|
|
|
|
|
|
|
|
# Estimate the number of rows given the tentative words per row
|
|
|
|
|
self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size)
|
|
|
|
|
self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row)
|
2018-10-23 02:02:21 +02:00
|
|
|
|
2019-07-19 23:58:37 +02:00
|
|
|
self.recompute_sizes()
|
2018-12-06 22:11:47 +01:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
SRAM for testing.
|
|
|
|
|
"""
|
|
|
|
|
|
2019-08-05 22:53:14 +02:00
|
|
|
debug.info(1,"Recomputing with words per row: {}".format(self.words_per_row))
|
|
|
|
|
|
2018-12-06 22:11:47 +01:00
|
|
|
# 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
|
|
|
|
|
|
2018-09-04 19:47:24 +02:00
|
|
|
# Fix the number of columns and rows
|
|
|
|
|
self.num_cols = int(self.words_per_row*self.word_size)
|
2019-12-08 14:24:39 +01:00
|
|
|
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
|
2020-03-22 21:54:49 +01:00
|
|
|
debug.info(1,"Rows: {} Cols: {}".format(self.num_rows_temp,self.num_cols))
|
2018-09-04 19:47:24 +02:00
|
|
|
|
|
|
|
|
# Compute the address and bank sizes
|
2019-12-08 14:24:39 +01:00
|
|
|
self.row_addr_size = ceil(log(self.num_rows, 2))
|
2018-09-04 19:47:24 +02:00
|
|
|
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))
|
2019-08-05 22:53:14 +02:00
|
|
|
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))
|
2018-09-04 19:47:24 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def estimate_words_per_row(self,tentative_num_cols, word_size):
|
|
|
|
|
"""
|
|
|
|
|
This provides a heuristic rounded estimate for the number of words
|
|
|
|
|
per row.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
if tentative_num_cols < 1.5*word_size:
|
|
|
|
|
return 1
|
2018-12-06 22:23:39 +01:00
|
|
|
elif tentative_num_cols < 3*word_size:
|
|
|
|
|
return 2
|
|
|
|
|
elif tentative_num_cols < 6*word_size:
|
2018-09-04 19:47:24 +02:00
|
|
|
return 4
|
|
|
|
|
else:
|
2018-12-06 22:57:38 +01:00
|
|
|
if tentative_num_cols > 16*word_size:
|
2018-12-06 22:23:39 +01:00
|
|
|
debug.warning("Reaching column mux size limit. Consider increasing above 8-way.")
|
|
|
|
|
return 8
|
2018-08-31 21:03:28 +02:00
|
|
|
|
2018-09-04 19:47:24 +02:00
|
|
|
def amend_words_per_row(self,tentative_num_rows, words_per_row):
|
|
|
|
|
"""
|
|
|
|
|
This picks the number of words per row more accurately by limiting
|
|
|
|
|
it to a minimum and maximum.
|
|
|
|
|
"""
|
|
|
|
|
# Recompute the words per row given a hard max
|
|
|
|
|
if(not OPTS.is_unit_test and tentative_num_rows > 512):
|
|
|
|
|
debug.check(tentative_num_rows*words_per_row <= 2048, "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
|