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-10-04 18:29:44 +02:00
|
|
|
import sys,re,shutil
|
|
|
|
|
from design import design
|
|
|
|
|
import debug
|
|
|
|
|
import math
|
|
|
|
|
import tech
|
|
|
|
|
from .stimuli import *
|
|
|
|
|
from .trim_spice import *
|
|
|
|
|
from .charutils import *
|
|
|
|
|
import utils
|
|
|
|
|
from globals import OPTS
|
|
|
|
|
|
|
|
|
|
class simulation():
|
|
|
|
|
|
|
|
|
|
def __init__(self, sram, spfile, corner):
|
|
|
|
|
self.sram = sram
|
|
|
|
|
|
|
|
|
|
self.name = self.sram.name
|
|
|
|
|
self.word_size = self.sram.word_size
|
|
|
|
|
self.addr_size = self.sram.addr_size
|
2019-07-03 19:14:15 +02:00
|
|
|
self.write_size = self.sram.write_size
|
2020-02-20 18:01:52 +01:00
|
|
|
self.num_spare_rows = self.sram.num_spare_rows
|
2020-06-03 14:31:30 +02:00
|
|
|
if not self.sram.num_spare_cols:
|
|
|
|
|
self.num_spare_cols = 0
|
|
|
|
|
else:
|
|
|
|
|
self.num_spare_cols = self.sram.num_spare_cols
|
2018-10-04 18:29:44 +02:00
|
|
|
self.sp_file = spfile
|
|
|
|
|
|
2018-11-08 21:19:40 +01:00
|
|
|
self.all_ports = self.sram.all_ports
|
|
|
|
|
self.readwrite_ports = self.sram.readwrite_ports
|
|
|
|
|
self.read_ports = self.sram.read_ports
|
|
|
|
|
self.write_ports = self.sram.write_ports
|
2020-02-20 18:01:52 +01:00
|
|
|
self.words_per_row = self.sram.words_per_row
|
2019-08-21 23:29:57 +02:00
|
|
|
if self.write_size:
|
2019-07-19 23:58:37 +02:00
|
|
|
self.num_wmasks = int(self.word_size/self.write_size)
|
|
|
|
|
else:
|
|
|
|
|
self.num_wmasks = 0
|
|
|
|
|
|
2018-10-04 18:29:44 +02:00
|
|
|
def set_corner(self,corner):
|
|
|
|
|
""" Set the corner values """
|
|
|
|
|
self.corner = corner
|
|
|
|
|
(self.process, self.vdd_voltage, self.temperature) = corner
|
|
|
|
|
|
|
|
|
|
def set_spice_constants(self):
|
|
|
|
|
""" sets feasible timing parameters """
|
|
|
|
|
self.period = tech.spice["feasible_period"]
|
|
|
|
|
self.slew = tech.spice["rise_time"]*2
|
2019-09-05 01:08:18 +02:00
|
|
|
self.load = tech.spice["dff_in_cap"]*4
|
2018-11-29 01:55:04 +01:00
|
|
|
|
2019-09-05 01:53:58 +02:00
|
|
|
self.v_high = self.vdd_voltage - tech.spice["nom_threshold"]
|
|
|
|
|
self.v_low = tech.spice["nom_threshold"]
|
2018-10-04 18:29:44 +02:00
|
|
|
self.gnd_voltage = 0
|
|
|
|
|
|
2019-05-14 10:15:50 +02:00
|
|
|
def create_signal_names(self):
|
2019-08-21 22:45:34 +02:00
|
|
|
self.addr_name = "a"
|
|
|
|
|
self.din_name = "din"
|
|
|
|
|
self.dout_name = "dout"
|
2019-05-14 10:15:50 +02:00
|
|
|
self.pins = self.gen_pin_names(port_signal_names=(self.addr_name,self.din_name,self.dout_name),
|
|
|
|
|
port_info=(len(self.all_ports),self.write_ports,self.read_ports),
|
|
|
|
|
abits=self.addr_size,
|
2020-06-03 14:31:30 +02:00
|
|
|
dbits=self.word_size + self.num_spare_cols)
|
2019-09-06 21:09:12 +02:00
|
|
|
debug.check(len(self.sram.pins) == len(self.pins),
|
|
|
|
|
"Number of pins generated for characterization \
|
2020-06-03 14:31:30 +02:00
|
|
|
do not match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(self.sram.pins,
|
2019-09-06 21:09:12 +02:00
|
|
|
self.pins))
|
2019-05-14 10:15:50 +02:00
|
|
|
#This is TODO once multiport control has been finalized.
|
|
|
|
|
#self.control_name = "CSB"
|
|
|
|
|
|
2018-10-04 18:29:44 +02:00
|
|
|
def set_stimulus_variables(self):
|
|
|
|
|
# Clock signals
|
|
|
|
|
self.cycle_times = []
|
|
|
|
|
self.t_current = 0
|
|
|
|
|
|
|
|
|
|
# control signals: only one cs_b for entire multiported sram, one we_b for each write port
|
2019-09-06 21:09:12 +02:00
|
|
|
self.csb_values = {port:[] for port in self.all_ports}
|
|
|
|
|
self.web_values = {port:[] for port in self.readwrite_ports}
|
|
|
|
|
|
|
|
|
|
# Raw values added as a bit vector
|
|
|
|
|
self.addr_value = {port:[] for port in self.all_ports}
|
|
|
|
|
self.data_value = {port:[] for port in self.write_ports}
|
|
|
|
|
self.wmask_value = {port:[] for port in self.write_ports}
|
2020-06-03 14:31:30 +02:00
|
|
|
self.spare_wen_value = {port:[] for port in self.write_ports}
|
2019-09-06 21:09:12 +02:00
|
|
|
|
|
|
|
|
# Three dimensional list to handle each addr and data bits for each port over the number of checks
|
|
|
|
|
self.addr_values = {port:[[] for bit in range(self.addr_size)] for port in self.all_ports}
|
2020-06-03 14:31:30 +02:00
|
|
|
self.data_values = {port:[[] for bit in range(self.word_size + self.num_spare_cols)] for port in self.write_ports}
|
2019-09-06 21:09:12 +02:00
|
|
|
self.wmask_values = {port:[[] for bit in range(self.num_wmasks)] for port in self.write_ports}
|
2020-06-03 14:31:30 +02:00
|
|
|
self.spare_wen_values = {port:[[] for bit in range(self.num_spare_cols)] for port in self.write_ports}
|
2018-10-08 15:34:36 +02:00
|
|
|
|
|
|
|
|
# For generating comments in SPICE stimulus
|
|
|
|
|
self.cycle_comments = []
|
2018-10-25 09:36:46 +02:00
|
|
|
self.fn_cycle_comments = []
|
2018-10-04 18:29:44 +02:00
|
|
|
|
|
|
|
|
def add_control_one_port(self, port, op):
|
|
|
|
|
"""Appends control signals for operation to a given port"""
|
|
|
|
|
#Determine values to write to port
|
|
|
|
|
web_val = 1
|
|
|
|
|
csb_val = 1
|
|
|
|
|
if op == "read":
|
2018-10-08 15:34:36 +02:00
|
|
|
csb_val = 0
|
2018-10-04 18:29:44 +02:00
|
|
|
elif op == "write":
|
|
|
|
|
csb_val = 0
|
|
|
|
|
web_val = 0
|
|
|
|
|
elif op != "noop":
|
|
|
|
|
debug.error("Could not add control signals for port {0}. Command {1} not recognized".format(port,op),1)
|
|
|
|
|
|
|
|
|
|
# Append the values depending on the type of port
|
|
|
|
|
self.csb_values[port].append(csb_val)
|
|
|
|
|
# If port is in both lists, add rw control signal. Condition indicates its a RW port.
|
2018-11-08 21:19:40 +01:00
|
|
|
if port in self.readwrite_ports:
|
2018-10-04 18:29:44 +02:00
|
|
|
self.web_values[port].append(web_val)
|
|
|
|
|
|
|
|
|
|
def add_data(self, data, port):
|
|
|
|
|
""" Add the array of data values """
|
2020-06-03 14:31:30 +02:00
|
|
|
debug.check(len(data)==(self.word_size + self.num_spare_cols), "Invalid data word size.")
|
2019-09-06 21:09:12 +02:00
|
|
|
|
|
|
|
|
self.data_value[port].append(data)
|
2020-06-03 14:31:30 +02:00
|
|
|
bit = self.word_size + self.num_spare_cols - 1
|
2018-10-04 18:29:44 +02:00
|
|
|
for c in data:
|
|
|
|
|
if c=="0":
|
|
|
|
|
self.data_values[port][bit].append(0)
|
|
|
|
|
elif c=="1":
|
|
|
|
|
self.data_values[port][bit].append(1)
|
|
|
|
|
else:
|
|
|
|
|
debug.error("Non-binary data string",1)
|
|
|
|
|
bit -= 1
|
|
|
|
|
|
|
|
|
|
def add_address(self, address, port):
|
|
|
|
|
""" Add the array of address values """
|
|
|
|
|
debug.check(len(address)==self.addr_size, "Invalid address size.")
|
|
|
|
|
|
2019-09-06 21:09:12 +02:00
|
|
|
self.addr_value[port].append(address)
|
2018-10-04 18:29:44 +02:00
|
|
|
bit = self.addr_size - 1
|
|
|
|
|
for c in address:
|
|
|
|
|
if c=="0":
|
|
|
|
|
self.addr_values[port][bit].append(0)
|
|
|
|
|
elif c=="1":
|
2020-06-03 14:31:30 +02:00
|
|
|
self.addr_values[port][bit].append(1)
|
2018-10-04 18:29:44 +02:00
|
|
|
else:
|
|
|
|
|
debug.error("Non-binary address string",1)
|
|
|
|
|
bit -= 1
|
2019-07-19 22:17:55 +02:00
|
|
|
|
2019-09-06 21:09:12 +02:00
|
|
|
|
2019-07-19 22:17:55 +02:00
|
|
|
def add_wmask(self, wmask, port):
|
|
|
|
|
""" Add the array of address values """
|
2019-07-22 20:19:14 +02:00
|
|
|
debug.check(len(wmask) == self.num_wmasks, "Invalid wmask size.")
|
2019-07-19 22:17:55 +02:00
|
|
|
|
2019-09-06 21:09:12 +02:00
|
|
|
self.wmask_value[port].append(wmask)
|
2019-07-24 00:58:54 +02:00
|
|
|
bit = self.num_wmasks - 1
|
2019-07-19 22:17:55 +02:00
|
|
|
for c in wmask:
|
|
|
|
|
if c == "0":
|
|
|
|
|
self.wmask_values[port][bit].append(0)
|
|
|
|
|
elif c == "1":
|
|
|
|
|
self.wmask_values[port][bit].append(1)
|
|
|
|
|
else:
|
2019-07-24 00:58:54 +02:00
|
|
|
debug.error("Non-binary wmask string", 1)
|
2019-07-19 22:17:55 +02:00
|
|
|
bit -= 1
|
2019-09-06 21:09:12 +02:00
|
|
|
|
2020-06-03 14:31:30 +02:00
|
|
|
def add_spare_wen(self, spare_wen, port):
|
|
|
|
|
""" Add the array of spare write enable values (for spare cols) """
|
|
|
|
|
debug.check(len(spare_wen) == self.num_spare_cols, "Invalid spare enable size.")
|
|
|
|
|
|
|
|
|
|
self.spare_wen_value[port].append(spare_wen)
|
|
|
|
|
bit = self.num_spare_cols - 1
|
|
|
|
|
for c in spare_wen:
|
|
|
|
|
if c == "0":
|
|
|
|
|
self.spare_wen_values[port][bit].append(0)
|
|
|
|
|
elif c == "1":
|
|
|
|
|
self.spare_wen_values[port][bit].append(1)
|
|
|
|
|
else:
|
|
|
|
|
debug.error("Non-binary spare enable signal string", 1)
|
|
|
|
|
bit -= 1
|
|
|
|
|
|
2019-07-24 00:58:54 +02:00
|
|
|
def add_write(self, comment, address, data, wmask, port):
|
2018-10-04 18:29:44 +02:00
|
|
|
""" Add the control values for a write cycle. """
|
2019-09-06 21:09:12 +02:00
|
|
|
debug.check(port in self.write_ports,
|
|
|
|
|
"Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port,
|
|
|
|
|
self.write_ports))
|
2018-10-25 09:36:46 +02:00
|
|
|
debug.info(2, comment)
|
|
|
|
|
self.fn_cycle_comments.append(comment)
|
2018-10-10 02:44:28 +02:00
|
|
|
self.append_cycle_comment(port, comment)
|
2018-10-25 08:29:09 +02:00
|
|
|
|
2018-10-04 18:29:44 +02:00
|
|
|
self.cycle_times.append(self.t_current)
|
|
|
|
|
self.t_current += self.period
|
|
|
|
|
|
|
|
|
|
self.add_control_one_port(port, "write")
|
|
|
|
|
self.add_data(data,port)
|
|
|
|
|
self.add_address(address,port)
|
2020-06-08 07:02:04 +02:00
|
|
|
self.add_wmask(wmask,port)
|
2020-06-03 14:31:30 +02:00
|
|
|
self.add_spare_wen("1" * self.num_spare_cols, port)
|
2018-10-04 18:29:44 +02:00
|
|
|
|
|
|
|
|
#Add noops to all other ports.
|
2018-11-08 21:19:40 +01:00
|
|
|
for unselected_port in self.all_ports:
|
2018-10-04 18:29:44 +02:00
|
|
|
if unselected_port != port:
|
2019-09-06 21:09:12 +02:00
|
|
|
self.add_noop_one_port(unselected_port)
|
2018-10-04 18:29:44 +02:00
|
|
|
|
2019-09-06 21:09:12 +02:00
|
|
|
def add_read(self, comment, address, port):
|
2018-10-04 18:29:44 +02:00
|
|
|
""" Add the control values for a read cycle. """
|
2019-09-06 21:09:12 +02:00
|
|
|
debug.check(port in self.read_ports,
|
|
|
|
|
"Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port,
|
|
|
|
|
self.read_ports))
|
2018-10-25 09:36:46 +02:00
|
|
|
debug.info(2, comment)
|
|
|
|
|
self.fn_cycle_comments.append(comment)
|
2018-10-10 02:44:28 +02:00
|
|
|
self.append_cycle_comment(port, comment)
|
2018-10-25 09:36:46 +02:00
|
|
|
|
2018-10-04 18:29:44 +02:00
|
|
|
self.cycle_times.append(self.t_current)
|
|
|
|
|
self.t_current += self.period
|
|
|
|
|
self.add_control_one_port(port, "read")
|
2020-06-08 07:02:04 +02:00
|
|
|
self.add_address(address, port)
|
|
|
|
|
|
2019-09-06 21:09:12 +02:00
|
|
|
# If the port is also a readwrite then add
|
|
|
|
|
# the same value as previous cycle
|
2018-11-08 21:19:40 +01:00
|
|
|
if port in self.write_ports:
|
2019-09-06 21:09:12 +02:00
|
|
|
try:
|
|
|
|
|
self.add_data(self.data_value[port][-1], port)
|
|
|
|
|
except:
|
2020-06-03 14:31:30 +02:00
|
|
|
self.add_data("0"*(self.word_size + self.num_spare_cols), port)
|
2019-09-06 21:09:12 +02:00
|
|
|
try:
|
|
|
|
|
self.add_wmask(self.wmask_value[port][-1], port)
|
|
|
|
|
except:
|
|
|
|
|
self.add_wmask("0"*self.num_wmasks, port)
|
2020-06-08 07:02:04 +02:00
|
|
|
self.add_spare_wen("0" * self.num_spare_cols, port)
|
2018-10-04 18:29:44 +02:00
|
|
|
|
|
|
|
|
#Add noops to all other ports.
|
2018-11-08 21:19:40 +01:00
|
|
|
for unselected_port in self.all_ports:
|
2018-10-04 18:29:44 +02:00
|
|
|
if unselected_port != port:
|
2019-09-06 21:09:12 +02:00
|
|
|
self.add_noop_one_port(unselected_port)
|
2018-10-08 15:34:36 +02:00
|
|
|
|
2019-09-06 21:09:12 +02:00
|
|
|
def add_noop_all_ports(self, comment):
|
2018-10-08 15:34:36 +02:00
|
|
|
""" Add the control values for a noop to all ports. """
|
2018-10-10 02:44:28 +02:00
|
|
|
debug.info(2, comment)
|
2018-10-25 09:36:46 +02:00
|
|
|
self.fn_cycle_comments.append(comment)
|
2018-10-10 02:44:28 +02:00
|
|
|
self.append_cycle_comment("All", comment)
|
2018-10-25 09:36:46 +02:00
|
|
|
|
2018-10-08 15:34:36 +02:00
|
|
|
self.cycle_times.append(self.t_current)
|
|
|
|
|
self.t_current += self.period
|
|
|
|
|
|
2018-11-08 21:19:40 +01:00
|
|
|
for port in self.all_ports:
|
2019-09-06 21:09:12 +02:00
|
|
|
self.add_noop_one_port(port)
|
2019-07-24 00:58:54 +02:00
|
|
|
|
|
|
|
|
def add_write_one_port(self, comment, address, data, wmask, port):
|
2018-10-08 15:34:36 +02:00
|
|
|
""" Add the control values for a write cycle. Does not increment the period. """
|
2019-09-06 21:09:12 +02:00
|
|
|
debug.check(port in self.write_ports,
|
|
|
|
|
"Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port,
|
|
|
|
|
self.write_ports))
|
2018-10-25 09:36:46 +02:00
|
|
|
debug.info(2, comment)
|
|
|
|
|
self.fn_cycle_comments.append(comment)
|
2019-07-22 20:19:14 +02:00
|
|
|
|
2018-10-08 15:34:36 +02:00
|
|
|
self.add_control_one_port(port, "write")
|
2019-09-06 21:09:12 +02:00
|
|
|
self.add_data(data, port)
|
|
|
|
|
self.add_address(address, port)
|
|
|
|
|
self.add_wmask(wmask, port)
|
2020-06-03 14:31:30 +02:00
|
|
|
self.add_spare_wen("1" * self.num_spare_cols, port)
|
2018-10-04 18:29:44 +02:00
|
|
|
|
2019-09-06 21:09:12 +02:00
|
|
|
def add_read_one_port(self, comment, address, port):
|
2018-10-08 15:34:36 +02:00
|
|
|
""" Add the control values for a read cycle. Does not increment the period. """
|
2019-09-06 21:09:12 +02:00
|
|
|
debug.check(port in self.read_ports,
|
|
|
|
|
"Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port,
|
|
|
|
|
self.read_ports))
|
2018-10-25 09:36:46 +02:00
|
|
|
debug.info(2, comment)
|
|
|
|
|
self.fn_cycle_comments.append(comment)
|
2018-10-25 08:29:09 +02:00
|
|
|
|
2018-10-04 18:29:44 +02:00
|
|
|
self.add_control_one_port(port, "read")
|
|
|
|
|
self.add_address(address, port)
|
2020-06-08 07:02:04 +02:00
|
|
|
|
2019-09-06 21:09:12 +02:00
|
|
|
# If the port is also a readwrite then add
|
|
|
|
|
# the same value as previous cycle
|
|
|
|
|
if port in self.write_ports:
|
|
|
|
|
try:
|
|
|
|
|
self.add_data(self.data_value[port][-1], port)
|
|
|
|
|
except:
|
2020-06-03 14:31:30 +02:00
|
|
|
self.add_data("0"*(self.word_size + self.num_spare_cols), port)
|
2019-09-06 21:09:12 +02:00
|
|
|
try:
|
|
|
|
|
self.add_wmask(self.wmask_value[port][-1], port)
|
|
|
|
|
except:
|
2020-06-08 07:02:04 +02:00
|
|
|
self.add_wmask("0"*self.num_wmasks, port)
|
|
|
|
|
self.add_spare_wen("0" * self.num_spare_cols, port)
|
2018-10-04 18:29:44 +02:00
|
|
|
|
2019-09-06 21:09:12 +02:00
|
|
|
def add_noop_one_port(self, port):
|
2018-10-08 15:34:36 +02:00
|
|
|
""" Add the control values for a noop to a single port. Does not increment the period. """
|
2018-10-04 18:29:44 +02:00
|
|
|
self.add_control_one_port(port, "noop")
|
2020-06-08 07:02:04 +02:00
|
|
|
|
2019-09-06 21:09:12 +02:00
|
|
|
try:
|
|
|
|
|
self.add_address(self.addr_value[port][-1], port)
|
|
|
|
|
except:
|
|
|
|
|
self.add_address("0"*self.addr_size, port)
|
|
|
|
|
|
|
|
|
|
# If the port is also a readwrite then add
|
|
|
|
|
# the same value as previous cycle
|
2018-11-08 21:19:40 +01:00
|
|
|
if port in self.write_ports:
|
2019-09-06 21:09:12 +02:00
|
|
|
try:
|
|
|
|
|
self.add_data(self.data_value[port][-1], port)
|
|
|
|
|
except:
|
2020-06-03 14:31:30 +02:00
|
|
|
self.add_data("0"*(self.word_size + self.num_spare_cols), port)
|
2019-09-06 21:09:12 +02:00
|
|
|
try:
|
|
|
|
|
self.add_wmask(self.wmask_value[port][-1], port)
|
|
|
|
|
except:
|
|
|
|
|
self.add_wmask("0"*self.num_wmasks, port)
|
2020-06-08 07:02:04 +02:00
|
|
|
self.add_spare_wen("0" * self.num_spare_cols, port)
|
|
|
|
|
|
2020-04-18 01:09:58 +02:00
|
|
|
def add_noop_clock_one_port(self, port):
|
|
|
|
|
""" Add the control values for a noop to a single port. Increments the period. """
|
|
|
|
|
debug.info(2, 'Clock only on port {}'.format(port))
|
|
|
|
|
self.fn_cycle_comments.append('Clock only on port {}'.format(port))
|
|
|
|
|
self.append_cycle_comment(port, 'Clock only on port {}'.format(port))
|
|
|
|
|
|
|
|
|
|
self.cycle_times.append(self.t_current)
|
|
|
|
|
self.t_current += self.period
|
|
|
|
|
|
|
|
|
|
self.add_noop_one_port(port)
|
|
|
|
|
|
|
|
|
|
#Add noops to all other ports.
|
|
|
|
|
for unselected_port in self.all_ports:
|
|
|
|
|
if unselected_port != port:
|
|
|
|
|
self.add_noop_one_port(unselected_port)
|
|
|
|
|
|
|
|
|
|
|
2018-10-25 09:36:46 +02:00
|
|
|
def append_cycle_comment(self, port, comment):
|
|
|
|
|
"""Add comment to list to be printed in stimulus file"""
|
|
|
|
|
#Clean up time before appending. Make spacing dynamic as well.
|
|
|
|
|
time = "{0:.2f} ns:".format(self.t_current)
|
|
|
|
|
time_spacing = len(time)+6
|
|
|
|
|
self.cycle_comments.append("Cycle {0:<6d} Port {1:<6} {2:<{3}}: {4}".format(len(self.cycle_times),
|
2019-09-06 21:09:12 +02:00
|
|
|
port,
|
|
|
|
|
time,
|
|
|
|
|
time_spacing,
|
|
|
|
|
comment))
|
2018-10-22 10:09:38 +02:00
|
|
|
|
2019-07-24 00:58:54 +02:00
|
|
|
def gen_cycle_comment(self, op, word, addr, wmask, port, t_current):
|
2018-10-22 10:09:38 +02:00
|
|
|
if op == "noop":
|
|
|
|
|
comment = "\tIdle during cycle {0} ({1}ns - {2}ns)".format(int(t_current/self.period),
|
2019-09-06 21:09:12 +02:00
|
|
|
t_current,
|
|
|
|
|
t_current+self.period)
|
2018-10-22 10:09:38 +02:00
|
|
|
elif op == "write":
|
2019-07-22 20:19:14 +02:00
|
|
|
comment = "\tWriting {0} to address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word,
|
2019-07-12 19:34:29 +02:00
|
|
|
addr,
|
|
|
|
|
port,
|
|
|
|
|
int(t_current/self.period),
|
|
|
|
|
t_current,
|
|
|
|
|
t_current+self.period)
|
2019-07-22 20:19:14 +02:00
|
|
|
elif op == "partial_write":
|
2019-07-22 21:44:35 +02:00
|
|
|
comment = "\tWriting (partial) {0} to address {1} with mask bit {2} (from port {3}) during cycle {4} ({5}ns - {6}ns)".format(word,
|
2019-08-05 22:53:14 +02:00
|
|
|
addr,
|
|
|
|
|
wmask,
|
|
|
|
|
port,
|
|
|
|
|
int(t_current / self.period),
|
|
|
|
|
t_current,
|
|
|
|
|
t_current + self.period)
|
2018-10-22 10:09:38 +02:00
|
|
|
else:
|
2018-10-31 06:19:26 +01:00
|
|
|
comment = "\tReading {0} from address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word,
|
2019-08-05 22:53:14 +02:00
|
|
|
addr,
|
|
|
|
|
port,
|
|
|
|
|
int(t_current/self.period),
|
|
|
|
|
t_current,
|
|
|
|
|
t_current+self.period)
|
|
|
|
|
|
|
|
|
|
|
2018-10-22 10:09:38 +02:00
|
|
|
return comment
|
|
|
|
|
|
2019-05-14 10:15:50 +02:00
|
|
|
def gen_pin_names(self, port_signal_names, port_info, abits, dbits):
|
|
|
|
|
"""Creates the pins names of the SRAM based on the no. of ports."""
|
|
|
|
|
#This may seem redundant as the pin names are already defined in the sram. However, it is difficult
|
|
|
|
|
#to extract the functionality from the names, so they are recreated. As the order is static, changing
|
|
|
|
|
#the order of the pin names will cause issues here.
|
|
|
|
|
pin_names = []
|
|
|
|
|
(addr_name, din_name, dout_name) = port_signal_names
|
|
|
|
|
(total_ports, write_index, read_index) = port_info
|
|
|
|
|
|
|
|
|
|
for write_input in write_index:
|
|
|
|
|
for i in range(dbits):
|
|
|
|
|
pin_names.append("{0}{1}_{2}".format(din_name,write_input, i))
|
|
|
|
|
|
|
|
|
|
for port in range(total_ports):
|
|
|
|
|
for i in range(abits):
|
|
|
|
|
pin_names.append("{0}{1}_{2}".format(addr_name,port,i))
|
|
|
|
|
|
|
|
|
|
#Control signals not finalized.
|
|
|
|
|
for port in range(total_ports):
|
|
|
|
|
pin_names.append("CSB{0}".format(port))
|
|
|
|
|
for port in range(total_ports):
|
|
|
|
|
if (port in read_index) and (port in write_index):
|
|
|
|
|
pin_names.append("WEB{0}".format(port))
|
2019-07-19 22:17:55 +02:00
|
|
|
|
|
|
|
|
for port in range(total_ports):
|
2019-09-05 01:08:18 +02:00
|
|
|
pin_names.append("{0}{1}".format("clk", port))
|
2019-07-19 22:17:55 +02:00
|
|
|
|
2019-08-21 23:29:57 +02:00
|
|
|
if self.write_size:
|
2019-07-25 21:24:27 +02:00
|
|
|
for port in write_index:
|
|
|
|
|
for bit in range(self.num_wmasks):
|
|
|
|
|
pin_names.append("WMASK{0}_{1}".format(port,bit))
|
2020-06-03 14:31:30 +02:00
|
|
|
|
|
|
|
|
if self.num_spare_cols:
|
|
|
|
|
for port in write_index:
|
|
|
|
|
for bit in range(self.num_spare_cols):
|
|
|
|
|
pin_names.append("SPARE_WEN{0}_{1}".format(port,bit))
|
2019-05-14 10:15:50 +02:00
|
|
|
|
|
|
|
|
for read_output in read_index:
|
|
|
|
|
for i in range(dbits):
|
|
|
|
|
pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i))
|
|
|
|
|
|
2019-09-05 01:08:18 +02:00
|
|
|
pin_names.append("{0}".format("vdd"))
|
|
|
|
|
pin_names.append("{0}".format("gnd"))
|
2019-05-14 10:15:50 +02:00
|
|
|
return pin_names
|
|
|
|
|
|