fix
This commit is contained in:
commit
33e50bbc8c
|
@ -18,5 +18,5 @@ end_section "OpenFPGA.build"
|
|||
|
||||
start_section "OpenFPGA.TaskTun" "${GREEN}..Running_Regression..${NC}"
|
||||
cd -
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py blif_vpr_flow --exit_on_fail
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py blif_vpr_flow tileable_routing --maxthreads 2
|
||||
end_section "OpenFPGA.TaskTun"
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
Binary file not shown.
After Width: | Height: | Size: 90 KiB |
|
@ -8,6 +8,8 @@ Extended Architecture Description Language
|
|||
:maxdepth: 2
|
||||
|
||||
generality
|
||||
|
||||
interconnect
|
||||
|
||||
spice_sim_setting
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
Interconnection extensions
|
||||
==========================
|
||||
|
||||
This section introduces extensions on the architecture description file about existing interconnection description.
|
||||
|
||||
Directlist
|
||||
----------
|
||||
|
||||
The original direct connections in the directlist section are documented here_. Its description is given below:
|
||||
|
||||
.. _here: http://docs.verilogtorouting.org/en/latest/arch/reference/?highlight=directlist#direct-inter-block-connections
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<directlist>
|
||||
<direct name="string" from_pin="string" to_pin="string" x_offset="int" y_offset="int" z_offset="int" switch_name="string"/>
|
||||
</directlist>
|
||||
|
||||
.. note:: These options are required
|
||||
|
||||
Our extension include three more options:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<directlist>
|
||||
<direct name="string" from_pin="string" to_pin="string" x_offset="int" y_offset="int" z_offset="int" switch_name="string" interconnection_type="string" x_dir="string" y_dir="string"/>
|
||||
</directlist>
|
||||
|
||||
.. note:: these options are optional. However, if *interconnection_type* is set *x_dir* and *y_dir* are required.
|
||||
|
||||
* **interconnection_type**: [``NONE`` | ``column`` | ``row``], specifies if it applies on a column or a row ot if it doesn't apply.
|
||||
|
||||
* **x_dir**: [``positive`` | ``negative``], specifies if the next cell to connect has a bigger or lower x value. Considering a coordinate system where (0,0) is the origin at the bottom left and *x* and *y* are positives:
|
||||
|
||||
* x_dir="positive":
|
||||
|
||||
* interconnection_type="column": a column will be connected to a column on the **right**, if it exists.
|
||||
|
||||
* interconnection_type="row": the most on the **right** cell from a row connection will connect the most on the **left** cell of next row, if it exists.
|
||||
|
||||
* x_dir="negative":
|
||||
|
||||
* interconnection_type="column": a column will be connected to a column on the **left**, if it exists.
|
||||
|
||||
* interconnection_type="row": the most on the **left** cell from a row connection will connect the most on the **right** cell of next row, if it exists.
|
||||
|
||||
* **y_dir**: [``positive`` | ``negative``], specifies if the next cell to connect has a bigger or lower x value. Considering a coordinate system where (0,0) is the origin at the bottom left and *x* and *y* are positives:
|
||||
|
||||
* y_dir="positive":
|
||||
|
||||
* interconnection_type="column": the **bottom** cell of a column will be connected to the next column **top** cell, if it exists.
|
||||
|
||||
* interconnection_type="row": a row will be connected on an **above** row, if it exists.
|
||||
|
||||
* y_dir="negative":
|
||||
|
||||
* interconnection_type="column": the **top** cell of a column will be connected to the next column **bottom** cell, if it exists.
|
||||
|
||||
* interconnection_type="row": a row will be connected on a row **below**, if it exists.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
For this example, we will study a scan-chain implementation. The description could be:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<directlist>
|
||||
<direct name="scff_chain" from_pin="clb.sc_out" to_pin="clb.sc_in" x_offset="0" y_offset="-1" z_offset="0" interconnection_type="column" x_dir="positive" y_dir="positive"/>
|
||||
</directlist>
|
||||
|
||||
:numref:`fig_p2p_exple` is the graphical representation of the above scan-chain description on a 4x4 FPGA.
|
||||
|
||||
.. _fig_p2p_exple:
|
||||
|
||||
.. figure:: ./figures/point2point_example.png
|
||||
|
||||
An example of scan-chain implementation
|
||||
|
||||
|
||||
In this figure, the red arrows represent the initial direct connection. The green arrows represent the point to point connection to connect all the columns of CLB.
|
||||
|
||||
Truth table
|
||||
-----------
|
||||
|
||||
A point to point connection can be applied in different ways than showed in the example section. To help the designer implement his point to point connection, a truth table with our new parameters id provided below.
|
||||
|
||||
:numref:`fig_p2p_trtable` provides all possible variable combination and the connection it will generate.
|
||||
|
||||
.. _fig_p2p_trtable:
|
||||
|
||||
.. figure:: ./figures/point2point_truthtable.png
|
||||
|
||||
Point to point truth table
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -558,7 +558,7 @@
|
|||
</mode>
|
||||
|
||||
<!-- Every input pin is driven by 15% of the tracks in a channel, every output pin is driven by 10% of the tracks in a channel -->
|
||||
<fc default_in_type="frac" default_in_val="0.055" default_out_type="frac" default_out_val="0.10"/>
|
||||
<fc default_in_type="frac" default_in_val="0.15" default_out_type="frac" default_out_val="0.10"/>
|
||||
|
||||
<!-- IOs go on the periphery of the FPGA, for consistency,
|
||||
make it physically equivalent on all sides so that only one definition of I/Os is needed.
|
||||
|
@ -1013,7 +1013,7 @@
|
|||
</direct>
|
||||
</interconnect>
|
||||
|
||||
<fc default_in_type="frac" default_in_val="0.055" default_out_type="frac" default_out_val="0.10">
|
||||
<fc default_in_type="frac" default_in_val="0.15" default_out_type="frac" default_out_val="0.10">
|
||||
<pin name="cin" fc_type="frac" fc_val="0"/>
|
||||
<pin name="cout" fc_type="frac" fc_val="0"/>
|
||||
</fc>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -202,11 +202,23 @@
|
|||
<design_technology type="cmos" topology="buffer" size="1" tapered="on" tap_drive_level="2" f_per_stage="4"/>
|
||||
<port type="input" prefix="in" size="1"/>
|
||||
<port type="output" prefix="out" size="1"/>
|
||||
<delay_matrix type="rise" in_port="in" out_port="out">
|
||||
10e-12
|
||||
</delay_matrix>
|
||||
<delay_matrix type="fall" in_port="in" out_port="out">
|
||||
10e-12
|
||||
</delay_matrix>
|
||||
</circuit_model>
|
||||
<circuit_model type="inv_buf" name="tap_buf4" prefix="tap_buf4" is_default="0">
|
||||
<design_technology type="cmos" topology="buffer" size="1" tapered="on" tap_drive_level="3" f_per_stage="4"/>
|
||||
<port type="input" prefix="in" size="1"/>
|
||||
<port type="output" prefix="out" size="1"/>
|
||||
<delay_matrix type="rise" in_port="in" out_port="out">
|
||||
10e-12
|
||||
</delay_matrix>
|
||||
<delay_matrix type="fall" in_port="in" out_port="out">
|
||||
10e-12
|
||||
</delay_matrix>
|
||||
</circuit_model>
|
||||
<circuit_model type="pass_gate" name="TGATE" prefix="TGATE" is_default="1">
|
||||
<design_technology type="cmos" topology="transmission_gate" nmos_size="1" pmos_size="2"/>
|
||||
|
@ -217,10 +229,10 @@
|
|||
<port type="input" prefix="selb" size="1"/>
|
||||
<port type="output" prefix="out" size="1"/>
|
||||
<delay_matrix type="rise" in_port="in sel selb" out_port="out">
|
||||
10e-12 0e-12 0e-12
|
||||
10e-12 5e-12 5e-12
|
||||
</delay_matrix>
|
||||
<delay_matrix type="fall" in_port="in sel selb" out_port="out">
|
||||
10e-12 0e-12 0e-12
|
||||
10e-12 5e-12 5e-12
|
||||
</delay_matrix>
|
||||
</circuit_model>
|
||||
<circuit_model type="gate" name="OR2" prefix="OR2" is_default="1">
|
||||
|
@ -230,17 +242,11 @@
|
|||
<port type="input" prefix="a" size="1"/>
|
||||
<port type="input" prefix="b" size="1"/>
|
||||
<port type="output" prefix="out" size="1"/>
|
||||
<delay_matrix type="rise" in_port="a" out_port="out">
|
||||
10e-12
|
||||
<delay_matrix type="rise" in_port="a b" out_port="out">
|
||||
10e-12 10e-12
|
||||
</delay_matrix>
|
||||
<delay_matrix type="rise" in_port="b" out_port="out">
|
||||
10e-12
|
||||
</delay_matrix>
|
||||
<delay_matrix type="fall" in_port="a" out_port="out">
|
||||
10e-12
|
||||
</delay_matrix>
|
||||
<delay_matrix type="fall" in_port="b" out_port="out">
|
||||
10e-12
|
||||
<delay_matrix type="fall" in_port="a b" out_port="out">
|
||||
10e-12 10e-12
|
||||
</delay_matrix>
|
||||
</circuit_model>
|
||||
<circuit_model type="chan_wire" name="chan_segment" prefix="track_seg" is_default="1">
|
||||
|
@ -325,7 +331,7 @@
|
|||
<port type="output" prefix="lut5_out" size="2" lut_frac_level="5" lut_output_mask="0,1"/>
|
||||
<port type="output" prefix="lut6_out" size="1" lut_output_mask="0"/>
|
||||
<port type="sram" prefix="sram" size="64"/>
|
||||
<port type="sram" prefix="mode" size="2" mode_select="true" circuit_model_name="sram6T_blwl" default_val="1"/>
|
||||
<port type="sram" prefix="mode" size="2" mode_select="true" circuit_model_name="sc_dff_compact" default_val="1"/>
|
||||
</circuit_model>
|
||||
<circuit_model type="lut" name="frac_lut4" prefix="frac_lut4" dump_structural_verilog="true">
|
||||
<design_technology type="cmos" fracturable_lut="true"/>
|
||||
|
@ -340,7 +346,7 @@
|
|||
<port type="output" prefix="lut3_out" size="2" lut_frac_level="3" lut_output_mask="0,1"/>
|
||||
<port type="output" prefix="lut4_out" size="1" lut_output_mask="0"/>
|
||||
<port type="sram" prefix="sram" size="16"/>
|
||||
<port type="sram" prefix="mode" size="2" mode_select="true" circuit_model_name="sram6T_blwl" default_val="1"/>
|
||||
<port type="sram" prefix="mode" size="2" mode_select="true" circuit_model_name="sc_dff_compact" default_val="1"/>
|
||||
</circuit_model>
|
||||
<circuit_model type="sram" name="sram6T" prefix="sram" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/sram.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/sram.v" >
|
||||
<design_technology type="cmos"/>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
read_verilog -container r -libname WORK -05 { ${SOURCE_DESIGN} }
|
||||
set_top r:${SOURCE_TOP_DIR}
|
||||
read_verilog -container i -libname WORK -05 { ${IMPL_DESIGN} }
|
||||
|
||||
set_top i:${IMPL_TOP_DIR}
|
||||
match
|
||||
${MATCH_MODUEL_LIST}
|
||||
verify
|
|
@ -659,6 +659,9 @@ def run_standard_vpr(bench_blif, fixed_chan_width, logfile, route_only=False):
|
|||
if args.vpr_use_tileable_route_chan_width:
|
||||
command += ["--use_tileable_route_chan_width"]
|
||||
|
||||
if args.vpr_fpga_x2p_compact_routing_hierarchy:
|
||||
command += ["--fpga_x2p_compact_routing_hierarchy"]
|
||||
|
||||
# FPGA_Spice Options
|
||||
if (args.power and args.vpr_fpga_spice):
|
||||
command += ["--fpga_spice"]
|
||||
|
@ -668,8 +671,6 @@ def run_standard_vpr(bench_blif, fixed_chan_width, logfile, route_only=False):
|
|||
if args.vpr_fpga_x2p_sim_window_size:
|
||||
command += ["--fpga_x2p_sim_window_size",
|
||||
args.vpr_fpga_x2p_sim_window_size]
|
||||
if args.vpr_fpga_x2p_compact_routing_hierarchy:
|
||||
command += ["--fpga_x2p_compact_routing_hierarchy"]
|
||||
|
||||
if args.vpr_fpga_spice_sim_mt_num:
|
||||
command += ["--fpga_spice_sim_mt_num",
|
||||
|
@ -858,7 +859,9 @@ def run_netlists_verification():
|
|||
if "Succeed" in output:
|
||||
logger.info("VVP Simulation Successful")
|
||||
else:
|
||||
logger.info(str(output).split("\n")[-1])
|
||||
logger.error(str(output).split("\n")[-1])
|
||||
if exit_if_fail:
|
||||
clean_up_and_exit("Failed to run VVP verification")
|
||||
ExecTime["VerificationEnd"] = time.time()
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
# Combination of architecture, benchmark and script paramters
|
||||
# Args : python3 run_fpga_task.py --help
|
||||
# Author : Ganesh Gore
|
||||
#Email : ganeshgore@utah.edu
|
||||
# Email : ganeshgore@utah.edu
|
||||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
|
||||
import os
|
||||
|
@ -36,7 +36,7 @@ if sys.version_info[0] < 3:
|
|||
# Configure logging system
|
||||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
logging.basicConfig(level=logging.INFO, stream=sys.stdout,
|
||||
format='%(levelname)s (%(threadName)10s) - %(message)s')
|
||||
format='%(levelname)s (%(threadName)15s) - %(message)s')
|
||||
logger = logging.getLogger('OpenFPGA_Task_logs')
|
||||
|
||||
|
||||
|
@ -48,14 +48,19 @@ parser.add_argument('tasks', nargs='+')
|
|||
parser.add_argument('--maxthreads', type=int, default=2,
|
||||
help="Number of fpga_flow threads to run default = 2," +
|
||||
"Typically <= Number of processors on the system")
|
||||
parser.add_argument('--remove_run_dir', type=str,
|
||||
help="Remove run dir " +
|
||||
"'all' to remove all." +
|
||||
"<int>,<int> to remove specific run dir" +
|
||||
"<int>-<int> To remove range of directory")
|
||||
parser.add_argument('--config', help="Override default configuration")
|
||||
parser.add_argument('--test_run', action="store_true",
|
||||
help="Dummy run shows final generated VPR commands")
|
||||
parser.add_argument('--debug', action="store_true",
|
||||
help="Run script in debug mode")
|
||||
parser.add_argument('--exit_on_fail', action="store_true",
|
||||
parser.add_argument('--continue_on_fail', action="store_true",
|
||||
help="Exit script with return code")
|
||||
parser.add_argument('--skip_thread_logs', action="store_true",
|
||||
parser.add_argument('--show_thread_logs', action="store_true",
|
||||
help="Skips logs from running thread")
|
||||
args = parser.parse_args()
|
||||
|
||||
|
@ -84,6 +89,8 @@ def main():
|
|||
logger.info("Currently running task %s" % eachtask)
|
||||
eachtask = eachtask.replace("\\", "/").split("/")
|
||||
job_run_list = generate_each_task_actions(eachtask)
|
||||
if args.remove_run_dir:
|
||||
continue
|
||||
eachtask = "_".join(eachtask)
|
||||
if not args.test_run:
|
||||
run_actions(job_run_list)
|
||||
|
@ -111,6 +118,40 @@ def validate_command_line_arguments():
|
|||
logger.info("Set up to run %d Parallel threads", args.maxthreads)
|
||||
|
||||
|
||||
def remove_run_dir():
|
||||
remove_dir = []
|
||||
try:
|
||||
argval = args.remove_run_dir.lower()
|
||||
if argval == "all":
|
||||
for eachRun in glob.glob("run*"):
|
||||
remove_dir += [eachRun]
|
||||
elif "-" in argval:
|
||||
minval, maxval = map(int, argval.split("-"))
|
||||
if minval > maxval:
|
||||
raise Exception("Enter valid range to remove")
|
||||
for eachRun in glob.glob("run*"):
|
||||
if minval <= int(eachRun[-3:]) <= maxval:
|
||||
remove_dir += [eachRun]
|
||||
elif "," in argval:
|
||||
for eachRun in argval.split(","):
|
||||
remove_dir += ["run%03d" % int(eachRun)]
|
||||
else:
|
||||
logger.error("Unknow argument to --remove_run_dir")
|
||||
except:
|
||||
logger.exception("Failed to parse remove rund_dir options")
|
||||
|
||||
try:
|
||||
for eachdir in remove_dir:
|
||||
logger.info('Removing run_dir %s' % (eachdir))
|
||||
if os.path.exists('latest'):
|
||||
if eachdir == os.readlink('latest'):
|
||||
remove_dir += ["latest"]
|
||||
shutil.rmtree(eachdir, ignore_errors=True)
|
||||
except:
|
||||
logger.exception("Failed to remove %s run directory" %
|
||||
(eachdir or "Unknown"))
|
||||
|
||||
|
||||
def generate_each_task_actions(taskname):
|
||||
"""
|
||||
This script generates all the scripts required for each benchmark
|
||||
|
@ -130,6 +171,9 @@ def generate_each_task_actions(taskname):
|
|||
# Create run directory for current task run ./runxxx
|
||||
run_dirs = [int(os.path.basename(x)[-3:]) for x in glob.glob('run*[0-9]')]
|
||||
curr_run_dir = "run%03d" % (max(run_dirs+[0, ])+1)
|
||||
if args.remove_run_dir:
|
||||
remove_run_dir()
|
||||
return
|
||||
try:
|
||||
os.mkdir(curr_run_dir)
|
||||
if os.path.islink('latest') or os.path.exists('latest'):
|
||||
|
@ -252,10 +296,10 @@ def generate_each_task_actions(taskname):
|
|||
flow_run_cmd_list.append({
|
||||
"arch": arch,
|
||||
"bench": bench,
|
||||
"name": "%02d_arch%s_%s" % (indx, bench["top_module"], lbl),
|
||||
"name": "%02d_%s_%s" % (indx, bench["top_module"], lbl),
|
||||
"run_dir": flow_run_dir,
|
||||
"commands": command,
|
||||
"finished" : False,
|
||||
"finished": False,
|
||||
"status": False})
|
||||
|
||||
logger.info('Found %d Architectures %d Benchmarks & %d Script Parameters' %
|
||||
|
@ -345,14 +389,11 @@ def strip_child_logger_info(line):
|
|||
|
||||
|
||||
def run_single_script(s, eachJob, job_list):
|
||||
logger.debug('Added job in pool')
|
||||
with s:
|
||||
logger.debug("Running OpenFPGA flow with " +
|
||||
" ".join(eachJob["commands"]))
|
||||
name = threading.currentThread().getName()
|
||||
thread_name = threading.currentThread().getName()
|
||||
eachJob["starttime"] = time.time()
|
||||
try:
|
||||
logfile = "%s_out.log" % name
|
||||
logfile = "%s_out.log" % thread_name
|
||||
with open(logfile, 'w+') as output:
|
||||
output.write("* "*20 + '\n')
|
||||
output.write("RunDirectory : %s\n" % os.getcwd())
|
||||
|
@ -360,46 +401,45 @@ def run_single_script(s, eachJob, job_list):
|
|||
eachJob["commands"]
|
||||
output.write(" ".join(command) + '\n')
|
||||
output.write("* "*20 + '\n')
|
||||
logger.debug("Running OpenFPGA flow with [%s]" % command)
|
||||
process = subprocess.Popen(command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True)
|
||||
for line in process.stdout:
|
||||
if not args.skip_thread_logs:
|
||||
if args.show_thread_logs:
|
||||
strip_child_logger_info(line[:-1])
|
||||
sys.stdout.buffer.flush()
|
||||
output.write(line)
|
||||
process.wait()
|
||||
if process.returncode:
|
||||
raise subprocess.CalledProcessError(0, command)
|
||||
raise subprocess.CalledProcessError(0, " ".join(command))
|
||||
eachJob["status"] = True
|
||||
except:
|
||||
logger.exception("Failed to execute openfpga flow - " +
|
||||
eachJob["name"])
|
||||
if args.exit_on_fail:
|
||||
clean_up_and_exit("Faile to run task %s exiting" % name)
|
||||
if not args.continue_on_fail:
|
||||
os._exit(1)
|
||||
eachJob["endtime"] = time.time()
|
||||
timediff = timedelta(seconds=(eachJob["endtime"]-eachJob["starttime"]))
|
||||
timestr = humanize.naturaldelta(timediff) if "humanize" in sys.modules \
|
||||
else str(timediff)
|
||||
logger.info("%s Finished with returncode %d, Time Taken %s " %
|
||||
(name, process.returncode, timestr))
|
||||
(thread_name, process.returncode, timestr))
|
||||
eachJob["finished"] = True
|
||||
no_of_finished_job = sum([ not eachJ["finished"] for eachJ in job_list])
|
||||
no_of_finished_job = sum([not eachJ["finished"] for eachJ in job_list])
|
||||
logger.info("***** %d runs pending *****" % (no_of_finished_job))
|
||||
|
||||
|
||||
def run_actions(job_list):
|
||||
thread_sema = threading.Semaphore(args.maxthreads)
|
||||
thred_list = []
|
||||
for index, eachjob in enumerate(job_list):
|
||||
JobID = 'Job_%02d' % (index+1)
|
||||
logger.info("Running %s = %s" % (JobID, eachjob["name"]))
|
||||
t = threading.Thread(target=run_single_script,
|
||||
name=JobID, args=(thread_sema, eachjob, job_list))
|
||||
thread_list = []
|
||||
for _, eachjob in enumerate(job_list):
|
||||
t = threading.Thread(target=run_single_script, name=eachjob["name"],
|
||||
args=(thread_sema, eachjob, job_list))
|
||||
t.start()
|
||||
thred_list.append(t)
|
||||
for eachthread in thred_list:
|
||||
thread_list.append(t)
|
||||
for eachthread in thread_list:
|
||||
eachthread.join()
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
from string import Template
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
import subprocess
|
||||
import logging
|
||||
from pprint import pprint
|
||||
|
||||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# Configure logging system
|
||||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
logging.basicConfig(level=logging.INFO, stream=sys.stdout,
|
||||
format='%(levelname)s (%(threadName)10s) - %(message)s')
|
||||
logger = logging.getLogger('Modelsim_run_log')
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('files', nargs='+')
|
||||
parser.add_argument('--modelsim_template', type=str,
|
||||
help="Modelsim verification template file")
|
||||
parser.add_argument('--run_sim', action="store_true",
|
||||
help="Execute generated script in formality")
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
if not args.modelsim_template:
|
||||
task_script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
args.modelsim_template = os.path.join(task_script_dir, os.pardir,
|
||||
"misc", "modelsim_template.j2")
|
||||
|
||||
args.modelsim_template = os.path.abspath(args.modelsim_template)
|
||||
|
||||
|
||||
def main():
|
||||
for eachFile in args.files:
|
||||
eachFile = os.path.abspath(eachFile)
|
||||
directory = os.path.dirname(eachFile)
|
||||
os.chdir(directory)
|
||||
with open(eachFile, 'r') as fp:
|
||||
lines = fp.read().split("\n")
|
||||
SplitL = [indx for indx, eachL in enumerate(lines) if eachL == ""]
|
||||
SplitL = list(zip([0] + SplitL[:-1], SplitL))
|
||||
for indx, eachSection in enumerate(SplitL):
|
||||
SplitL[indx] = list(filter(None, lines[slice(*eachSection)]))
|
||||
|
||||
match_str = "set_user_match r:%s i:%s -type port -noninverted"
|
||||
lables = {"SOURCE_DESIGN": " ".join(SplitL[0]),
|
||||
"SOURCE_TOP_DIR": "/WORK/" + " ".join(SplitL[1]),
|
||||
"IMPL_DESIGN": " ".join(SplitL[2]),
|
||||
"IMPL_TOP_DIR": "/WORK/" + " ".join(SplitL[3]),
|
||||
"MATCH_MODUEL_LIST": "\n".join([match_str % tuple(eachPort.split()) for eachPort in SplitL[4]])
|
||||
}
|
||||
|
||||
tmpl = Template(open(args.modelsim_template, encoding='utf-8').read())
|
||||
with open("Output.tcl", 'w', encoding='utf-8') as tclout:
|
||||
tclout.write(tmpl.substitute(lables))
|
||||
if args.run_sim:
|
||||
formality_run_string = ["formality", "-file", "Output.tcl"]
|
||||
run_command("Modelsim run", "modelsim_run.log", formality_run_string)
|
||||
else:
|
||||
with open("Output.tcl", 'r', encoding='utf-8') as tclout:
|
||||
print(tclout.read())
|
||||
|
||||
|
||||
def run_command(taskname, logfile, command, exit_if_fail=True):
|
||||
logger.info("Launching %s " % taskname)
|
||||
with open(logfile, 'w+') as output:
|
||||
try:
|
||||
output.write(" ".join(command)+"\n")
|
||||
process = subprocess.run(command,
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
output.write(process.stdout)
|
||||
if process.returncode:
|
||||
logger.error("%s run failed with returncode %d" %
|
||||
(taskname, process.returncode))
|
||||
except (Exception, subprocess.CalledProcessError) as e:
|
||||
logger.exception("failed to execute %s" % taskname)
|
||||
return None
|
||||
logger.info("%s is written in file %s" % (taskname, logfile))
|
||||
return process.stdout
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -17,9 +17,12 @@ fpga_flow=vpr_blif
|
|||
[ARCHITECTURES]
|
||||
# arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml
|
||||
arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml
|
||||
arch2=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k8_N10_sram_chain_FC_template.xml
|
||||
arch3=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml
|
||||
arch4=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml
|
||||
arch2=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml
|
||||
arch3=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml
|
||||
arch4=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml
|
||||
arch5=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml
|
||||
#arch5=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml
|
||||
#arch4=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k8_N10_sram_chain_FC_template.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/Test_Modes/test_modes.blif
|
||||
|
@ -30,21 +33,20 @@ bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/Test_Modes/test_mode
|
|||
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/Test_Modes/test_modes.v
|
||||
bench0_chan_width = 300
|
||||
|
||||
[SCRIPT_PARAM_FIX_ROUTE_CHAN_WIDTH]
|
||||
fix_route_chan_width=300
|
||||
vpr_fpga_verilog_include_icarus_simulator=
|
||||
vpr_fpga_verilog_formal_verification_top_netlist=
|
||||
vpr_fpga_verilog_include_timing=
|
||||
vpr_fpga_verilog_include_signal_init=
|
||||
vpr_fpga_verilog_print_autocheck_top_testbench=
|
||||
vpr_fpga_bitstream_generator=
|
||||
vpr_fpga_verilog_print_user_defined_template=
|
||||
vpr_fpga_verilog_print_report_timing_tcl=
|
||||
vpr_fpga_verilog_print_sdc_pnr=
|
||||
vpr_fpga_verilog_print_sdc_analysis=
|
||||
vpr_fpga_x2p_compact_routing_hierarchy=
|
||||
end_flow_with_test=
|
||||
|
||||
#[SCRIPT_PARAM_FIX_ROUTE_CHAN_WIDTH]
|
||||
#fix_route_chan_width=300
|
||||
#vpr_fpga_verilog_include_icarus_simulator=
|
||||
#vpr_fpga_verilog_formal_verification_top_netlist=
|
||||
#vpr_fpga_verilog_include_timing=
|
||||
#vpr_fpga_verilog_include_signal_init=
|
||||
#vpr_fpga_verilog_print_autocheck_top_testbench=
|
||||
#vpr_fpga_bitstream_generator=
|
||||
#vpr_fpga_verilog_print_user_defined_template=
|
||||
#vpr_fpga_verilog_print_report_timing_tcl=
|
||||
#vpr_fpga_verilog_print_sdc_pnr=
|
||||
#vpr_fpga_verilog_print_sdc_analysis=
|
||||
##vpr_fpga_x2p_compact_routing_hierarchy=
|
||||
#end_flow_with_test=
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||
min_route_chan_width=1.3
|
||||
|
@ -58,7 +60,7 @@ vpr_fpga_verilog_print_user_defined_template=
|
|||
vpr_fpga_verilog_print_report_timing_tcl=
|
||||
vpr_fpga_verilog_print_sdc_pnr=
|
||||
vpr_fpga_verilog_print_sdc_analysis=
|
||||
vpr_fpga_x2p_compact_routing_hierarchy=
|
||||
#vpr_fpga_x2p_compact_routing_hierarchy=
|
||||
end_flow_with_test=
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# Configuration file for running experiments
|
||||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
|
||||
# Each job execute fpga_flow script on combination of architecture & benchmark
|
||||
# timeout_each_job is timeout for each job
|
||||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
|
||||
[GENERAL]
|
||||
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
|
||||
power_analysis = true
|
||||
spice_output=false
|
||||
verilog_output=true
|
||||
timeout_each_job = 20*60
|
||||
fpga_flow=vpr_blif
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/Test_Modes/test_modes.blif
|
||||
|
||||
[SYNTHESIS_PARAM]
|
||||
bench0_top = test_modes
|
||||
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/Test_Modes/test_modes.act
|
||||
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/Test_Modes/test_modes.v
|
||||
bench0_chan_width = 300
|
||||
|
||||
[SCRIPT_PARAM_FIX_ROUTE_CHAN_WIDTH]
|
||||
fix_route_chan_width=300
|
||||
vpr_fpga_verilog_include_icarus_simulator=
|
||||
vpr_fpga_verilog_formal_verification_top_netlist=
|
||||
vpr_fpga_verilog_include_timing=
|
||||
vpr_fpga_verilog_include_signal_init=
|
||||
vpr_fpga_verilog_print_autocheck_top_testbench=
|
||||
vpr_fpga_bitstream_generator=
|
||||
vpr_fpga_verilog_print_user_defined_template=
|
||||
#vpr_fpga_verilog_print_report_timing_tcl=
|
||||
vpr_fpga_verilog_print_sdc_pnr=
|
||||
vpr_fpga_verilog_print_sdc_analysis=
|
||||
vpr_fpga_x2p_compact_routing_hierarchy=
|
||||
end_flow_with_test=
|
||||
|
||||
#[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||
#min_route_chan_width=1.3
|
||||
#vpr_fpga_verilog_include_icarus_simulator=
|
||||
#vpr_fpga_verilog_formal_verification_top_netlist=
|
||||
#vpr_fpga_verilog_include_timing=
|
||||
#vpr_fpga_verilog_include_signal_init=
|
||||
#vpr_fpga_verilog_print_autocheck_top_testbench=
|
||||
#vpr_fpga_bitstream_generator=
|
||||
#vpr_fpga_verilog_print_user_defined_template=
|
||||
#vpr_fpga_verilog_print_report_timing_tcl=
|
||||
#vpr_fpga_verilog_print_sdc_pnr=
|
||||
#vpr_fpga_verilog_print_sdc_analysis=
|
||||
#vpr_fpga_x2p_compact_routing_hierarchy=
|
||||
#end_flow_with_test=
|
|
@ -0,0 +1,133 @@
|
|||
# python3 openfpga_flow/scripts/run_fpga_flow.py \
|
||||
# ./openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml \
|
||||
# ./openfpga_flow/benchmarks/MCNC_Verilog/s298/s298.v \
|
||||
# --top_module s298 \
|
||||
# --power \
|
||||
# --power_tech ./openfpga_flow/tech/PTM_22nm/22nm.xml \
|
||||
# --min_route_chan_width 1.3 \
|
||||
# --vpr_fpga_verilog \
|
||||
# --vpr_fpga_verilog_dir . \
|
||||
# --vpr_fpga_x2p_rename_illegal_port \
|
||||
# --end_flow_with_test \
|
||||
# --vpr_fpga_verilog_include_icarus_simulator \
|
||||
# --vpr_fpga_verilog_formal_verification_top_netlist \
|
||||
# --vpr_fpga_verilog_include_timing \
|
||||
# --vpr_fpga_verilog_include_signal_init \
|
||||
# --vpr_fpga_verilog_print_autocheck_top_testbench
|
||||
|
||||
# Test popular multi-mode architecture
|
||||
python3 openfpga_flow/scripts/run_fpga_flow.py \
|
||||
./openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml \
|
||||
./openfpga_flow/benchmarks/Test_Modes/test_modes.blif \
|
||||
--fpga_flow vpr_blif \
|
||||
--top_module test_modes \
|
||||
--activity_file ./openfpga_flow/benchmarks/Test_Modes/test_modes.act \
|
||||
--base_verilog ./openfpga_flow/benchmarks/Test_Modes/test_modes.v \
|
||||
--power \
|
||||
--power_tech ./openfpga_flow/tech/PTM_45nm/45nm.xml \
|
||||
#--fix_route_chan_width 300 \
|
||||
--min_route_chan_width 1.3 \
|
||||
--vpr_fpga_verilog \
|
||||
--vpr_fpga_verilog_dir . \
|
||||
--vpr_fpga_x2p_rename_illegal_port \
|
||||
--vpr_fpga_verilog_include_icarus_simulator \
|
||||
--vpr_fpga_verilog_formal_verification_top_netlist \
|
||||
--vpr_fpga_verilog_include_timing \
|
||||
--vpr_fpga_verilog_include_signal_init \
|
||||
--vpr_fpga_verilog_print_autocheck_top_testbench \
|
||||
--debug \
|
||||
--vpr_fpga_bitstream_generator \
|
||||
--vpr_fpga_verilog_print_user_defined_template \
|
||||
--vpr_fpga_verilog_print_report_timing_tcl \
|
||||
--vpr_fpga_verilog_print_sdc_pnr \
|
||||
--vpr_fpga_verilog_print_sdc_analysis \
|
||||
--vpr_fpga_x2p_compact_routing_hierarchy \
|
||||
--end_flow_with_test
|
||||
|
||||
# Test Standard cell MUX2
|
||||
python3 openfpga_flow/scripts/run_fpga_flow.py \
|
||||
./openfpga_flow/arch/template/k8_N10_sram_chain_FC_template.xml \
|
||||
./openfpga_flow/benchmarks/Test_Modes/test_modes.blif \
|
||||
--fpga_flow vpr_blif \
|
||||
--top_module test_modes \
|
||||
--activity_file ./openfpga_flow/benchmarks/Test_Modes/test_modes.act \
|
||||
--base_verilog ./openfpga_flow/benchmarks/Test_Modes/test_modes.v \
|
||||
--power \
|
||||
--power_tech ./openfpga_flow/tech/PTM_45nm/45nm.xml \
|
||||
#--fix_route_chan_width 300 \
|
||||
--min_route_chan_width 1.3 \
|
||||
--vpr_fpga_verilog \
|
||||
--vpr_fpga_verilog_dir . \
|
||||
--vpr_fpga_x2p_rename_illegal_port \
|
||||
--vpr_fpga_verilog_include_icarus_simulator \
|
||||
--vpr_fpga_verilog_formal_verification_top_netlist \
|
||||
--vpr_fpga_verilog_include_timing \
|
||||
--vpr_fpga_verilog_include_signal_init \
|
||||
--vpr_fpga_verilog_print_autocheck_top_testbench \
|
||||
--debug \
|
||||
--vpr_fpga_bitstream_generator \
|
||||
--vpr_fpga_verilog_print_user_defined_template \
|
||||
--vpr_fpga_verilog_print_report_timing_tcl \
|
||||
--vpr_fpga_verilog_print_sdc_pnr \
|
||||
--vpr_fpga_verilog_print_sdc_analysis \
|
||||
--vpr_fpga_x2p_compact_routing_hierarchy \
|
||||
--end_flow_with_test
|
||||
|
||||
# Test local encoder feature
|
||||
python3 openfpga_flow/scripts/run_fpga_flow.py \
|
||||
./openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml \
|
||||
./openfpga_flow/benchmarks/Test_Modes/test_modes.blif \
|
||||
--fpga_flow vpr_blif \
|
||||
--top_module test_modes \
|
||||
--activity_file ./openfpga_flow/benchmarks/Test_Modes/test_modes.act \
|
||||
--base_verilog ./openfpga_flow/benchmarks/Test_Modes/test_modes.v \
|
||||
--power \
|
||||
--power_tech ./openfpga_flow/tech/PTM_45nm/45nm.xml \
|
||||
--fix_route_chan_width 300 \
|
||||
--vpr_fpga_verilog \
|
||||
--vpr_fpga_verilog_dir . \
|
||||
--vpr_fpga_x2p_rename_illegal_port \
|
||||
--vpr_fpga_verilog_include_icarus_simulator \
|
||||
--vpr_fpga_verilog_formal_verification_top_netlist \
|
||||
--vpr_fpga_verilog_include_timing \
|
||||
--vpr_fpga_verilog_include_signal_init \
|
||||
--vpr_fpga_verilog_print_autocheck_top_testbench \
|
||||
--debug \
|
||||
--vpr_fpga_bitstream_generator \
|
||||
--vpr_fpga_verilog_print_user_defined_template \
|
||||
--vpr_fpga_verilog_print_report_timing_tcl \
|
||||
--vpr_fpga_verilog_print_sdc_pnr \
|
||||
--vpr_fpga_verilog_print_sdc_analysis \
|
||||
--vpr_fpga_x2p_compact_routing_hierarchy \
|
||||
--end_flow_with_test
|
||||
|
||||
# Test tileable routing feature
|
||||
#python3 openfpga_flow/scripts/run_fpga_flow.py \
|
||||
#./openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml \
|
||||
#./openfpga_flow/benchmarks/Test_Modes/test_modes.blif \
|
||||
#--fpga_flow vpr_blif \
|
||||
#--top_module test_modes \
|
||||
#--activity_file ./openfpga_flow/benchmarks/Test_Modes/test_modes.act \
|
||||
#--base_verilog ./openfpga_flow/benchmarks/Test_Modes/test_modes.v \
|
||||
#--power \
|
||||
#--power_tech ./openfpga_flow/tech/PTM_45nm/45nm.xml \
|
||||
##--fix_route_chan_width 300 \
|
||||
#--min_route_chan_width 1.3 \
|
||||
#--vpr_fpga_verilog \
|
||||
#--vpr_fpga_verilog_dir . \
|
||||
#--vpr_fpga_x2p_rename_illegal_port \
|
||||
#--vpr_fpga_verilog_include_icarus_simulator \
|
||||
#--vpr_fpga_verilog_formal_verification_top_netlist \
|
||||
#--vpr_fpga_verilog_include_timing \
|
||||
#--vpr_fpga_verilog_include_signal_init \
|
||||
#--vpr_fpga_verilog_print_autocheck_top_testbench \
|
||||
#--debug \
|
||||
#--vpr_fpga_bitstream_generator \
|
||||
#--vpr_fpga_verilog_print_user_defined_template \
|
||||
#--vpr_fpga_verilog_print_report_timing_tcl \
|
||||
#--vpr_fpga_verilog_print_sdc_pnr \
|
||||
#--vpr_fpga_verilog_print_sdc_analysis \
|
||||
#--vpr_fpga_x2p_compact_routing_hierarchy \
|
||||
#--vpr_use_tileable_route_chan_width \
|
||||
#--end_flow_with_test
|
||||
|
|
@ -286,14 +286,14 @@ size_t check_ff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
|||
}
|
||||
|
||||
/************************************************************************
|
||||
* A function to check the port map of SCFF circuit model
|
||||
* A function to check the port map of CCFF circuit model
|
||||
***********************************************************************/
|
||||
size_t check_scff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||
size_t check_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
size_t num_err = 0;
|
||||
|
||||
/* Check the type of circuit model */
|
||||
VTR_ASSERT(SPICE_MODEL_SCFF == circuit_lib.model_type(circuit_model));
|
||||
VTR_ASSERT(SPICE_MODEL_CCFF == circuit_lib.model_type(circuit_model));
|
||||
|
||||
/* Check if we have D, Set and Reset */
|
||||
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||
|
@ -404,9 +404,9 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) {
|
|||
* 2. Circuit models have unique prefix
|
||||
* 3. Check IOPADs have input and output ports
|
||||
* 4. Check MUXes has been defined and has input and output ports
|
||||
* 5. We must have at least one SRAM or SCFF
|
||||
* 5. We must have at least one SRAM or CCFF
|
||||
* 6. SRAM must have at least an input and an output ports
|
||||
* 7. SCFF must have at least a clock, an input and an output ports
|
||||
* 7. CCFF must have at least a clock, an input and an output ports
|
||||
* 8. FF must have at least a clock, an input and an output ports
|
||||
* 9. LUT must have at least an input, an output and a SRAM ports
|
||||
* 10. We must have default circuit models for these types: MUX, channel wires and wires
|
||||
|
@ -456,13 +456,13 @@ void check_circuit_library(const CircuitLibrary& circuit_lib) {
|
|||
|
||||
num_err += check_circuit_model_port_required(circuit_lib, SPICE_MODEL_MUX, mux_port_types_required);
|
||||
|
||||
/* 5. We must have at least one SRAM or SCFF */
|
||||
/* 5. We must have at least one SRAM or CCFF */
|
||||
if ( ( 0 == circuit_lib.models_by_type(SPICE_MODEL_SRAM).size())
|
||||
&& ( 0 == circuit_lib.models_by_type(SPICE_MODEL_SCFF).size()) ) {
|
||||
&& ( 0 == circuit_lib.models_by_type(SPICE_MODEL_CCFF).size()) ) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"At least one %s or %s circuit model is required!\n",
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(SPICE_MODEL_SRAM)],
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(SPICE_MODEL_SCFF)]);
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(SPICE_MODEL_CCFF)]);
|
||||
/* Incremental the counter for errors */
|
||||
num_err++;
|
||||
}
|
||||
|
@ -474,13 +474,13 @@ void check_circuit_library(const CircuitLibrary& circuit_lib) {
|
|||
|
||||
num_err += check_circuit_model_port_required(circuit_lib, SPICE_MODEL_SRAM, sram_port_types_required);
|
||||
|
||||
/* 7. SCFF must have at least a clock, an input and an output ports*/
|
||||
std::vector<enum e_spice_model_port_type> scff_port_types_required;
|
||||
scff_port_types_required.push_back(SPICE_MODEL_PORT_CLOCK);
|
||||
scff_port_types_required.push_back(SPICE_MODEL_PORT_INPUT);
|
||||
scff_port_types_required.push_back(SPICE_MODEL_PORT_OUTPUT);
|
||||
/* 7. CCFF must have at least a clock, an input and an output ports*/
|
||||
std::vector<enum e_spice_model_port_type> ccff_port_types_required;
|
||||
ccff_port_types_required.push_back(SPICE_MODEL_PORT_CLOCK);
|
||||
ccff_port_types_required.push_back(SPICE_MODEL_PORT_INPUT);
|
||||
ccff_port_types_required.push_back(SPICE_MODEL_PORT_OUTPUT);
|
||||
|
||||
num_err += check_circuit_model_port_required(circuit_lib, SPICE_MODEL_SCFF, scff_port_types_required);
|
||||
num_err += check_circuit_model_port_required(circuit_lib, SPICE_MODEL_CCFF, ccff_port_types_required);
|
||||
|
||||
/* 8. FF must have at least a clock, an input and an output ports*/
|
||||
std::vector<enum e_spice_model_port_type> ff_port_types_required;
|
||||
|
|
|
@ -71,7 +71,7 @@ size_t check_one_circuit_model_port_type_and_size_required(const CircuitLibrary&
|
|||
size_t check_ff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
size_t check_scff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||
size_t check_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
size_t check_sram_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||
|
|
|
@ -612,7 +612,7 @@ std::vector<CircuitPortId> CircuitLibrary::model_global_ports_by_type(const Circ
|
|||
}
|
||||
|
||||
/* Recursively find all the global ports in the circuit model / sub circuit_model
|
||||
* but ignore all the SRAM and SCFF, which are configuration memories
|
||||
* but ignore all the SRAM and CCFF, which are configuration memories
|
||||
*/
|
||||
std::vector<CircuitPortId> CircuitLibrary::model_global_ports_by_type(const CircuitModelId& model_id,
|
||||
const enum e_spice_model_port_type& type,
|
||||
|
@ -621,7 +621,7 @@ std::vector<CircuitPortId> CircuitLibrary::model_global_ports_by_type(const Circ
|
|||
std::vector<enum e_spice_model_type> ignore_list;
|
||||
if (true == ignore_config_memories) {
|
||||
ignore_list.push_back(SPICE_MODEL_SRAM);
|
||||
ignore_list.push_back(SPICE_MODEL_SCFF);
|
||||
ignore_list.push_back(SPICE_MODEL_CCFF);
|
||||
}
|
||||
return model_global_ports_by_type(model_id, type, recursive, ignore_list);
|
||||
}
|
||||
|
@ -1875,7 +1875,7 @@ void CircuitLibrary::build_submodels() {
|
|||
/* Build a unique list */
|
||||
for (const auto& cand : candidates) {
|
||||
/* Make sure the model id is unique in the list */
|
||||
if (true == is_unique_submodel(model,cand)) {
|
||||
if (true == is_unique_submodel(model, cand)) {
|
||||
sub_models_[model].push_back(cand);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -453,8 +453,8 @@ class CircuitLibrary {
|
|||
void link_buffer_model(const CircuitModelId& model_id);
|
||||
void link_pass_gate_logic_model(const CircuitModelId& model_id);
|
||||
bool is_unique_submodel(const CircuitModelId& model_id, const CircuitModelId& submodel_id);
|
||||
void build_submodels();
|
||||
void build_model_timing_graph(const CircuitModelId& model_id);
|
||||
void build_submodels();
|
||||
public: /* Public Mutators: builders */
|
||||
void build_model_links();
|
||||
void build_timing_graphs();
|
||||
|
@ -471,11 +471,12 @@ class CircuitLibrary {
|
|||
public: /* Internal mutators: build fast look-ups */
|
||||
void build_model_lookup();
|
||||
void build_model_port_lookup();
|
||||
private: /* Internal invalidators/validators */
|
||||
/* Validators */
|
||||
public: /* Public invalidators/validators */
|
||||
bool valid_model_id(const CircuitModelId& model_id) const;
|
||||
bool valid_circuit_port_id(const CircuitPortId& circuit_port_id) const;
|
||||
bool valid_circuit_pin_id(const CircuitPortId& circuit_port_id, const size_t& pin_id) const;
|
||||
private: /* Internal invalidators/validators */
|
||||
/* Validators */
|
||||
bool valid_edge_id(const CircuitEdgeId& edge_id) const;
|
||||
bool valid_delay_type(const CircuitModelId& model_id, const enum spice_model_delay_type& delay_type) const;
|
||||
bool valid_circuit_edge_id(const CircuitEdgeId& circuit_edge_id) const;
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/**********************************************************
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2018 LNIS - The University of Utah
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
***********************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Filename: circuit_library_utils.cpp
|
||||
* Created by: Xifan Tang
|
||||
* Change history:
|
||||
* +-------------------------------------+
|
||||
* | Date | Author | Notes
|
||||
* +-------------------------------------+
|
||||
* | 2019/09/27 | Xifan Tang | Created
|
||||
* +-------------------------------------+
|
||||
***********************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Function to perform fundamental operation for the circuit library
|
||||
* These functions are not universal methods for the CircuitLibrary class
|
||||
* They are made to ease the development in some specific purposes
|
||||
* Please classify such functions in this file
|
||||
***********************************************************************/
|
||||
|
||||
/* Header files should be included in a sequence */
|
||||
/* Standard header files required go first */
|
||||
#include <algorithm>
|
||||
|
||||
#include "vtr_assert.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include "circuit_library_utils.h"
|
||||
|
||||
/********************************************************************
|
||||
* Get the model id of a SRAM model that is used to configure
|
||||
* a circuit model
|
||||
*******************************************************************/
|
||||
std::vector<CircuitModelId> find_circuit_sram_models(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
/* SRAM model id is stored in the sram ports of a circuit model */
|
||||
std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM);
|
||||
std::vector<CircuitModelId> sram_models;
|
||||
|
||||
/* Create a list of sram models, but avoid duplicated model ids */
|
||||
for (const auto& sram_port : sram_ports) {
|
||||
CircuitModelId sram_model = circuit_lib.port_tri_state_model(sram_port);
|
||||
VTR_ASSERT( true == circuit_lib.valid_model_id(sram_model) );
|
||||
if (sram_models.end() != std::find(sram_models.begin(), sram_models.end(), sram_model)) {
|
||||
continue; /* Already in the list, skip the addition */
|
||||
}
|
||||
/* Not in the list, add it */
|
||||
sram_models.push_back(sram_model);
|
||||
}
|
||||
|
||||
return sram_models;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Find regular (not mode select) sram ports of a circuit model
|
||||
*******************************************************************/
|
||||
std::vector<CircuitPortId> find_circuit_regular_sram_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true);
|
||||
std::vector<CircuitPortId> regular_sram_ports;
|
||||
|
||||
for (const auto& port : sram_ports) {
|
||||
if (true == circuit_lib.port_is_mode_select(port)) {
|
||||
continue;
|
||||
}
|
||||
regular_sram_ports.push_back(port);
|
||||
}
|
||||
|
||||
return regular_sram_ports;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/********************************************************************
|
||||
* Header file for circuit_library_utils.cpp
|
||||
*******************************************************************/
|
||||
#ifndef CIRCUIT_LIBRARY_UTILS_H
|
||||
#define CIRCUIT_LIBRARY_UTILS_H
|
||||
|
||||
/* Header files should be included in a sequence */
|
||||
/* Standard header files required go first */
|
||||
|
||||
#include <vector>
|
||||
#include "circuit_library.h"
|
||||
|
||||
std::vector<CircuitModelId> find_circuit_sram_models(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
std::vector<CircuitPortId> find_circuit_regular_sram_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
#endif
|
|
@ -66,7 +66,7 @@ enum e_spice_model_type {
|
|||
SPICE_MODEL_FF,
|
||||
SPICE_MODEL_SRAM,
|
||||
SPICE_MODEL_HARDLOGIC,
|
||||
SPICE_MODEL_SCFF,
|
||||
SPICE_MODEL_CCFF,
|
||||
SPICE_MODEL_IOPAD,
|
||||
SPICE_MODEL_INVBUF,
|
||||
SPICE_MODEL_PASSGATE,
|
||||
|
@ -74,7 +74,7 @@ enum e_spice_model_type {
|
|||
NUM_CIRCUIT_MODEL_TYPES
|
||||
};
|
||||
/* Strings correspond to each port type */
|
||||
constexpr std::array<const char*, NUM_CIRCUIT_MODEL_TYPES> CIRCUIT_MODEL_TYPE_STRING = {{"CHAN_WIRE", "WIRE", "MUX", "LUT", "FF", "SRAM", "HARDLOGIC", "SCFF", "IOPAD", "INVBUF", "PASSGATE", "GATE"}};
|
||||
constexpr std::array<const char*, NUM_CIRCUIT_MODEL_TYPES> CIRCUIT_MODEL_TYPE_STRING = {{"CHAN_WIRE", "WIRE", "MUX", "LUT", "FF", "SRAM", "HARDLOGIC", "CCFF", "IOPAD", "INVBUF", "PASSGATE", "GATE"}};
|
||||
|
||||
enum e_spice_model_design_tech {
|
||||
SPICE_MODEL_DESIGN_CMOS,
|
||||
|
|
|
@ -136,10 +136,14 @@ void BasicPort::revert() {
|
|||
|
||||
/* rotate: increase both lsb and msb by an offset */
|
||||
bool BasicPort::rotate(const size_t& offset) {
|
||||
/* If current port is invalid or offset is 0,
|
||||
* we do nothing
|
||||
*/
|
||||
if ((0 == offset) || (0 == get_width())) {
|
||||
/* If offset is 0, we do nothing */
|
||||
if (0 == offset) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If current width is 0, we set a width using the offset! */
|
||||
if (0 == get_width()) {
|
||||
set_width(offset);
|
||||
return true;
|
||||
}
|
||||
/* check if leads to overflow:
|
||||
|
|
|
@ -924,6 +924,10 @@ typedef struct s_direct_inf {
|
|||
int y_offset;
|
||||
int z_offset;
|
||||
int line;
|
||||
/* Aurelien: point to point support in direct connection from directlist */
|
||||
enum e_point2point_interconnection_type interconnection_type;
|
||||
enum e_point2point_interconnection_dir x_dir;
|
||||
enum e_point2point_interconnection_dir y_dir;
|
||||
/* Xifan Tang: FPGA-SPICE support */
|
||||
char* spice_model_name;
|
||||
t_spice_model* spice_model;
|
||||
|
|
|
@ -3578,6 +3578,9 @@ static void ProcessDirects(INOUTP ezxml_t Parent, OUTP t_direct_inf **Directs,
|
|||
const char *direct_name;
|
||||
const char *from_pin_name;
|
||||
const char *to_pin_name;
|
||||
const char *point2point_type;
|
||||
const char *x_dir;
|
||||
const char *y_dir;
|
||||
|
||||
ezxml_t Node;
|
||||
|
||||
|
@ -3632,6 +3635,77 @@ static void ProcessDirects(INOUTP ezxml_t Parent, OUTP t_direct_inf **Directs,
|
|||
ezxml_set_attr(Node, "y_offset", NULL);
|
||||
ezxml_set_attr(Node, "z_offset", NULL);
|
||||
|
||||
// Aurelien: Read point to point connection parameters
|
||||
if((!FindProperty(Node, "interconnection_type", FALSE)) ||
|
||||
(0 == strcmp(FindProperty(Node, "interconnection_type", FALSE), "NONE"))) {
|
||||
(*Directs)[i].interconnection_type = NO_P2P;
|
||||
} else if(0 == strcmp(FindProperty(Node, "interconnection_type", FALSE), "column")) {
|
||||
(*Directs)[i].interconnection_type = P2P_DIRECT_COLUMN;
|
||||
} else if(0 == strcmp(FindProperty(Node, "interconnection_type", FALSE), "row")) {
|
||||
(*Directs)[i].interconnection_type = P2P_DIRECT_ROW;
|
||||
} else {
|
||||
(*Directs)[i].interconnection_type = NUM_POINT2POINT_INTERCONNECT_TYPE;
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"Invalid point to point connection '%s' in directlist. '%s' value should be '%s', '%s' or '%s' !\n",
|
||||
(*Directs)[i].name,
|
||||
"interconnection_type",
|
||||
"column",
|
||||
"row",
|
||||
"NONE" );
|
||||
exit(1);
|
||||
}
|
||||
if((P2P_DIRECT_COLUMN == (*Directs)[i].interconnection_type) ||
|
||||
(P2P_DIRECT_ROW == (*Directs)[i].interconnection_type)){
|
||||
if(0 == strcmp(FindProperty(Node, "x_dir", TRUE), "positive")){
|
||||
(*Directs)[i].x_dir = POSITIVE_DIR;
|
||||
} else if(0 == strcmp(FindProperty(Node, "x_dir", TRUE), "negative")){
|
||||
(*Directs)[i].x_dir = NEGATIVE_DIR;
|
||||
} else {
|
||||
(*Directs)[i].x_dir = NUM_POINT2POINT_INTERCONNECT_DIR;
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"Invalid point to point connection '%s' in directlist. '%s' value should be '%s' or '%s' !\n",
|
||||
(*Directs)[i].name,
|
||||
"x_dir",
|
||||
"positive",
|
||||
"negative" );
|
||||
}
|
||||
if(0 == strcmp(FindProperty(Node, "y_dir", TRUE), "positive")){
|
||||
(*Directs)[i].y_dir = POSITIVE_DIR;
|
||||
} else if(0 == strcmp(FindProperty(Node, "y_dir", TRUE), "negative")){
|
||||
(*Directs)[i].y_dir = NEGATIVE_DIR;
|
||||
} else {
|
||||
(*Directs)[i].y_dir = NUM_POINT2POINT_INTERCONNECT_DIR;
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"Invalid point to point connection '%s' in directlist. '%s' value should be '%s' or '%s' !\n",
|
||||
(*Directs)[i].name,
|
||||
"y_dir",
|
||||
"positive",
|
||||
"negative" );
|
||||
}
|
||||
} else {
|
||||
if(NULL == FindProperty(Node, "x_dir", FALSE)){
|
||||
(*Directs)[i].x_dir = NUM_POINT2POINT_INTERCONNECT_DIR;
|
||||
} else if(0 == strcmp(FindProperty(Node, "x_dir", FALSE), "positive")){
|
||||
(*Directs)[i].x_dir = POSITIVE_DIR;
|
||||
} else if(0 == strcmp(FindProperty(Node, "x_dir", FALSE), "negative")){
|
||||
(*Directs)[i].x_dir = NEGATIVE_DIR;
|
||||
} else {
|
||||
(*Directs)[i].x_dir = NUM_POINT2POINT_INTERCONNECT_DIR;
|
||||
}
|
||||
if(NULL == FindProperty(Node, "y_dir", FALSE)){
|
||||
(*Directs)[i].y_dir = NUM_POINT2POINT_INTERCONNECT_DIR;
|
||||
} else if(0 == strcmp(FindProperty(Node, "y_dir", FALSE), "positive")){
|
||||
(*Directs)[i].y_dir = POSITIVE_DIR;
|
||||
} else if(0 == strcmp(FindProperty(Node, "y_dir", FALSE), "negative")){
|
||||
(*Directs)[i].y_dir = NEGATIVE_DIR;
|
||||
} else {
|
||||
(*Directs)[i].y_dir = NUM_POINT2POINT_INTERCONNECT_DIR;
|
||||
}
|
||||
}
|
||||
ezxml_set_attr(Node, "x_dir", NULL);
|
||||
ezxml_set_attr(Node, "y_dir", NULL);
|
||||
ezxml_set_attr(Node, "interconnection_type", NULL);
|
||||
|
||||
/* Check that the direct chain connection is not zero in both direction */
|
||||
if ((*Directs)[i].x_offset == 0 && (*Directs)[i].y_offset == 0) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
|
|
|
@ -915,7 +915,7 @@ static void ProcessSpiceModel(ezxml_t Parent,
|
|||
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"hard_logic")) {
|
||||
spice_model->type = SPICE_MODEL_HARDLOGIC;
|
||||
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"sff")) {
|
||||
spice_model->type = SPICE_MODEL_SCFF;
|
||||
spice_model->type = SPICE_MODEL_CCFF;
|
||||
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"iopad")) {
|
||||
spice_model->type = SPICE_MODEL_IOPAD;
|
||||
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"inv_buf")) {
|
||||
|
@ -1417,7 +1417,7 @@ static void check_spice_models(int num_spice_model,
|
|||
}
|
||||
}
|
||||
/* Check scan-chain dff has input and output, clock ports*/
|
||||
if (SPICE_MODEL_SCFF == spice_models[i].type) {
|
||||
if (SPICE_MODEL_CCFF == spice_models[i].type) {
|
||||
has_sram = 1;
|
||||
has_clock_port = 0;
|
||||
has_in_port = 0;
|
||||
|
|
|
@ -5,6 +5,20 @@
|
|||
#include "linkedlist.h"
|
||||
#include "circuit_library.h"
|
||||
|
||||
/* Aurelien: point to point connection */
|
||||
enum e_point2point_interconnection_type {
|
||||
NO_P2P,
|
||||
P2P_DIRECT_COLUMN,
|
||||
P2P_DIRECT_ROW,
|
||||
NUM_POINT2POINT_INTERCONNECT_TYPE
|
||||
};
|
||||
|
||||
enum e_point2point_interconnection_dir {
|
||||
POSITIVE_DIR,
|
||||
NEGATIVE_DIR,
|
||||
NUM_POINT2POINT_INTERCONNECT_DIR
|
||||
};
|
||||
|
||||
/* Xifan TANG: Spice support*/
|
||||
enum e_spice_tech_lib_type {
|
||||
SPICE_LIB_INDUSTRY,
|
||||
|
@ -476,12 +490,12 @@ struct s_mem_bank_info {
|
|||
};
|
||||
|
||||
/* Scan-chain Flip-flops information */
|
||||
typedef struct s_scff_info t_scff_info;
|
||||
struct s_scff_info {
|
||||
typedef struct s_ccff_info t_ccff_info;
|
||||
struct s_ccff_info {
|
||||
t_spice_model* mem_model; /* SPICE model of a memory bit */
|
||||
int num_mem_bit; /* Number of memory bits in total */
|
||||
int num_scff; /* Number of Scan-chain flip-flops */
|
||||
/* TODO: More to be added, SCFF support is naive now */
|
||||
int num_ccff; /* Number of Scan-chain flip-flops */
|
||||
/* TODO: More to be added, CCFF support is naive now */
|
||||
};
|
||||
|
||||
/* Standalone SRAMs information */
|
||||
|
@ -495,7 +509,7 @@ struct s_standalone_sram_info {
|
|||
struct s_sram_orgz_info {
|
||||
enum e_sram_orgz type;
|
||||
t_mem_bank_info* mem_bank_info; /* Only be allocated when orgz type is memory bank */
|
||||
t_scff_info* scff_info; /* Only be allocated when orgz type is scan-chain */
|
||||
t_ccff_info* ccff_info; /* Only be allocated when orgz type is scan-chain */
|
||||
t_standalone_sram_info* standalone_sram_info; /* Only be allocated when orgz type is standalone */
|
||||
|
||||
/* Head of configuration bits,
|
||||
|
|
|
@ -1123,6 +1123,10 @@ typedef struct s_clb_to_clb_directs {
|
|||
t_type_descriptor *to_clb_type;
|
||||
int to_clb_pin_start_index;
|
||||
int to_clb_pin_end_index;
|
||||
/* Aurelien: point to point support in direct connection from directlist */
|
||||
enum e_point2point_interconnection_type interconnection_type;
|
||||
enum e_point2point_interconnection_dir x_dir;
|
||||
enum e_point2point_interconnection_dir y_dir;
|
||||
/* Xifan Tang: add useful addition info to this struct */
|
||||
int x_offset;
|
||||
int y_offset;
|
||||
|
|
|
@ -27,12 +27,14 @@
|
|||
* We plus 1, which is all-zero condition for outputs
|
||||
***************************************************************************************/
|
||||
size_t find_mux_local_decoder_addr_size(const size_t& data_size) {
|
||||
/* Make sure we have a encoder which is at least 2 ! */
|
||||
/* if data size is 1, it is an corner case for the decoder (addr = 1) */
|
||||
if (1 == data_size) {
|
||||
return 1;
|
||||
}
|
||||
VTR_ASSERT (2 <= data_size);
|
||||
return ceil(log(data_size) / log(2));
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
* Try to find if the decoder already exists in the library,
|
||||
* If there is no such decoder, add it to the library
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include "decoder_library.h"
|
||||
|
||||
bool need_mux_local_decoder(const size_t& data_size);
|
||||
|
||||
size_t find_mux_local_decoder_addr_size(const size_t& data_size);
|
||||
|
||||
DecoderId add_mux_local_decoder_to_library(DecoderLibrary& decoder_lib,
|
||||
|
|
|
@ -65,6 +65,14 @@ MuxGraph::mem_range MuxGraph::memories() const {
|
|||
return vtr::make_range(mem_ids_.begin(), mem_ids_.end());
|
||||
}
|
||||
|
||||
std::vector<size_t> MuxGraph::levels() const {
|
||||
std::vector<size_t> graph_levels;
|
||||
for (size_t lvl = 0; lvl < num_levels(); ++lvl) {
|
||||
graph_levels.push_back(lvl);
|
||||
}
|
||||
return graph_levels;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Public Accessors: Data query
|
||||
*************************************************/
|
||||
|
@ -158,6 +166,14 @@ size_t MuxGraph::num_memory_bits() const {
|
|||
return mem_ids_.size();
|
||||
}
|
||||
|
||||
/* Find the number of SRAMs at a level in the MUX graph */
|
||||
size_t MuxGraph::num_memory_bits_at_level(const size_t& level) const {
|
||||
/* need to check if the graph is valid or not */
|
||||
VTR_ASSERT_SAFE(valid_level(level));
|
||||
VTR_ASSERT_SAFE(valid_mux_graph());
|
||||
return mem_lookup_[level].size();
|
||||
}
|
||||
|
||||
/* Find the number of nodes at a given level in the MUX graph */
|
||||
size_t MuxGraph::num_nodes_at_level(const size_t& level) const {
|
||||
/* validate the level numbers */
|
||||
|
@ -310,6 +326,7 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const {
|
|||
}
|
||||
/* Not found, we add a memory bit and record in the mem-to-mem map */
|
||||
MuxMemId mem_subgraph = mux_graph.add_mem();
|
||||
mux_graph.set_mem_level(mem_subgraph, 0);
|
||||
mem2mem_map[mem_origin] = mem_subgraph;
|
||||
/* configure the edge */
|
||||
mux_graph.edge_mem_ids_[edge2edge_map[edge_origin]] = mem_subgraph;
|
||||
|
@ -317,6 +334,7 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const {
|
|||
|
||||
/* Since the graph is finalized, it is time to build the fast look-up */
|
||||
mux_graph.build_node_lookup();
|
||||
mux_graph.build_mem_lookup();
|
||||
|
||||
return mux_graph;
|
||||
}
|
||||
|
@ -519,11 +537,20 @@ MuxMemId MuxGraph::add_mem() {
|
|||
MuxMemId mem = MuxMemId(mem_ids_.size());
|
||||
/* Push to the node list */
|
||||
mem_ids_.push_back(mem);
|
||||
mem_levels_.push_back(size_t(-1));
|
||||
/* Resize the other node-related vectors */
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
/* Configure the level of a memory */
|
||||
void MuxGraph::set_mem_level(const MuxMemId& mem, const size_t& level) {
|
||||
/* Make sure we have valid edge and mem */
|
||||
VTR_ASSERT( valid_mem_id(mem) );
|
||||
|
||||
mem_levels_[mem] = level;
|
||||
}
|
||||
|
||||
/* Link an edge to a memory bit */
|
||||
void MuxGraph::set_edge_mem_id(const MuxEdgeId& edge, const MuxMemId& mem) {
|
||||
/* Make sure we have valid edge and mem */
|
||||
|
@ -593,8 +620,11 @@ void MuxGraph::build_multilevel_mux_graph(const size_t& mux_size,
|
|||
num_mems_per_level = 1;
|
||||
}
|
||||
/* Number of memory bits is definite, add them */
|
||||
for (size_t i = 0; i < num_mems_per_level * num_levels; ++i) {
|
||||
add_mem();
|
||||
for (size_t ilvl = 0; ilvl < num_levels; ++ilvl) {
|
||||
for (size_t imem = 0; imem < num_mems_per_level; ++imem) {
|
||||
MuxMemId mem = add_mem();
|
||||
mem_levels_[mem] = ilvl;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a fast node lookup locally.
|
||||
|
@ -747,6 +777,7 @@ void MuxGraph::build_onelevel_mux_graph(const size_t& mux_size,
|
|||
|
||||
/* Create a memory bit*/
|
||||
MuxMemId mem = add_mem();
|
||||
mem_levels_[mem] = 0;
|
||||
/* Link the edge to a memory bit */
|
||||
set_edge_mem_id(edge, mem);
|
||||
}
|
||||
|
@ -863,6 +894,7 @@ void MuxGraph::build_mux_graph(const CircuitLibrary& circuit_lib,
|
|||
|
||||
/* Since the graph is finalized, it is time to build the fast look-up */
|
||||
build_node_lookup();
|
||||
build_mem_lookup();
|
||||
|
||||
/* For fracturable LUTs, we need to add more outputs to the MUX graph */
|
||||
if ( (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model))
|
||||
|
@ -895,10 +927,34 @@ void MuxGraph::build_node_lookup() {
|
|||
}
|
||||
}
|
||||
|
||||
/* Build fast mem lookup */
|
||||
void MuxGraph::build_mem_lookup() {
|
||||
/* Invalidate the mem lookup if necessary */
|
||||
invalidate_mem_lookup();
|
||||
|
||||
/* Find the maximum number of levels */
|
||||
size_t num_levels = 0;
|
||||
for (auto mem : memories()) {
|
||||
num_levels = std::max((int)mem_levels_[mem], (int)num_levels);
|
||||
}
|
||||
|
||||
/* Resize mem_lookup */
|
||||
mem_lookup_.resize(num_levels + 1);
|
||||
for (auto mem : memories()) {
|
||||
/* Categorize mem nodes into mem_lookup */
|
||||
mem_lookup_[mem_levels_[mem]].push_back(mem);
|
||||
}
|
||||
}
|
||||
|
||||
/* Invalidate (empty) the node fast lookup*/
|
||||
void MuxGraph::invalidate_node_lookup() {
|
||||
node_lookup_.clear();
|
||||
}
|
||||
|
||||
/* Invalidate (empty) the mem fast lookup*/
|
||||
void MuxGraph::invalidate_mem_lookup() {
|
||||
mem_lookup_.clear();
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Private validators
|
||||
|
|
|
@ -62,6 +62,7 @@ class MuxGraph {
|
|||
std::vector<MuxNodeId> non_input_nodes() const;
|
||||
edge_range edges() const;
|
||||
mem_range memories() const;
|
||||
std::vector<size_t> levels() const;
|
||||
public: /* Public accessors: Data query */
|
||||
/* Find the number of inputs in the MUX graph */
|
||||
size_t num_inputs() const;
|
||||
|
@ -76,6 +77,8 @@ class MuxGraph {
|
|||
size_t num_node_levels() const;
|
||||
/* Find the number of SRAMs in the MUX graph */
|
||||
size_t num_memory_bits() const;
|
||||
/* Find the number of SRAMs at a level in the MUX graph */
|
||||
size_t num_memory_bits_at_level(const size_t& level) const;
|
||||
/* Find the number of nodes at a given level in the MUX graph */
|
||||
size_t num_nodes_at_level(const size_t& level) const;
|
||||
/* Find the level of a node */
|
||||
|
@ -112,6 +115,8 @@ class MuxGraph {
|
|||
MuxEdgeId add_edge(const MuxNodeId& from_node, const MuxNodeId& to_node);
|
||||
/* Add a memory bit to the MuxGraph */
|
||||
MuxMemId add_mem();
|
||||
/* Configure the level of a memory */
|
||||
void set_mem_level(const MuxMemId& mem, const size_t& level);
|
||||
/* Link an edge to a mem */
|
||||
void set_edge_mem_id(const MuxEdgeId& edge, const MuxMemId& mem);
|
||||
private: /* Private mutators : graph builders */
|
||||
|
@ -130,6 +135,8 @@ class MuxGraph {
|
|||
const CircuitModelId& circuit_model);
|
||||
/* Build fast node lookup */
|
||||
void build_node_lookup();
|
||||
/* Build fast mem lookup */
|
||||
void build_mem_lookup();
|
||||
private: /* Private validators */
|
||||
/* valid ids */
|
||||
bool valid_node_id(const MuxNodeId& node) const;
|
||||
|
@ -141,6 +148,7 @@ class MuxGraph {
|
|||
/* validate/invalidate node lookup */
|
||||
bool valid_node_lookup() const;
|
||||
void invalidate_node_lookup();
|
||||
void invalidate_mem_lookup();
|
||||
/* validate graph */
|
||||
bool valid_mux_graph() const;
|
||||
private: /* Internal data */
|
||||
|
@ -161,10 +169,13 @@ class MuxGraph {
|
|||
vtr::vector<MuxEdgeId, bool> edge_inv_mem_; /* if the edge is controlled by an inverted output of a memory bit */
|
||||
|
||||
vtr::vector<MuxMemId, MuxMemId> mem_ids_; /* ids of configuration memories */
|
||||
vtr::vector<MuxMemId, size_t> mem_levels_; /* ids of configuration memories */
|
||||
|
||||
/* fast look-up */
|
||||
typedef std::vector<std::vector<std::vector<MuxNodeId>>> NodeLookup;
|
||||
mutable NodeLookup node_lookup_; /* [num_levels][num_types][num_nodes_per_level] */
|
||||
typedef std::vector<std::vector<MuxMemId>> MemLookup;
|
||||
mutable MemLookup mem_lookup_; /* [num_levels][num_mems_per_level] */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,8 +32,9 @@ class MuxLibrary {
|
|||
public: /* Public mutators */
|
||||
/* Add a mux to the library */
|
||||
void add_mux(const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model, const size_t& mux_size);
|
||||
private: /* Private accessors */
|
||||
public: /* Public validators */
|
||||
bool valid_mux_id(const MuxId& mux) const;
|
||||
private: /* Private accessors */
|
||||
bool valid_mux_lookup() const;
|
||||
bool valid_mux_circuit_model_id(const CircuitModelId& circuit_model) const;
|
||||
bool valid_mux_size(const CircuitModelId& circuit_model, const size_t& mux_size) const;
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
* that are used to implement a multiplexer
|
||||
*************************************************/
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
#include "spice_types.h"
|
||||
#include "util.h"
|
||||
#include "vtr_assert.h"
|
||||
#include "decoder_library_utils.h"
|
||||
#include "mux_utils.h"
|
||||
|
||||
/* Validate the number of inputs for a multiplexer implementation,
|
||||
|
@ -177,9 +179,15 @@ std::vector<bool> build_mux_intermediate_buffer_location_map(const CircuitLibrar
|
|||
std::string location_map_str;
|
||||
|
||||
/* ONLY for LUTs: intermediate buffers may exist if specified */
|
||||
if (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model)) {
|
||||
if (SPICE_MODEL_LUT != circuit_lib.model_type(circuit_model)) {
|
||||
return location_map;
|
||||
}
|
||||
|
||||
/* Get location map when the flag of intermediate buffer is on */
|
||||
if (true == circuit_lib.is_lut_intermediate_buffered(circuit_model)) {
|
||||
location_map_str = circuit_lib.lut_intermediate_buffer_location_map(circuit_model);
|
||||
}
|
||||
|
||||
/* If no location map is specified, we can return here */
|
||||
if (location_map_str.empty()) {
|
||||
return location_map;
|
||||
|
@ -231,3 +239,150 @@ MuxLibrary convert_mux_arch_to_library(const CircuitLibrary& circuit_lib, t_llis
|
|||
|
||||
return mux_lib;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Find the number of reserved configuration bits for a multiplexer
|
||||
* The reserved configuration bits is only used by ReRAM-based multiplexers
|
||||
* It is actually the shared BL/WLs among ReRAMs
|
||||
*************************************************/
|
||||
size_t find_mux_num_reserved_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const MuxGraph& mux_graph) {
|
||||
if (SPICE_MODEL_DESIGN_RRAM != circuit_lib.design_tech_type(mux_model)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<size_t> mux_branch_sizes = mux_graph.branch_sizes();
|
||||
/* For tree-like multiplexers: they have two shared configuration bits */
|
||||
if ( (1 == mux_branch_sizes.size())
|
||||
&& (2 == mux_branch_sizes[0]) ) {
|
||||
return mux_branch_sizes[0];
|
||||
}
|
||||
/* One-level multiplexer */
|
||||
if ( 1 == mux_graph.num_levels() ) {
|
||||
return mux_graph.num_inputs();
|
||||
}
|
||||
/* Multi-level multiplexers: TODO: This should be better tested and clarified
|
||||
* Now the multi-level multiplexers are treated as cascaded one-level multiplexers
|
||||
* Use the maximum branch sizes and multiply it by the number of levels
|
||||
*/
|
||||
std::vector<size_t>::iterator max_mux_branch_size = std::max_element(mux_branch_sizes.begin(), mux_branch_sizes.end());
|
||||
return mux_graph.num_levels() * (*max_mux_branch_size);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Find the number of configuration bits for a CMOS multiplexer
|
||||
* In general, the number of configuration bits is
|
||||
* the number of memory bits for a mux_graph
|
||||
* However, when local decoders are used,
|
||||
* the number of configuration bits are reduced to log2(X)
|
||||
*************************************************/
|
||||
static
|
||||
size_t find_cmos_mux_num_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const MuxGraph& mux_graph,
|
||||
const e_sram_orgz& sram_orgz_type) {
|
||||
size_t num_config_bits = 0;
|
||||
|
||||
switch (sram_orgz_type) {
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
num_config_bits = mux_graph.num_memory_bits();
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s,LINE[%d])Invalid type of SRAM organization!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (false == circuit_lib.mux_use_local_encoder(mux_model)) {
|
||||
return num_config_bits;
|
||||
}
|
||||
|
||||
num_config_bits = 0;
|
||||
/* Multiplexer local encoders are applied to memory bits at each stage */
|
||||
for (const auto& lvl : mux_graph.levels()) {
|
||||
num_config_bits += find_mux_local_decoder_addr_size(mux_graph.num_memory_bits_at_level(lvl));
|
||||
}
|
||||
|
||||
return num_config_bits;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Find the number of configuration bits for a RRAM multiplexer
|
||||
* In general, the number of configuration bits is
|
||||
* the number of levels for a mux_graph
|
||||
* This is due to only the last BL/WL of the multiplexer is
|
||||
* independent from each other
|
||||
* However, when local decoders are used,
|
||||
* the number of configuration bits should be consider all the
|
||||
* shared(reserved) configuration bits and independent bits
|
||||
*************************************************/
|
||||
static
|
||||
size_t find_rram_mux_num_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const MuxGraph& mux_graph,
|
||||
const e_sram_orgz& sram_orgz_type) {
|
||||
size_t num_config_bits = 0;
|
||||
switch (sram_orgz_type) {
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
/* In memory bank, by intensively share the Bit/Word Lines,
|
||||
* we only need 1 additional BL and WL for each MUX level.
|
||||
*/
|
||||
num_config_bits = mux_graph.num_levels();
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
/* Currently we DO NOT SUPPORT THESE, given an invalid number */
|
||||
num_config_bits = size_t(-1);
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s,LINE[%d])Invalid type of SRAM organization!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (true == circuit_lib.mux_use_local_encoder(mux_model)) {
|
||||
/* TODO: this is a to-do work for ReRAM-based multiplexers and FPGAs
|
||||
* The number of states of a local decoder only depends on how many
|
||||
* memory bits that the multiplexer will have
|
||||
* This may NOT be correct!!!
|
||||
*/
|
||||
return find_mux_local_decoder_addr_size(mux_graph.num_memory_bits());
|
||||
}
|
||||
|
||||
return num_config_bits;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Find the number of configuration bits for
|
||||
* a routing multiplexer
|
||||
* Two cases are considered here.
|
||||
* They are placed in different branches (sub-functions)
|
||||
* in order to be easy in extending to new technology!
|
||||
*************************************************/
|
||||
size_t find_mux_num_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const MuxGraph& mux_graph,
|
||||
const e_sram_orgz& sram_orgz_type) {
|
||||
size_t num_config_bits = size_t(-1);
|
||||
|
||||
switch (circuit_lib.design_tech_type(mux_model)) {
|
||||
case SPICE_MODEL_DESIGN_CMOS:
|
||||
num_config_bits = find_cmos_mux_num_config_bits(circuit_lib, mux_model, mux_graph, sram_orgz_type);
|
||||
break;
|
||||
case SPICE_MODEL_DESIGN_RRAM:
|
||||
num_config_bits = find_rram_mux_num_config_bits(circuit_lib, mux_model, mux_graph, sram_orgz_type);
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s,LINE[%d])Invalid design_technology of MUX(name: %s)\n",
|
||||
__FILE__, __LINE__, circuit_lib.model_name(mux_model).c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return num_config_bits;
|
||||
}
|
||||
|
|
|
@ -37,4 +37,13 @@ std::vector<bool> build_mux_intermediate_buffer_location_map(const CircuitLibrar
|
|||
|
||||
MuxLibrary convert_mux_arch_to_library(const CircuitLibrary& circuit_lib, t_llist* muxes_head);
|
||||
|
||||
size_t find_mux_num_reserved_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const MuxGraph& mux_graph);
|
||||
|
||||
size_t find_mux_num_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const MuxGraph& mux_graph,
|
||||
const e_sram_orgz& sram_orgz_type);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/******************************************************************************
|
||||
* This file introduces a data structure to store bitstream-related information
|
||||
******************************************************************************/
|
||||
#ifndef BITSTREAM_CONTEXT_H
|
||||
#define BITSTREAM_CONTEXT_H
|
||||
|
||||
#include "vtr_vector.h"
|
||||
#include "bitstream_context_fwd.h"
|
||||
|
||||
class BitstreamContext {
|
||||
private: /* Internal data */
|
||||
enum e_sram_orgz config_scheme_; /* The type of configuration protocol */
|
||||
CircuitModelId& sram_model_; /* The memory circuit model used by the Bitstream generation */
|
||||
size_t num_memory_bits_; /* Number of memory bits */
|
||||
size_t num_bls_; /* Number of Bit Lines */
|
||||
size_t num_wls_; /* Number of Word Lines */
|
||||
|
||||
size_t num_reserved_bls_; /* Number of reserved Bit Lines, ONLY applicable to RRAM-based FPGA */
|
||||
size_t num_reserved_wls_; /* Number of reserved Word Lines, ONLY applicable to RRAM-based FPGA */
|
||||
/* Unique id of a bit in the Bitstream */
|
||||
vtr::vector<ConfigBitId, ConfigBitId> bit_ids_;
|
||||
/* Bit line address of a bit in the Bitream: ONLY applicable to memory-decoders */
|
||||
vtr::vector<ConfigBitId, size_t> bl_addr_;
|
||||
/* Word line address of a bit in the Bitream: ONLY applicable to memory-decoders */
|
||||
vtr::vector<ConfigBitId, size_t> wl_addr_;
|
||||
/* value of a bit in the Bitream */
|
||||
vtr::vector<ConfigBitId, bool> bit_val_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/**************************************************
|
||||
* This file includes only declarations for
|
||||
* the data structures for module managers
|
||||
* Please refer to module_manager.h for more details
|
||||
*************************************************/
|
||||
#ifndef MODULE_MANAGER_FWD_H
|
||||
#define MODULE_MANAGER_FWD_H
|
||||
|
||||
#include "vtr_strong_id.h"
|
||||
|
||||
/* Strong Ids for ModuleManager */
|
||||
struct config_bit_id_tag;
|
||||
|
||||
typedef vtr::StrongId<config_bit_id_tag> ConfigBitId;
|
||||
|
||||
class BitstreamContext;
|
||||
|
||||
#endif
|
|
@ -270,7 +270,7 @@ int count_num_sram_bits_one_spice_model(t_spice_model* cur_spice_model,
|
|||
case SPICE_MODEL_FF:
|
||||
case SPICE_MODEL_SRAM:
|
||||
case SPICE_MODEL_HARDLOGIC:
|
||||
case SPICE_MODEL_SCFF:
|
||||
case SPICE_MODEL_CCFF:
|
||||
case SPICE_MODEL_IOPAD:
|
||||
return count_num_sram_bits_one_generic_spice_model(cur_spice_model);
|
||||
default:
|
||||
|
@ -336,7 +336,7 @@ int count_num_mode_bits_one_spice_model(t_spice_model* cur_spice_model) {
|
|||
case SPICE_MODEL_FF:
|
||||
case SPICE_MODEL_SRAM:
|
||||
case SPICE_MODEL_HARDLOGIC:
|
||||
case SPICE_MODEL_SCFF:
|
||||
case SPICE_MODEL_CCFF:
|
||||
case SPICE_MODEL_IOPAD:
|
||||
return count_num_mode_bits_one_generic_spice_model(cur_spice_model);
|
||||
default:
|
||||
|
@ -528,7 +528,7 @@ int count_num_reserved_conf_bits_one_spice_model(t_spice_model* cur_spice_model,
|
|||
case SPICE_MODEL_FF:
|
||||
case SPICE_MODEL_SRAM:
|
||||
case SPICE_MODEL_HARDLOGIC:
|
||||
case SPICE_MODEL_SCFF:
|
||||
case SPICE_MODEL_CCFF:
|
||||
case SPICE_MODEL_IOPAD:
|
||||
/* Other block, we just count the number SRAM ports defined by user */
|
||||
num_reserved_conf_bits = 0;
|
||||
|
@ -829,7 +829,7 @@ int count_num_conf_bits_one_spice_model(t_spice_model* cur_spice_model,
|
|||
case SPICE_MODEL_FF:
|
||||
case SPICE_MODEL_SRAM:
|
||||
case SPICE_MODEL_HARDLOGIC:
|
||||
case SPICE_MODEL_SCFF:
|
||||
case SPICE_MODEL_CCFF:
|
||||
case SPICE_MODEL_IOPAD:
|
||||
return count_num_conf_bits_one_generic_spice_model(cur_spice_model, cur_sram_orgz_type);
|
||||
default:
|
||||
|
@ -919,7 +919,7 @@ int count_num_reserved_conf_bit_one_interc(t_interconnect* cur_interc,
|
|||
/* add configuration bits of a MUX to linked-list
|
||||
* when SRAM organization type is scan-chain */
|
||||
void
|
||||
add_mux_scff_conf_bits_to_llist(int mux_size,
|
||||
add_mux_ccff_conf_bits_to_llist(int mux_size,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
int num_mux_sram_bits, int* mux_sram_bits,
|
||||
t_spice_model* mux_spice_model) {
|
||||
|
@ -1134,7 +1134,7 @@ add_mux_conf_bits_to_llist(int mux_size,
|
|||
switch (cur_sram_orgz_info->type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
add_mux_scff_conf_bits_to_llist(mux_size, cur_sram_orgz_info,
|
||||
add_mux_ccff_conf_bits_to_llist(mux_size, cur_sram_orgz_info,
|
||||
num_mux_sram_bits, mux_sram_bits,
|
||||
mux_spice_model);
|
||||
break;
|
||||
|
@ -1152,9 +1152,9 @@ add_mux_conf_bits_to_llist(int mux_size,
|
|||
return;
|
||||
}
|
||||
|
||||
/* Add SCFF configutration bits to a linked list*/
|
||||
/* Add CCFF configutration bits to a linked list*/
|
||||
static
|
||||
void add_sram_scff_conf_bits_to_llist(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
void add_sram_ccff_conf_bits_to_llist(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
int num_sram_bits, int* sram_bits) {
|
||||
int ibit, cur_mem_bit;
|
||||
t_conf_bit** sram_bit = NULL;
|
||||
|
@ -1304,7 +1304,7 @@ add_sram_conf_bits_to_llist(t_sram_orgz_info* cur_sram_orgz_info, int mem_index,
|
|||
switch (cur_sram_orgz_info->type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
add_sram_scff_conf_bits_to_llist(cur_sram_orgz_info,
|
||||
add_sram_ccff_conf_bits_to_llist(cur_sram_orgz_info,
|
||||
num_sram_bits, sram_bits);
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
|
|
|
@ -30,7 +30,7 @@ int count_num_reserved_conf_bit_one_interc(t_interconnect* cur_interc,
|
|||
enum e_sram_orgz cur_sram_orgz_type);
|
||||
|
||||
void
|
||||
add_mux_scff_conf_bits_to_llist(int mux_size,
|
||||
add_mux_ccff_conf_bits_to_llist(int mux_size,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
int num_mux_sram_bits, int* mux_sram_bits,
|
||||
t_spice_model* mux_spice_model);
|
||||
|
|
|
@ -189,20 +189,20 @@ int multilevel_mux_last_level_input_num(int num_level, int num_input_per_unit,
|
|||
|
||||
/***************************************************************************************
|
||||
* Find the number of inputs for a encoder with a given output size
|
||||
* Inputs
|
||||
* | | | | |
|
||||
* +-----------+
|
||||
* / \
|
||||
* / Encoder \
|
||||
* +-----------------+
|
||||
* | | | | | | | |
|
||||
* Outputs
|
||||
*
|
||||
* The outputs are assumes to be one-hot codes (at most only one '1' exist)
|
||||
* Considering this fact, there are only num_of_outputs + 1 conditions to be encoded.
|
||||
* Therefore, the number of inputs is ceil(log(num_of_outputs+1)/log(2))
|
||||
* We plus 1, which is all-zero condition for outputs
|
||||
***************************************************************************************/
|
||||
* Inputs
|
||||
* | | | | |
|
||||
* +-----------+
|
||||
* / \
|
||||
* / Encoder \
|
||||
* +-----------------+
|
||||
* | | | | | | | |
|
||||
* Outputs
|
||||
*
|
||||
* The outputs are assumes to be one-hot codes (at most only one '1' exist)
|
||||
* Considering this fact, there are only num_of_outputs + 1 conditions to be encoded.
|
||||
* Therefore, the number of inputs is ceil(log(num_of_outputs+1)/log(2))
|
||||
* We plus 1, which is all-zero condition for outputs
|
||||
****************************************************************************************/
|
||||
int determine_mux_local_encoder_num_inputs(int num_outputs) {
|
||||
return ceil(log(num_outputs) / log(2));
|
||||
}
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
/********************************************************************
|
||||
* This file includes functions to
|
||||
* generate module/port names for Verilog
|
||||
* and SPICE netlists
|
||||
* This file includes functions to generate module/port names for
|
||||
* Verilog and SPICE netlists
|
||||
*
|
||||
* IMPORTANT: keep all the naming functions in this file to be
|
||||
* generic for both Verilog and SPICE generators
|
||||
********************************************************************/
|
||||
#include "vtr_assert.h"
|
||||
|
||||
#include "sides.h"
|
||||
#include "fpga_x2p_utils.h"
|
||||
#include "circuit_library_utils.h"
|
||||
#include "fpga_x2p_naming.h"
|
||||
|
||||
/************************************************
|
||||
|
@ -17,8 +19,8 @@
|
|||
* Case 1 : If there is NO intermediate buffer followed by,
|
||||
* the node name will be mux_l<node_level>_in
|
||||
***********************************************/
|
||||
std::string generate_verilog_mux_node_name(const size_t& node_level,
|
||||
const bool& add_buffer_postfix) {
|
||||
std::string generate_mux_node_name(const size_t& node_level,
|
||||
const bool& add_buffer_postfix) {
|
||||
/* Generate the basic node_name */
|
||||
std::string node_name = "mux_l" + std::to_string(node_level) + "_in";
|
||||
|
||||
|
@ -37,10 +39,10 @@ std::string generate_verilog_mux_node_name(const size_t& node_level,
|
|||
* 1. LUTs are named as <model_name>_mux
|
||||
* 2. MUXes are named as <model_name>_size<num_inputs>
|
||||
***********************************************/
|
||||
std::string generate_verilog_mux_subckt_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const std::string& postfix) {
|
||||
std::string generate_mux_subckt_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const std::string& postfix) {
|
||||
std::string module_name = circuit_lib.model_name(circuit_model);
|
||||
/* Check the model type and give different names */
|
||||
if (SPICE_MODEL_MUX == circuit_lib.model_type(circuit_model)) {
|
||||
|
@ -63,11 +65,11 @@ std::string generate_verilog_mux_subckt_name(const CircuitLibrary& circuit_lib,
|
|||
* Generate the module name of a branch for a
|
||||
* multiplexer in Verilog format
|
||||
***********************************************/
|
||||
std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const size_t& branch_mux_size,
|
||||
const std::string& postfix) {
|
||||
std::string generate_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const size_t& branch_mux_size,
|
||||
const std::string& postfix) {
|
||||
/* If the tgate spice model of this MUX is a MUX2 standard cell,
|
||||
* the mux_subckt name will be the name of the standard cell
|
||||
*/
|
||||
|
@ -78,7 +80,7 @@ std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circui
|
|||
}
|
||||
std::string branch_postfix = postfix + "_size" + std::to_string(branch_mux_size);
|
||||
|
||||
return generate_verilog_mux_subckt_name(circuit_lib, circuit_model, mux_size, branch_postfix);
|
||||
return generate_mux_subckt_name(circuit_lib, circuit_model, mux_size, branch_postfix);
|
||||
}
|
||||
|
||||
/************************************************
|
||||
|
@ -139,3 +141,459 @@ std::string generate_memory_module_name(const CircuitLibrary& circuit_lib,
|
|||
return std::string( circuit_lib.model_name(circuit_model) + "_" + circuit_lib.model_name(sram_model) + postfix );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the netlist name for a unique routing block
|
||||
* It could be
|
||||
* 1. Routing channel
|
||||
* 2. Connection block
|
||||
* 3. Switch block
|
||||
* A unique block id should be given
|
||||
*********************************************************************/
|
||||
std::string generate_routing_block_netlist_name(const std::string& prefix,
|
||||
const size_t& block_id,
|
||||
const std::string& postfix) {
|
||||
return std::string( prefix + std::to_string(block_id) + postfix );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the netlist name for a routing block with a given coordinate
|
||||
* It could be
|
||||
* 1. Routing channel
|
||||
* 2. Connection block
|
||||
* 3. Switch block
|
||||
*********************************************************************/
|
||||
std::string generate_routing_block_netlist_name(const std::string& prefix,
|
||||
const vtr::Point<size_t>& coordinate,
|
||||
const std::string& postfix) {
|
||||
return std::string( prefix + std::to_string(coordinate.x()) + std::string("_") + std::to_string(coordinate.y()) + postfix );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the module name for a unique routing channel
|
||||
*********************************************************************/
|
||||
std::string generate_routing_channel_module_name(const t_rr_type& chan_type,
|
||||
const size_t& block_id) {
|
||||
/* Channel must be either CHANX or CHANY */
|
||||
VTR_ASSERT( (CHANX == chan_type) || (CHANY == chan_type) );
|
||||
|
||||
/* Create a map between chan_type and module_prefix */
|
||||
std::map<t_rr_type, std::string> module_prefix_map;
|
||||
/* TODO: use a constexpr string to replace the fixed name? */
|
||||
module_prefix_map[CHANX] = std::string("chanx");
|
||||
module_prefix_map[CHANY] = std::string("chany");
|
||||
|
||||
return std::string( module_prefix_map[chan_type] + std::string("_") + std::to_string(block_id) + std::string("_") );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the module name for a routing channel with a given coordinate
|
||||
*********************************************************************/
|
||||
std::string generate_routing_channel_module_name(const t_rr_type& chan_type,
|
||||
const vtr::Point<size_t>& coordinate) {
|
||||
/* Channel must be either CHANX or CHANY */
|
||||
VTR_ASSERT( (CHANX == chan_type) || (CHANY == chan_type) );
|
||||
|
||||
/* Create a map between chan_type and module_prefix */
|
||||
std::map<t_rr_type, std::string> module_prefix_map;
|
||||
/* TODO: use a constexpr string to replace the fixed name? */
|
||||
module_prefix_map[CHANX] = std::string("chanx");
|
||||
module_prefix_map[CHANY] = std::string("chany");
|
||||
|
||||
return std::string( module_prefix_map[chan_type] + std::to_string(coordinate.x()) + std::string("_") + std::to_string(coordinate.y()) + std::string("_") );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for a routing track with a given coordinate
|
||||
* and port direction
|
||||
*********************************************************************/
|
||||
std::string generate_routing_track_port_name(const t_rr_type& chan_type,
|
||||
const vtr::Point<size_t>& coordinate,
|
||||
const size_t& track_id,
|
||||
const PORTS& port_direction) {
|
||||
/* Channel must be either CHANX or CHANY */
|
||||
VTR_ASSERT( (CHANX == chan_type) || (CHANY == chan_type) );
|
||||
|
||||
/* Create a map between chan_type and module_prefix */
|
||||
std::map<t_rr_type, std::string> module_prefix_map;
|
||||
/* TODO: use a constexpr string to replace the fixed name? */
|
||||
module_prefix_map[CHANX] = std::string("chanx");
|
||||
module_prefix_map[CHANY] = std::string("chany");
|
||||
|
||||
std::string port_name = module_prefix_map[chan_type];
|
||||
port_name += std::string("_" + std::to_string(coordinate.x()) + std::string("__") + std::to_string(coordinate.y()) + std::string("__"));
|
||||
|
||||
switch (port_direction) {
|
||||
case OUT_PORT:
|
||||
port_name += std::string("out_");
|
||||
break;
|
||||
case IN_PORT:
|
||||
port_name += std::string("in_");
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File: %s [LINE%d]) Invalid direction of chan_rr_node!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Add the track id to the port name */
|
||||
port_name += std::to_string(track_id) + std::string("_");
|
||||
|
||||
return port_name;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the module name for a switch block with a given coordinate
|
||||
*********************************************************************/
|
||||
std::string generate_switch_block_module_name(const vtr::Point<size_t>& coordinate) {
|
||||
return std::string( "sb_" + std::to_string(coordinate.x()) + std::string("__") + std::to_string(coordinate.y()) + std::string("_") );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for a Grid
|
||||
* TODO: add more comments about why we need different names for
|
||||
* top and non-top netlists
|
||||
*********************************************************************/
|
||||
std::string generate_grid_port_name(const vtr::Point<size_t>& coordinate,
|
||||
const size_t& height,
|
||||
const e_side& side,
|
||||
const size_t& pin_id,
|
||||
const bool& for_top_netlist) {
|
||||
if (true == for_top_netlist) {
|
||||
std::string port_name = std::string("grid_");
|
||||
port_name += std::to_string(coordinate.x());
|
||||
port_name += std::string("__");
|
||||
port_name += std::to_string(coordinate.y());
|
||||
port_name += std::string("__pin_");
|
||||
port_name += std::to_string(height);
|
||||
port_name += std::string("__");
|
||||
port_name += std::to_string(size_t(side));
|
||||
port_name += std::string("__");
|
||||
port_name += std::to_string(pin_id);
|
||||
port_name += std::string("_");
|
||||
return port_name;
|
||||
}
|
||||
/* For non-top netlist */
|
||||
VTR_ASSERT( false == for_top_netlist );
|
||||
Side side_manager(side);
|
||||
std::string port_name = std::string(side_manager.to_string());
|
||||
port_name += std::string("_height_");
|
||||
port_name += std::to_string(height);
|
||||
port_name += std::string("__pin_");
|
||||
port_name += std::to_string(pin_id);
|
||||
port_name += std::string("_");
|
||||
return port_name;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for a reserved sram port, i.e., BLB/WL port
|
||||
* When port_type is BLB, a string denoting to the reserved BLB port is generated
|
||||
* When port_type is WL, a string denoting to the reserved WL port is generated
|
||||
*
|
||||
* DO NOT put any SRAM organization check codes HERE!!!
|
||||
* Even though the reserved BLB/WL ports are used by RRAM-based FPGA only,
|
||||
* try to keep this function does simple job.
|
||||
* Check codes should be added outside, when print the ports to files!!!
|
||||
*********************************************************************/
|
||||
std::string generate_reserved_sram_port_name(const e_spice_model_port_type& port_type) {
|
||||
VTR_ASSERT( (port_type == SPICE_MODEL_PORT_BLB) || (port_type == SPICE_MODEL_PORT_WL) );
|
||||
|
||||
if (SPICE_MODEL_PORT_BLB == port_type) {
|
||||
return std::string("reserved_blb");
|
||||
}
|
||||
return std::string("reserved_wl");
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for a sram port, used for formal verification
|
||||
* The port name is named after the cell name of SRAM in circuit library
|
||||
*********************************************************************/
|
||||
std::string generate_formal_verification_sram_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model) {
|
||||
std::string port_name = circuit_lib.model_name(sram_model) + std::string("_out_fm");
|
||||
|
||||
return port_name;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the head port name of a configuration chain
|
||||
* TODO: This could be replaced as a constexpr string
|
||||
*********************************************************************/
|
||||
std::string generate_configuration_chain_head_name() {
|
||||
return std::string("ccff_head");
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the tail port name of a configuration chain
|
||||
* TODO: This could be replaced as a constexpr string
|
||||
*********************************************************************/
|
||||
std::string generate_configuration_chain_tail_name() {
|
||||
return std::string("ccff_tail");
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the memory output port name of a configuration chain
|
||||
* TODO: This could be replaced as a constexpr string
|
||||
*********************************************************************/
|
||||
std::string generate_configuration_chain_data_out_name() {
|
||||
return std::string("mem_out");
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the inverted memory output port name of a configuration chain
|
||||
* TODO: This could be replaced as a constexpr string
|
||||
*********************************************************************/
|
||||
std::string generate_configuration_chain_inverted_data_out_name() {
|
||||
return std::string("mem_outb");
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the addr port (input) for a local decoder of a multiplexer
|
||||
* TODO: This could be replaced as a constexpr string
|
||||
*********************************************************************/
|
||||
std::string generate_mux_local_decoder_addr_port_name() {
|
||||
return std::string("addr");
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the data port (output) for a local decoder of a multiplexer
|
||||
* TODO: This could be replaced as a constexpr string
|
||||
*********************************************************************/
|
||||
std::string generate_mux_local_decoder_data_port_name() {
|
||||
return std::string("data");
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the inverted data port (output) for a local decoder of a multiplexer
|
||||
* TODO: This could be replaced as a constexpr string
|
||||
*********************************************************************/
|
||||
std::string generate_mux_local_decoder_data_inv_port_name() {
|
||||
return std::string("data_inv");
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name of a local configuration bus
|
||||
* TODO: This could be replaced as a constexpr string
|
||||
*********************************************************************/
|
||||
std::string generate_local_config_bus_port_name() {
|
||||
return std::string("config_bus");
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for a regular sram port which appears in the
|
||||
* port list of a module
|
||||
* The port name is named after the cell name of SRAM in circuit library
|
||||
*********************************************************************/
|
||||
std::string generate_sram_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const e_spice_model_port_type& port_type) {
|
||||
std::string port_name = circuit_lib.model_name(sram_model) + std::string("_");
|
||||
|
||||
switch (sram_orgz_type) {
|
||||
case SPICE_SRAM_STANDALONE: {
|
||||
/* Two types of ports are available:
|
||||
* (1) Regular output of a SRAM, enabled by port type of INPUT
|
||||
* (2) Inverted output of a SRAM, enabled by port type of OUTPUT
|
||||
*/
|
||||
if (SPICE_MODEL_PORT_INPUT == port_type) {
|
||||
port_name += std::string("out");
|
||||
} else {
|
||||
VTR_ASSERT( SPICE_MODEL_PORT_OUTPUT == port_type );
|
||||
port_name += std::string("outb");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
/* Two types of ports are available:
|
||||
* (1) Head of a chain of Configuration-chain Flip-Flops (CCFFs), enabled by port type of INPUT
|
||||
* (2) Tail of a chian of Configuration-chain Flip-flops (CCFFs), enabled by port type of OUTPUT
|
||||
* +------+ +------+ +------+
|
||||
* Head --->| CCFF |--->| CCFF |--->| CCFF |---> Tail
|
||||
* +------+ +------+ +------+
|
||||
*/
|
||||
if (SPICE_MODEL_PORT_INPUT == port_type) {
|
||||
port_name += std::string("ccff_head");
|
||||
} else {
|
||||
VTR_ASSERT( SPICE_MODEL_PORT_OUTPUT == port_type );
|
||||
port_name += std::string("ccff_tail");
|
||||
}
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
/* Four types of ports are available:
|
||||
* (1) Bit Lines (BLs) of a SRAM cell, enabled by port type of BL
|
||||
* (2) Word Lines (WLs) of a SRAM cell, enabled by port type of WL
|
||||
* (3) Inverted Bit Lines (BLBs) of a SRAM cell, enabled by port type of BLB
|
||||
* (4) Inverted Word Lines (WLBs) of a SRAM cell, enabled by port type of WLB
|
||||
*
|
||||
* BL BLB WL WLB BL BLB WL WLB BL BLB WL WLB
|
||||
* [0] [0] [0] [0] [1] [1] [1] [1] [i] [i] [i] [i]
|
||||
* ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
|
||||
* | | | | | | | | | | | |
|
||||
* +----------+ +----------+ +----------+
|
||||
* | SRAM | | SRAM | ... | SRAM |
|
||||
* +----------+ +----------+ +----------+
|
||||
*/
|
||||
if (SPICE_MODEL_PORT_BL == port_type) {
|
||||
port_name += std::string("bl");
|
||||
} else if (SPICE_MODEL_PORT_WL == port_type) {
|
||||
port_name += std::string("wl");
|
||||
} else if (SPICE_MODEL_PORT_BLB == port_type) {
|
||||
port_name += std::string("blb");
|
||||
} else {
|
||||
VTR_ASSERT( SPICE_MODEL_PORT_WLB == port_type );
|
||||
port_name += std::string("wlb");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return port_name;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for a regular sram port which is an internal
|
||||
* wire of a module
|
||||
* The port name is named after the cell name of SRAM in circuit library
|
||||
*********************************************************************/
|
||||
std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const e_spice_model_port_type& port_type) {
|
||||
std::string port_name = circuit_lib.model_name(sram_model) + std::string("_");
|
||||
|
||||
switch (sram_orgz_type) {
|
||||
case SPICE_SRAM_STANDALONE: {
|
||||
/* Two types of ports are available:
|
||||
* (1) Regular output of a SRAM, enabled by port type of INPUT
|
||||
* (2) Inverted output of a SRAM, enabled by port type of OUTPUT
|
||||
*/
|
||||
if (SPICE_MODEL_PORT_INPUT == port_type) {
|
||||
port_name += std::string("out_local_bus");
|
||||
} else {
|
||||
VTR_ASSERT( SPICE_MODEL_PORT_OUTPUT == port_type );
|
||||
port_name += std::string("outb_local_bus");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
/* Three types of ports are available:
|
||||
* (1) Input of Configuration-chain Flip-Flops (CCFFs), enabled by port type of INPUT
|
||||
* (2) Output of a chian of Configuration-chain Flip-flops (CCFFs), enabled by port type of OUTPUT
|
||||
* (2) Inverted output of a chian of Configuration-chain Flip-flops (CCFFs), enabled by port type of INOUT
|
||||
* +------+ +------+ +------+
|
||||
* Head --->| CCFF |--->| CCFF |--->| CCFF |---> Tail
|
||||
* +------+ +------+ +------+
|
||||
*/
|
||||
if (SPICE_MODEL_PORT_INPUT == port_type) {
|
||||
port_name += std::string("ccff_in_local_bus");
|
||||
} else if ( SPICE_MODEL_PORT_OUTPUT == port_type ) {
|
||||
port_name += std::string("ccff_out_local_bus");
|
||||
} else {
|
||||
VTR_ASSERT( SPICE_MODEL_PORT_INOUT == port_type );
|
||||
port_name += std::string("ccff_outb_local_bus");
|
||||
}
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK: {
|
||||
/* Two types of ports are available:
|
||||
* (1) Regular output of a SRAM, enabled by port type of INPUT
|
||||
* (2) Inverted output of a SRAM, enabled by port type of OUTPUT
|
||||
*/
|
||||
if (SPICE_MODEL_PORT_INPUT == port_type) {
|
||||
port_name += std::string("out_local_bus");
|
||||
} else {
|
||||
VTR_ASSERT( SPICE_MODEL_PORT_OUTPUT == port_type );
|
||||
port_name += std::string("outb_local_bus");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return port_name;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for the input bus of a routing multiplexer
|
||||
* This is very useful in Verilog code generation where the inputs of
|
||||
* a routing multiplexer may come from different ports.
|
||||
* On the other side, the datapath input of a routing multiplexer
|
||||
* is defined as a bus port.
|
||||
* Therefore, to interface, a bus port is required, and this function
|
||||
* give a name to the bus port
|
||||
* To keep the bus port name unique to each multiplexer we will instance,
|
||||
* a mux_instance_id should be provided by user
|
||||
*********************************************************************/
|
||||
std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const size_t& mux_size,
|
||||
const size_t& mux_instance_id) {
|
||||
std::string postfix = std::string("_") + std::to_string(mux_instance_id) + std::string("_inbus");
|
||||
return generate_mux_subckt_name(circuit_lib, mux_model, mux_size, postfix);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the name of a bus port which is wired to the configuration
|
||||
* ports of a routing multiplexer
|
||||
* This port is supposed to be used locally inside a Verilog/SPICE module
|
||||
*********************************************************************/
|
||||
std::string generate_mux_config_bus_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const size_t& mux_size,
|
||||
const size_t& bus_id,
|
||||
const bool& inverted) {
|
||||
std::string postfix = std::string("_configbus") + std::to_string(bus_id);
|
||||
/* Add a bar to the end of the name for inverted bus ports */
|
||||
if (true == inverted) {
|
||||
postfix += std::string("_b");
|
||||
}
|
||||
|
||||
return generate_mux_subckt_name(circuit_lib, mux_model, mux_size, postfix);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for a SRAM port of a circuit
|
||||
* This name is used for local wires that connecting SRAM ports
|
||||
* of a circuit model inside a Verilog/SPICE module
|
||||
* Note that the SRAM ports share the same naming
|
||||
* convention regardless of their configuration style
|
||||
*********************************************************************/
|
||||
std::string generate_local_sram_port_name(const std::string& port_prefix,
|
||||
const size_t& instance_id,
|
||||
const e_spice_model_port_type& port_type) {
|
||||
std::string port_name = port_prefix + std::string("_") + std::to_string(instance_id) + std::string("_");
|
||||
|
||||
if (SPICE_MODEL_PORT_INPUT == port_type) {
|
||||
port_name += std::string("out");
|
||||
} else {
|
||||
VTR_ASSERT( SPICE_MODEL_PORT_OUTPUT == port_type );
|
||||
port_name += std::string("outb");
|
||||
}
|
||||
|
||||
return port_name;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for a SRAM port of a routing multiplexer
|
||||
* This name is used for local wires that connecting SRAM ports
|
||||
* of routing multiplexers inside a Verilog/SPICE module
|
||||
* Note that the SRAM ports of routing multiplexers share the same naming
|
||||
* convention regardless of their configuration style
|
||||
**********************************************************************/
|
||||
std::string generate_mux_sram_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const size_t& mux_size,
|
||||
const size_t& mux_instance_id,
|
||||
const e_spice_model_port_type& port_type) {
|
||||
std::string prefix = generate_mux_subckt_name(circuit_lib, mux_model, mux_size, std::string());
|
||||
return generate_local_sram_port_name(prefix, mux_instance_id, port_type);
|
||||
}
|
||||
|
|
|
@ -9,21 +9,23 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "vtr_geometry.h"
|
||||
#include "circuit_library.h"
|
||||
#include "vpr_types.h"
|
||||
|
||||
std::string generate_verilog_mux_node_name(const size_t& node_level,
|
||||
const bool& add_buffer_postfix);
|
||||
std::string generate_mux_node_name(const size_t& node_level,
|
||||
const bool& add_buffer_postfix);
|
||||
|
||||
std::string generate_verilog_mux_subckt_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const std::string& posfix) ;
|
||||
std::string generate_mux_subckt_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const std::string& posfix) ;
|
||||
|
||||
std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const size_t& branch_mux_size,
|
||||
const std::string& posfix);
|
||||
std::string generate_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const size_t& branch_mux_size,
|
||||
const std::string& posfix);
|
||||
|
||||
std::string generate_mux_local_decoder_subckt_name(const size_t& addr_size,
|
||||
const size_t& data_size);
|
||||
|
@ -38,4 +40,83 @@ std::string generate_memory_module_name(const CircuitLibrary& circuit_lib,
|
|||
const CircuitModelId& sram_model,
|
||||
const std::string& postfix);
|
||||
|
||||
std::string generate_routing_block_netlist_name(const std::string& prefix,
|
||||
const size_t& block_id,
|
||||
const std::string& postfix);
|
||||
|
||||
std::string generate_routing_block_netlist_name(const std::string& prefix,
|
||||
const vtr::Point<size_t>& block_id,
|
||||
const std::string& postfix);
|
||||
|
||||
std::string generate_routing_channel_module_name(const t_rr_type& chan_type,
|
||||
const size_t& block_id);
|
||||
|
||||
std::string generate_routing_channel_module_name(const t_rr_type& chan_type,
|
||||
const vtr::Point<size_t>& coordinate);
|
||||
|
||||
std::string generate_routing_track_port_name(const t_rr_type& chan_type,
|
||||
const vtr::Point<size_t>& coordinate,
|
||||
const size_t& track_id,
|
||||
const PORTS& port_direction);
|
||||
|
||||
std::string generate_switch_block_module_name(const vtr::Point<size_t>& coordinate);
|
||||
|
||||
std::string generate_grid_port_name(const vtr::Point<size_t>& coordinate,
|
||||
const size_t& height,
|
||||
const e_side& side,
|
||||
const size_t& pin_id,
|
||||
const bool& for_top_netlist);
|
||||
|
||||
std::string generate_reserved_sram_port_name(const e_spice_model_port_type& port_type);
|
||||
|
||||
std::string generate_formal_verification_sram_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model);
|
||||
|
||||
std::string generate_configuration_chain_head_name();
|
||||
|
||||
std::string generate_configuration_chain_tail_name();
|
||||
|
||||
std::string generate_configuration_chain_data_out_name();
|
||||
|
||||
std::string generate_configuration_chain_inverted_data_out_name();
|
||||
|
||||
std::string generate_mux_local_decoder_addr_port_name();
|
||||
|
||||
std::string generate_mux_local_decoder_data_port_name();
|
||||
|
||||
std::string generate_mux_local_decoder_data_inv_port_name();
|
||||
|
||||
std::string generate_local_config_bus_port_name();
|
||||
|
||||
std::string generate_sram_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const e_spice_model_port_type& port_type);
|
||||
|
||||
std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const e_spice_model_port_type& port_type);
|
||||
|
||||
std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const size_t& mux_size,
|
||||
const size_t& mux_instance_id);
|
||||
|
||||
std::string generate_mux_config_bus_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const size_t& mux_size,
|
||||
const size_t& bus_id,
|
||||
const bool& inverted);
|
||||
|
||||
std::string generate_local_sram_port_name(const std::string& port_prefix,
|
||||
const size_t& instance_id,
|
||||
const e_spice_model_port_type& port_type);
|
||||
|
||||
std::string generate_mux_sram_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const size_t& mux_size,
|
||||
const size_t& mux_instance_id,
|
||||
const e_spice_model_port_type& port_type);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -344,7 +344,7 @@ void init_and_check_one_sram_inf_orgz(t_sram_inf_orgz* cur_sram_inf_orgz,
|
|||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
vpr_printf(TIO_MESSAGE_INFO, "INFO: Checking if SRAM spice model fit scan-chain organization...\n");
|
||||
if (SPICE_MODEL_SCFF != cur_sram_inf_orgz->spice_model->type) {
|
||||
if (SPICE_MODEL_CCFF != cur_sram_inf_orgz->spice_model->type) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,LINE[%d]) Scan-chain SRAM organization requires a SPICE model(type=sff)!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
|
@ -548,7 +548,6 @@ void init_check_arch_spice_models(t_arch* arch,
|
|||
get_default_spice_model(SPICE_MODEL_WIRE,
|
||||
arch->spice->num_spice_model,
|
||||
arch->spice->spice_models);
|
||||
continue;
|
||||
} else {
|
||||
arch->Directs[i].spice_model =
|
||||
find_name_matched_spice_model(arch->Directs[i].spice_model_name,
|
||||
|
@ -562,7 +561,7 @@ void init_check_arch_spice_models(t_arch* arch,
|
|||
arch->Directs[i].spice_model_name,
|
||||
arch->Directs[i].name);
|
||||
exit(1);
|
||||
} else if (SPICE_MODEL_CHAN_WIRE != arch->Directs[i].spice_model->type) {
|
||||
} else if (SPICE_MODEL_WIRE != arch->Directs[i].spice_model->type) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(FILE:%s, LINE[%d])Invalid SPICE model(%s) type of CLB to CLB Direct Connection (name=%s)! Should be chan_wire!\n",
|
||||
__FILE__ , __LINE__,
|
||||
arch->Directs[i].spice_model_name,
|
||||
|
|
|
@ -1094,7 +1094,7 @@ char* generate_string_spice_model_type(enum e_spice_model_type spice_model_type)
|
|||
case SPICE_MODEL_IOPAD:
|
||||
ret = "iopad";
|
||||
break;
|
||||
case SPICE_MODEL_SCFF:
|
||||
case SPICE_MODEL_CCFF:
|
||||
ret = "Scan-chain Flip-flop";
|
||||
break;
|
||||
default:
|
||||
|
@ -2220,7 +2220,7 @@ void check_sram_spice_model_ports(t_spice_model* cur_spice_model,
|
|||
}
|
||||
|
||||
void check_ff_spice_model_ports(t_spice_model* cur_spice_model,
|
||||
boolean is_scff) {
|
||||
boolean is_ccff) {
|
||||
int iport;
|
||||
int num_input_ports;
|
||||
t_spice_model_port** input_ports = NULL;
|
||||
|
@ -2232,22 +2232,22 @@ void check_ff_spice_model_ports(t_spice_model* cur_spice_model,
|
|||
int num_err = 0;
|
||||
|
||||
/* Check the type of SPICE model */
|
||||
if (FALSE == is_scff) {
|
||||
if (FALSE == is_ccff) {
|
||||
assert(SPICE_MODEL_FF == cur_spice_model->type);
|
||||
} else {
|
||||
assert(SPICE_MODEL_SCFF == cur_spice_model->type);
|
||||
assert(SPICE_MODEL_CCFF == cur_spice_model->type);
|
||||
}
|
||||
/* Check if we have D, Set and Reset */
|
||||
input_ports = find_spice_model_ports(cur_spice_model, SPICE_MODEL_PORT_INPUT, &num_input_ports, FALSE);
|
||||
if (TRUE == is_scff) {
|
||||
if (TRUE == is_ccff) {
|
||||
if (1 > num_input_ports) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) SCFF SPICE MODEL should at least have an input port!\n",
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) CCFF SPICE MODEL should at least have an input port!\n",
|
||||
__FILE__, __LINE__);
|
||||
num_err++;
|
||||
}
|
||||
for (iport = 0; iport < num_input_ports; iport++) {
|
||||
if (1 != input_ports[iport]->size) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) SCFF SPICE MODEL: each input port with size 1!\n",
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) CCFF SPICE MODEL: each input port with size 1!\n",
|
||||
__FILE__, __LINE__);
|
||||
num_err++;
|
||||
}
|
||||
|
@ -2269,20 +2269,20 @@ void check_ff_spice_model_ports(t_spice_model* cur_spice_model,
|
|||
/* Check if we have clock */
|
||||
clock_ports = find_spice_model_ports(cur_spice_model, SPICE_MODEL_PORT_CLOCK, &num_clock_ports, FALSE);
|
||||
if (1 > num_clock_ports) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) [FF|SCFF] SPICE MODEL should have at least 1 clock port!\n",
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) [FF|CCFF] SPICE MODEL should have at least 1 clock port!\n",
|
||||
__FILE__, __LINE__);
|
||||
num_err++;
|
||||
}
|
||||
for (iport = 0; iport < num_clock_ports; iport++) {
|
||||
if (1 != clock_ports[iport]->size) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) [FF|SCFF] SPICE MODEL: 1 clock port with size 1!\n",
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) [FF|CCFF] SPICE MODEL: 1 clock port with size 1!\n",
|
||||
__FILE__, __LINE__);
|
||||
num_err++;
|
||||
}
|
||||
}
|
||||
/* Check if we have output */
|
||||
output_ports = find_spice_model_ports(cur_spice_model, SPICE_MODEL_PORT_OUTPUT, &num_output_ports, TRUE);
|
||||
if (FALSE == is_scff) {
|
||||
if (FALSE == is_ccff) {
|
||||
if (1 != output_ports[0]->size) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) FF SPICE MODEL: each output port with size 1!\n",
|
||||
__FILE__, __LINE__);
|
||||
|
@ -2290,12 +2290,12 @@ void check_ff_spice_model_ports(t_spice_model* cur_spice_model,
|
|||
}
|
||||
} else {
|
||||
if (2 != num_output_ports) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) SCFF SPICE MODEL should have 2 output ports!\n",
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) CCFF SPICE MODEL should have 2 output ports!\n",
|
||||
__FILE__, __LINE__);
|
||||
num_err++;
|
||||
for (iport = 0; iport < num_output_ports; iport++) {
|
||||
if (1 != output_ports[iport]->size) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) SCFF SPICE MODEL: the output port (%s) should have a size of 1!\n",
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) CCFF SPICE MODEL: the output port (%s) should have a size of 1!\n",
|
||||
__FILE__, __LINE__, output_ports[iport]->prefix);
|
||||
num_err++;
|
||||
}
|
||||
|
@ -2462,11 +2462,11 @@ void free_one_mem_bank_info(t_mem_bank_info* mem_bank_info) {
|
|||
return;
|
||||
}
|
||||
|
||||
t_scff_info* alloc_one_scff_info() {
|
||||
return (t_scff_info*)my_malloc(sizeof(t_scff_info));
|
||||
t_ccff_info* alloc_one_ccff_info() {
|
||||
return (t_ccff_info*)my_malloc(sizeof(t_ccff_info));
|
||||
}
|
||||
|
||||
void free_one_scff_info(t_scff_info* scff_info) {
|
||||
void free_one_ccff_info(t_ccff_info* ccff_info) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2501,23 +2501,23 @@ void update_mem_bank_info_num_mem_bit(t_mem_bank_info* cur_mem_bank_info,
|
|||
return;
|
||||
}
|
||||
|
||||
void init_scff_info(t_scff_info* cur_scff_info,
|
||||
void init_ccff_info(t_ccff_info* cur_ccff_info,
|
||||
t_spice_model* cur_mem_model) {
|
||||
assert(NULL != cur_scff_info);
|
||||
assert(NULL != cur_ccff_info);
|
||||
assert(NULL != cur_mem_model);
|
||||
|
||||
cur_scff_info->mem_model = cur_mem_model;
|
||||
cur_scff_info->num_mem_bit = 0;
|
||||
cur_scff_info->num_scff = 0;
|
||||
cur_ccff_info->mem_model = cur_mem_model;
|
||||
cur_ccff_info->num_mem_bit = 0;
|
||||
cur_ccff_info->num_ccff = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void update_scff_info_num_mem_bit(t_scff_info* cur_scff_info,
|
||||
void update_ccff_info_num_mem_bit(t_ccff_info* cur_ccff_info,
|
||||
int num_mem_bit) {
|
||||
assert(NULL != cur_scff_info);
|
||||
assert(NULL != cur_ccff_info);
|
||||
|
||||
cur_scff_info->num_mem_bit = num_mem_bit;
|
||||
cur_ccff_info->num_mem_bit = num_mem_bit;
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -2573,8 +2573,8 @@ void init_sram_orgz_info(t_sram_orgz_info* cur_sram_orgz_info,
|
|||
num_bl_per_sram, num_wl_per_sram);
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
cur_sram_orgz_info->scff_info = alloc_one_scff_info();
|
||||
init_scff_info(cur_sram_orgz_info->scff_info, cur_mem_model);
|
||||
cur_sram_orgz_info->ccff_info = alloc_one_ccff_info();
|
||||
init_ccff_info(cur_sram_orgz_info->ccff_info, cur_mem_model);
|
||||
break;
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
cur_sram_orgz_info->standalone_sram_info = alloc_one_standalone_sram_info();
|
||||
|
@ -2624,7 +2624,7 @@ void free_sram_orgz_info(t_sram_orgz_info* cur_sram_orgz_info,
|
|||
free_one_mem_bank_info(cur_sram_orgz_info->mem_bank_info);
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
free_one_scff_info(cur_sram_orgz_info->scff_info);
|
||||
free_one_ccff_info(cur_sram_orgz_info->ccff_info);
|
||||
break;
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
free_one_standalone_sram_info(cur_sram_orgz_info->standalone_sram_info);
|
||||
|
@ -2831,7 +2831,7 @@ int get_sram_orgz_info_num_mem_bit(t_sram_orgz_info* cur_sram_orgz_info) {
|
|||
case SPICE_SRAM_STANDALONE:
|
||||
return cur_sram_orgz_info->standalone_sram_info->num_mem_bit;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
return cur_sram_orgz_info->scff_info->num_mem_bit;
|
||||
return cur_sram_orgz_info->ccff_info->num_mem_bit;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
return cur_sram_orgz_info->mem_bank_info->num_mem_bit;
|
||||
default:
|
||||
|
@ -2854,7 +2854,7 @@ void update_sram_orgz_info_num_mem_bit(t_sram_orgz_info* cur_sram_orgz_info,
|
|||
update_standalone_sram_info_num_mem_bit(cur_sram_orgz_info->standalone_sram_info, new_num_mem_bit);
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
update_scff_info_num_mem_bit(cur_sram_orgz_info->scff_info, new_num_mem_bit);
|
||||
update_ccff_info_num_mem_bit(cur_sram_orgz_info->ccff_info, new_num_mem_bit);
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
update_mem_bank_info_num_mem_bit(cur_sram_orgz_info->mem_bank_info, new_num_mem_bit);
|
||||
|
@ -2903,7 +2903,7 @@ void get_sram_orgz_info_mem_model(t_sram_orgz_info* cur_sram_orgz_info,
|
|||
(*mem_model_ptr) = cur_sram_orgz_info->standalone_sram_info->mem_model;
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
(*mem_model_ptr) = cur_sram_orgz_info->scff_info->mem_model;
|
||||
(*mem_model_ptr) = cur_sram_orgz_info->ccff_info->mem_model;
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
(*mem_model_ptr) = cur_sram_orgz_info->mem_bank_info->mem_model;
|
||||
|
@ -2929,7 +2929,7 @@ void update_sram_orgz_info_mem_model(t_sram_orgz_info* cur_sram_orgz_info,
|
|||
cur_sram_orgz_info->standalone_sram_info->mem_model = cur_mem_model;
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
cur_sram_orgz_info->scff_info->mem_model = cur_mem_model;
|
||||
cur_sram_orgz_info->ccff_info->mem_model = cur_mem_model;
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
cur_sram_orgz_info->mem_bank_info->mem_model = cur_mem_model;
|
||||
|
@ -3179,6 +3179,10 @@ void config_circuit_models_sram_port_to_default_sram_model(CircuitLibrary& circu
|
|||
}
|
||||
}
|
||||
}
|
||||
/* TODO: this should be done right after XML parsing!!!
|
||||
* Rebuild the submodels for circuit_library, because we have created links for ports
|
||||
*/
|
||||
circuit_lib.build_model_links();
|
||||
}
|
||||
|
||||
void determine_sb_port_coordinator(t_sb cur_sb_info, int side,
|
||||
|
|
|
@ -235,7 +235,7 @@ void check_sram_spice_model_ports(t_spice_model* cur_spice_model,
|
|||
boolean include_bl_wl);
|
||||
|
||||
void check_ff_spice_model_ports(t_spice_model* cur_spice_model,
|
||||
boolean is_scff);
|
||||
boolean is_ccff);
|
||||
|
||||
/* Functions to manipulate t_conf_bit and t_conf_bit_info */
|
||||
void free_conf_bit(t_conf_bit* conf_bit);
|
||||
|
@ -270,9 +270,9 @@ t_mem_bank_info* alloc_one_mem_bank_info();
|
|||
|
||||
void free_one_mem_bank_info(t_mem_bank_info* mem_bank_info);
|
||||
|
||||
t_scff_info* alloc_one_scff_info();
|
||||
t_ccff_info* alloc_one_ccff_info();
|
||||
|
||||
void free_one_scff_info(t_scff_info* scff_info);
|
||||
void free_one_ccff_info(t_ccff_info* ccff_info);
|
||||
|
||||
t_standalone_sram_info* alloc_one_standalone_sram_info();
|
||||
|
||||
|
@ -299,10 +299,10 @@ void get_sram_orgz_info_reserved_blwl(t_sram_orgz_info* cur_sram_orgz_info,
|
|||
void update_mem_bank_info_num_mem_bit(t_mem_bank_info* cur_mem_bank_info,
|
||||
int num_mem_bit);
|
||||
|
||||
void init_scff_info(t_scff_info* cur_scff_info,
|
||||
void init_ccff_info(t_ccff_info* cur_ccff_info,
|
||||
t_spice_model* cur_mem_model);
|
||||
|
||||
void update_scff_info_num_mem_bit(t_scff_info* cur_scff_info,
|
||||
void update_ccff_info_num_mem_bit(t_ccff_info* cur_ccff_info,
|
||||
int num_mem_bit);
|
||||
|
||||
void init_standalone_sram_info(t_standalone_sram_info* cur_standalone_sram_info,
|
||||
|
|
|
@ -114,7 +114,7 @@ CircuitModelId link_circuit_model_by_name_and_type(const char* circuit_model_nam
|
|||
/************************************************************************
|
||||
* Link circuit model to the SRAM organization
|
||||
* Case 1: standalone organization required a SRAM circuit model
|
||||
* Case 1: scan-chain organization required a SCFF circuit model
|
||||
* Case 1: configuration-chain organization required a CCFF circuit model
|
||||
* Case 1: memory-bank organization required a SRAM circuit model
|
||||
***********************************************************************/
|
||||
static
|
||||
|
@ -128,9 +128,9 @@ void link_one_sram_inf_orgz(t_sram_inf_orgz* cur_sram_inf_orgz,
|
|||
/* Check the type of SRAM_Ciruit_MODEL required by different sram organization */
|
||||
/* check SRAM ports
|
||||
* Checker for circuit models used by the SRAM organization
|
||||
* either SRAMs or SCFFs
|
||||
* 1. It will check the basic port required for SRAMs and SCFFs
|
||||
* 2. It will check any special ports required for SRAMs and SCFFs
|
||||
* either SRAMs or CCFFs
|
||||
* 1. It will check the basic port required for SRAMs and CCFFs
|
||||
* 2. It will check any special ports required for SRAMs and CCFFs
|
||||
*/
|
||||
switch (cur_sram_inf_orgz->type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
|
@ -145,8 +145,8 @@ void link_one_sram_inf_orgz(t_sram_inf_orgz* cur_sram_inf_orgz,
|
|||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
/* check Scan-chain Flip-flop ports */
|
||||
cur_sram_inf_orgz->circuit_model = link_circuit_model_by_name_and_type(cur_sram_inf_orgz->spice_model_name, circuit_lib, SPICE_MODEL_SCFF);
|
||||
check_scff_circuit_model_ports(circuit_lib, cur_sram_inf_orgz->circuit_model);
|
||||
cur_sram_inf_orgz->circuit_model = link_circuit_model_by_name_and_type(cur_sram_inf_orgz->spice_model_name, circuit_lib, SPICE_MODEL_CCFF);
|
||||
check_ccff_circuit_model_ports(circuit_lib, cur_sram_inf_orgz->circuit_model);
|
||||
break;
|
||||
case SPICE_SRAM_LOCAL_ENCODER:
|
||||
/* Wipe out LOCAL ENCODER, it is not supported here ! */
|
||||
|
@ -482,7 +482,7 @@ void link_circuit_library_to_arch(t_arch* arch,
|
|||
/* Check Circuit models first*/
|
||||
VTR_ASSERT_SAFE( (NULL != arch) && (NULL != arch->spice) );
|
||||
|
||||
/* 1. Link the spice model defined in pb_types and routing switches */
|
||||
/* 1. Link the circuit model defined in pb_types and routing switches */
|
||||
/* Step A: Check routing switches, connection blocks*/
|
||||
if (0 >= arch->num_cb_switch) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
|
@ -500,7 +500,7 @@ void link_circuit_library_to_arch(t_arch* arch,
|
|||
__FILE__, __LINE__, arch->cb_switches[i].spice_model_name, arch->cb_switches[i].name);
|
||||
exit(1);
|
||||
}
|
||||
/* Check the spice model structure is matched with the structure in switch_inf */
|
||||
/* Check the circuit model structure is matched with the structure in switch_inf */
|
||||
if (0 < check_circuit_model_structure_match_switch_inf(arch->cb_switches[i], arch->spice->circuit_lib)) {
|
||||
exit(1);
|
||||
}
|
||||
|
@ -544,7 +544,7 @@ void link_circuit_library_to_arch(t_arch* arch,
|
|||
/* Step C: Find SRAM Model*/
|
||||
link_sram_inf(&(arch->sram_inf), arch->spice->circuit_lib);
|
||||
|
||||
/* Step D: Find the segment spice_model*/
|
||||
/* Step D: Find the segment circuit_model*/
|
||||
for (int i = 0; i < arch->num_segments; i++) {
|
||||
arch->Segments[i].circuit_model = link_circuit_model_by_name_and_type(arch->Segments[i].spice_model_name,
|
||||
arch->spice->circuit_lib, SPICE_MODEL_CHAN_WIRE);
|
||||
|
@ -562,7 +562,7 @@ void link_circuit_library_to_arch(t_arch* arch,
|
|||
for (int i = 0; i < arch->num_directs; i++) {
|
||||
arch->Directs[i].circuit_model = link_circuit_model_by_name_and_type(arch->Directs[i].spice_model_name,
|
||||
arch->spice->circuit_lib, SPICE_MODEL_WIRE);
|
||||
/* Check SPICE model type */
|
||||
/* Check Circuit model type */
|
||||
if (CircuitModelId::INVALID() == arch->Directs[i].circuit_model) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s, LINE[%d])Invalid circuit model name(%s) of CLB to CLB Direct Connection (name=%s) is undefined in circuit models!\n",
|
||||
|
|
|
@ -106,6 +106,13 @@ bool ModuleManager::port_is_register(const ModuleId& module, const ModulePortId&
|
|||
return port_is_register_[module][port];
|
||||
}
|
||||
|
||||
/* Return the pre-processing flag of a port */
|
||||
std::string ModuleManager::port_preproc_flag(const ModuleId& module, const ModulePortId& port) const {
|
||||
/* validate both module id and port id*/
|
||||
VTR_ASSERT(valid_module_port_id(module, port));
|
||||
return port_preproc_flags_[module][port];
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Public Mutators
|
||||
******************************************************************************/
|
||||
|
@ -131,6 +138,7 @@ ModuleId ModuleManager::add_module(const std::string& name) {
|
|||
ports_.emplace_back();
|
||||
port_types_.emplace_back();
|
||||
port_is_register_.emplace_back();
|
||||
port_preproc_flags_.emplace_back();
|
||||
|
||||
/* Register in the name-to-id map */
|
||||
name_id_map_[name] = module;
|
||||
|
@ -155,6 +163,7 @@ ModulePortId ModuleManager::add_port(const ModuleId& module,
|
|||
ports_[module].push_back(port_info);
|
||||
port_types_[module].push_back(port_type);
|
||||
port_is_register_[module].push_back(false);
|
||||
port_preproc_flags_[module].emplace_back(); /* Create an empty string for the pre-processing flags */
|
||||
|
||||
/* Update fast look-up for port */
|
||||
port_lookup_[module][port_type].push_back(port);
|
||||
|
@ -178,6 +187,13 @@ void ModuleManager::set_port_is_register(const ModuleId& module, const std::stri
|
|||
port_is_register_[module][port] = is_register;
|
||||
}
|
||||
|
||||
/* Set the preprocessing flag for a port */
|
||||
void ModuleManager::set_port_preproc_flag(const ModuleId& module, const ModulePortId& port, const std::string& preproc_flag) {
|
||||
/* Must find something, otherwise drop an error */
|
||||
VTR_ASSERT(valid_module_port_id(module, port));
|
||||
port_preproc_flags_[module][port] = preproc_flag;
|
||||
}
|
||||
|
||||
/* Add a child module to a parent module */
|
||||
void ModuleManager::add_child_module(const ModuleId& parent_module, const ModuleId& child_module) {
|
||||
/* Validate the id of both parent and child modules */
|
||||
|
|
|
@ -48,6 +48,8 @@ class ModuleManager {
|
|||
size_t num_instance(const ModuleId& parent_module, const ModuleId& child_module) const;
|
||||
/* Find if a port is register */
|
||||
bool port_is_register(const ModuleId& module, const ModulePortId& port) const;
|
||||
/* Return the pre-processing flag of a port */
|
||||
std::string port_preproc_flag(const ModuleId& module, const ModulePortId& port) const;
|
||||
public: /* Public mutators */
|
||||
/* Add a module */
|
||||
ModuleId add_module(const std::string& name);
|
||||
|
@ -58,11 +60,14 @@ class ModuleManager {
|
|||
void set_module_name(const ModuleId& module, const std::string& name);
|
||||
/* Set a port to be a register */
|
||||
void set_port_is_register(const ModuleId& module, const std::string& port_name, const bool& is_register);
|
||||
/* Set the preprocessing flag for a port */
|
||||
void set_port_preproc_flag(const ModuleId& module, const ModulePortId& port, const std::string& preproc_flag);
|
||||
/* Add a child module to a parent module */
|
||||
void add_child_module(const ModuleId& parent_module, const ModuleId& child_module);
|
||||
private: /* Private validators/invalidators */
|
||||
public: /* Public validators/invalidators */
|
||||
bool valid_module_id(const ModuleId& module) const;
|
||||
bool valid_module_port_id(const ModuleId& module, const ModulePortId& port) const;
|
||||
private: /* Private validators/invalidators */
|
||||
void invalidate_name2id_map();
|
||||
void invalidate_port_lookup();
|
||||
private: /* Internal data */
|
||||
|
@ -76,6 +81,7 @@ class ModuleManager {
|
|||
vtr::vector<ModuleId, vtr::vector<ModulePortId, BasicPort>> ports_; /* List of ports for each Module */
|
||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, enum e_module_port_type>> port_types_; /* Type of ports */
|
||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, bool>> port_is_register_; /* If the port is a register, use for Verilog port definition. If enabled: <port_type> reg <port_name> */
|
||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, std::string>> port_preproc_flags_; /* If a port is available only when a pre-processing flag is enabled. This is to record the pre-processing flags */
|
||||
|
||||
/* fast look-up for module */
|
||||
std::map<std::string, ModuleId> name_id_map_;
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
|
||||
#include "circuit_library.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
#include "fpga_x2p_naming.h"
|
||||
|
||||
#include "module_manager_utils.h"
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -72,3 +75,285 @@ ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
|
|||
return add_circuit_model_to_module_manager(module_manager, circuit_lib, circuit_model, circuit_lib.model_name(circuit_model));
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add a list of ports that are used for reserved SRAM ports to a module
|
||||
* in the module manager
|
||||
* The reserved SRAM ports are mainly designed for RRAM-based FPGA,
|
||||
* which are shared across modules.
|
||||
* Note that different modules may require different size of reserved
|
||||
* SRAM ports but their LSB must all start from 0
|
||||
* +---------+
|
||||
* reserved_sram_port[0:X] --->| ModuleA |
|
||||
* +---------+
|
||||
*
|
||||
* +---------+
|
||||
* reserved_sram_port[0:Y] --->| ModuleB |
|
||||
* +---------+
|
||||
*
|
||||
********************************************************************/
|
||||
void add_reserved_sram_ports_to_module_manager(ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const size_t& port_size) {
|
||||
/* Add a reserved BLB port to the module */
|
||||
std::string blb_port_name = generate_reserved_sram_port_name(SPICE_MODEL_PORT_BLB);
|
||||
BasicPort blb_module_port(blb_port_name, port_size);
|
||||
/* Add generated ports to the ModuleManager */
|
||||
module_manager.add_port(module_id, blb_module_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
|
||||
/* Add a reserved BLB port to the module */
|
||||
std::string wl_port_name = generate_reserved_sram_port_name(SPICE_MODEL_PORT_WL);
|
||||
BasicPort wl_module_port(wl_port_name, port_size);
|
||||
/* Add generated ports to the ModuleManager */
|
||||
module_manager.add_port(module_id, wl_module_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add a list of ports that are used for formal verification to a module
|
||||
* in the module manager
|
||||
*
|
||||
* The formal verification port will appear only when a pre-processing flag is defined
|
||||
* This function will add the pre-processing flag along with the port
|
||||
********************************************************************/
|
||||
void add_formal_verification_sram_ports_to_module_manager(ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const std::string& preproc_flag,
|
||||
const size_t& port_size) {
|
||||
/* Create a port */
|
||||
std::string port_name = generate_formal_verification_sram_port_name(circuit_lib, sram_model);
|
||||
BasicPort module_port(port_name, port_size);
|
||||
/* Add generated ports to the ModuleManager */
|
||||
ModulePortId port_id = module_manager.add_port(module_id, module_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
/* Add pre-processing flag if defined */
|
||||
module_manager.set_port_preproc_flag(module_id, port_id, preproc_flag);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add a list of ports that are used for SRAM configuration to a module
|
||||
* in the module manager
|
||||
* The type and names of added ports strongly depend on the
|
||||
* organization of SRAMs.
|
||||
* 1. Standalone SRAMs:
|
||||
* two ports will be added, which are regular output and inverted output
|
||||
* 2. Scan-chain Flip-flops:
|
||||
* two ports will be added, which are the head of scan-chain
|
||||
* and the tail of scan-chain
|
||||
* IMPORTANT: the port size will be forced to 1 in this case
|
||||
* because the head and tail are both 1-bit ports!!!
|
||||
* 3. Memory decoders:
|
||||
* 2-4 ports will be added, depending on the ports available in the SRAM
|
||||
* Among these, two ports are mandatory: BL and WL
|
||||
* The other two ports are optional: BLB and WLB
|
||||
* Note that the constraints are correletated to the checking rules
|
||||
* in check_circuit_library()
|
||||
********************************************************************/
|
||||
void add_sram_ports_to_module_manager(ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_sram_orgz sram_orgz_type,
|
||||
const size_t& port_size) {
|
||||
/* Prepare a list of port types to be added, the port type will be used to create port names */
|
||||
std::vector<e_spice_model_port_type> model_port_types;
|
||||
/* Prepare a list of module port types to be added, the port type will be used to specify the port type in Verilog/SPICE module */
|
||||
std::vector<ModuleManager::e_module_port_type> module_port_types;
|
||||
/* Actual port size may be different from user specification. Think about CCFF */
|
||||
size_t sram_port_size = port_size;
|
||||
|
||||
switch (sram_orgz_type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
model_port_types.push_back(SPICE_MODEL_PORT_INPUT);
|
||||
module_port_types.push_back(ModuleManager::MODULE_INPUT_PORT);
|
||||
model_port_types.push_back(SPICE_MODEL_PORT_OUTPUT);
|
||||
module_port_types.push_back(ModuleManager::MODULE_INPUT_PORT);
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
model_port_types.push_back(SPICE_MODEL_PORT_INPUT);
|
||||
module_port_types.push_back(ModuleManager::MODULE_INPUT_PORT);
|
||||
model_port_types.push_back(SPICE_MODEL_PORT_OUTPUT);
|
||||
module_port_types.push_back(ModuleManager::MODULE_OUTPUT_PORT);
|
||||
/* CCFF head/tail are single-bit ports */
|
||||
sram_port_size = 1;
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK: {
|
||||
std::vector<e_spice_model_port_type> ports_to_search;
|
||||
ports_to_search.push_back(SPICE_MODEL_PORT_BL);
|
||||
ports_to_search.push_back(SPICE_MODEL_PORT_WL);
|
||||
ports_to_search.push_back(SPICE_MODEL_PORT_BLB);
|
||||
ports_to_search.push_back(SPICE_MODEL_PORT_WLB);
|
||||
/* Try to find a BL/WL/BLB/WLB port and update the port types/module port types to be added */
|
||||
for (const auto& port_to_search : ports_to_search) {
|
||||
std::vector<CircuitPortId> found_port = circuit_lib.model_ports_by_type(sram_model, port_to_search);
|
||||
if (0 == found_port.size()) {
|
||||
continue;
|
||||
}
|
||||
model_port_types.push_back(port_to_search);
|
||||
module_port_types.push_back(ModuleManager::MODULE_INPUT_PORT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid type of SRAM organization !\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Add ports to the module manager */
|
||||
for (size_t iport = 0; iport < model_port_types.size(); ++iport) {
|
||||
/* Create a port */
|
||||
std::string port_name = generate_sram_port_name(circuit_lib, sram_model, sram_orgz_type, model_port_types[iport]);
|
||||
BasicPort module_port(port_name, sram_port_size);
|
||||
/* Add generated ports to the ModuleManager */
|
||||
module_manager.add_port(module_id, module_port, module_port_types[iport]);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Create a port-to-port map for a CMOS memory module
|
||||
*
|
||||
* Configuration Chain
|
||||
* -------------------
|
||||
*
|
||||
* config_bus (head) config_bus (tail)
|
||||
* | ^
|
||||
* v |
|
||||
* +-------------------------------------+
|
||||
* | CMOS-based Memory Module |
|
||||
* +-------------------------------------+
|
||||
* | |
|
||||
* v v
|
||||
* sram_out sram_outb
|
||||
*
|
||||
*
|
||||
* Memory bank
|
||||
* -----------
|
||||
*
|
||||
* config_bus (BL) config_bus (WL)
|
||||
* | |
|
||||
* v v
|
||||
* +-------------------------------------+
|
||||
* | CMOS-based Memory Module |
|
||||
* +-------------------------------------+
|
||||
* | |
|
||||
* v v
|
||||
* sram_out sram_outb
|
||||
*
|
||||
**********************************************************************/
|
||||
static
|
||||
std::map<std::string, BasicPort> generate_cmos_mem_module_port2port_map(const ModuleManager& module_manager,
|
||||
const ModuleId& mem_module,
|
||||
const std::vector<BasicPort>& config_bus_ports,
|
||||
const std::vector<BasicPort>& mem_output_bus_ports,
|
||||
const e_sram_orgz& sram_orgz_type) {
|
||||
std::map<std::string, BasicPort> port2port_name_map;
|
||||
|
||||
switch (sram_orgz_type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
/* Nothing to do */
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN: {
|
||||
/* Link the head port of the memory module:
|
||||
* the LSB of config bus port is the head port index
|
||||
*/
|
||||
VTR_ASSERT( 1 == config_bus_ports.size() );
|
||||
BasicPort head_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_lsb(), config_bus_ports[0].get_lsb());
|
||||
port2port_name_map[generate_configuration_chain_head_name()] = head_port;
|
||||
|
||||
/* Link the tail port of the memory module:
|
||||
* the MSB of config bus port is the tail port index
|
||||
*/
|
||||
BasicPort tail_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_msb(), config_bus_ports[0].get_msb());
|
||||
port2port_name_map[generate_configuration_chain_tail_name()] = tail_port;
|
||||
|
||||
/* Link the SRAM output ports of the memory module */
|
||||
VTR_ASSERT( 2 == mem_output_bus_ports.size() );
|
||||
port2port_name_map[generate_configuration_chain_data_out_name()] = mem_output_bus_ports[0];
|
||||
port2port_name_map[generate_configuration_chain_inverted_data_out_name()] = mem_output_bus_ports[1];
|
||||
break;
|
||||
}
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid type of SRAM organization!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return port2port_name_map;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Create a port-to-port map for a ReRAM-based memory module
|
||||
* Memory bank
|
||||
* -----------
|
||||
*
|
||||
* config_bus (BL) config_bus (WL)
|
||||
* | |
|
||||
* v v
|
||||
* +-------------------------------------+
|
||||
* | ReRAM-based Memory Module |
|
||||
* +-------------------------------------+
|
||||
* | |
|
||||
* v v
|
||||
* Mem_out Mem_outb
|
||||
**********************************************************************/
|
||||
static
|
||||
std::map<std::string, BasicPort> generate_rram_mem_module_port2port_map(const ModuleManager& module_manager,
|
||||
const ModuleId& mem_module,
|
||||
const e_sram_orgz& sram_orgz_type) {
|
||||
std::map<std::string, BasicPort> port2port_name_map;
|
||||
|
||||
switch (sram_orgz_type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
/* Not supported */
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
/* TODO: to be supported */
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
/* TODO: link BL/WL/Reserved Ports to the inputs of a memory module */
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid type of SRAM organization!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return port2port_name_map;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Create a port-to-port map for a memory module
|
||||
* The content of the port-to-port map will depend not only
|
||||
* the design technology of the memory cells but also the
|
||||
* configuration styles of FPGA fabric.
|
||||
* Here we will branch on the design technology
|
||||
**********************************************************************/
|
||||
std::map<std::string, BasicPort> generate_mem_module_port2port_map(const ModuleManager& module_manager,
|
||||
const ModuleId& mem_module,
|
||||
const std::vector<BasicPort>& config_bus_ports,
|
||||
const std::vector<BasicPort>& mem_output_bus_ports,
|
||||
const e_spice_model_design_tech& mem_design_tech,
|
||||
const e_sram_orgz& sram_orgz_type) {
|
||||
std::map<std::string, BasicPort> port2port_name_map;
|
||||
|
||||
switch (mem_design_tech) {
|
||||
case SPICE_MODEL_DESIGN_CMOS:
|
||||
port2port_name_map = generate_cmos_mem_module_port2port_map(module_manager, mem_module, config_bus_ports, mem_output_bus_ports, sram_orgz_type);
|
||||
break;
|
||||
case SPICE_MODEL_DESIGN_RRAM:
|
||||
port2port_name_map = generate_rram_mem_module_port2port_map(module_manager, mem_module, sram_orgz_type);
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid type of memory design technology !\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return port2port_name_map;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
#define MODULE_MANAGER_UTILS_H
|
||||
|
||||
/* Include other header files which are dependency on the function declared below */
|
||||
#include <vector>
|
||||
#include "device_port.h"
|
||||
#include "spice_types.h"
|
||||
#include "circuit_library.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
|
@ -17,5 +20,30 @@ ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
|
|||
ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model);
|
||||
|
||||
void add_reserved_sram_ports_to_module_manager(ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const size_t& port_size);
|
||||
|
||||
void add_formal_verification_sram_ports_to_module_manager(ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const std::string& preproc_flag,
|
||||
const size_t& port_size);
|
||||
|
||||
void add_sram_ports_to_module_manager(ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_sram_orgz sram_orgz_type,
|
||||
const size_t& port_size);
|
||||
|
||||
std::map<std::string, BasicPort> generate_mem_module_port2port_map(const ModuleManager& module_manager,
|
||||
const ModuleId& mem_module,
|
||||
const std::vector<BasicPort>& config_bus_ports,
|
||||
const std::vector<BasicPort>& mem_output_bus_ports,
|
||||
const e_spice_model_design_tech& mem_design_tech,
|
||||
const e_sram_orgz& sram_orgz_type);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/********************************************************************
|
||||
* This file includes most utilized function for rr_block data structures
|
||||
*******************************************************************/
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "vtr_assert.h"
|
||||
#include "vpr_types.h"
|
||||
#include "fpga_x2p_types.h"
|
||||
#include "rr_blocks_utils.h"
|
||||
|
||||
/*********************************************************************
|
||||
* This function will find the global ports required by a Switch Block
|
||||
* module. It will find all the circuit models in the circuit library
|
||||
* that may be included in the Switch Block
|
||||
* Collect the global ports from the circuit_models and merge with the same name
|
||||
********************************************************************/
|
||||
std::vector<CircuitPortId> find_switch_block_global_ports(const RRGSB& rr_gsb,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::vector<t_switch_inf>& switch_lib) {
|
||||
std::vector<CircuitModelId> sub_models;
|
||||
/* Walk through the OUTPUT nodes at each side of a GSB,
|
||||
* get the switch id of incoming edges
|
||||
* and get the circuit model linked to the switch id
|
||||
*/
|
||||
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
|
||||
Side side_manager(side);
|
||||
for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) {
|
||||
if (OUT_PORT != rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) {
|
||||
continue;
|
||||
}
|
||||
/* Find the driver switch of the node */
|
||||
short driver_switch = rr_gsb.get_chan_node(side_manager.get_side(), itrack)->drive_switches[DEFAULT_SWITCH_ID];
|
||||
/* Find the circuit model id of the driver switch */
|
||||
VTR_ASSERT( (size_t)driver_switch < switch_lib.size() );
|
||||
/* Get the model, and try to add to the sub_model list */
|
||||
CircuitModelId switch_circuit_model = switch_lib[driver_switch].circuit_model;
|
||||
/* Make sure it is a valid id */
|
||||
VTR_ASSERT( CircuitModelId::INVALID() != switch_circuit_model );
|
||||
/* Get the model, and try to add to the sub_model list */
|
||||
if (sub_models.end() == std::find(sub_models.begin(), sub_models.end(), switch_circuit_model)) {
|
||||
/* Not yet in the list, add it */
|
||||
sub_models.push_back(switch_circuit_model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<CircuitPortId> global_ports;
|
||||
/* Iterate over the model list, and add the global ports*/
|
||||
for (const auto& model : sub_models) {
|
||||
std::vector<CircuitPortId> temp_global_ports = circuit_lib.model_global_ports(model, true);
|
||||
/* Add the temp_global_ports to the list to be returned, make sure we do not have any duplicated ports */
|
||||
for (const auto& port_candidate : temp_global_ports) {
|
||||
if (global_ports.end() == std::find(global_ports.begin(), global_ports.end(), port_candidate)) {
|
||||
/* Not yet in the list, add it */
|
||||
global_ports.push_back(port_candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return global_ports;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* This function will find the number of multiplexers required by
|
||||
* a Switch Block module.
|
||||
********************************************************************/
|
||||
size_t find_switch_block_number_of_muxes(const RRGSB& rr_gsb) {
|
||||
size_t num_muxes = 0;
|
||||
/* Walk through the OUTPUT nodes at each side of a GSB,
|
||||
* get the switch id of incoming edges
|
||||
* and get the circuit model linked to the switch id
|
||||
*/
|
||||
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
|
||||
Side side_manager(side);
|
||||
for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) {
|
||||
if (OUT_PORT != rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) {
|
||||
continue;
|
||||
}
|
||||
/* Check if this node is just a passing wire */
|
||||
if (true == rr_gsb.is_sb_node_passing_wire(side_manager.get_side(), itrack)) {
|
||||
continue;
|
||||
}
|
||||
/* Check if this node has more than 2 drivers */
|
||||
if (2 > rr_gsb.get_chan_node(side_manager.get_side(), itrack)->num_drive_rr_nodes) {
|
||||
continue;
|
||||
}
|
||||
/* This means we need a multiplexer, update the counter */
|
||||
num_muxes++;
|
||||
}
|
||||
}
|
||||
return num_muxes;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/********************************************************************
|
||||
* Header file for rr_block_utils.cpp
|
||||
*******************************************************************/
|
||||
#ifndef RR_BLOCKS_UTILS_H
|
||||
#define RR_BLOCKS_UTILS_H
|
||||
|
||||
/* Include other header file required by the function declaration */
|
||||
#include <vector>
|
||||
#include "physical_types.h"
|
||||
#include "circuit_library.h"
|
||||
#include "rr_blocks.h"
|
||||
|
||||
std::vector<CircuitPortId> find_switch_block_global_ports(const RRGSB& rr_gsb,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::vector<t_switch_inf>& switch_lib);
|
||||
|
||||
size_t find_switch_block_number_of_muxes(const RRGSB& rr_gsb);
|
||||
|
||||
#endif
|
|
@ -351,10 +351,10 @@ void fprint_spice_sram_one_outport(FILE* fp,
|
|||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
if (0 == port_type_index) {
|
||||
port_name = "scff_out";
|
||||
port_name = "ccff_out";
|
||||
} else {
|
||||
assert(1 == port_type_index);
|
||||
port_name = "scff_outb";
|
||||
port_name = "ccff_outb";
|
||||
}
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
|
@ -696,7 +696,7 @@ void fprint_global_pad_ports_spice_model(FILE* fp,
|
|||
case SPICE_MODEL_LUT:
|
||||
case SPICE_MODEL_FF:
|
||||
case SPICE_MODEL_HARDLOGIC:
|
||||
case SPICE_MODEL_SCFF:
|
||||
case SPICE_MODEL_CCFF:
|
||||
case SPICE_MODEL_INVBUF:
|
||||
case SPICE_MODEL_PASSGATE:
|
||||
case SPICE_MODEL_GATE:
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
#include "verilog_global.h"
|
||||
#include "verilog_utils.h"
|
||||
#include "verilog_submodules.h"
|
||||
#include "verilog_decoder.h"
|
||||
#include "verilog_decoders.h"
|
||||
#include "verilog_pbtypes.h"
|
||||
#include "verilog_routing.h"
|
||||
#include "verilog_compact_netlist.h"
|
||||
|
@ -266,10 +268,21 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup,
|
|||
dump_verilog_simulation_preproc(src_dir_path,
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
|
||||
|
||||
/* Generate primitive Verilog modules, which are corner stones of FPGA fabric
|
||||
* Note that this function MUST be called before Verilog generation of
|
||||
* core logic (i.e., logic blocks and routing resources) !!!
|
||||
* This is because that this function will add the primitive Verilog modules to
|
||||
* the module manager.
|
||||
* Without the modules in the module manager, core logic generation is not possible!!!
|
||||
*/
|
||||
dump_verilog_submodules(module_manager, mux_lib, sram_verilog_orgz_info, src_dir_path, submodule_dir_path,
|
||||
Arch, &vpr_setup.RoutingArch,
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
|
||||
|
||||
/* Dump routing resources: switch blocks, connection blocks and channel tracks */
|
||||
dump_verilog_routing_resources(sram_verilog_orgz_info, src_dir_path, rr_dir_path, Arch, &vpr_setup.RoutingArch,
|
||||
num_rr_nodes, rr_node, rr_node_indices, rr_indexed_data,
|
||||
vpr_setup.FPGA_SPICE_Opts);
|
||||
print_verilog_routing_resources(module_manager, mux_lib, sram_verilog_orgz_info, src_dir_path, rr_dir_path, Arch, vpr_setup.RoutingArch,
|
||||
num_rr_nodes, rr_node, rr_node_indices, rr_indexed_data,
|
||||
vpr_setup.FPGA_SPICE_Opts);
|
||||
|
||||
/* Dump logic blocks
|
||||
* Branches to go:
|
||||
|
@ -280,10 +293,18 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup,
|
|||
lb_dir_path, &Arch,
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
||||
|
||||
/* Dump internal structures of submodules */
|
||||
dump_verilog_submodules(module_manager, mux_lib, sram_verilog_orgz_info, src_dir_path, submodule_dir_path,
|
||||
Arch, &vpr_setup.RoutingArch,
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
|
||||
/* Generate the Verilog module of the configuration peripheral protocol
|
||||
* which loads bitstream to FPGA fabric
|
||||
* TODO: generate the BL/WL decoders!!!!
|
||||
*
|
||||
* IMPORTANT: this function should be called after Verilog generation of
|
||||
* core logic (i.e., logic blocks and routing resources) !!!
|
||||
* This is due to the configuration protocol requires the total
|
||||
* number of memory cells across the FPGA fabric
|
||||
*/
|
||||
print_verilog_config_peripherals(module_manager, sram_verilog_orgz_info, std::string(src_dir_path), std::string(submodule_dir_path));
|
||||
/* TODO: This is the old function, which will be deprecated when refactoring is done */
|
||||
dump_verilog_config_peripherals(sram_verilog_orgz_info, src_dir_path, submodule_dir_path);
|
||||
|
||||
/* Dump top-level verilog */
|
||||
dump_compact_verilog_top_netlist(sram_verilog_orgz_info, chomped_circuit_name,
|
||||
|
|
|
@ -79,7 +79,7 @@ char* generate_compact_verilog_grid_module_name(t_type_ptr phy_block_type,
|
|||
|
||||
/* ONLY for compact Verilog netlists:
|
||||
* Update the grid_index_low and grid_index_high for each spice_models
|
||||
* Currently, we focus on three spice_models: SRAMs/SCFFs/IOPADs
|
||||
* Currently, we focus on three spice_models: SRAMs/CCFFs/IOPADs
|
||||
*/
|
||||
static
|
||||
void compact_verilog_update_one_spice_model_grid_index(t_type_ptr phy_block_type,
|
||||
|
@ -102,7 +102,7 @@ void compact_verilog_update_one_spice_model_grid_index(t_type_ptr phy_block_type
|
|||
case SPICE_MODEL_HARDLOGIC:
|
||||
case SPICE_MODEL_GATE:
|
||||
break;
|
||||
case SPICE_MODEL_SCFF:
|
||||
case SPICE_MODEL_CCFF:
|
||||
case SPICE_MODEL_SRAM:
|
||||
stamped_cnt = spice_model[i].cnt;
|
||||
spice_model[i].grid_index_low[grid_x][grid_y] = stamped_cnt;
|
||||
|
@ -158,7 +158,7 @@ void compact_verilog_update_sram_orgz_info_grid_index(t_sram_orgz_info* cur_sram
|
|||
|
||||
/* ONLY for compact Verilog netlists:
|
||||
* Update the grid_index_low and grid_index_high for each spice_models
|
||||
* Currently, we focus on three spice_models: SRAMs/SCFFs/IOPADs
|
||||
* Currently, we focus on three spice_models: SRAMs/CCFFs/IOPADs
|
||||
* IMPORTANT: The sequence of for loop should be consistent with
|
||||
* 1. bitstream logic block
|
||||
* 2. verilog pbtypes logic block
|
||||
|
@ -653,7 +653,7 @@ void dump_compact_verilog_defined_one_grid(t_sram_orgz_info* cur_sram_orgz_info,
|
|||
}
|
||||
|
||||
/* Dump ports only visible during formal verification*/
|
||||
if (0 < (cur_sram_orgz_info->grid_conf_bits_msb[ix][iy] - 1
|
||||
if (0 < (cur_sram_orgz_info->grid_conf_bits_msb[ix][iy]
|
||||
- cur_sram_orgz_info->grid_conf_bits_lsb[ix][iy])) {
|
||||
fprintf(fp, "\n");
|
||||
fprintf(fp, "`ifdef %s\n", verilog_formal_verification_preproc_flag);
|
||||
|
@ -1097,9 +1097,11 @@ void dump_compact_verilog_defined_one_channel(FILE* fp,
|
|||
fprintf(fp, "(");
|
||||
fprintf(fp, "\n");
|
||||
/* dump global ports */
|
||||
/*
|
||||
if (0 < dump_verilog_global_ports(fp, global_ports_head, FALSE, is_explicit_mapping)) {
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
*/
|
||||
|
||||
/* LEFT/BOTTOM side port of CHANX/CHANY */
|
||||
/* We apply an opposite port naming rule than function: fprint_routing_chan_subckt
|
||||
|
|
|
@ -241,7 +241,7 @@ void dump_verilog_decoder(FILE* fp,
|
|||
}
|
||||
|
||||
/* For standalone-SRAM configuration organization:
|
||||
* Dump the module of configuration module which connect configuration ports to SRAMs/SCFFs
|
||||
* Dump the module of configuration module which connect configuration ports to SRAMs/CCFFs
|
||||
*/
|
||||
static
|
||||
void dump_verilog_standalone_sram_config_module(FILE* fp,
|
||||
|
@ -288,7 +288,7 @@ void dump_verilog_standalone_sram_config_module(FILE* fp,
|
|||
|
||||
|
||||
/* For scan-chain configuration organization:
|
||||
* Dump the module of configuration module which connect configuration ports to SRAMs/SCFFs
|
||||
* Dump the module of configuration module which connect configuration ports to SRAMs/CCFFs
|
||||
*/
|
||||
static
|
||||
void dump_verilog_scan_chain_config_module(FILE* fp,
|
||||
|
@ -331,7 +331,7 @@ void dump_verilog_scan_chain_config_module(FILE* fp,
|
|||
fprintf(fp, ";\n");
|
||||
|
||||
/* Verilog Module body */
|
||||
/* Connect the head of current scff to the tail of previous scff*/
|
||||
/* Connect the head of current ccff to the tail of previous ccff*/
|
||||
fprintf(fp, " ");
|
||||
fprintf(fp, "assign ");
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, 1, num_mem_bits - 1, -1, VERILOG_PORT_CONKT);
|
||||
|
@ -405,7 +405,7 @@ void dump_verilog_membank_one_inv_module(FILE* fp,
|
|||
}
|
||||
|
||||
/* For Memory-bank configuration organization:
|
||||
* Dump the module of configuration module which connect configuration ports to SRAMs/SCFFs
|
||||
* Dump the module of configuration module which connect configuration ports to SRAMs/CCFFs
|
||||
*/
|
||||
static
|
||||
void dump_verilog_membank_config_module(FILE* fp,
|
||||
|
|
|
@ -59,17 +59,17 @@ void print_verilog_mux_local_decoder_module(std::fstream& fp,
|
|||
VTR_ASSERT(ModuleId::INVALID() != module_id);
|
||||
/* Add module ports */
|
||||
/* Add each input port */
|
||||
BasicPort addr_port("addr", addr_size);
|
||||
BasicPort addr_port(generate_mux_local_decoder_addr_port_name(), addr_size);
|
||||
module_manager.add_port(module_id, addr_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
/* Add each output port */
|
||||
BasicPort data_port("data", data_size);
|
||||
BasicPort data_port(generate_mux_local_decoder_data_port_name(), data_size);
|
||||
module_manager.add_port(module_id, data_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||
/* Data port is registered. It should be outputted as
|
||||
* output reg [lsb:msb] data
|
||||
*/
|
||||
module_manager.set_port_is_register(module_id, data_port.get_name(), true);
|
||||
/* Add data_in port */
|
||||
BasicPort data_inv_port("data_inv", data_size);
|
||||
BasicPort data_inv_port(generate_mux_local_decoder_data_inv_port_name(), data_size);
|
||||
VTR_ASSERT(true == decoder_lib.use_data_inv_port(decoder));
|
||||
module_manager.add_port(module_id, data_inv_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||
|
||||
|
@ -81,6 +81,20 @@ void print_verilog_mux_local_decoder_module(std::fstream& fp,
|
|||
|
||||
/* Print the truth table of this decoder */
|
||||
/* Internal logics */
|
||||
/* Early exit: Corner case for data size = 1 the logic is very simple:
|
||||
* data = addr;
|
||||
* data_inv = ~data_inv
|
||||
*/
|
||||
if (1 == data_size) {
|
||||
print_verilog_wire_connection(fp, addr_port, data_port, false);
|
||||
print_verilog_wire_connection(fp, data_inv_port, data_port, true);
|
||||
print_verilog_comment(fp, std::string("----- END Verilog codes for Decoder convert " + std::to_string(addr_size) + "-bit addr to " + std::to_string(data_size) + "-bit data -----"));
|
||||
|
||||
/* Put an end to the Verilog module */
|
||||
print_verilog_module_end(fp, module_name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We use a magic number -1 as the addr=1 should be mapped to ...1
|
||||
* Otherwise addr will map addr=1 to ..10
|
||||
* Note that there should be a range for the shift operators
|
||||
|
@ -194,7 +208,7 @@ void print_verilog_submodule_mux_local_decoders(ModuleManager& module_manager,
|
|||
* Note that only when there are >=2 memories, a decoder is needed
|
||||
*/
|
||||
size_t decoder_data_size = branch_mux_graph.num_memory_bits();
|
||||
if (2 > decoder_data_size) {
|
||||
if (0 == decoder_data_size) {
|
||||
continue;
|
||||
}
|
||||
/* Try to find if the decoder already exists in the library,
|
||||
|
@ -216,3 +230,150 @@ void print_verilog_submodule_mux_local_decoders(ModuleManager& module_manager,
|
|||
submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_fname.c_str());
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
* For scan-chain configuration organization:
|
||||
* Generate the Verilog module of configuration module
|
||||
* which connect configuration ports to SRAMs/CCFFs in a chain:
|
||||
*
|
||||
* +------+ +------+ +------+
|
||||
* cc_in--->| CCFF |--->| CCFF |---> ... --->| CCFF |----> sc_out
|
||||
* +------+ +------+ +------+
|
||||
***************************************************************************************/
|
||||
static
|
||||
void print_verilog_scan_chain_config_module(ModuleManager& module_manager,
|
||||
std::fstream& fp,
|
||||
t_sram_orgz_info* cur_sram_orgz_info) {
|
||||
/* Validate the FILE handler */
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Get the total memory bits */
|
||||
int num_mem_bits = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info);
|
||||
|
||||
/* Create a module definition for the configuration chain */
|
||||
print_verilog_comment(fp, std::string("----- BEGIN Configuration Peripheral for Scan-chain FFs -----"));
|
||||
|
||||
/* Create a Verilog Module based on the circuit model, and add to module manager */
|
||||
ModuleId module_id = module_manager.add_module(std::string(verilog_config_peripheral_prefix));
|
||||
VTR_ASSERT(ModuleId::INVALID() != module_id);
|
||||
/* Add module ports */
|
||||
/* Add the head of scan-chain: a 1-bit input port */
|
||||
BasicPort sc_head_port(std::string(top_netlist_scan_chain_head_prefix), 1);
|
||||
module_manager.add_port(module_id, sc_head_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
/* Add the inputs of scan-chain FFs, which are the outputs of the module */
|
||||
BasicPort cc_input_port(std::string("chain_input"), num_mem_bits);
|
||||
module_manager.add_port(module_id, cc_input_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||
/* Add the outputs of scan-chain FFs, which are inputs of the module */
|
||||
BasicPort sc_output_port(std::string("chain_output"), num_mem_bits);
|
||||
module_manager.add_port(module_id, sc_output_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
|
||||
/* dump module definition + ports */
|
||||
print_verilog_module_declaration(fp, module_manager, module_id);
|
||||
/* Finish dumping ports */
|
||||
|
||||
/* Declare the sc_output_port is a wire */
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, sc_output_port) << ";" << std::endl;
|
||||
fp << std::endl;
|
||||
|
||||
/* Connect scan-chain input to the first scan-chain input */
|
||||
BasicPort sc_first_input_port(cc_input_port.get_name(), 1);
|
||||
print_verilog_wire_connection(fp, sc_first_input_port, sc_head_port, false);
|
||||
|
||||
/* Connect the head of current ccff to the tail of previous ccff*/
|
||||
BasicPort chain_output_port(cc_input_port.get_name(), 1, num_mem_bits - 1);
|
||||
BasicPort chain_input_port(sc_output_port.get_name(), 0, num_mem_bits - 2);
|
||||
print_verilog_wire_connection(fp, chain_output_port, chain_input_port, false);
|
||||
|
||||
print_verilog_comment(fp, std::string("----- END Configuration Peripheral for Scan-chain FFs -----"));
|
||||
|
||||
/* Put an end to the Verilog module */
|
||||
print_verilog_module_end(fp, module_manager.module_name(module_id));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
* Generate the configuration peripheral circuits for the top-level Verilog netlist
|
||||
* This function will create Verilog modules depending on the configuration scheme:
|
||||
* 1. Scan-chain:
|
||||
* It will create a module which connects the Scan-Chain Flip-Flops (CCFFs)
|
||||
* as a chain:
|
||||
*
|
||||
* +------+ +------+ +------+
|
||||
* cc_in--->| CCFF |--->| CCFF |---> ... --->| CCFF |----> sc_out
|
||||
* +------+ +------+ +------+
|
||||
*
|
||||
* 2. Memory bank:
|
||||
* It will create a BL decoder and a WL decoder which will configure the SRAMs
|
||||
* as a memory bank
|
||||
*
|
||||
* +------------------------+
|
||||
* | WL Decoder |
|
||||
* +------------------------+
|
||||
* | | | ... | |
|
||||
* v v v v v
|
||||
* +---------+ +------------------------+
|
||||
* | |--->| |
|
||||
* | | | |
|
||||
* | BL |--->| |
|
||||
* | Decoder | .. | FPGA Core logic |
|
||||
* | | .. | |
|
||||
* | |--->| |
|
||||
* +---------+ +------------------------+
|
||||
***************************************************************************************/
|
||||
void print_verilog_config_peripherals(ModuleManager& module_manager,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& submodule_dir) {
|
||||
std::string verilog_fname(submodule_dir + config_peripheral_verilog_file_name);
|
||||
verilog_fname += ".bak";
|
||||
|
||||
/* Create the file stream */
|
||||
std::fstream fp;
|
||||
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
|
||||
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Print out debugging information for if the file is not opened/created properly */
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Creating Verilog netlist for configuration peripherals (%s)...\n",
|
||||
verilog_fname.c_str());
|
||||
|
||||
print_verilog_file_header(fp, "Configuration Peripheral Circuits");
|
||||
|
||||
print_verilog_include_defines_preproc_file(fp, verilog_dir);
|
||||
|
||||
/* Create a library for decoders */
|
||||
DecoderLibrary decoder_lib;
|
||||
|
||||
switch(cur_sram_orgz_info->type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
print_verilog_scan_chain_config_module(module_manager, fp, cur_sram_orgz_info);
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
/* TODO: Finish refactoring this part after the sram_orgz_info ! */
|
||||
/*
|
||||
dump_verilog_decoder(fp, cur_sram_orgz_info);
|
||||
dump_verilog_membank_config_module(fp, cur_sram_orgz_info);
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid type of SRAM organization in Verilog Generator!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Close the file stream */
|
||||
fp.close();
|
||||
|
||||
/* Add fname to the linked list when debugging is finished */
|
||||
/* TODO: uncomment this when it is ready to be plugged-in
|
||||
submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_fname.c_str());
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,4 +21,9 @@ void print_verilog_submodule_mux_local_decoders(ModuleManager& module_manager,
|
|||
const std::string& verilog_dir,
|
||||
const std::string& submodule_dir);
|
||||
|
||||
void print_verilog_config_peripherals(ModuleManager& module_manager,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& submodule_dir);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -39,203 +39,217 @@
|
|||
#include "verilog_routing.h"
|
||||
#include "verilog_tcl_utils.h"
|
||||
|
||||
|
||||
static void searching_used_latch(FILE *fp, t_pb * pb, int pb_index, char* chomped_circuit_name, char* inst_name){
|
||||
int i, j;
|
||||
// char* tmp = NULL;
|
||||
const t_pb_type *pb_type;
|
||||
t_mode *mode;
|
||||
t_pb_graph_node * node;
|
||||
// char* index = NULL;
|
||||
static void searching_used_latch(FILE *fp, t_pb *pb, int pb_index, char *chomped_circuit_name, char *inst_name)
|
||||
{
|
||||
int i, j;
|
||||
// char* tmp = NULL;
|
||||
const t_pb_type *pb_type;
|
||||
t_mode *mode;
|
||||
t_pb_graph_node *node;
|
||||
// char* index = NULL;
|
||||
|
||||
pb_type = pb->pb_graph_node->pb_type;
|
||||
node = pb->pb_graph_node->physical_pb_graph_node;
|
||||
mode = &pb_type->modes[pb->mode];
|
||||
pb_type = pb->pb_graph_node->pb_type;
|
||||
node = pb->pb_graph_node->physical_pb_graph_node;
|
||||
mode = &pb_type->modes[pb->mode];
|
||||
|
||||
// tmp = (char*) my_malloc(sizeof(1 + (strlen(ff_hierarchy) + 1 + strlen(my_strcat(pb_type->name, index)))));
|
||||
// tmp = ff_hierarchy;
|
||||
// index = my_strcat("_", my_strcat(my_itoa(pb_index), "_"));
|
||||
// tmp = (char*) my_malloc(sizeof(1 + (strlen(ff_hierarchy) + 1 + strlen(my_strcat(pb_type->name, index)))));
|
||||
// tmp = ff_hierarchy;
|
||||
// index = my_strcat("_", my_strcat(my_itoa(pb_index), "_"));
|
||||
|
||||
if (pb_type->num_modes > 0) {
|
||||
for (i = 0; i < mode->num_pb_type_children; i++) {
|
||||
for (j = 0; j < mode->pb_type_children[i].num_pb; j++) {
|
||||
// if(strcmp(pb_type->name, mode->name) != 0)
|
||||
// tmp = my_strcat(tmp, my_strcat("/", my_strcat(pb_type->name, index)));
|
||||
if(pb->child_pbs[i][j].name != NULL)
|
||||
searching_used_latch(fp, &pb->child_pbs[i][j], j, chomped_circuit_name, inst_name);
|
||||
}
|
||||
}
|
||||
} else if((pb_type->class_type == LATCH_CLASS) && (pb->name)){
|
||||
// tmp = my_strcat(tmp, my_strcat("/", my_strcat(pb_type->physical_pb_type_name, my_strcat(index, "/dff_0_"))));
|
||||
fprintf(fp, "set_user_match r:/WORK/%s/%s_reg i:/WORK/%s/%sdff_0 -type cell -noninverted\n", chomped_circuit_name,
|
||||
pb->name,
|
||||
inst_name,
|
||||
gen_verilog_one_pb_graph_node_full_name_in_hierarchy(node) );
|
||||
}
|
||||
//free(tmp); //Looks like is the cause of a double free, once free executated next iteration as no value in tmp
|
||||
return;
|
||||
if (pb_type->num_modes > 0)
|
||||
{
|
||||
for (i = 0; i < mode->num_pb_type_children; i++)
|
||||
{
|
||||
for (j = 0; j < mode->pb_type_children[i].num_pb; j++)
|
||||
{
|
||||
// if(strcmp(pb_type->name, mode->name) != 0)
|
||||
// tmp = my_strcat(tmp, my_strcat("/", my_strcat(pb_type->name, index)));
|
||||
if (pb->child_pbs[i][j].name != NULL)
|
||||
searching_used_latch(fp, &pb->child_pbs[i][j], j, chomped_circuit_name, inst_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((pb_type->class_type == LATCH_CLASS) && (pb->name))
|
||||
{
|
||||
// tmp = my_strcat(tmp, my_strcat("/", my_strcat(pb_type->physical_pb_type_name, my_strcat(index, "/dff_0_"))));
|
||||
fprintf(fp, "set_user_match r:/WORK/%s/%s_reg i:/WORK/%s/%sdff_0 -type cell -noninverted\n", chomped_circuit_name,
|
||||
pb->name,
|
||||
inst_name,
|
||||
gen_verilog_one_pb_graph_node_full_name_in_hierarchy(node));
|
||||
}
|
||||
//free(tmp); //Looks like is the cause of a double free, once free executated next iteration as no value in tmp
|
||||
return;
|
||||
}
|
||||
|
||||
static void clb_iteration(FILE *fp, char* chomped_circuit_name, int h){
|
||||
t_pb* pb;
|
||||
char* inst_name = NULL;
|
||||
const t_pb_type *pb_type;
|
||||
t_mode *mode;
|
||||
int i, j, x_pos, y_pos;
|
||||
char* grid_x = NULL;
|
||||
char* grid_y = NULL;
|
||||
static void clb_iteration(FILE *fp, char *chomped_circuit_name, int h)
|
||||
{
|
||||
t_pb *pb;
|
||||
char *inst_name = NULL;
|
||||
const t_pb_type *pb_type;
|
||||
t_mode *mode;
|
||||
int i, j, x_pos, y_pos;
|
||||
char *grid_x = NULL;
|
||||
char *grid_y = NULL;
|
||||
|
||||
x_pos = block[h].x;
|
||||
y_pos = block[h].y;
|
||||
x_pos = block[h].x;
|
||||
y_pos = block[h].y;
|
||||
|
||||
pb = (t_pb*) block[h].pb;
|
||||
pb = (t_pb *)block[h].pb;
|
||||
|
||||
pb_type = pb->pb_graph_node->pb_type;
|
||||
mode = &pb_type->modes[pb->mode];
|
||||
pb_type = pb->pb_graph_node->pb_type;
|
||||
mode = &pb_type->modes[pb->mode];
|
||||
|
||||
grid_x = my_strcat("_", my_strcat(my_itoa(x_pos), "_"));
|
||||
grid_y = my_strcat("_", my_strcat(my_itoa(y_pos), "_"));
|
||||
grid_x = my_strcat("_", my_strcat(my_itoa(x_pos), "_"));
|
||||
grid_y = my_strcat("_", my_strcat(my_itoa(y_pos), "_"));
|
||||
|
||||
|
||||
if (strcmp(pb_type->name, FILL_TYPE->name) == 0) {
|
||||
inst_name = my_strcat(chomped_circuit_name, my_strcat(formal_verification_top_postfix, my_strcat("/", my_strcat(formal_verification_top_module_uut_name, my_strcat("/grid",my_strcat(grid_x, my_strcat(grid_y, "/" )))))));
|
||||
if (pb_type->num_modes > 0) {
|
||||
for (i = 0; i < mode->num_pb_type_children; i++) {
|
||||
inst_name = my_strcat(inst_name, my_strcat("grid_", my_strcat(pb_type->name, my_strcat("_", my_strcat(my_itoa(i), "_")))));
|
||||
for (j = 0; j < mode->pb_type_children[i].num_pb; j++) {
|
||||
/* If child pb is not used but routing is used, I must print things differently */
|
||||
if ((pb->child_pbs[i] != NULL)
|
||||
&& (pb->child_pbs[i][j].name != NULL)) {
|
||||
searching_used_latch(fp, &pb->child_pbs[i][j], j, chomped_circuit_name, inst_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
if (strcmp(pb_type->name, FILL_TYPE->name) == 0)
|
||||
{
|
||||
inst_name = my_strcat(chomped_circuit_name, my_strcat(formal_verification_top_postfix, my_strcat("/", my_strcat(formal_verification_top_module_uut_name, my_strcat("/grid", my_strcat(grid_x, my_strcat(grid_y, "/")))))));
|
||||
if (pb_type->num_modes > 0)
|
||||
{
|
||||
for (i = 0; i < mode->num_pb_type_children; i++)
|
||||
{
|
||||
inst_name = my_strcat(inst_name, my_strcat("grid_", my_strcat(pb_type->name, my_strcat("_", my_strcat(my_itoa(i), "_")))));
|
||||
for (j = 0; j < mode->pb_type_children[i].num_pb; j++)
|
||||
{
|
||||
/* If child pb is not used but routing is used, I must print things differently */
|
||||
if ((pb->child_pbs[i] != NULL) && (pb->child_pbs[i][j].name != NULL))
|
||||
{
|
||||
searching_used_latch(fp, &pb->child_pbs[i][j], j, chomped_circuit_name, inst_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void match_registers(FILE *fp, char* chomped_circuit_name) {
|
||||
int h;
|
||||
|
||||
for(h = 0; h < copy_nb_clusters; h++)
|
||||
clb_iteration(fp, chomped_circuit_name, h);
|
||||
/* for(h = 0; h < copy_nb_clusters; h++){
|
||||
free_cb(copy_clb[h].pb);
|
||||
free(copy_clb[h].name);
|
||||
free(copy_clb[h].nets);
|
||||
free(copy_clb[h].pb);
|
||||
}*/
|
||||
// free(copy_clb);
|
||||
// free(block);
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
void formality_include_user_defined_verilog_netlists(FILE* fp,
|
||||
t_spice spice) {
|
||||
static void formality_include_user_defined_verilog_netlists(FILE *fp,
|
||||
t_spice spice)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* A valid file handler*/
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])Invalid File Handler!\n",
|
||||
if (NULL == fp)
|
||||
{
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])Invalid File Handler!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Include user-defined sub-circuit netlist */
|
||||
for (i = 0; i < spice.num_include_netlist; i++) {
|
||||
if (0 == spice.include_netlists[i].included) {
|
||||
for (i = 0; i < spice.num_include_netlist; i++)
|
||||
{
|
||||
if (0 == spice.include_netlists[i].included)
|
||||
{
|
||||
assert(NULL != spice.include_netlists[i].path);
|
||||
fprintf(fp, "%s ", spice.include_netlists[i].path);
|
||||
fprintf(fp, "%s \n", spice.include_netlists[i].path);
|
||||
spice.include_netlists[i].included = 1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(1 == spice.include_netlists[i].included);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void write_formality_script (t_syn_verilog_opts fpga_verilog_opts,
|
||||
char* fm_dir_formatted,
|
||||
char* src_dir_formatted,
|
||||
char* chomped_circuit_name,
|
||||
t_spice spice){
|
||||
int iblock;
|
||||
char* formality_script_file_name = NULL;
|
||||
char* benchmark_path = NULL;
|
||||
char* original_output_name = NULL;
|
||||
/* int output_length; */
|
||||
/* int pos; */
|
||||
FILE* fp = NULL;
|
||||
void write_formality_script(t_syn_verilog_opts fpga_verilog_opts,
|
||||
char *fm_dir_formatted,
|
||||
char *src_dir_formatted,
|
||||
char *chomped_circuit_name,
|
||||
t_spice spice)
|
||||
{
|
||||
int iblock, h;
|
||||
char *formScriptfp = NULL;
|
||||
char *benchmark_path = NULL;
|
||||
char *original_output_name = NULL;
|
||||
/* int output_length; */
|
||||
/* int pos; */
|
||||
FILE *fp = NULL;
|
||||
|
||||
if(TRUE == fpga_verilog_opts.print_autocheck_top_testbench){
|
||||
if (TRUE == fpga_verilog_opts.print_autocheck_top_testbench)
|
||||
{
|
||||
benchmark_path = fpga_verilog_opts.reference_verilog_benchmark_file;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
benchmark_path = "Insert verilog benchmark path";
|
||||
}
|
||||
|
||||
formality_script_file_name = my_strcat(fm_dir_formatted, my_strcat(chomped_circuit_name, formality_script_name_postfix));
|
||||
fp = fopen(formality_script_file_name, "w");
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s,LINE[%d])Failure in create formality script %s",
|
||||
__FILE__, __LINE__, formality_script_file_name);
|
||||
exit(1);
|
||||
}
|
||||
formScriptfp = my_strcat(fm_dir_formatted,
|
||||
my_strcat(chomped_circuit_name,
|
||||
formality_script_name_postfix));
|
||||
fp = fopen(formScriptfp, "w");
|
||||
if (NULL == fp)
|
||||
{
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s,LINE[%d])Failure in create formality script %s",
|
||||
__FILE__, __LINE__, formScriptfp);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Load Verilog benchmark as reference */
|
||||
fprintf(fp, "read_verilog -container r -libname WORK -05 { %s }\n", benchmark_path);
|
||||
fprintf(fp, "%s\n\n", benchmark_path);
|
||||
|
||||
/* Set reference top */
|
||||
fprintf(fp, "set_top r:/WORK/%s\n", chomped_circuit_name);
|
||||
fprintf(fp, "%s\n\n", chomped_circuit_name);
|
||||
|
||||
/* Load generated verilog as implemnetation */
|
||||
fprintf(fp, "read_verilog -container i -libname WORK -05 { ");
|
||||
fprintf(fp, "%s%s%s ", src_dir_formatted,
|
||||
chomped_circuit_name,
|
||||
verilog_top_postfix);
|
||||
fprintf(fp, "%s%s%s ", src_dir_formatted,
|
||||
chomped_circuit_name,
|
||||
formal_verification_verilog_file_postfix);
|
||||
fprintf(fp, "%s%s%s\n", src_dir_formatted, chomped_circuit_name,
|
||||
verilog_top_postfix);
|
||||
|
||||
fprintf(fp, "%s%s%s\n", src_dir_formatted,
|
||||
chomped_circuit_name,
|
||||
formal_verification_verilog_file_postfix);
|
||||
|
||||
init_include_user_defined_verilog_netlists(spice);
|
||||
formality_include_user_defined_verilog_netlists(fp, spice);
|
||||
fprintf(fp, "%s%s%s ", src_dir_formatted,
|
||||
default_rr_dir_name,
|
||||
routing_verilog_file_name);
|
||||
fprintf(fp, "%s%s%s ", src_dir_formatted,
|
||||
default_lb_dir_name,
|
||||
logic_block_verilog_file_name);
|
||||
fprintf(fp, "%s%s%s ", src_dir_formatted,
|
||||
default_submodule_dir_name,
|
||||
submodule_verilog_file_name);
|
||||
fprintf(fp, "}\n");
|
||||
fprintf(fp, "%s%s%s\n", src_dir_formatted,
|
||||
default_rr_dir_name,
|
||||
routing_verilog_file_name);
|
||||
fprintf(fp, "%s%s%s\n", src_dir_formatted,
|
||||
default_lb_dir_name,
|
||||
logic_block_verilog_file_name);
|
||||
fprintf(fp, "%s%s%s\n", src_dir_formatted,
|
||||
default_submodule_dir_name,
|
||||
submodule_verilog_file_name);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
/* Set implementation top */
|
||||
fprintf(fp, "set_top i:/WORK/%s\n", my_strcat(chomped_circuit_name, formal_verification_top_postfix));
|
||||
fprintf(fp, "%s\n", my_strcat(chomped_circuit_name, formal_verification_top_postfix));
|
||||
/* Run matching */
|
||||
fprintf(fp, "match\n");
|
||||
fprintf(fp, "\n");
|
||||
/* Add manual matching for the outputs */
|
||||
for (iblock = 0; iblock < num_logical_blocks; iblock++) {
|
||||
for (iblock = 0; iblock < num_logical_blocks; iblock++)
|
||||
{
|
||||
original_output_name = NULL;
|
||||
if (iopad_verilog_model == logical_block[iblock].mapped_spice_model) {
|
||||
if (iopad_verilog_model == logical_block[iblock].mapped_spice_model)
|
||||
{
|
||||
/* Make sure We find the correct logical block !*/
|
||||
assert((VPACK_INPAD == logical_block[iblock].type)
|
||||
||(VPACK_OUTPAD == logical_block[iblock].type));
|
||||
if(VPACK_OUTPAD == logical_block[iblock].type){
|
||||
assert((VPACK_INPAD == logical_block[iblock].type) || (VPACK_OUTPAD == logical_block[iblock].type));
|
||||
if (VPACK_OUTPAD == logical_block[iblock].type)
|
||||
{
|
||||
/* output_length = strlen(logical_block[iblock].name); */
|
||||
original_output_name = logical_block[iblock].name + 4;
|
||||
/* printf("%s", original_output_name); */
|
||||
fprintf(fp, "set_user_match r:/WORK/%s/%s i:/WORK/%s/%s[0] -type port -noninverted\n",
|
||||
// fprintf(fp, "set_user_match r:/WORK/%s/%s i:/WORK/%s/%s[0] -type port -noninverted\n",
|
||||
fprintf(fp, "/WORK/%s/%s /WORK/%s/%s[0]\n",
|
||||
chomped_circuit_name,
|
||||
original_output_name,
|
||||
original_output_name,
|
||||
my_strcat(chomped_circuit_name, formal_verification_top_postfix),
|
||||
my_strcat(logical_block[iblock].name, formal_verification_top_module_port_postfix));
|
||||
my_strcat(logical_block[iblock].name, formal_verification_top_module_port_postfix));
|
||||
}
|
||||
}
|
||||
}
|
||||
match_registers(fp, chomped_circuit_name);
|
||||
|
||||
for (h = 0; h < copy_nb_clusters; h++)
|
||||
clb_iteration(fp, chomped_circuit_name, h);
|
||||
|
||||
/* Run verification */
|
||||
fprintf(fp, "verify\n");
|
||||
fprintf(fp, "\n");
|
||||
/* Script END */
|
||||
fclose(fp);
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ char* top_netlist_normal_bl_port_postfix = "_bl";
|
|||
char* top_netlist_normal_wl_port_postfix = "_wl";
|
||||
char* top_netlist_normal_blb_port_postfix = "_blb";
|
||||
char* top_netlist_normal_wlb_port_postfix = "_wlb";
|
||||
char* top_netlist_scan_chain_head_prefix = "sc_in";
|
||||
char* top_netlist_scan_chain_head_prefix = "cc_in";
|
||||
|
||||
char* top_tb_reset_port_name = "greset";
|
||||
char* top_tb_set_port_name = "gset";
|
||||
|
|
|
@ -113,6 +113,9 @@ void write_include_netlists (char* src_dir_formatted,
|
|||
fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted,
|
||||
default_submodule_dir_name,
|
||||
submodule_verilog_file_name);
|
||||
fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted,
|
||||
default_submodule_dir_name,
|
||||
config_peripheral_verilog_file_name);
|
||||
init_include_user_defined_verilog_netlists(spice);
|
||||
include_netlists_include_user_defined_verilog_netlists(fp, spice);
|
||||
|
||||
|
|
|
@ -299,7 +299,7 @@ void print_verilog_submodule_lut(ModuleManager& module_manager,
|
|||
/* Instanciate the multiplexing structure for the LUT */
|
||||
print_verilog_comment(fp, std::string("---- BEGIN Instanciation of LUT multiplexer module -----"));
|
||||
/* Find the name of LUT MUX: no need to provide a mux size, just give an invalid number (=-1) */
|
||||
std::string lut_mux_module_name = generate_verilog_mux_subckt_name(circuit_lib, circuit_model, size_t(-1), std::string(""));
|
||||
std::string lut_mux_module_name = generate_mux_subckt_name(circuit_lib, circuit_model, size_t(-1), std::string(""));
|
||||
/* Find the module id of LUT MUX in the module manager */
|
||||
ModuleId lut_mux_module_id = module_manager.find_module(lut_mux_module_name);
|
||||
/* We must have a valid id */
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "module_manager.h"
|
||||
#include "physical_types.h"
|
||||
#include "vpr_types.h"
|
||||
#include "circuit_library_utils.h"
|
||||
#include "mux_utils.h"
|
||||
|
||||
/* FPGA-X2P context header files */
|
||||
|
@ -27,10 +28,7 @@
|
|||
#include "verilog_memory.h"
|
||||
|
||||
/*********************************************************************
|
||||
* Generate Verilog modules for the memories that are used
|
||||
* by CMOS (SRAM-based) multiplexers
|
||||
* We support:
|
||||
* 1. Flat memory modules
|
||||
* Flat memory modules
|
||||
*
|
||||
* in[0] in[1] in[N]
|
||||
* | | |
|
||||
|
@ -43,68 +41,15 @@
|
|||
* v v v
|
||||
* +------------------------------------+
|
||||
* | Multiplexer Configuration port |
|
||||
*
|
||||
* 2. TODO: Local decoders
|
||||
*
|
||||
* in[0] in[1] in[N]
|
||||
* | | |
|
||||
* v v v
|
||||
* +-------+ +-------+ +-------+
|
||||
* | SRAM | | SRAM | ... | SRAM |
|
||||
* | [0] | | [1] | | [N-1] |
|
||||
* +-------+ +-------+ +-------+
|
||||
* | | ... |
|
||||
* v v v
|
||||
* +------------------------------------+
|
||||
* | Local decoders |
|
||||
* +------------------------------------+
|
||||
* | | ... |
|
||||
* v v v
|
||||
* +------------------------------------+
|
||||
* | Multiplexer Configuration port |
|
||||
*
|
||||
* 3. TODO: Scan-chain organization
|
||||
*
|
||||
* in[0] in[1] in[N]
|
||||
* | | |
|
||||
* v v v
|
||||
* +-------+ +-------+ +-------+
|
||||
* scan-chain--->| SRAM |--->| SRAM |--->... --->| SRAM |---->scan-chain
|
||||
* input&clock | [0] | | [1] | | [N-1] | output
|
||||
* +-------+ +-------+ +-------+
|
||||
* | | ... |
|
||||
* v v v
|
||||
* +-----------------------------------------+
|
||||
* | Multiplexer Configuration port |
|
||||
*
|
||||
* 4. TODO: Memory bank organization
|
||||
*
|
||||
* Bit lines Word lines
|
||||
* | |
|
||||
* v v
|
||||
* +------------------------------------+
|
||||
* | Multiplexer Configuration port |
|
||||
* +------------------------------------+
|
||||
* | | |
|
||||
* v v v
|
||||
* +-------+ +-------+ +-------+
|
||||
* | SRAM | | SRAM | ... | SRAM |
|
||||
* | [0] | | [1] | | [N-1] |
|
||||
* +-------+ +-------+ +-------+
|
||||
* | | ... |
|
||||
* v v v
|
||||
* +------------------------------------+
|
||||
* | Multiplexer Configuration port |
|
||||
|
||||
*
|
||||
********************************************************************/
|
||||
static
|
||||
void print_verilog_memory_module(ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
std::fstream& fp,
|
||||
const std::string& module_name,
|
||||
const CircuitModelId& sram_model,
|
||||
const size_t& num_mems) {
|
||||
void print_verilog_memory_standalone_module(ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
std::fstream& fp,
|
||||
const std::string& module_name,
|
||||
const CircuitModelId& sram_model,
|
||||
const size_t& num_mems) {
|
||||
/* Make sure we have a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
|
@ -120,6 +65,236 @@ void print_verilog_memory_module(ModuleManager& module_manager,
|
|||
std::vector<CircuitPortId> sram_input_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
/* Get the output ports from the SRAM */
|
||||
std::vector<CircuitPortId> sram_output_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_OUTPUT, true);
|
||||
|
||||
/* Add module ports: the ports come from the SRAM modules */
|
||||
/* Add each global port */
|
||||
for (const auto& port : sram_global_ports) {
|
||||
/* Configure each global port: global ports are shared among the SRAMs, so it is independent from the memory size */
|
||||
BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
||||
module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT);
|
||||
}
|
||||
/* Add each input port */
|
||||
for (const auto& port : sram_input_ports) {
|
||||
BasicPort input_port(circuit_lib.port_lib_name(port), num_mems);
|
||||
module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
}
|
||||
/* Add each output port: port width should match the number of memories */
|
||||
for (const auto& port : sram_output_ports) {
|
||||
BasicPort output_port(circuit_lib.port_lib_name(port), num_mems);
|
||||
module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||
}
|
||||
|
||||
/* dump module definition + ports */
|
||||
print_verilog_module_declaration(fp, module_manager, module_id);
|
||||
/* Finish dumping ports */
|
||||
|
||||
/* Find the sram module in the module manager */
|
||||
ModuleId sram_module_id = module_manager.find_module(circuit_lib.model_name(sram_model));
|
||||
|
||||
/* Instanciate each submodule */
|
||||
for (size_t i = 0; i < num_mems; ++i) {
|
||||
/* Create a port-to-port map */
|
||||
std::map<std::string, BasicPort> port2port_name_map;
|
||||
/* Map instance inputs [i] to SRAM module input */
|
||||
for (const auto& port : sram_input_ports) {
|
||||
BasicPort instance_input_port(circuit_lib.port_lib_name(port), i, i);
|
||||
port2port_name_map[circuit_lib.port_lib_name(port)] = instance_input_port;
|
||||
}
|
||||
/* Map instance outputs [i] to SRAM module input */
|
||||
for (const auto& port : sram_output_ports) {
|
||||
BasicPort instance_output_port(circuit_lib.port_lib_name(port), i, i);
|
||||
port2port_name_map[circuit_lib.port_lib_name(port)] = instance_output_port;
|
||||
}
|
||||
|
||||
/* Output an instance of the module */
|
||||
print_verilog_module_instance(fp, module_manager, module_id, sram_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(sram_model));
|
||||
/* IMPORTANT: this update MUST be called after the instance outputting!!!!
|
||||
* update the module manager with the relationship between the parent and child modules
|
||||
*/
|
||||
module_manager.add_child_module(module_id, sram_module_id);
|
||||
}
|
||||
|
||||
/* Put an end to the Verilog module */
|
||||
print_verilog_module_end(fp, module_name);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Scan-chain organization
|
||||
*
|
||||
* +-------+ +-------+ +-------+
|
||||
* scan-chain--->| CCFF |--->| CCFF |--->... --->| CCFF |---->scan-chain
|
||||
* input&clock | [0] | | [1] | | [N-1] | output
|
||||
* +-------+ +-------+ +-------+
|
||||
* | | ... |
|
||||
* v v v
|
||||
* +-----------------------------------------+
|
||||
* | Multiplexer Configuration port |
|
||||
*
|
||||
********************************************************************/
|
||||
static
|
||||
void print_verilog_memory_chain_module(ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
std::fstream& fp,
|
||||
const std::string& module_name,
|
||||
const CircuitModelId& sram_model,
|
||||
const size_t& num_mems) {
|
||||
/* Make sure we have a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Create a module and add to the module manager */
|
||||
ModuleId module_id = module_manager.add_module(module_name);
|
||||
VTR_ASSERT(ModuleId::INVALID() != module_id);
|
||||
/* Get the global ports required by the SRAM */
|
||||
std::vector<enum e_spice_model_port_type> global_port_types;
|
||||
global_port_types.push_back(SPICE_MODEL_PORT_CLOCK);
|
||||
global_port_types.push_back(SPICE_MODEL_PORT_INPUT);
|
||||
std::vector<CircuitPortId> sram_global_ports = circuit_lib.model_global_ports_by_type(sram_model, global_port_types, true, false);
|
||||
/* Get the input ports from the SRAM */
|
||||
std::vector<CircuitPortId> sram_input_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
/* Should have only 1 input port */
|
||||
VTR_ASSERT( 1 == sram_input_ports.size() );
|
||||
/* Get the output ports from the SRAM */
|
||||
std::vector<CircuitPortId> sram_output_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_OUTPUT, true);
|
||||
/* Should have only 1 or 2 output port */
|
||||
VTR_ASSERT( (1 == sram_output_ports.size()) || ( 2 == sram_output_ports.size()) );
|
||||
|
||||
/* Add module ports: the ports come from the SRAM modules */
|
||||
/* Add each global port */
|
||||
for (const auto& port : sram_global_ports) {
|
||||
/* Configure each global port: global ports are shared among the SRAMs, so it is independent from the memory size */
|
||||
BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
||||
module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT);
|
||||
}
|
||||
/* Add an input port, which is the head of configuration chain in the module */
|
||||
/* TODO: restriction!!!
|
||||
* consider only the first input of the CCFF model as the D port,
|
||||
* which will be connected to the head of the chain
|
||||
*/
|
||||
BasicPort chain_head_port(generate_configuration_chain_head_name(),
|
||||
circuit_lib.port_size(sram_input_ports[0]));
|
||||
module_manager.add_port(module_id, chain_head_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
/* Add an output port, which is the tail of configuration chain in the module */
|
||||
/* TODO: restriction!!!
|
||||
* consider only the first output of the CCFF model as the Q port,
|
||||
* which will be connected to the tail of the chain
|
||||
*/
|
||||
BasicPort chain_tail_port(generate_configuration_chain_tail_name(),
|
||||
circuit_lib.port_size(sram_output_ports[0]));
|
||||
module_manager.add_port(module_id, chain_tail_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
/* Add each output port: port width should match the number of memories */
|
||||
for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) {
|
||||
std::string port_name;
|
||||
if (0 == iport) {
|
||||
port_name = generate_configuration_chain_data_out_name();
|
||||
} else {
|
||||
VTR_ASSERT( 1 == iport);
|
||||
port_name = generate_configuration_chain_inverted_data_out_name();
|
||||
}
|
||||
BasicPort output_port(port_name, num_mems);
|
||||
module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||
}
|
||||
|
||||
/* dump module definition + ports */
|
||||
print_verilog_module_declaration(fp, module_manager, module_id);
|
||||
/* Finish dumping ports */
|
||||
|
||||
/* Find the sram module in the module manager */
|
||||
ModuleId sram_module_id = module_manager.find_module(circuit_lib.model_name(sram_model));
|
||||
|
||||
/* Instanciate each submodule */
|
||||
for (size_t i = 0; i < num_mems; ++i) {
|
||||
/* Create a port-to-port map */
|
||||
std::map<std::string, BasicPort> port2port_name_map;
|
||||
/* Map instance inputs [i] to SRAM module input */
|
||||
for (const auto& port : sram_input_ports) {
|
||||
BasicPort instance_input_port(circuit_lib.port_lib_name(port), i, i);
|
||||
port2port_name_map[circuit_lib.port_lib_name(port)] = instance_input_port;
|
||||
}
|
||||
/* Map instance outputs [i] to SRAM module input */
|
||||
for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) {
|
||||
std::string port_name;
|
||||
if (0 == iport) {
|
||||
port_name = generate_configuration_chain_data_out_name();
|
||||
} else {
|
||||
VTR_ASSERT( 1 == iport);
|
||||
port_name = generate_configuration_chain_inverted_data_out_name();
|
||||
}
|
||||
BasicPort instance_output_port(port_name, i, i);
|
||||
port2port_name_map[circuit_lib.port_lib_name(sram_output_ports[iport])] = instance_output_port;
|
||||
}
|
||||
|
||||
/* Output an instance of the module */
|
||||
print_verilog_module_instance(fp, module_manager, module_id, sram_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(sram_model));
|
||||
/* IMPORTANT: this update MUST be called after the instance outputting!!!!
|
||||
* update the module manager with the relationship between the parent and child modules
|
||||
*/
|
||||
module_manager.add_child_module(module_id, sram_module_id);
|
||||
}
|
||||
|
||||
/* Wire the memory cells into a chain
|
||||
* The head of the chain will be wired to the input port of the first CCFF
|
||||
* The tail of the chain will be wired to the output port of the last CCFF
|
||||
* The output of each CCFF will be wired to the input of the next CCFFF in the chain
|
||||
*/
|
||||
BasicPort first_ccff_input_port(circuit_lib.port_lib_name(sram_input_ports[0]), 0, 0);
|
||||
print_verilog_wire_connection(fp, first_ccff_input_port, chain_head_port, false);
|
||||
|
||||
BasicPort last_ccff_output_port(generate_configuration_chain_data_out_name(), num_mems - 1, num_mems - 1);
|
||||
print_verilog_wire_connection(fp, chain_tail_port, last_ccff_output_port, false);
|
||||
|
||||
BasicPort chain_output_port(generate_configuration_chain_data_out_name(), 0, num_mems - 2);
|
||||
BasicPort chain_input_port(circuit_lib.port_lib_name(sram_input_ports[0]), 1, num_mems - 1);
|
||||
print_verilog_wire_connection(fp, chain_input_port, chain_output_port, false);
|
||||
|
||||
/* Put an end to the Verilog module */
|
||||
print_verilog_module_end(fp, module_name);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Memory bank organization
|
||||
*
|
||||
* Bit lines(BL/BLB) Word lines (WL/WLB)
|
||||
* | |
|
||||
* v v
|
||||
* +------------------------------------+
|
||||
* | Memory Module Configuration port |
|
||||
* +------------------------------------+
|
||||
* | | |
|
||||
* v v v
|
||||
* +-------+ +-------+ +-------+
|
||||
* | SRAM | | SRAM | ... | SRAM |
|
||||
* | [0] | | [1] | | [N-1] |
|
||||
* +-------+ +-------+ +-------+
|
||||
* | | ... |
|
||||
* v v v
|
||||
* +------------------------------------+
|
||||
* | Multiplexer Configuration port |
|
||||
*
|
||||
********************************************************************/
|
||||
static
|
||||
void print_verilog_memory_bank_module(ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
std::fstream& fp,
|
||||
const std::string& module_name,
|
||||
const CircuitModelId& sram_model,
|
||||
const size_t& num_mems) {
|
||||
/* Make sure we have a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Create a module and add to the module manager */
|
||||
ModuleId module_id = module_manager.add_module(module_name);
|
||||
VTR_ASSERT(ModuleId::INVALID() != module_id);
|
||||
/* Get the global ports required by the SRAM */
|
||||
std::vector<enum e_spice_model_port_type> global_port_types;
|
||||
global_port_types.push_back(SPICE_MODEL_PORT_CLOCK);
|
||||
global_port_types.push_back(SPICE_MODEL_PORT_INPUT);
|
||||
std::vector<CircuitPortId> sram_global_ports = circuit_lib.model_global_ports_by_type(sram_model, global_port_types, true, false);
|
||||
/* Get the input ports from the SRAM */
|
||||
std::vector<CircuitPortId> sram_input_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
/* A SRAM cell with BL/WL should not have any input */
|
||||
VTR_ASSERT( 0 == sram_input_ports.size() );
|
||||
/* Get the output ports from the SRAM */
|
||||
std::vector<CircuitPortId> sram_output_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_OUTPUT, true);
|
||||
/* Get the BL/WL ports from the SRAM */
|
||||
std::vector<CircuitPortId> sram_bl_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_BL, true);
|
||||
std::vector<CircuitPortId> sram_blb_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_BLB, true);
|
||||
|
@ -133,7 +308,7 @@ void print_verilog_memory_module(ModuleManager& module_manager,
|
|||
BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
||||
module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT);
|
||||
}
|
||||
/* Add each input port: port width should match the number of memories */
|
||||
/* Add each input port */
|
||||
for (const auto& port : sram_input_ports) {
|
||||
BasicPort input_port(circuit_lib.port_lib_name(port), num_mems);
|
||||
module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
|
@ -208,10 +383,52 @@ void print_verilog_memory_module(ModuleManager& module_manager,
|
|||
module_manager.add_child_module(module_id, sram_module_id);
|
||||
}
|
||||
|
||||
/* TODO: if a local memory decoder is required, instanciate it here */
|
||||
|
||||
/* Put an end to the Verilog module */
|
||||
print_verilog_module_end(fp, module_name);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* Generate Verilog modules for the memories that are used
|
||||
* by a circuit model
|
||||
* The organization of memory circuit will depend on the style of
|
||||
* configuration protocols
|
||||
* Currently, we support
|
||||
* 1. Flat SRAM organization
|
||||
* 2. Configuration chain
|
||||
* 3. Memory bank (memory decoders)
|
||||
********************************************************************/
|
||||
static
|
||||
void print_verilog_memory_module(ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
std::fstream& fp,
|
||||
const std::string& module_name,
|
||||
const CircuitModelId& sram_model,
|
||||
const size_t& num_mems) {
|
||||
switch (sram_orgz_type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
print_verilog_memory_standalone_module(module_manager, circuit_lib, fp,
|
||||
module_name, sram_model, num_mems);
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
print_verilog_memory_chain_module(module_manager, circuit_lib, fp,
|
||||
module_name, sram_model, num_mems);
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
print_verilog_memory_bank_module(module_manager, circuit_lib, fp,
|
||||
module_name, sram_model, num_mems);
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, LINE%d) Invalid SRAM organization!\n",
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* Generate Verilog modules for the memories that are used
|
||||
* by multiplexers
|
||||
|
@ -228,28 +445,27 @@ void print_verilog_memory_module(ModuleManager& module_manager,
|
|||
static
|
||||
void print_verilog_mux_memory_module(ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
std::fstream& fp,
|
||||
const CircuitModelId& mux_model,
|
||||
const MuxGraph& mux_graph) {
|
||||
/* Find the actual number of configuration bits, based on the mux graph
|
||||
* Due to the use of local decoders inside mux, this may be
|
||||
*/
|
||||
size_t num_config_bits = find_mux_num_config_bits(circuit_lib, mux_model, mux_graph, sram_orgz_type);
|
||||
/* Multiplexers built with different technology is in different organization */
|
||||
switch (circuit_lib.design_tech_type(mux_model)) {
|
||||
case SPICE_MODEL_DESIGN_CMOS: {
|
||||
/* Generate module name */
|
||||
std::string module_name = generate_verilog_mux_subckt_name(circuit_lib, mux_model,
|
||||
find_mux_num_datapath_inputs(circuit_lib, mux_model, mux_graph.num_inputs()),
|
||||
std::string(verilog_mem_posfix));
|
||||
std::string module_name = generate_mux_subckt_name(circuit_lib, mux_model,
|
||||
find_mux_num_datapath_inputs(circuit_lib, mux_model, mux_graph.num_inputs()),
|
||||
std::string(verilog_mem_posfix));
|
||||
|
||||
/* Get the sram ports from the mux */
|
||||
std::vector<CircuitPortId> mux_sram_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_SRAM, true);
|
||||
VTR_ASSERT( 1 == mux_sram_ports.size() );
|
||||
/* Get the circuit model for the memory circuit used by the multiplexer */
|
||||
CircuitModelId sram_model = circuit_lib.port_tri_state_model(mux_sram_ports[0]);
|
||||
VTR_ASSERT(CircuitModelId::INVALID() != sram_model);
|
||||
std::vector<CircuitModelId> sram_models = find_circuit_sram_models(circuit_lib, mux_model);
|
||||
VTR_ASSERT( 1 == sram_models.size() );
|
||||
|
||||
/* Find the number of SRAMs in the module, this is also the port width */
|
||||
size_t num_mems = mux_graph.num_memory_bits();
|
||||
|
||||
print_verilog_memory_module(module_manager, circuit_lib, fp, module_name, sram_model, num_mems);
|
||||
print_verilog_memory_module(module_manager, circuit_lib, sram_orgz_type, fp, module_name, sram_models[0], num_config_bits);
|
||||
break;
|
||||
}
|
||||
case SPICE_MODEL_DESIGN_RRAM:
|
||||
|
@ -286,6 +502,7 @@ void print_verilog_mux_memory_module(ModuleManager& module_manager,
|
|||
void print_verilog_submodule_memories(ModuleManager& module_manager,
|
||||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& submodule_dir) {
|
||||
/* Plug in with the mux subckt */
|
||||
|
@ -319,7 +536,7 @@ void print_verilog_submodule_memories(ModuleManager& module_manager,
|
|||
continue;
|
||||
}
|
||||
/* Create a Verilog module for the memories used by the multiplexer */
|
||||
print_verilog_mux_memory_module(module_manager, circuit_lib, fp, mux_model, mux_graph);
|
||||
print_verilog_mux_memory_module(module_manager, circuit_lib, sram_orgz_type, fp, mux_model, mux_graph);
|
||||
}
|
||||
|
||||
/* Create the memory circuits for non-MUX circuit models.
|
||||
|
@ -361,7 +578,7 @@ void print_verilog_submodule_memories(ModuleManager& module_manager,
|
|||
std::string module_name = generate_memory_module_name(circuit_lib, model, sram_models[0], std::string(verilog_mem_posfix));
|
||||
|
||||
/* Create a Verilog module for the memories used by the circuit model */
|
||||
print_verilog_memory_module(module_manager, circuit_lib, fp, module_name, sram_models[0], num_mems);
|
||||
print_verilog_memory_module(module_manager, circuit_lib, sram_orgz_type, fp, module_name, sram_models[0], num_mems);
|
||||
}
|
||||
|
||||
/* Close the file stream */
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
void print_verilog_submodule_memories(ModuleManager& module_manager,
|
||||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& submodule_dir);
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "physical_types.h"
|
||||
#include "vpr_types.h"
|
||||
#include "mux_utils.h"
|
||||
#include "circuit_library_utils.h"
|
||||
#include "decoder_library_utils.h"
|
||||
|
||||
/* FPGA-X2P context header files */
|
||||
#include "spice_types.h"
|
||||
|
@ -691,7 +693,7 @@ void generate_verilog_mux_branch_module(ModuleManager& module_manager,
|
|||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const MuxGraph& mux_graph) {
|
||||
std::string module_name = generate_verilog_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, mux_graph.num_inputs(), verilog_mux_basis_posfix);
|
||||
std::string module_name = generate_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, mux_graph.num_inputs(), verilog_mux_basis_posfix);
|
||||
|
||||
/* Multiplexers built with different technology is in different organization */
|
||||
switch (circuit_lib.design_tech_type(circuit_model)) {
|
||||
|
@ -760,13 +762,13 @@ void generate_verilog_cmos_mux_module_mux2_multiplexing_structure(ModuleManager&
|
|||
/* Print local wires which are the nodes in the mux graph */
|
||||
for (size_t level = 0; level < mux_graph.num_levels(); ++level) {
|
||||
/* Print the internal wires located at this level */
|
||||
BasicPort internal_wire_port(generate_verilog_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
|
||||
BasicPort internal_wire_port(generate_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_port) << ";" << std::endl;
|
||||
/* Identify if an intermediate buffer is needed */
|
||||
if (false == inter_buffer_location_map[level]) {
|
||||
continue;
|
||||
}
|
||||
BasicPort internal_wire_buffered_port(generate_verilog_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
|
||||
BasicPort internal_wire_buffered_port(generate_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_buffered_port) << std::endl;
|
||||
}
|
||||
print_verilog_comment(fp, std::string("---- END Internal wires of a CMOS MUX module -----"));
|
||||
|
@ -832,7 +834,7 @@ void generate_verilog_cmos_mux_module_mux2_multiplexing_structure(ModuleManager&
|
|||
/* Generate the port info of each input node */
|
||||
size_t input_node_level = mux_graph.node_level(input_node);
|
||||
size_t input_node_index_at_level = mux_graph.node_index_at_level(input_node);
|
||||
BasicPort instance_input_port(generate_verilog_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
|
||||
BasicPort instance_input_port(generate_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
|
||||
|
||||
/* Link nodes to input ports for the branch module */
|
||||
std::string module_input_port_name = circuit_lib.port_lib_name(std_cell_input_ports[&input_node - &input_nodes[0]]);
|
||||
|
@ -841,7 +843,7 @@ void generate_verilog_cmos_mux_module_mux2_multiplexing_structure(ModuleManager&
|
|||
|
||||
/* Build the link between output_node[0] and std_cell_output_port[0] */
|
||||
{ /* Create a code block to accommodate the local variables */
|
||||
BasicPort instance_output_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
BasicPort instance_output_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
std::string module_output_port_name = circuit_lib.port_lib_name(std_cell_output_ports[0]);
|
||||
port2port_name_map[module_output_port_name] = instance_output_port;
|
||||
}
|
||||
|
@ -853,6 +855,10 @@ void generate_verilog_cmos_mux_module_mux2_multiplexing_structure(ModuleManager&
|
|||
/* Generate the port info of each mem node */
|
||||
BasicPort instance_mem_port(circuit_lib.port_lib_name(mux_regular_sram_ports[0]), size_t(mem), size_t(mem));
|
||||
std::string module_mem_port_name = circuit_lib.port_lib_name(std_cell_input_ports[2]);
|
||||
/* If use local decoders, we should use another name for the mem port */
|
||||
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
|
||||
instance_mem_port.set_name(generate_mux_local_decoder_data_port_name());
|
||||
}
|
||||
port2port_name_map[module_mem_port_name] = instance_mem_port;
|
||||
}
|
||||
|
||||
|
@ -876,8 +882,8 @@ void generate_verilog_cmos_mux_module_mux2_multiplexing_structure(ModuleManager&
|
|||
/* We must have a valid model id */
|
||||
VTR_ASSERT(CircuitModelId::INVALID() != buffer_model);
|
||||
|
||||
BasicPort buffer_instance_input_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
BasicPort buffer_instance_output_port(generate_verilog_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
|
||||
BasicPort buffer_instance_input_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
BasicPort buffer_instance_output_port(generate_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
|
||||
|
||||
print_verilog_buffer_instance(fp, module_manager, circuit_lib, module_id, buffer_model, buffer_instance_input_port, buffer_instance_output_port);
|
||||
|
||||
|
@ -910,19 +916,8 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
|
|||
/* Find the actual mux size */
|
||||
size_t mux_size = find_mux_num_datapath_inputs(circuit_lib, circuit_model, mux_graph.num_inputs());
|
||||
|
||||
/* TODO: these are duplicated codes, find a way to simplify it!!!
|
||||
* Get the regular (non-mode-select) sram ports from the mux
|
||||
*/
|
||||
std::vector<CircuitPortId> mux_regular_sram_ports;
|
||||
for (const auto& port : circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true)) {
|
||||
/* Multiplexing structure does not mode_sram_ports, they are handled in LUT modules
|
||||
* Here we just bypass it.
|
||||
*/
|
||||
if (true == circuit_lib.port_is_mode_select(port)) {
|
||||
continue;
|
||||
}
|
||||
mux_regular_sram_ports.push_back(port);
|
||||
}
|
||||
/* Get the regular (non-mode-select) sram ports from the mux */
|
||||
std::vector<CircuitPortId> mux_regular_sram_ports = find_circuit_regular_sram_ports(circuit_lib, circuit_model);
|
||||
VTR_ASSERT(1 == mux_regular_sram_ports.size());
|
||||
|
||||
/* Build the location map of intermediate buffers */
|
||||
|
@ -934,13 +929,13 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
|
|||
/* Print local wires which are the nodes in the mux graph */
|
||||
for (size_t level = 0; level < mux_graph.num_levels(); ++level) {
|
||||
/* Print the internal wires located at this level */
|
||||
BasicPort internal_wire_port(generate_verilog_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
|
||||
BasicPort internal_wire_port(generate_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_port) << ";" << std::endl;
|
||||
/* Identify if an intermediate buffer is needed */
|
||||
if (false == inter_buffer_location_map[level]) {
|
||||
continue;
|
||||
}
|
||||
BasicPort internal_wire_buffered_port(generate_verilog_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
|
||||
BasicPort internal_wire_buffered_port(generate_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_buffered_port) << std::endl;
|
||||
}
|
||||
print_verilog_comment(fp, std::string("---- END Internal wires of a CMOS MUX module -----"));
|
||||
|
@ -982,7 +977,7 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
|
|||
|
||||
/* Instanciate the branch module which is a tgate-based module
|
||||
*/
|
||||
std::string branch_module_name= generate_verilog_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, branch_size, verilog_mux_basis_posfix);
|
||||
std::string branch_module_name= generate_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, branch_size, verilog_mux_basis_posfix);
|
||||
/* Get the moduleId for the submodule */
|
||||
ModuleId branch_module_id = module_manager.find_module(branch_module_name);
|
||||
/* We must have one */
|
||||
|
@ -998,13 +993,13 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
|
|||
/* Generate the port info of each input node */
|
||||
size_t input_node_level = mux_graph.node_level(input_node);
|
||||
size_t input_node_index_at_level = mux_graph.node_index_at_level(input_node);
|
||||
BasicPort branch_node_input_port(generate_verilog_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
|
||||
BasicPort branch_node_input_port(generate_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
|
||||
branch_node_input_ports.push_back(branch_node_input_port);
|
||||
}
|
||||
|
||||
/* Create the port info for the input */
|
||||
/* TODO: the naming could be more flexible? */
|
||||
BasicPort instance_input_port = generate_verilog_bus_port(branch_node_input_ports, std::string(generate_verilog_mux_node_name(output_node_level, false) + "_in"));
|
||||
BasicPort instance_input_port = generate_verilog_bus_port(branch_node_input_ports, std::string(generate_mux_node_name(output_node_level, false) + "_in"));
|
||||
/* If we have more than 1 port in the combined instance ports ,
|
||||
* output a local wire */
|
||||
if (1 < combine_verilog_ports(branch_node_input_ports).size()) {
|
||||
|
@ -1023,7 +1018,7 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
|
|||
port2port_name_map[module_input_port.get_name()] = instance_input_port;
|
||||
|
||||
/* Link nodes to output ports for the branch module */
|
||||
BasicPort instance_output_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
BasicPort instance_output_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
ModulePortId module_output_port_id = module_manager.find_module_port(branch_module_id, "out");
|
||||
VTR_ASSERT(ModulePortId::INVALID() != module_output_port_id);
|
||||
/* Get the port from module */
|
||||
|
@ -1035,12 +1030,16 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
|
|||
for (const auto& mem : mems) {
|
||||
/* Generate the port info of each mem node */
|
||||
BasicPort branch_node_mem_port(circuit_lib.port_lib_name(mux_regular_sram_ports[0]), size_t(mem), size_t(mem));
|
||||
/* If use local decoders, we should use another name for the mem port */
|
||||
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
|
||||
branch_node_mem_port.set_name(generate_mux_local_decoder_data_port_name());
|
||||
}
|
||||
branch_node_mem_ports.push_back(branch_node_mem_port);
|
||||
}
|
||||
|
||||
/* Create the port info for the input */
|
||||
/* TODO: the naming could be more flexible? */
|
||||
BasicPort instance_mem_port = generate_verilog_bus_port(branch_node_mem_ports, std::string(generate_verilog_mux_node_name(output_node_level, false) + "_mem"));
|
||||
BasicPort instance_mem_port = generate_verilog_bus_port(branch_node_mem_ports, std::string(generate_mux_node_name(output_node_level, false) + "_mem"));
|
||||
/* If we have more than 1 port in the combined instance ports ,
|
||||
* output a local wire */
|
||||
if (1 < combine_verilog_ports(branch_node_mem_ports).size()) {
|
||||
|
@ -1065,12 +1064,16 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
|
|||
for (const auto& mem : mems) {
|
||||
/* Generate the port info of each mem node */
|
||||
BasicPort branch_node_mem_inv_port(circuit_lib.port_lib_name(mux_regular_sram_ports[0]) + "_inv", size_t(mem), size_t(mem));
|
||||
/* If use local decoders, we should use another name for the mem port */
|
||||
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
|
||||
branch_node_mem_inv_port.set_name(generate_mux_local_decoder_data_inv_port_name());
|
||||
}
|
||||
branch_node_mem_inv_ports.push_back(branch_node_mem_inv_port);
|
||||
}
|
||||
|
||||
/* Create the port info for the input */
|
||||
/* TODO: the naming could be more flexible? */
|
||||
BasicPort instance_mem_inv_port = generate_verilog_bus_port(branch_node_mem_inv_ports, std::string(generate_verilog_mux_node_name(output_node_level, false) + "_mem_inv"));
|
||||
BasicPort instance_mem_inv_port = generate_verilog_bus_port(branch_node_mem_inv_ports, std::string(generate_mux_node_name(output_node_level, false) + "_mem_inv"));
|
||||
/* If we have more than 1 port in the combined instance ports ,
|
||||
* output a local wire */
|
||||
if (1 < combine_verilog_ports(branch_node_mem_inv_ports).size()) {
|
||||
|
@ -1110,8 +1113,8 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
|
|||
/* We must have a valid model id */
|
||||
VTR_ASSERT(CircuitModelId::INVALID() != buffer_model);
|
||||
|
||||
BasicPort buffer_instance_input_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
BasicPort buffer_instance_output_port(generate_verilog_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
|
||||
BasicPort buffer_instance_input_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
BasicPort buffer_instance_output_port(generate_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
|
||||
|
||||
print_verilog_buffer_instance(fp, module_manager, circuit_lib, module_id, buffer_model, buffer_instance_input_port, buffer_instance_output_port);
|
||||
|
||||
|
@ -1167,7 +1170,7 @@ void generate_verilog_cmos_mux_module_input_buffers(ModuleManager& module_manage
|
|||
BasicPort instance_input_port(module_input_port.get_name(), size_t(input_index), size_t(input_index));
|
||||
|
||||
/* Create the port information of the MUX graph input, which is the output of buffer instance */
|
||||
BasicPort instance_output_port(generate_verilog_mux_node_name(input_node_level, false), input_node_index_at_level, input_node_index_at_level);
|
||||
BasicPort instance_output_port(generate_mux_node_name(input_node_level, false), input_node_index_at_level, input_node_index_at_level);
|
||||
|
||||
/* For last input:
|
||||
* Add a constant value to the last input, if this MUX needs a constant input
|
||||
|
@ -1261,7 +1264,7 @@ void generate_verilog_cmos_mux_module_output_buffers(ModuleManager& module_manag
|
|||
VTR_ASSERT(MuxNodeId::INVALID() != mux_graph.node_id(output_node_level, output_node_index_at_level));
|
||||
|
||||
/* Create the port information of the MUX input, which is the input of buffer instance */
|
||||
BasicPort instance_input_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
BasicPort instance_input_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
|
||||
/* Create the port information of the module output at the given pin range, which is the output of buffer instance */
|
||||
BasicPort instance_output_port(module_output_port.get_name(), pin, pin);
|
||||
|
@ -1315,8 +1318,11 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
|
|||
std::vector<CircuitPortId> mux_input_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
/* Get the output ports from the mux */
|
||||
std::vector<CircuitPortId> mux_output_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_OUTPUT, true);
|
||||
/* Get the sram ports from the mux */
|
||||
std::vector<CircuitPortId> mux_sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true);
|
||||
/* Get the sram ports from the mux
|
||||
* Multiplexing structure does not mode_sram_ports, they are handled in LUT modules
|
||||
* Here we just bypass it.
|
||||
*/
|
||||
std::vector<CircuitPortId> mux_sram_ports = find_circuit_regular_sram_ports(circuit_lib, circuit_model);
|
||||
|
||||
/* Make sure we have a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
@ -1329,6 +1335,18 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
|
|||
/* Find out the number of memory bits */
|
||||
size_t num_mems = mux_graph.num_memory_bits();
|
||||
|
||||
/* The size of of memory ports depend on
|
||||
* if a local encoder is used for the mux or not
|
||||
* Multiplexer local encoders are applied to memory bits at each stage
|
||||
*/
|
||||
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
|
||||
num_mems = 0;
|
||||
for (const auto& lvl : mux_graph.levels()) {
|
||||
size_t data_size = mux_graph.num_memory_bits_at_level(lvl);
|
||||
num_mems += find_mux_local_decoder_addr_size(data_size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check codes to ensure the port of Verilog netlists will match */
|
||||
/* MUX graph must have only 1 output */
|
||||
VTR_ASSERT(1 == mux_input_ports.size());
|
||||
|
@ -1383,12 +1401,6 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
|
|||
|
||||
size_t sram_port_cnt = 0;
|
||||
for (const auto& port : mux_sram_ports) {
|
||||
/* Multiplexing structure does not mode_sram_ports, they are handled in LUT modules
|
||||
* Here we just bypass it.
|
||||
*/
|
||||
if (true == circuit_lib.port_is_mode_select(port)) {
|
||||
continue;
|
||||
}
|
||||
BasicPort mem_port(circuit_lib.port_lib_name(port), num_mems);
|
||||
module_manager.add_port(module_id, mem_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
BasicPort mem_inv_port(std::string(circuit_lib.port_lib_name(port) + "_inv"), num_mems);
|
||||
|
@ -1396,11 +1408,56 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
|
|||
/* Update counter */
|
||||
sram_port_cnt++;
|
||||
}
|
||||
VTR_ASSERT(1 == sram_port_cnt);
|
||||
|
||||
/* dump module definition + ports */
|
||||
print_verilog_module_declaration(fp, module_manager, module_id);
|
||||
|
||||
/* TODO: Print the internal logic in Verilog codes */
|
||||
/* Add local decoder instance here */
|
||||
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
|
||||
BasicPort decoder_data_port(generate_mux_local_decoder_data_port_name(), mux_graph.num_memory_bits());
|
||||
BasicPort decoder_data_inv_port(generate_mux_local_decoder_data_inv_port_name(), mux_graph.num_memory_bits());
|
||||
/* Print local wires to bridge the port of module and memory inputs
|
||||
* of each MUX branch instance
|
||||
*/
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, decoder_data_port) << ";" << std::endl;
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, decoder_data_inv_port) << ";" << std::endl;
|
||||
|
||||
/* Local port to record the LSB and MSB of each level, here, we deposite (0, 0) */
|
||||
BasicPort lvl_addr_port(circuit_lib.port_lib_name(mux_sram_ports[0]), 0);
|
||||
BasicPort lvl_data_port(decoder_data_port.get_name(), 0);
|
||||
BasicPort lvl_data_inv_port(decoder_data_inv_port.get_name(), 0);
|
||||
for (const auto& lvl : mux_graph.levels()) {
|
||||
size_t addr_size = find_mux_local_decoder_addr_size(mux_graph.num_memory_bits_at_level(lvl));
|
||||
size_t data_size = mux_graph.num_memory_bits_at_level(lvl);
|
||||
/* Update the LSB and MSB of addr and data port for the current level */
|
||||
lvl_addr_port.rotate(addr_size);
|
||||
lvl_data_port.rotate(data_size);
|
||||
lvl_data_inv_port.rotate(data_size);
|
||||
/* Print the instance of local decoder */
|
||||
std::string decoder_module_name = generate_mux_local_decoder_subckt_name(addr_size, data_size);
|
||||
ModuleId decoder_module = module_manager.find_module(decoder_module_name);
|
||||
VTR_ASSERT(ModuleId::INVALID() != decoder_module);
|
||||
|
||||
/* Create a port-to-port map */
|
||||
std::map<std::string, BasicPort> decoder_port2port_name_map;
|
||||
decoder_port2port_name_map[generate_mux_local_decoder_addr_port_name()] = lvl_addr_port;
|
||||
decoder_port2port_name_map[generate_mux_local_decoder_data_port_name()] = lvl_data_port;
|
||||
decoder_port2port_name_map[generate_mux_local_decoder_data_inv_port_name()] = lvl_data_inv_port;
|
||||
|
||||
/* Print an instance of the MUX Module */
|
||||
print_verilog_comment(fp, std::string("----- BEGIN Instanciation of a local decoder -----"));
|
||||
print_verilog_module_instance(fp, module_manager, module_id, decoder_module, decoder_port2port_name_map, circuit_lib.dump_explicit_port_map(circuit_model));
|
||||
print_verilog_comment(fp, std::string("----- END Instanciation of a local decoder -----"));
|
||||
fp << std::endl;
|
||||
/* IMPORTANT: this update MUST be called after the instance outputting!!!!
|
||||
* update the module manager with the relationship between the parent and child modules
|
||||
*/
|
||||
module_manager.add_child_module(module_id, decoder_module);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the internal logic in Verilog codes */
|
||||
/* Print the Multiplexing structure in Verilog codes
|
||||
* Separated generation strategy on using standard cell MUX2 or TGATE,
|
||||
* 1. MUX2 has a fixed port map: input_port[0] and input_port[1] is the data_path input
|
||||
|
@ -1467,13 +1524,13 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu
|
|||
/* Print local wires which are the nodes in the mux graph */
|
||||
for (size_t level = 0; level < mux_graph.num_levels(); ++level) {
|
||||
/* Print the internal wires located at this level */
|
||||
BasicPort internal_wire_port(generate_verilog_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
|
||||
BasicPort internal_wire_port(generate_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_port) << ";" << std::endl;
|
||||
/* Identify if an intermediate buffer is needed */
|
||||
if (false == inter_buffer_location_map[level]) {
|
||||
continue;
|
||||
}
|
||||
BasicPort internal_wire_buffered_port(generate_verilog_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
|
||||
BasicPort internal_wire_buffered_port(generate_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_buffered_port) << std::endl;
|
||||
}
|
||||
print_verilog_comment(fp, std::string("---- END Internal wires of a RRAM-based MUX module -----"));
|
||||
|
@ -1515,7 +1572,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu
|
|||
|
||||
/* Instanciate the branch module which is a tgate-based module
|
||||
*/
|
||||
std::string branch_module_name= generate_verilog_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, branch_size, verilog_mux_basis_posfix);
|
||||
std::string branch_module_name= generate_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, branch_size, verilog_mux_basis_posfix);
|
||||
/* Get the moduleId for the submodule */
|
||||
ModuleId branch_module_id = module_manager.find_module(branch_module_name);
|
||||
/* We must have one */
|
||||
|
@ -1531,13 +1588,13 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu
|
|||
/* Generate the port info of each input node */
|
||||
size_t input_node_level = mux_graph.node_level(input_node);
|
||||
size_t input_node_index_at_level = mux_graph.node_index_at_level(input_node);
|
||||
BasicPort branch_node_input_port(generate_verilog_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
|
||||
BasicPort branch_node_input_port(generate_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
|
||||
branch_node_input_ports.push_back(branch_node_input_port);
|
||||
}
|
||||
|
||||
/* Create the port info for the input */
|
||||
/* TODO: the naming could be more flexible? */
|
||||
BasicPort instance_input_port = generate_verilog_bus_port(branch_node_input_ports, std::string(generate_verilog_mux_node_name(output_node_level, false) + "_in"));
|
||||
BasicPort instance_input_port = generate_verilog_bus_port(branch_node_input_ports, std::string(generate_mux_node_name(output_node_level, false) + "_in"));
|
||||
/* If we have more than 1 port in the combined instance ports ,
|
||||
* output a local wire */
|
||||
if (1 < combine_verilog_ports(branch_node_input_ports).size()) {
|
||||
|
@ -1556,7 +1613,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu
|
|||
port2port_name_map[module_input_port.get_name()] = instance_input_port;
|
||||
|
||||
/* Link nodes to output ports for the branch module */
|
||||
BasicPort instance_output_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
BasicPort instance_output_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
ModulePortId module_output_port_id = module_manager.find_module_port(branch_module_id, "out");
|
||||
VTR_ASSERT(ModulePortId::INVALID() != module_output_port_id);
|
||||
/* Get the port from module */
|
||||
|
@ -1589,7 +1646,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu
|
|||
|
||||
/* Create the port info for the input */
|
||||
/* TODO: the naming could be more flexible? */
|
||||
BasicPort instance_blb_port = generate_verilog_bus_port(branch_node_blb_ports, std::string(generate_verilog_mux_node_name(output_node_level, false) + "_blb"));
|
||||
BasicPort instance_blb_port = generate_verilog_bus_port(branch_node_blb_ports, std::string(generate_mux_node_name(output_node_level, false) + "_blb"));
|
||||
/* If we have more than 1 port in the combined instance ports ,
|
||||
* output a local wire */
|
||||
if (1 < combine_verilog_ports(branch_node_blb_ports).size()) {
|
||||
|
@ -1630,7 +1687,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu
|
|||
|
||||
/* Create the port info for the WL */
|
||||
/* TODO: the naming could be more flexible? */
|
||||
BasicPort instance_wl_port = generate_verilog_bus_port(branch_node_wl_ports, std::string(generate_verilog_mux_node_name(output_node_level, false) + "_wl"));
|
||||
BasicPort instance_wl_port = generate_verilog_bus_port(branch_node_wl_ports, std::string(generate_mux_node_name(output_node_level, false) + "_wl"));
|
||||
/* If we have more than 1 port in the combined instance ports ,
|
||||
* output a local wire */
|
||||
if (1 < combine_verilog_ports(branch_node_wl_ports).size()) {
|
||||
|
@ -1669,8 +1726,8 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu
|
|||
/* We must have a valid model id */
|
||||
VTR_ASSERT(CircuitModelId::INVALID() != buffer_model);
|
||||
|
||||
BasicPort buffer_instance_input_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
BasicPort buffer_instance_output_port(generate_verilog_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
|
||||
BasicPort buffer_instance_input_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
|
||||
BasicPort buffer_instance_output_port(generate_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
|
||||
|
||||
print_verilog_buffer_instance(fp, module_manager, circuit_lib, module_id, buffer_model, buffer_instance_input_port, buffer_instance_output_port);
|
||||
|
||||
|
@ -1825,9 +1882,9 @@ void generate_verilog_mux_module(ModuleManager& module_manager,
|
|||
std::fstream& fp,
|
||||
const CircuitModelId& circuit_model,
|
||||
const MuxGraph& mux_graph) {
|
||||
std::string module_name = generate_verilog_mux_subckt_name(circuit_lib, circuit_model,
|
||||
find_mux_num_datapath_inputs(circuit_lib, circuit_model, mux_graph.num_inputs()),
|
||||
std::string(""));
|
||||
std::string module_name = generate_mux_subckt_name(circuit_lib, circuit_model,
|
||||
find_mux_num_datapath_inputs(circuit_lib, circuit_model, mux_graph.num_inputs()),
|
||||
std::string(""));
|
||||
|
||||
/* Multiplexers built with different technology is in different organization */
|
||||
switch (circuit_lib.design_tech_type(circuit_model)) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,13 @@
|
|||
/***********************************************
|
||||
* Header file for verilog_routing.cpp
|
||||
**********************************************/
|
||||
#ifndef VERILOG_ROUTING_H
|
||||
#define VERILOG_ROUTING_H
|
||||
|
||||
/* Include other header files which are dependency on the function declared below */
|
||||
#include "mux_library.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
void dump_verilog_routing_chan_subckt(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* verilog_dir,
|
||||
char* subckt_dir,
|
||||
|
@ -134,14 +142,20 @@ void dump_verilog_routing_connection_box_subckt(t_sram_orgz_info* cur_sram_orgz_
|
|||
bool is_explicit_mapping);
|
||||
|
||||
|
||||
void dump_verilog_routing_resources(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* verilog_dir,
|
||||
char* subckt_dir,
|
||||
t_arch arch,
|
||||
t_det_routing_arch* routing_arch,
|
||||
int LL_num_rr_nodes, t_rr_node* LL_rr_node,
|
||||
t_ivec*** LL_rr_node_indices,
|
||||
t_rr_indexed_data* LL_rr_indexed_data,
|
||||
t_fpga_spice_opts FPGA_SPICE_Opts);
|
||||
std::string generate_grid_side_port_name(const vtr::Point<size_t>& coordinate,
|
||||
const e_side& side,
|
||||
const size_t& pin_id);
|
||||
|
||||
void print_verilog_routing_resources(ModuleManager& module_manager,
|
||||
const MuxLibrary& mux_lib,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* verilog_dir,
|
||||
char* subckt_dir,
|
||||
const t_arch& arch,
|
||||
const t_det_routing_arch& routing_arch,
|
||||
int LL_num_rr_nodes, t_rr_node* LL_rr_node,
|
||||
t_ivec*** LL_rr_node_indices,
|
||||
t_rr_indexed_data* LL_rr_indexed_data,
|
||||
const t_fpga_spice_opts& FPGA_SPICE_Opts);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -726,7 +726,8 @@ void dump_verilog_cmos_mux_tree_structure(FILE* fp,
|
|||
for (i = 0; i < spice_mux_arch.num_level + 1; i++) {
|
||||
inter_buf_loc[i] = FALSE;
|
||||
}
|
||||
if (NULL != spice_model.lut_intermediate_buffer->location_map) {
|
||||
if ( (TRUE == spice_model.lut_intermediate_buffer->exist)
|
||||
&& (NULL != spice_model.lut_intermediate_buffer->location_map) ) {
|
||||
assert ((size_t)spice_mux_arch.num_level - 1 == strlen(spice_model.lut_intermediate_buffer->location_map));
|
||||
/* For intermediate buffers */
|
||||
for (i = 0; i < spice_mux_arch.num_level - 1; i++) {
|
||||
|
@ -993,7 +994,7 @@ void dump_verilog_cmos_mux_multilevel_structure(FILE* fp,
|
|||
if (TRUE == spice_model.design_tech_info.mux_info->local_encoder) {
|
||||
/* Get the number of inputs */
|
||||
int num_outputs = cur_num_input_basis;
|
||||
int num_inputs = determine_mux_local_encoder_num_inputs(num_outputs);
|
||||
int num_inputs = determine_mux_local_encoder_num_inputs(num_outputs);
|
||||
/* Find the decoder name */
|
||||
fprintf(fp, "%s %s_%d_ (",
|
||||
generate_verilog_decoder_subckt_name(num_inputs, num_outputs),
|
||||
|
@ -2040,7 +2041,7 @@ void dump_verilog_cmos_mux_mem_submodule(FILE* fp,
|
|||
/* Asserts*/
|
||||
assert ((1 == num_sram_port) && (NULL != sram_port));
|
||||
assert (NULL != sram_port[0]->spice_model);
|
||||
assert ((SPICE_MODEL_SCFF == sram_port[0]->spice_model->type)
|
||||
assert ((SPICE_MODEL_CCFF == sram_port[0]->spice_model->type)
|
||||
|| (SPICE_MODEL_SRAM == sram_port[0]->spice_model->type));
|
||||
|
||||
/* Get the memory model */
|
||||
|
@ -3268,9 +3269,13 @@ void dump_verilog_submodules(ModuleManager& module_manager,
|
|||
dump_verilog_submodule_muxes(cur_sram_orgz_info, verilog_dir, submodule_dir, routing_arch->num_switch,
|
||||
switch_inf, Arch.spice, routing_arch, fpga_verilog_opts.dump_explicit_verilog);
|
||||
|
||||
/* NOTE: local decoders generation must go before the MUX generation!!!
|
||||
* because local decoders modules will be instanciated in the MUX modules
|
||||
*/
|
||||
print_verilog_submodule_mux_local_decoders(module_manager, mux_lib, Arch.spice->circuit_lib,
|
||||
std::string(verilog_dir), std::string(submodule_dir));
|
||||
print_verilog_submodule_muxes(module_manager, mux_lib, Arch.spice->circuit_lib, cur_sram_orgz_info, std::string(verilog_dir), std::string(submodule_dir));
|
||||
|
||||
print_verilog_submodule_mux_local_decoders(module_manager, mux_lib, Arch.spice->circuit_lib, std::string(verilog_dir), std::string(submodule_dir));
|
||||
|
||||
/* 2. LUTes */
|
||||
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of LUTs...\n");
|
||||
|
@ -3288,12 +3293,11 @@ void dump_verilog_submodules(ModuleManager& module_manager,
|
|||
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of memories...\n");
|
||||
dump_verilog_submodule_memories(cur_sram_orgz_info, verilog_dir, submodule_dir, routing_arch->num_switch,
|
||||
switch_inf, Arch.spice, routing_arch, fpga_verilog_opts.dump_explicit_verilog);
|
||||
print_verilog_submodule_memories(module_manager, mux_lib, Arch.spice->circuit_lib, std::string(verilog_dir), std::string(submodule_dir));
|
||||
print_verilog_submodule_memories(module_manager, mux_lib, Arch.spice->circuit_lib,
|
||||
cur_sram_orgz_info->type,
|
||||
std::string(verilog_dir), std::string(submodule_dir));
|
||||
|
||||
/* 5. Dump decoder modules only when memory bank is required */
|
||||
dump_verilog_config_peripherals(cur_sram_orgz_info, verilog_dir, submodule_dir);
|
||||
|
||||
/* 6. Dump template for all the modules */
|
||||
/* 5. Dump template for all the modules */
|
||||
if (TRUE == fpga_verilog_opts.print_user_defined_template) {
|
||||
print_verilog_submodule_templates(module_manager, Arch.spice->circuit_lib, L_segment_vec, std::string(verilog_dir), std::string(submodule_dir));
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "verilog_decoder.h"
|
||||
#include "verilog_top_netlist_utils.h"
|
||||
|
||||
|
||||
/* Local Subroutines declaration */
|
||||
|
||||
/******** Subroutines ***********/
|
||||
|
@ -191,8 +192,8 @@ void dump_verilog_top_netlist_scan_chain_ports(t_sram_orgz_info* cur_sram_orgz_i
|
|||
static
|
||||
void dump_verilog_top_netlist_scan_chain_internal_wires(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp) {
|
||||
t_spice_model* scff_mem_model = NULL;
|
||||
int num_scffs;
|
||||
t_spice_model* ccff_mem_model = NULL;
|
||||
int num_ccffs;
|
||||
|
||||
/* A valid file handler */
|
||||
if (NULL == fp) {
|
||||
|
@ -200,23 +201,23 @@ void dump_verilog_top_netlist_scan_chain_internal_wires(t_sram_orgz_info* cur_sr
|
|||
exit(1);
|
||||
}
|
||||
|
||||
num_scffs = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info);
|
||||
get_sram_orgz_info_mem_model(cur_sram_orgz_info, &scff_mem_model);
|
||||
num_ccffs = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info);
|
||||
get_sram_orgz_info_mem_model(cur_sram_orgz_info, &ccff_mem_model);
|
||||
/* Check */
|
||||
assert( SPICE_MODEL_SCFF == scff_mem_model->type );
|
||||
assert( SPICE_MODEL_CCFF == ccff_mem_model->type );
|
||||
|
||||
/* Delcare local wires */
|
||||
fprintf(fp, " wire [0:%d] %s_scff_in_local_bus;\n",
|
||||
num_scffs - 1, scff_mem_model->prefix);
|
||||
fprintf(fp, " wire [0:%d] %s_ccff_in_local_bus;\n",
|
||||
num_ccffs - 1, ccff_mem_model->prefix);
|
||||
|
||||
fprintf(fp, " wire [0:%d] %s_scff_out_local_bus;\n",
|
||||
num_scffs - 1, scff_mem_model->prefix);
|
||||
fprintf(fp, " wire [0:%d] %s_ccff_out_local_bus;\n",
|
||||
num_ccffs - 1, ccff_mem_model->prefix);
|
||||
|
||||
/* Dump ports only visible during formal verification*/
|
||||
fprintf(fp, "`ifdef %s\n", verilog_formal_verification_preproc_flag);
|
||||
fprintf(fp, " ");
|
||||
dump_verilog_formal_verification_sram_ports(fp, cur_sram_orgz_info,
|
||||
0, num_scffs - 1,
|
||||
0, num_ccffs - 1,
|
||||
VERILOG_PORT_WIRE, false);
|
||||
fprintf(fp, ";\n");
|
||||
fprintf(fp, "`endif\n");
|
||||
|
@ -224,8 +225,8 @@ void dump_verilog_top_netlist_scan_chain_internal_wires(t_sram_orgz_info* cur_sr
|
|||
|
||||
/* Exception for head: connect to primary inputs */
|
||||
/*
|
||||
fprintf(fp, " assign %s_scff_in[%d] = %s;\n",
|
||||
scff_mem_model->prefix, 0,
|
||||
fprintf(fp, " assign %s_ccff_in[%d] = %s;\n",
|
||||
ccff_mem_model->prefix, 0,
|
||||
top_netlist_scan_chain_head_prefix);
|
||||
*/
|
||||
/* Connected the scan-chain flip-flops */
|
||||
|
@ -234,10 +235,10 @@ void dump_verilog_top_netlist_scan_chain_internal_wires(t_sram_orgz_info* cur_sr
|
|||
fprintf(fp, " genvar i;\n");
|
||||
fprintf(fp, " generate\n");
|
||||
fprintf(fp, " for (i = %d; i < %d; i = i + 1) begin\n",
|
||||
1, num_scffs - 1);
|
||||
fprintf(fp, "assign %s_scff_in[i] = %s_scff_out[i - 1];\n",
|
||||
scff_mem_model->prefix,
|
||||
scff_mem_model->prefix);
|
||||
1, num_ccffs - 1);
|
||||
fprintf(fp, "assign %s_ccff_in[i] = %s_ccff_out[i - 1];\n",
|
||||
ccff_mem_model->prefix,
|
||||
ccff_mem_model->prefix);
|
||||
fprintf(fp, " end\n");
|
||||
fprintf(fp, " endgenerate;\n");
|
||||
*/
|
||||
|
@ -482,9 +483,11 @@ void dump_verilog_defined_one_channel(FILE* fp,
|
|||
fprintf(fp, "(");
|
||||
fprintf(fp, "\n");
|
||||
/* dump global ports */
|
||||
/*
|
||||
if (0 < dump_verilog_global_ports(fp, global_ports_head, FALSE, is_explicit_mapping)) {
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
*/
|
||||
|
||||
/* LEFT/BOTTOM side port of CHANX/CHANY */
|
||||
/* We apply an opposite port naming rule than function: fprint_routing_chan_subckt
|
||||
|
@ -928,7 +931,7 @@ void dump_verilog_one_clb2clb_direct(FILE* fp,
|
|||
exit(1);
|
||||
}
|
||||
|
||||
for (ipin = 0; ipin < cur_direct->from_clb_pin_end_index - cur_direct->from_clb_pin_start_index; ipin++) {
|
||||
for (ipin = 0; ipin < 1 + cur_direct->from_clb_pin_end_index - cur_direct->from_clb_pin_start_index; ipin++) {
|
||||
/* Update pin index and get the side of the pins on grids */
|
||||
cur_from_clb_pin_index = cur_direct->from_clb_pin_start_index + ipin;
|
||||
cur_to_clb_pin_index = cur_direct->to_clb_pin_start_index + ipin;
|
||||
|
@ -952,7 +955,7 @@ void dump_verilog_one_clb2clb_direct(FILE* fp,
|
|||
dump_verilog_toplevel_one_grid_side_pin_with_given_index(fp, IPIN,
|
||||
cur_to_clb_pin_index,
|
||||
cur_to_clb_pin_side,
|
||||
to_grid_x, from_grid_y,
|
||||
to_grid_x, to_grid_y,
|
||||
FALSE);
|
||||
fprintf(fp, ");\n");
|
||||
|
||||
|
@ -961,7 +964,7 @@ void dump_verilog_one_clb2clb_direct(FILE* fp,
|
|||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply CLB to CLB direct connections to a Verilog netlist
|
||||
*/
|
||||
|
@ -992,12 +995,12 @@ void dump_verilog_clb2clb_directs(FILE* fp,
|
|||
*/
|
||||
for (idirect = 0; idirect < num_directs; idirect++) {
|
||||
/* Bypass unmatch types */
|
||||
if (grid[ix][iy].type != direct[idirect].from_clb_type) {
|
||||
continue;
|
||||
}
|
||||
/* Apply x/y_offset */
|
||||
to_clb_x = ix + direct[idirect].x_offset;
|
||||
to_clb_y = iy + direct[idirect].y_offset;
|
||||
if (grid[ix][iy].type != direct[idirect].from_clb_type) {
|
||||
continue;
|
||||
}
|
||||
/* see if the destination CLB is in the bound */
|
||||
if ((FALSE == is_grid_coordinate_in_range(0, nx, to_clb_x))
|
||||
||(FALSE == is_grid_coordinate_in_range(0, ny, to_clb_y))) {
|
||||
|
@ -1008,21 +1011,157 @@ void dump_verilog_clb2clb_directs(FILE* fp,
|
|||
continue;
|
||||
}
|
||||
*/
|
||||
/* Check if the to_clb_type matches */
|
||||
if (grid[to_clb_x][to_clb_y].type != direct[idirect].to_clb_type) {
|
||||
continue;
|
||||
}
|
||||
/* Bypass x/y_offset = 1
|
||||
* since it may be addressed in Connection blocks
|
||||
if (1 == (x_offset + y_offset)) {
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
/* Now we can print a direct connection with the spice models */
|
||||
dump_verilog_one_clb2clb_direct(fp,
|
||||
ix, iy,
|
||||
to_clb_x, to_clb_y,
|
||||
&direct[idirect]);
|
||||
|
||||
/* Check if the to_clb_type matches */
|
||||
if (grid[to_clb_x][to_clb_y].type == direct[idirect].to_clb_type) {
|
||||
/* Now we can print a direct connection with the spice models */
|
||||
dump_verilog_one_clb2clb_direct(fp,
|
||||
ix, iy,
|
||||
to_clb_x, to_clb_y,
|
||||
&direct[idirect]);
|
||||
/* Check if we can make a point to point connection between direct connection */
|
||||
}else if((P2P_DIRECT_COLUMN == direct[idirect].interconnection_type) ||
|
||||
(P2P_DIRECT_ROW == direct[idirect].interconnection_type)){
|
||||
/* Check in which case we are to adapt coordinates */
|
||||
if((P2P_DIRECT_COLUMN == direct[idirect].interconnection_type) &&
|
||||
(POSITIVE_DIR == direct[idirect].x_dir) &&
|
||||
(POSITIVE_DIR == direct[idirect].y_dir)){ // Bottom to Top on Right
|
||||
if (grid[ix][iy].type == direct[idirect].from_clb_type) {
|
||||
to_clb_x = ix + 1;
|
||||
to_clb_y = ny + 1;
|
||||
do{ // Find next available type
|
||||
to_clb_y --; // Scan types from Top to Bottom
|
||||
if(0 > to_clb_y){ // If scan fails scan the column on the Right until match or no more column
|
||||
to_clb_x ++;
|
||||
to_clb_y = ny;
|
||||
}
|
||||
} while((grid[to_clb_x][to_clb_y].type != direct[idirect].to_clb_type) &&
|
||||
(nx > to_clb_x));
|
||||
}
|
||||
} else if((P2P_DIRECT_COLUMN == direct[idirect].interconnection_type) &&
|
||||
(POSITIVE_DIR == direct[idirect].x_dir) &&
|
||||
(NEGATIVE_DIR == direct[idirect].y_dir)){ // Top to Bottom on Right
|
||||
if (grid[ix][iy].type != direct[idirect].from_clb_type) {
|
||||
to_clb_x = ix + 1;
|
||||
to_clb_y = -1;
|
||||
do{ // Find next available type
|
||||
to_clb_y ++; // Scan types from Bottom to Top
|
||||
if(ny < to_clb_y){ // If scan fails scan the column on the Right until match or no more column
|
||||
to_clb_x ++;
|
||||
to_clb_y = 0;
|
||||
}
|
||||
} while((grid[to_clb_x][to_clb_y].type != direct[idirect].to_clb_type) &&
|
||||
(nx >= to_clb_x));
|
||||
}
|
||||
} else if((P2P_DIRECT_COLUMN == direct[idirect].interconnection_type) &&
|
||||
(NEGATIVE_DIR == direct[idirect].x_dir) &&
|
||||
(NEGATIVE_DIR == direct[idirect].y_dir)){ // Top to Bottom on Left
|
||||
if (grid[ix][iy].type != direct[idirect].from_clb_type) {
|
||||
to_clb_x = ix - 1;
|
||||
to_clb_y = -1;
|
||||
do{ // Find next available type
|
||||
to_clb_y ++; // Scan types from Bottom to Top
|
||||
if(ny < to_clb_y){ // If scan fails scan the column on the Left until match or no more column
|
||||
to_clb_x --;
|
||||
to_clb_y = 0;
|
||||
}
|
||||
} while((grid[to_clb_x][to_clb_y].type != direct[idirect].to_clb_type) &&
|
||||
(0 <= to_clb_x));
|
||||
}
|
||||
} else if((P2P_DIRECT_COLUMN == direct[idirect].interconnection_type) &&
|
||||
(NEGATIVE_DIR == direct[idirect].x_dir) &&
|
||||
(POSITIVE_DIR == direct[idirect].y_dir)){ // Bottom to Top on Left
|
||||
if (grid[ix][iy].type != direct[idirect].from_clb_type) {
|
||||
to_clb_x = ix - 1;
|
||||
to_clb_y = ny + 1;
|
||||
do{ // Find next available type
|
||||
to_clb_y --; // Scan types from Top to Bottom
|
||||
if(0 > to_clb_y){ // If scan fails scan the column on the Left until match or no more column
|
||||
to_clb_x --;
|
||||
to_clb_y = ny;
|
||||
}
|
||||
} while((grid[to_clb_x][to_clb_y].type != direct[idirect].to_clb_type) &&
|
||||
(0 <= to_clb_x));
|
||||
}
|
||||
} else if((P2P_DIRECT_ROW == direct[idirect].interconnection_type) &&
|
||||
(POSITIVE_DIR == direct[idirect].x_dir) &&
|
||||
(POSITIVE_DIR == direct[idirect].y_dir)){ // Left to Right Above
|
||||
if (grid[ix][iy].type != direct[idirect].from_clb_type) {
|
||||
to_clb_x = nx + 1;
|
||||
to_clb_y = iy + 1;
|
||||
do{ // Find next available type
|
||||
to_clb_x --; // Scan types from Right to Left
|
||||
if(0 > to_clb_x){ // If scan fails scan the row above until match or no more row
|
||||
to_clb_x = nx;
|
||||
to_clb_y ++;
|
||||
}
|
||||
} while((grid[to_clb_x][to_clb_y].type != direct[idirect].to_clb_type) &&
|
||||
(ny >= to_clb_y));
|
||||
}
|
||||
} else if((P2P_DIRECT_ROW == direct[idirect].interconnection_type) &&
|
||||
(POSITIVE_DIR == direct[idirect].x_dir) &&
|
||||
(NEGATIVE_DIR == direct[idirect].y_dir)){ // Left to Right Below
|
||||
if (grid[ix][iy].type != direct[idirect].from_clb_type) {
|
||||
to_clb_x = nx + 1;
|
||||
to_clb_y = iy - 1;
|
||||
do{ // Find next available type
|
||||
to_clb_x --; // Scan types from Right to Left
|
||||
if(0 > to_clb_x){ // If scan fails scan the row below until match or no more row
|
||||
to_clb_x = nx;
|
||||
to_clb_y --;
|
||||
}
|
||||
} while((grid[to_clb_x][to_clb_y].type != direct[idirect].to_clb_type) &&
|
||||
(0 <= to_clb_y));
|
||||
}
|
||||
} else if((P2P_DIRECT_ROW == direct[idirect].interconnection_type) &&
|
||||
(NEGATIVE_DIR == direct[idirect].x_dir) &&
|
||||
(NEGATIVE_DIR == direct[idirect].y_dir)){ // Right to Left Below
|
||||
if (grid[ix][iy].type != direct[idirect].from_clb_type) {
|
||||
to_clb_x = -1;
|
||||
to_clb_y = iy - 1;
|
||||
do{ // Find next available type
|
||||
to_clb_x ++; // Scan types from Left to Right
|
||||
if(nx < to_clb_x){ // If scan fails scan the row below until match or no more row
|
||||
to_clb_x = 0;
|
||||
to_clb_y --;
|
||||
}
|
||||
} while((grid[to_clb_x][to_clb_y].type != direct[idirect].to_clb_type) &&
|
||||
(0 <= to_clb_y));
|
||||
}
|
||||
} else if((P2P_DIRECT_ROW == direct[idirect].interconnection_type) &&
|
||||
(NEGATIVE_DIR == direct[idirect].x_dir) &&
|
||||
(POSITIVE_DIR == direct[idirect].y_dir)){ // Right to Left Above
|
||||
if (grid[ix][iy].type != direct[idirect].from_clb_type) {
|
||||
to_clb_x = -1;
|
||||
to_clb_y = iy + 1;
|
||||
do{ // Find next available type
|
||||
to_clb_x ++; // Scan types from Left to Right
|
||||
if(nx < to_clb_x){ // If scan fails scan the row below until match or no more row
|
||||
to_clb_x = 0;
|
||||
to_clb_y ++;
|
||||
}
|
||||
} while((grid[to_clb_x][to_clb_y].type != direct[idirect].to_clb_type) &&
|
||||
(ny >= to_clb_y));
|
||||
}
|
||||
}
|
||||
if(grid[to_clb_x][to_clb_y].type == direct[idirect].from_clb_type){
|
||||
/* Now we can print a direct connection with the spice models */
|
||||
fprintf(fp, " //----- Point to Point from grid_%d__%d_ to grid_%d__%d_ -----\n", ix, iy,
|
||||
to_clb_x, to_clb_y);
|
||||
dump_verilog_one_clb2clb_direct(fp,
|
||||
ix, iy,
|
||||
to_clb_x, to_clb_y,
|
||||
&direct[idirect]);
|
||||
fprintf(fp, " //----- END Point to Point from grid_%d__%d_ to grid_%d__%d_ -----\n", ix, iy,
|
||||
to_clb_x, to_clb_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1104,7 +1243,7 @@ void dump_verilog_configuration_circuits_scan_chains(t_sram_orgz_info* cur_sram_
|
|||
}
|
||||
fprintf(fp, ",\n");
|
||||
if (true == is_explicit_mapping) {
|
||||
fprintf(fp, ".scff_scff_in_local_bus (");
|
||||
fprintf(fp, ".ccff_ccff_in_local_bus (");
|
||||
}
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, 0, num_mem_bits - 1, -1, VERILOG_PORT_CONKT);
|
||||
if (true == is_explicit_mapping) {
|
||||
|
@ -1112,7 +1251,7 @@ void dump_verilog_configuration_circuits_scan_chains(t_sram_orgz_info* cur_sram_
|
|||
}
|
||||
fprintf(fp, ",\n");
|
||||
if (true == is_explicit_mapping) {
|
||||
fprintf(fp, ".scff_scff_out_local_bus (");
|
||||
fprintf(fp, ".ccff_ccff_out_local_bus (");
|
||||
}
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, 0, num_mem_bits - 1, 0, VERILOG_PORT_CONKT);
|
||||
if (true == is_explicit_mapping) {
|
||||
|
|
|
@ -1187,7 +1187,6 @@ void dump_verilog_mux_sram_one_local_outport(FILE* fp,
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Always dump the output ports of a SRAM */
|
||||
void dump_verilog_sram_one_local_outport(FILE* fp,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
|
@ -1220,12 +1219,12 @@ void dump_verilog_sram_one_local_outport(FILE* fp,
|
|||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
if (0 == port_type_index) {
|
||||
port_name = "scff_out_local_bus";
|
||||
port_name = "ccff_out_local_bus";
|
||||
} else if (1 == port_type_index) {
|
||||
port_name = "scff_outb_local_bus";
|
||||
port_name = "ccff_outb_local_bus";
|
||||
} else {
|
||||
assert(-1 == port_type_index);
|
||||
port_name = "scff_in_local_bus";
|
||||
port_name = "ccff_in_local_bus";
|
||||
}
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
|
@ -1289,12 +1288,12 @@ void dump_verilog_sram_one_outport(FILE* fp,
|
|||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
if (0 == port_type_index) {
|
||||
port_name = "scff_out";
|
||||
port_name = "ccff_out";
|
||||
} else if (1 == port_type_index) {
|
||||
port_name = "scff_outb";
|
||||
port_name = "ccff_outb";
|
||||
} else {
|
||||
assert(-1 == port_type_index);
|
||||
port_name = "scff_in";
|
||||
port_name = "ccff_in";
|
||||
}
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
|
@ -1386,7 +1385,7 @@ void dump_verilog_formal_verification_sram_ports(FILE* fp,
|
|||
port_name = "out_fm";
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
mem_model = cur_sram_orgz_info->scff_info->mem_model;
|
||||
mem_model = cur_sram_orgz_info->ccff_info->mem_model;
|
||||
port_name = "out_fm";
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
|
@ -1450,12 +1449,12 @@ void dump_verilog_sram_one_port(FILE* fp,
|
|||
}
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
mem_model = cur_sram_orgz_info->scff_info->mem_model;
|
||||
mem_model = cur_sram_orgz_info->ccff_info->mem_model;
|
||||
if (0 == port_type_index) {
|
||||
port_name = "scff_head";
|
||||
port_name = "ccff_head";
|
||||
} else if (1 == port_type_index) {
|
||||
assert(1 == port_type_index);
|
||||
port_name = "scff_tail";
|
||||
port_name = "ccff_tail";
|
||||
/* Special case: scan-chain ff output should be an output always */
|
||||
if (VERILOG_PORT_INPUT == dump_port_type) {
|
||||
actual_dump_port_type = VERILOG_PORT_OUTPUT;
|
||||
|
@ -1594,7 +1593,7 @@ void dump_verilog_sram_local_ports(FILE* fp,
|
|||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
/* Dump the first port: SRAM_out of CMOS MUX or BL of RRAM MUX */
|
||||
if (true == is_explicit_mapping) {
|
||||
fprintf(fp, ".scff_scff_head(");
|
||||
fprintf(fp, ".ccff_ccff_head(");
|
||||
}
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
|
||||
sram_lsb, sram_lsb,
|
||||
|
@ -1605,7 +1604,7 @@ void dump_verilog_sram_local_ports(FILE* fp,
|
|||
fprintf(fp, ",\n");
|
||||
/* Dump the first port: SRAM_outb of CMOS MUX or WL of RRAM MUX */
|
||||
if (true == is_explicit_mapping) {
|
||||
fprintf(fp, ".scff_scff_tail(");
|
||||
fprintf(fp, ".ccff_ccff_tail(");
|
||||
}
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
|
||||
sram_msb, sram_msb,
|
||||
|
@ -1833,7 +1832,7 @@ void dump_verilog_mux_sram_submodule(FILE* fp, t_sram_orgz_info* cur_sram_orgz_i
|
|||
assert(NULL != cur_sram_orgz_info);
|
||||
assert(NULL != cur_sram_verilog_model);
|
||||
assert((SPICE_MODEL_SRAM == cur_sram_verilog_model->type)
|
||||
|| (SPICE_MODEL_SCFF == cur_sram_verilog_model->type));
|
||||
|| (SPICE_MODEL_CCFF == cur_sram_verilog_model->type));
|
||||
|
||||
/* Get current index of SRAM module */
|
||||
cur_num_sram = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info);
|
||||
|
@ -1999,7 +1998,7 @@ void dump_verilog_sram_submodule(FILE* fp, t_sram_orgz_info* cur_sram_orgz_info,
|
|||
assert(NULL != cur_sram_orgz_info);
|
||||
assert(NULL != cur_sram_verilog_model);
|
||||
assert((SPICE_MODEL_SRAM == cur_sram_verilog_model->type)
|
||||
|| (SPICE_MODEL_SCFF == cur_sram_verilog_model->type));
|
||||
|| (SPICE_MODEL_CCFF == cur_sram_verilog_model->type));
|
||||
|
||||
/* Get current index of SRAM module */
|
||||
cur_num_sram = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info);
|
||||
|
@ -2125,7 +2124,7 @@ void dump_verilog_sram_submodule(FILE* fp, t_sram_orgz_info* cur_sram_orgz_info,
|
|||
return;
|
||||
}
|
||||
|
||||
void dump_verilog_scff_config_bus(FILE* fp,
|
||||
void dump_verilog_ccff_config_bus(FILE* fp,
|
||||
t_spice_model* mem_spice_model,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
int lsb, int msb,
|
||||
|
@ -2134,7 +2133,7 @@ void dump_verilog_scff_config_bus(FILE* fp,
|
|||
|
||||
/* Check */
|
||||
assert(NULL != mem_spice_model);
|
||||
assert(SPICE_MODEL_SCFF == mem_spice_model->type);
|
||||
assert(SPICE_MODEL_CCFF == mem_spice_model->type);
|
||||
|
||||
/* Check the file handler*/
|
||||
if (NULL == fp) {
|
||||
|
@ -2178,17 +2177,17 @@ void dump_verilog_mem_config_bus(FILE* fp, t_spice_model* mem_spice_model,
|
|||
/* Check */
|
||||
assert(NULL != mem_spice_model);
|
||||
assert((SPICE_MODEL_SRAM == mem_spice_model->type)
|
||||
|| (SPICE_MODEL_SCFF == mem_spice_model->type));
|
||||
|| (SPICE_MODEL_CCFF == mem_spice_model->type));
|
||||
|
||||
/* Depend on the style of configuraion circuit */
|
||||
switch (cur_sram_orgz_info->type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
/* We need to connect SCFF inputs and outputs in cacading
|
||||
/* We need to connect CCFF inputs and outputs in cacading
|
||||
* Scan-chain FF outputs are directly wired to SRAM inputs of MUXes
|
||||
*/
|
||||
/* Connect first SCFF to the head */
|
||||
/* Connect first CCFF to the head */
|
||||
/*
|
||||
fprintf(fp, "assign ");
|
||||
dump_verilog_sram_one_outport(fp, cur_sram_orgz_info, cur_num_sram, cur_num_sram, -1, VERILOG_PORT_CONKT);
|
||||
|
@ -2196,7 +2195,7 @@ void dump_verilog_mem_config_bus(FILE* fp, t_spice_model* mem_spice_model,
|
|||
dump_verilog_sram_one_port(fp, cur_sram_orgz_info, cur_num_sram, cur_num_sram, 0, VERILOG_PORT_CONKT);
|
||||
fprintf(fp, ";\n");
|
||||
*/
|
||||
/* Connect last SCFF to the tail */
|
||||
/* Connect last CCFF to the tail */
|
||||
/*
|
||||
fprintf(fp, "assign ");
|
||||
dump_verilog_sram_one_port(fp, cur_sram_orgz_info, cur_num_sram + num_mem_conf_bits - 1, cur_num_sram + num_mem_conf_bits - 1, 1, VERILOG_PORT_CONKT);
|
||||
|
@ -2204,8 +2203,8 @@ void dump_verilog_mem_config_bus(FILE* fp, t_spice_model* mem_spice_model,
|
|||
dump_verilog_sram_one_outport(fp, cur_sram_orgz_info, cur_num_sram + num_mem_conf_bits - 1, cur_num_sram + num_mem_conf_bits - 1, 0, VERILOG_PORT_CONKT);
|
||||
fprintf(fp, ";\n");
|
||||
*/
|
||||
/* Connect SCFFs into chains */
|
||||
/* Cascade the SCFF between head and tail */
|
||||
/* Connect CCFFs into chains */
|
||||
/* Cascade the CCFF between head and tail */
|
||||
/*
|
||||
if (1 < num_mem_conf_bits) {
|
||||
fprintf(fp, "assign ");
|
||||
|
@ -2365,10 +2364,10 @@ void dump_verilog_cmos_mux_config_bus(FILE* fp, t_spice_model* mux_spice_model,
|
|||
cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
|
||||
1, VERILOG_PORT_WIRE);
|
||||
fprintf(fp, ";\n");
|
||||
/* We need to connect SCFF inputs and outputs in cacading
|
||||
/* We need to connect CCFF inputs and outputs in cacading
|
||||
* Scan-chain FF outputs are directly wired to SRAM inputs of MUXes
|
||||
*/
|
||||
/* Connect first SCFF to the head */
|
||||
/* Connect first CCFF to the head */
|
||||
fprintf(fp, "assign ");
|
||||
dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info,
|
||||
mux_spice_model, mux_size,
|
||||
|
@ -2379,7 +2378,7 @@ void dump_verilog_cmos_mux_config_bus(FILE* fp, t_spice_model* mux_spice_model,
|
|||
cur_num_sram, cur_num_sram,
|
||||
-1, VERILOG_PORT_CONKT);
|
||||
fprintf(fp, ";\n");
|
||||
/* Connect last SCFF to the tail */
|
||||
/* Connect last CCFF to the tail */
|
||||
fprintf(fp, "assign ");
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
|
||||
cur_num_sram + num_mux_conf_bits - 1, cur_num_sram + num_mux_conf_bits - 1,
|
||||
|
@ -2390,10 +2389,10 @@ void dump_verilog_cmos_mux_config_bus(FILE* fp, t_spice_model* mux_spice_model,
|
|||
cur_num_sram + num_mux_conf_bits - 1, cur_num_sram + num_mux_conf_bits - 1,
|
||||
0, VERILOG_PORT_CONKT);
|
||||
fprintf(fp, ";\n");
|
||||
/* Connect SCFFs into chains */
|
||||
/* Connect the first SCFF (LSB) to the head */
|
||||
/* Connect the last SCFF (MSB) to the tail */
|
||||
/* Cascade the SCFF between head and tail */
|
||||
/* Connect CCFFs into chains */
|
||||
/* Connect the first CCFF (LSB) to the head */
|
||||
/* Connect the last CCFF (MSB) to the tail */
|
||||
/* Cascade the CCFF between head and tail */
|
||||
if (1 < num_mux_conf_bits) {
|
||||
fprintf(fp, "assign ");
|
||||
dump_verilog_mux_sram_one_outport(fp, cur_sram_orgz_info,
|
||||
|
@ -2790,20 +2789,20 @@ void dump_verilog_sram_config_bus_internal_wires(FILE* fp, t_sram_orgz_info* cur
|
|||
fprintf(fp, ";\n");
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, lsb, msb, 1, VERILOG_PORT_WIRE);
|
||||
fprintf(fp, ";\n");
|
||||
/* Connect first SCFF to the head */
|
||||
/* Connect first CCFF to the head */
|
||||
fprintf(fp, "assign ");
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, lsb, lsb, -1, VERILOG_PORT_CONKT);
|
||||
fprintf(fp, " = ");
|
||||
dump_verilog_sram_one_port(fp, cur_sram_orgz_info, lsb, lsb, 0, VERILOG_PORT_CONKT);
|
||||
fprintf(fp, ";\n");
|
||||
/* Connect last SCFF to the tail */
|
||||
/* Connect last CCFF to the tail */
|
||||
fprintf(fp, "assign ");
|
||||
dump_verilog_sram_one_port(fp, cur_sram_orgz_info, msb, msb, 1, VERILOG_PORT_CONKT);
|
||||
fprintf(fp, " = ");
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, msb, msb, 0, VERILOG_PORT_CONKT);
|
||||
fprintf(fp, ";\n");
|
||||
/* Connect SCFFs into chains */
|
||||
/* Cascade the SCFF between head and tail */
|
||||
/* Connect CCFFs into chains */
|
||||
/* Cascade the CCFF between head and tail */
|
||||
if (1 < msb - lsb) {
|
||||
fprintf(fp, "assign ");
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
|
||||
|
@ -3048,7 +3047,7 @@ int dump_verilog_mem_module_one_port_map(FILE* fp,
|
|||
|
||||
/*
|
||||
* Dump the port map of a memory module
|
||||
* which consist of a number of SRAMs/SCFFs etc.
|
||||
* which consist of a number of SRAMs/CCFFs etc.
|
||||
*/
|
||||
void dump_verilog_mem_module_port_map(FILE* fp,
|
||||
t_spice_model* mem_model,
|
||||
|
@ -3158,7 +3157,7 @@ void dump_verilog_mem_sram_submodule(FILE* fp,
|
|||
assert(NULL != cur_sram_orgz_info);
|
||||
assert(NULL != cur_sram_verilog_model);
|
||||
assert((SPICE_MODEL_SRAM == cur_sram_verilog_model->type)
|
||||
|| (SPICE_MODEL_SCFF == cur_sram_verilog_model->type));
|
||||
|| (SPICE_MODEL_CCFF == cur_sram_verilog_model->type));
|
||||
|
||||
switch (cur_sram_orgz_info->type) {
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
|
|
|
@ -165,7 +165,7 @@ void dump_verilog_mux_sram_submodule(FILE* fp, t_sram_orgz_info* cur_sram_orgz_i
|
|||
void dump_verilog_sram_submodule(FILE* fp, t_sram_orgz_info* cur_sram_orgz_info,
|
||||
t_spice_model* sram_verilog_model);
|
||||
|
||||
void dump_verilog_scff_config_bus(FILE* fp,
|
||||
void dump_verilog_ccff_config_bus(FILE* fp,
|
||||
t_spice_model* mem_spice_model,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
int lsb, int msb,
|
||||
|
|
|
@ -9,9 +9,11 @@
|
|||
#include "vtr_assert.h"
|
||||
|
||||
/* Device-level header files */
|
||||
#include "circuit_library_utils.h"
|
||||
|
||||
/* FPGA-X2P context header files */
|
||||
#include "spice_types.h"
|
||||
#include "fpga_x2p_naming.h"
|
||||
#include "fpga_x2p_utils.h"
|
||||
|
||||
/* FPGA-Verilog context header files */
|
||||
|
@ -70,6 +72,25 @@ void print_verilog_comment(std::fstream& fp,
|
|||
fp << "// " << comment << std::endl;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print the declaration of a Verilog preprocessing flag
|
||||
***********************************************/
|
||||
void print_verilog_preprocessing_flag(std::fstream& fp,
|
||||
const std::string& preproc_flag) {
|
||||
check_file_handler(fp);
|
||||
|
||||
fp << "`ifdef " << preproc_flag << std::endl;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print the endif of a Verilog preprocessing flag
|
||||
***********************************************/
|
||||
void print_verilog_endif(std::fstream& fp) {
|
||||
check_file_handler(fp);
|
||||
|
||||
fp << "`endif" << std::endl;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print a Verilog module definition
|
||||
* We use the following format:
|
||||
|
@ -94,19 +115,41 @@ void print_verilog_module_definition(std::fstream& fp,
|
|||
|
||||
/* Port sequence: global, inout, input, output and clock ports, */
|
||||
size_t port_cnt = 0;
|
||||
bool printed_ifdef = false; /* A flag to tell if an ifdef has been printed for the last port */
|
||||
for (const auto& kv : port_type2type_map) {
|
||||
for (const auto& port : module_manager.module_ports_by_type(module_id, kv.first)) {
|
||||
if (0 != port_cnt) {
|
||||
/* Do not dump a comma for the first port */
|
||||
fp << "," << std::endl;
|
||||
}
|
||||
|
||||
if (true == printed_ifdef) {
|
||||
/* Print an endif to pair the ifdef */
|
||||
print_verilog_endif(fp);
|
||||
/* Reset the flag */
|
||||
printed_ifdef = false;
|
||||
}
|
||||
|
||||
ModulePortId port_id = module_manager.find_module_port(module_id, port.get_name());
|
||||
VTR_ASSERT(ModulePortId::INVALID() != port_id);
|
||||
/* Print pre-processing flag for a port, if defined */
|
||||
std::string preproc_flag = module_manager.port_preproc_flag(module_id, port_id);
|
||||
if (false == preproc_flag.empty()) {
|
||||
/* Print an ifdef Verilog syntax */
|
||||
print_verilog_preprocessing_flag(fp, preproc_flag);
|
||||
/* Raise the flag */
|
||||
printed_ifdef = true;
|
||||
}
|
||||
|
||||
/* Create a space for "module <module_name>" except the first line! */
|
||||
if (0 != port_cnt) {
|
||||
std::string port_whitespace(module_head_line.length(), ' ');
|
||||
fp << port_whitespace;
|
||||
}
|
||||
/* Print port */
|
||||
fp << generate_verilog_port(kv.second, port);
|
||||
/* Print port: only the port name is enough */
|
||||
fp << port.get_name();
|
||||
|
||||
/* Increase the counter */
|
||||
port_cnt++;
|
||||
}
|
||||
}
|
||||
|
@ -131,10 +174,24 @@ void print_verilog_module_ports(std::fstream& fp,
|
|||
/* Port sequence: global, inout, input, output and clock ports, */
|
||||
for (const auto& kv : port_type2type_map) {
|
||||
for (const auto& port : module_manager.module_ports_by_type(module_id, kv.first)) {
|
||||
ModulePortId port_id = module_manager.find_module_port(module_id, port.get_name());
|
||||
VTR_ASSERT(ModulePortId::INVALID() != port_id);
|
||||
/* Print pre-processing flag for a port, if defined */
|
||||
std::string preproc_flag = module_manager.port_preproc_flag(module_id, port_id);
|
||||
if (false == preproc_flag.empty()) {
|
||||
/* Print an ifdef Verilog syntax */
|
||||
print_verilog_preprocessing_flag(fp, preproc_flag);
|
||||
}
|
||||
|
||||
/* Print port */
|
||||
fp << "//----- " << module_manager.module_port_type_str(kv.first) << " -----" << std::endl;
|
||||
fp << generate_verilog_port(kv.second, port);
|
||||
fp << ";" << std::endl;
|
||||
|
||||
if (false == preproc_flag.empty()) {
|
||||
/* Print an endif to pair the ifdef */
|
||||
print_verilog_endif(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,9 +206,22 @@ void print_verilog_module_ports(std::fstream& fp,
|
|||
if (false == module_manager.port_is_register(module_id, port_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Print pre-processing flag for a port, if defined */
|
||||
std::string preproc_flag = module_manager.port_preproc_flag(module_id, port_id);
|
||||
if (false == preproc_flag.empty()) {
|
||||
/* Print an ifdef Verilog syntax */
|
||||
print_verilog_preprocessing_flag(fp, preproc_flag);
|
||||
}
|
||||
|
||||
/* Print port */
|
||||
fp << generate_verilog_port(VERILOG_PORT_REG, port);
|
||||
fp << ";" << std::endl;
|
||||
|
||||
if (false == preproc_flag.empty()) {
|
||||
/* Print an endif to pair the ifdef */
|
||||
print_verilog_endif(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
fp << "//----- END Registered ports -----" << std::endl;
|
||||
|
@ -380,7 +450,7 @@ std::string generate_verilog_ports(const std::vector<BasicPort>& merged_ports) {
|
|||
if (&port != &merged_ports[0]) {
|
||||
verilog_line += ", ";
|
||||
}
|
||||
verilog_line += generate_verilog_port(VERILOG_PORT_CONKT, merged_ports[0]);
|
||||
verilog_line += generate_verilog_port(VERILOG_PORT_CONKT, port);
|
||||
}
|
||||
verilog_line += "}";
|
||||
|
||||
|
@ -578,3 +648,400 @@ void print_verilog_buffer_instance(std::fstream& fp,
|
|||
module_manager.add_child_module(parent_module_id, buffer_module_id);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print local wires that are used for SRAM configuration
|
||||
* The local wires are strongly dependent on the organization of SRAMs.
|
||||
* Standalone SRAMs:
|
||||
* -----------------
|
||||
* No need for local wires, their outputs are port of the module
|
||||
*
|
||||
* Module
|
||||
* +------------------------------+
|
||||
* | Sub-module |
|
||||
* | +---------------------+ |
|
||||
* | | sram_out|---->|---->sram_out
|
||||
* | | | |
|
||||
* | | sram_out|---->|---->sram_out
|
||||
* | | | |
|
||||
* | +---------------------+ |
|
||||
* +------------------------------+
|
||||
*
|
||||
* Configuration chain-style
|
||||
* -------------------------
|
||||
* wire [0:N] config_bus
|
||||
*
|
||||
*
|
||||
* Module
|
||||
* +--------------------------------------------------------------+
|
||||
* | config_bus config_bus config_bus config_bus |
|
||||
* | [0] [1] [2] [N] |
|
||||
* | | | | | |
|
||||
* | v v v v |
|
||||
* ccff_head| ----------+ +---------+ +------------+ +----------------|-> ccff_tail
|
||||
* | | ^ | ^ | ^ |
|
||||
* | head v |tail v | v | |
|
||||
* | +----------+ +----------+ +----------+ |
|
||||
* | | Memory | | Memory | | Memory | |
|
||||
* | | Module | | Module | ... | Module | |
|
||||
* | | [0] | | [1] | | [N] | |
|
||||
* | +----------+ +----------+ +----------+ |
|
||||
* | | | | |
|
||||
* | v v v |
|
||||
* | +----------+ +----------+ +----------+ |
|
||||
* | | MUX | | MUX | | MUX | |
|
||||
* | | Module | | Module | ... | Module | |
|
||||
* | | [0] | | [1] | | [N] | |
|
||||
* | +----------+ +----------+ +----------+ |
|
||||
* | |
|
||||
* +--------------------------------------------------------------+
|
||||
*
|
||||
* Memory bank-style
|
||||
* -----------------
|
||||
* two ports will be added, which are regular output and inverted output
|
||||
* Note that the outputs are the data outputs of SRAMs
|
||||
* BL/WLs of memory decoders are ports of module but not local wires
|
||||
*
|
||||
* Module
|
||||
* +-------------------------------------------------+
|
||||
* | |
|
||||
BL/WL bus --+--------+------------+-----------------+ |
|
||||
* | | | | |
|
||||
* | BL/WL v BL/WL v BL/WL v |
|
||||
* | +----------+ +----------+ +----------+ |
|
||||
* | | Memory | | Memory | | Memory | |
|
||||
* | | Module | | Module | ... | Module | |
|
||||
* | | [0] | | [1] | | [N] | |
|
||||
* | +----------+ +----------+ +----------+ |
|
||||
* | | | | |
|
||||
* | v v v |
|
||||
* | +----------+ +----------+ +----------+ |
|
||||
* | | MUX | | MUX | | MUX | |
|
||||
* | | Module | | Module | ... | Module | |
|
||||
* | | [0] | | [1] | | [N] | |
|
||||
* | +----------+ +----------+ +----------+ |
|
||||
* | |
|
||||
* +-------------------------------------------------+
|
||||
*
|
||||
********************************************************************/
|
||||
void print_verilog_local_sram_wires(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_sram_orgz sram_orgz_type,
|
||||
const size_t& port_size) {
|
||||
/* Make sure we have a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Port size must be at least one! */
|
||||
if (0 == port_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Depend on the configuraion style */
|
||||
switch(sram_orgz_type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
/* Nothing to do here */
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN: {
|
||||
/* Generate the name of local wire for the CCFF inputs, CCFF output and inverted output */
|
||||
/* [0] => CCFF input */
|
||||
BasicPort ccff_config_bus_port(generate_local_config_bus_port_name(), port_size);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, ccff_config_bus_port) << ";" << std::endl;
|
||||
/* Connect first CCFF to the head */
|
||||
/* Head is always a 1-bit port */
|
||||
BasicPort ccff_head_port(generate_sram_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_INPUT), 1);
|
||||
BasicPort ccff_head_local_port(ccff_config_bus_port.get_name(), 1);
|
||||
print_verilog_wire_connection(fp, ccff_head_local_port, ccff_head_port, false);
|
||||
/* Connect last CCFF to the tail */
|
||||
/* Tail is always a 1-bit port */
|
||||
BasicPort ccff_tail_port(generate_sram_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_OUTPUT), 1);
|
||||
BasicPort ccff_tail_local_port(ccff_config_bus_port.get_name(), ccff_config_bus_port.get_msb(), ccff_config_bus_port.get_msb());
|
||||
print_verilog_wire_connection(fp, ccff_tail_local_port, ccff_tail_port, false);
|
||||
break;
|
||||
}
|
||||
case SPICE_SRAM_MEMORY_BANK: {
|
||||
/* Generate the name of local wire for the SRAM output and inverted output */
|
||||
std::vector<BasicPort> sram_ports;
|
||||
/* [0] => SRAM output */
|
||||
sram_ports.push_back(BasicPort(generate_sram_local_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_INPUT), port_size));
|
||||
/* [1] => SRAM inverted output */
|
||||
sram_ports.push_back(BasicPort(generate_sram_local_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_OUTPUT), port_size));
|
||||
/* Print local wire definition */
|
||||
for (const auto& sram_port : sram_ports) {
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, sram_port) << ";" << std::endl;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid SRAM organization!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Print a number of bus ports which are wired to the configuration
|
||||
* ports of a CMOS (SRAM-based) routing multiplexer
|
||||
* This port is supposed to be used locally inside a Verilog/SPICE module
|
||||
*
|
||||
* The following shows a few representative examples:
|
||||
*
|
||||
* For standalone configuration style:
|
||||
* ------------------------------------
|
||||
* No bus needed
|
||||
*
|
||||
* Configuration chain-style
|
||||
* -------------------------
|
||||
* wire [0:N] config_bus
|
||||
*
|
||||
* config_bus config_bus config_bus config_bus
|
||||
* [0] [1] [2] [N]
|
||||
* | | | |
|
||||
* v v v v
|
||||
* ccff_head ----------+ +---------+ +------------+ +----> ccff_tail
|
||||
* | ^ | ^ | ^
|
||||
* head v |tail v | v |
|
||||
* +----------+ +----------+ +----------+
|
||||
* | Memory | | Memory | | Memory |
|
||||
* | Module | | Module | ... | Module |
|
||||
* | [0] | | [1] | | [N] |
|
||||
* +----------+ +----------+ +----------+
|
||||
* | | |
|
||||
* v v v
|
||||
* +----------+ +----------+ +----------+
|
||||
* | MUX | | MUX | | MUX |
|
||||
* | Module | | Module | ... | Module |
|
||||
* | [0] | | [1] | | [N] |
|
||||
* +----------+ +----------+ +----------+
|
||||
*
|
||||
* Memory bank-style
|
||||
* -----------------
|
||||
* BL/WL bus --+------------+-------------------->
|
||||
* | | |
|
||||
* BL/WL v BL/WL v BL/WL v
|
||||
* +----------+ +----------+ +----------+
|
||||
* | Memory | | Memory | | Memory |
|
||||
* | Module | | Module | ... | Module |
|
||||
* | [0] | | [1] | | [N] |
|
||||
* +----------+ +----------+ +----------+
|
||||
* | | |
|
||||
* v v v
|
||||
* +----------+ +----------+ +----------+
|
||||
* | MUX | | MUX | | MUX |
|
||||
* | Module | | Module | ... | Module |
|
||||
* | [0] | | [1] | | [N] |
|
||||
* +----------+ +----------+ +----------+
|
||||
*
|
||||
*********************************************************************/
|
||||
static
|
||||
void print_verilog_local_config_bus(std::fstream& fp,
|
||||
const std::string& prefix,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const size_t& instance_id,
|
||||
const size_t& num_conf_bits) {
|
||||
/* Make sure we have a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
switch(sram_orgz_type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
/* Not need for configuration bus
|
||||
* The configuration ports of SRAM are directly wired to the ports of modules
|
||||
*/
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
case SPICE_SRAM_MEMORY_BANK: {
|
||||
/* Two configuration buses should be outputted
|
||||
* One for the regular SRAM ports of a routing multiplexer
|
||||
* The other for the inverted SRAM ports of a routing multiplexer
|
||||
*/
|
||||
BasicPort config_port(generate_local_sram_port_name(prefix, instance_id, SPICE_MODEL_PORT_INPUT),
|
||||
num_conf_bits);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, config_port) << ";" << std::endl;
|
||||
BasicPort inverted_config_port(generate_local_sram_port_name(prefix, instance_id, SPICE_MODEL_PORT_OUTPUT),
|
||||
num_conf_bits);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, inverted_config_port) << ";" << std::endl;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid SRAM organization!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Print a number of bus ports which are wired to the configuration
|
||||
* ports of a ReRAM-based routing multiplexer
|
||||
* This port is supposed to be used locally inside a Verilog/SPICE module
|
||||
*
|
||||
* Currently support:
|
||||
* For memory-bank configuration style:
|
||||
* ------------------------------------
|
||||
* Different than CMOS routing multiplexers, ReRAM multiplexers require
|
||||
* reserved BL/WLs to be grouped in buses
|
||||
*
|
||||
* Module Port
|
||||
* |
|
||||
* v
|
||||
* regular/reserved bus_port --+----------------+----> ...
|
||||
* | |
|
||||
* bl/wl/../sram_ports v v
|
||||
* +-----------+ +-----------+
|
||||
* | Memory | | Memory |
|
||||
* | Module[0] | | Module[1] | ...
|
||||
* +-----------+ +-----------+
|
||||
* | |
|
||||
* v v
|
||||
* +-----------+ +-----------+
|
||||
* | Routing | | Routing |
|
||||
* | MUX [0] | | MUX[1] | ...
|
||||
* +-----------+ +-----------+
|
||||
*
|
||||
*********************************************************************/
|
||||
static
|
||||
void print_verilog_rram_mux_config_bus(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const size_t& mux_size,
|
||||
const size_t& mux_instance_id,
|
||||
const size_t& num_reserved_conf_bits,
|
||||
const size_t& num_conf_bits) {
|
||||
/* Make sure we have a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
switch(sram_orgz_type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
/* Not need for configuration bus
|
||||
* The configuration ports of SRAM are directly wired to the ports of modules
|
||||
*/
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN: {
|
||||
/* Not supported yet.
|
||||
* Configuration chain may be only applied to ReRAM-based multiplexers with local decoders
|
||||
*/
|
||||
break;
|
||||
}
|
||||
case SPICE_SRAM_MEMORY_BANK: {
|
||||
/* This is currently most used in ReRAM FPGAs */
|
||||
/* Print configuration bus to group reserved BL/WLs */
|
||||
BasicPort reserved_bl_bus(generate_reserved_sram_port_name(SPICE_MODEL_PORT_BL),
|
||||
num_reserved_conf_bits);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, reserved_bl_bus) << ";" << std::endl;
|
||||
BasicPort reserved_wl_bus(generate_reserved_sram_port_name(SPICE_MODEL_PORT_WL),
|
||||
num_reserved_conf_bits);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, reserved_wl_bus) << ";" << std::endl;
|
||||
|
||||
/* Print configuration bus to group BL/WLs */
|
||||
BasicPort bl_bus(generate_mux_config_bus_port_name(circuit_lib, mux_model, mux_size, 0, false),
|
||||
num_conf_bits + num_reserved_conf_bits);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, bl_bus) << ";" << std::endl;
|
||||
BasicPort wl_bus(generate_mux_config_bus_port_name(circuit_lib, mux_model, mux_size, 1, false),
|
||||
num_conf_bits + num_reserved_conf_bits);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, wl_bus) << ";" << std::endl;
|
||||
|
||||
/* Print bus to group SRAM outputs, this is to interface memory cells to routing multiplexers */
|
||||
BasicPort sram_output_bus(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_INPUT),
|
||||
num_conf_bits);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, sram_output_bus) << ";" << std::endl;
|
||||
BasicPort inverted_sram_output_bus(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_OUTPUT),
|
||||
num_conf_bits);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, inverted_sram_output_bus) << ";" << std::endl;
|
||||
|
||||
/* Get the SRAM model of the mux_model */
|
||||
std::vector<CircuitModelId> sram_models = find_circuit_sram_models(circuit_lib, mux_model);
|
||||
/* TODO: maybe later multiplexers may have mode select ports... This should be relaxed */
|
||||
VTR_ASSERT( 1 == sram_models.size() );
|
||||
|
||||
/* Wire the reserved configuration bits to part of bl/wl buses */
|
||||
BasicPort bl_bus_reserved_bits(bl_bus.get_name(), num_reserved_conf_bits);
|
||||
print_verilog_wire_connection(fp, bl_bus_reserved_bits, reserved_bl_bus, false);
|
||||
BasicPort wl_bus_reserved_bits(wl_bus.get_name(), num_reserved_conf_bits);
|
||||
print_verilog_wire_connection(fp, wl_bus_reserved_bits, reserved_wl_bus, false);
|
||||
|
||||
/* Connect SRAM BL/WLs to bus */
|
||||
BasicPort mux_bl_wire(generate_sram_port_name(circuit_lib, sram_models[0], sram_orgz_type, SPICE_MODEL_PORT_BL),
|
||||
num_conf_bits);
|
||||
BasicPort bl_bus_regular_bits(bl_bus.get_name(), num_reserved_conf_bits, num_reserved_conf_bits + num_conf_bits - 1);
|
||||
print_verilog_wire_connection(fp, bl_bus_regular_bits, mux_bl_wire, false);
|
||||
BasicPort mux_wl_wire(generate_sram_port_name(circuit_lib, sram_models[0], sram_orgz_type, SPICE_MODEL_PORT_WL),
|
||||
num_conf_bits);
|
||||
BasicPort wl_bus_regular_bits(wl_bus.get_name(), num_reserved_conf_bits, num_reserved_conf_bits + num_conf_bits - 1);
|
||||
print_verilog_wire_connection(fp, wl_bus_regular_bits, mux_wl_wire, false);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid SRAM organization!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Print a number of bus ports which are wired to the configuration
|
||||
* ports of a memory module, which consists of a number of configuration
|
||||
* memory cells, such as SRAMs.
|
||||
* Note that the configuration bus will only interface the memory
|
||||
* module, rather than the programming routing multiplexers, LUTs, IOs
|
||||
* etc. This helps us to keep clean and simple Verilog generation
|
||||
*********************************************************************/
|
||||
void print_verilog_mux_config_bus(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const size_t& mux_size,
|
||||
const size_t& mux_instance_id,
|
||||
const size_t& num_reserved_conf_bits,
|
||||
const size_t& num_conf_bits) {
|
||||
/* Depend on the design technology of this MUX:
|
||||
* bus connections are different
|
||||
* SRAM MUX: bus is connected to the output ports of SRAM
|
||||
* RRAM MUX: bus is connected to the BL/WL of MUX
|
||||
* TODO: Maybe things will become even more complicated,
|
||||
* the bus connections may depend on the type of configuration circuit...
|
||||
* Currently, this is fine.
|
||||
*/
|
||||
switch (circuit_lib.design_tech_type(mux_model)) {
|
||||
case SPICE_MODEL_DESIGN_CMOS: {
|
||||
std::string prefix = generate_mux_subckt_name(circuit_lib, mux_model, mux_size, std::string());
|
||||
print_verilog_local_config_bus(fp, prefix, sram_orgz_type, mux_instance_id, num_conf_bits);
|
||||
break;
|
||||
}
|
||||
case SPICE_MODEL_DESIGN_RRAM:
|
||||
print_verilog_rram_mux_config_bus(fp, circuit_lib, mux_model, sram_orgz_type, mux_size, mux_instance_id, num_reserved_conf_bits, num_conf_bits);
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid design technology for routing multiplexer!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Print a wire to connect MUX configuration ports
|
||||
* This function connects the sram ports to the ports of a Verilog module
|
||||
* used for formal verification
|
||||
*********************************************************************/
|
||||
void print_verilog_formal_verification_mux_sram_ports_wiring(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const size_t& mux_size,
|
||||
const size_t& mux_instance_id,
|
||||
const size_t& num_conf_bits) {
|
||||
BasicPort mux_sram_output(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_INPUT),
|
||||
num_conf_bits);
|
||||
/* Get the SRAM model of the mux_model */
|
||||
std::vector<CircuitModelId> sram_models = find_circuit_sram_models(circuit_lib, mux_model);
|
||||
/* TODO: maybe later multiplexers may have mode select ports... This should be relaxed */
|
||||
VTR_ASSERT( 1 == sram_models.size() );
|
||||
BasicPort formal_verification_port(generate_formal_verification_sram_port_name(circuit_lib, sram_models[0]),
|
||||
num_conf_bits);
|
||||
print_verilog_wire_connection(fp, mux_sram_output, formal_verification_port, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,11 @@ void print_verilog_include_defines_preproc_file(std::fstream& fp,
|
|||
void print_verilog_comment(std::fstream& fp,
|
||||
const std::string& comment);
|
||||
|
||||
void print_verilog_preprocessing_flag(std::fstream& fp,
|
||||
const std::string& preproc_flag);
|
||||
|
||||
void print_verilog_endif(std::fstream& fp);
|
||||
|
||||
void print_verilog_module_definition(std::fstream& fp,
|
||||
const ModuleManager& module_manager, const ModuleId& module_id);
|
||||
|
||||
|
@ -79,4 +84,26 @@ void print_verilog_buffer_instance(std::fstream& fp,
|
|||
const BasicPort& instance_input_port,
|
||||
const BasicPort& instance_output_port);
|
||||
|
||||
void print_verilog_local_sram_wires(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_sram_orgz sram_orgz_type,
|
||||
const size_t& port_size);
|
||||
|
||||
void print_verilog_mux_config_bus(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const size_t& mux_size,
|
||||
const size_t& mux_instance_id,
|
||||
const size_t& num_reserved_conf_bits,
|
||||
const size_t& num_conf_bits);
|
||||
|
||||
void print_verilog_formal_verification_mux_sram_ports_wiring(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const size_t& mux_size,
|
||||
const size_t& mux_instance_id,
|
||||
const size_t& num_conf_bits);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1245,7 +1245,10 @@ t_clb_to_clb_directs * alloc_and_load_clb_to_clb_directs(INP const t_direct_inf
|
|||
vpr_printf(TIO_MESSAGE_ERROR, "[LINE %d] Range mismatch from %s to %s.\n", directs[i].line, directs[i].from_pin, directs[i].to_pin);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Aurelien: assign point to point parameters */
|
||||
clb_to_clb_directs[i].interconnection_type = directs[i].interconnection_type;
|
||||
clb_to_clb_directs[i].x_dir = directs[i].x_dir;
|
||||
clb_to_clb_directs[i].y_dir = directs[i].y_dir;
|
||||
/* Xifan Tang: assign values to x,y,z_offset */
|
||||
clb_to_clb_directs[i].x_offset = directs[i].x_offset;
|
||||
clb_to_clb_directs[i].y_offset = directs[i].y_offset;
|
||||
|
|
Loading…
Reference in New Issue