This commit is contained in:
Baudouin Chauviere 2019-10-01 16:54:16 -06:00
commit 33e50bbc8c
76 changed files with 7831 additions and 1101 deletions

View File

@ -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

View File

@ -8,6 +8,8 @@ Extended Architecture Description Language
:maxdepth: 2
generality
interconnect
spice_sim_setting

View File

@ -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

View File

@ -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

View File

@ -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"/>

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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=

View File

@ -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=

133
run_test.sh Normal file
View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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,

View File

@ -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:

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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);

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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",

View File

@ -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 */

View File

@ -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_;

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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:

View File

@ -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,

View File

@ -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

View File

@ -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,

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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";

View File

@ -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);

View File

@ -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 */

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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));
}

View File

@ -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) {

View File

@ -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:

View File

@ -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,

View File

@ -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);
}

View File

@ -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

View File

@ -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;