diff --git a/.travis/script.sh b/.travis/script.sh index 10cf00931..fa9e95ea8 100755 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -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" diff --git a/docs/source/arch_lang/figures/point2point_example.png b/docs/source/arch_lang/figures/point2point_example.png new file mode 100644 index 000000000..a63df9d38 Binary files /dev/null and b/docs/source/arch_lang/figures/point2point_example.png differ diff --git a/docs/source/arch_lang/figures/point2point_truthtable.png b/docs/source/arch_lang/figures/point2point_truthtable.png new file mode 100644 index 000000000..d81bab338 Binary files /dev/null and b/docs/source/arch_lang/figures/point2point_truthtable.png differ diff --git a/docs/source/arch_lang/index.rst b/docs/source/arch_lang/index.rst index bafd8f6e2..86edc3886 100644 --- a/docs/source/arch_lang/index.rst +++ b/docs/source/arch_lang/index.rst @@ -8,6 +8,8 @@ Extended Architecture Description Language :maxdepth: 2 generality + + interconnect spice_sim_setting diff --git a/docs/source/arch_lang/interconnect.rst b/docs/source/arch_lang/interconnect.rst new file mode 100644 index 000000000..a6542ccb5 --- /dev/null +++ b/docs/source/arch_lang/interconnect.rst @@ -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 + + + + + +.. note:: These options are required + +Our extension include three more options: + +.. code-block:: xml + + + + + +.. 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 + + + + + +: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 diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml new file mode 100644 index 000000000..fa32d4e41 --- /dev/null +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml @@ -0,0 +1,1042 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + + + + 10e-12 5e-12 5e-12 + + + 10e-12 5e-12 5e-12 + + + + + + + + + + + 10e-12 10e-12 + + + 10e-12 10e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + + + + 1 1 1 1 1 + 1 1 1 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + io.outpad io.inpad + io.outpad io.inpad + io.outpad io.inpad + io.outpad io.inpad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 255e-12 + 255e-12 + 255e-12 + 255e-12 + 255e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 202e-12 + 202e-12 + 202e-12 + 202e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 261e-12 + 261e-12 + 261e-12 + 261e-12 + 261e-12 + 261e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + clb.cin clb.cin_trick clb.regin clb.clk + clb.I0[9:0] clb.I1[9:0] clb.O[9:0] + clb.cout clb.regout clb.I2[9:0] clb.I3[9:0] clb.O[19:10] + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml new file mode 100644 index 000000000..ff9d23ac1 --- /dev/null +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml @@ -0,0 +1,1040 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + + + + 10e-12 5e-12 5e-12 + + + 10e-12 5e-12 5e-12 + + + + + + + + + + + 10e-12 10e-12 + + + 10e-12 10e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + + + + 1 1 1 1 1 + 1 1 1 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + io.outpad io.inpad + io.outpad io.inpad + io.outpad io.inpad + io.outpad io.inpad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 255e-12 + 255e-12 + 255e-12 + 255e-12 + 255e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 202e-12 + 202e-12 + 202e-12 + 202e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 261e-12 + 261e-12 + 261e-12 + 261e-12 + 261e-12 + 261e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + clb.cin clb.cin_trick clb.regin clb.clk + clb.I0[9:0] clb.I1[9:0] clb.O[9:0] + clb.cout clb.regout clb.I2[9:0] clb.I3[9:0] clb.O[19:10] + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml index 57967f2e9..ce1615d0b 100644 --- a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml @@ -558,7 +558,7 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + + + + 10e-12 5e-12 5e-12 + + + 10e-12 5e-12 5e-12 + + + + + + + + + + + 10e-12 10e-12 + + + 10e-12 10e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + + + + 1 1 1 1 1 + 1 1 1 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + io.outpad io.inpad + io.outpad io.inpad + io.outpad io.inpad + io.outpad io.inpad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 255e-12 + 255e-12 + 255e-12 + 255e-12 + 255e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 202e-12 + 202e-12 + 202e-12 + 202e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 261e-12 + 261e-12 + 261e-12 + 261e-12 + 261e-12 + 261e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + clb.cin clb.cin_trick clb.regin clb.clk + clb.I0[9:0] clb.I1[9:0] clb.O[9:0] + clb.cout clb.regout clb.I2[9:0] clb.I3[9:0] clb.O[19:10] + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/arch/template/k8_N10_sram_chain_FC_template.xml b/openfpga_flow/arch/template/k8_N10_sram_chain_FC_template.xml index 25577a130..4ff2c0800 100644 --- a/openfpga_flow/arch/template/k8_N10_sram_chain_FC_template.xml +++ b/openfpga_flow/arch/template/k8_N10_sram_chain_FC_template.xml @@ -202,11 +202,23 @@ + + 10e-12 + + + 10e-12 + + + 10e-12 + + + 10e-12 + @@ -217,10 +229,10 @@ - 10e-12 0e-12 0e-12 + 10e-12 5e-12 5e-12 - 10e-12 0e-12 0e-12 + 10e-12 5e-12 5e-12 @@ -230,17 +242,11 @@ - - 10e-12 + + 10e-12 10e-12 - - 10e-12 - - - 10e-12 - - - 10e-12 + + 10e-12 10e-12 @@ -325,7 +331,7 @@ - + @@ -340,7 +346,7 @@ - + diff --git a/openfpga_flow/misc/modelsim_template.j2 b/openfpga_flow/misc/modelsim_template.j2 new file mode 100644 index 000000000..cfa43d11c --- /dev/null +++ b/openfpga_flow/misc/modelsim_template.j2 @@ -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 diff --git a/openfpga_flow/scripts/run_fpga_flow.py b/openfpga_flow/scripts/run_fpga_flow.py index fcd1d1721..6a203e302 100644 --- a/openfpga_flow/scripts/run_fpga_flow.py +++ b/openfpga_flow/scripts/run_fpga_flow.py @@ -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() diff --git a/openfpga_flow/scripts/run_fpga_task.py b/openfpga_flow/scripts/run_fpga_task.py index 06a5358fb..a46c99e79 100644 --- a/openfpga_flow/scripts/run_fpga_task.py +++ b/openfpga_flow/scripts/run_fpga_task.py @@ -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." + + ", to remove specific run dir" + + "- 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() diff --git a/openfpga_flow/scripts/run_modelsim.py b/openfpga_flow/scripts/run_modelsim.py new file mode 100644 index 000000000..e8dca5cb4 --- /dev/null +++ b/openfpga_flow/scripts/run_modelsim.py @@ -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() diff --git a/openfpga_flow/tasks/blif_vpr_flow/config/task.conf b/openfpga_flow/tasks/blif_vpr_flow/config/task.conf index 867f75964..cf283f22a 100644 --- a/openfpga_flow/tasks/blif_vpr_flow/config/task.conf +++ b/openfpga_flow/tasks/blif_vpr_flow/config/task.conf @@ -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= diff --git a/openfpga_flow/tasks/tileable_routing/config/task.conf b/openfpga_flow/tasks/tileable_routing/config/task.conf new file mode 100644 index 000000000..3a7f092a6 --- /dev/null +++ b/openfpga_flow/tasks/tileable_routing/config/task.conf @@ -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= diff --git a/run_test.sh b/run_test.sh new file mode 100644 index 000000000..027a1bea4 --- /dev/null +++ b/run_test.sh @@ -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 + diff --git a/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp b/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp index d32578d2d..f9e3bb9e1 100644 --- a/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp +++ b/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp @@ -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 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 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 ff_port_types_required; diff --git a/vpr7_x2p/libarchfpga/SRC/check_circuit_library.h b/vpr7_x2p/libarchfpga/SRC/check_circuit_library.h index 2d0bd3f03..dd6114696 100644 --- a/vpr7_x2p/libarchfpga/SRC/check_circuit_library.h +++ b/vpr7_x2p/libarchfpga/SRC/check_circuit_library.h @@ -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, diff --git a/vpr7_x2p/libarchfpga/SRC/circuit_library.cpp b/vpr7_x2p/libarchfpga/SRC/circuit_library.cpp index 6a7d23a64..5b7c7b62d 100644 --- a/vpr7_x2p/libarchfpga/SRC/circuit_library.cpp +++ b/vpr7_x2p/libarchfpga/SRC/circuit_library.cpp @@ -612,7 +612,7 @@ std::vector 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 CircuitLibrary::model_global_ports_by_type(const CircuitModelId& model_id, const enum e_spice_model_port_type& type, @@ -621,7 +621,7 @@ std::vector CircuitLibrary::model_global_ports_by_type(const Circ std::vector 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); } } diff --git a/vpr7_x2p/libarchfpga/SRC/circuit_library.h b/vpr7_x2p/libarchfpga/SRC/circuit_library.h index 56de466a7..8080d2ea3 100644 --- a/vpr7_x2p/libarchfpga/SRC/circuit_library.h +++ b/vpr7_x2p/libarchfpga/SRC/circuit_library.h @@ -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; diff --git a/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.cpp b/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.cpp new file mode 100644 index 000000000..63fcb15eb --- /dev/null +++ b/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.cpp @@ -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 + +#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 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 sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM); + std::vector 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 find_circuit_regular_sram_ports(const CircuitLibrary& circuit_lib, + const CircuitModelId& circuit_model) { + std::vector sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true); + std::vector 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; +} diff --git a/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.h b/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.h new file mode 100644 index 000000000..f4323f391 --- /dev/null +++ b/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.h @@ -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 +#include "circuit_library.h" + +std::vector find_circuit_sram_models(const CircuitLibrary& circuit_lib, + const CircuitModelId& circuit_model); + +std::vector find_circuit_regular_sram_ports(const CircuitLibrary& circuit_lib, + const CircuitModelId& circuit_model); + +#endif diff --git a/vpr7_x2p/libarchfpga/SRC/circuit_types.h b/vpr7_x2p/libarchfpga/SRC/circuit_types.h index 92e8b1c61..9a0e72dda 100644 --- a/vpr7_x2p/libarchfpga/SRC/circuit_types.h +++ b/vpr7_x2p/libarchfpga/SRC/circuit_types.h @@ -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 CIRCUIT_MODEL_TYPE_STRING = {{"CHAN_WIRE", "WIRE", "MUX", "LUT", "FF", "SRAM", "HARDLOGIC", "SCFF", "IOPAD", "INVBUF", "PASSGATE", "GATE"}}; +constexpr std::array 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, diff --git a/vpr7_x2p/libarchfpga/SRC/device_port.cpp b/vpr7_x2p/libarchfpga/SRC/device_port.cpp index 2de15172d..38241f198 100644 --- a/vpr7_x2p/libarchfpga/SRC/device_port.cpp +++ b/vpr7_x2p/libarchfpga/SRC/device_port.cpp @@ -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: diff --git a/vpr7_x2p/libarchfpga/SRC/physical_types.h b/vpr7_x2p/libarchfpga/SRC/physical_types.h index 81de09866..e9fb0745e 100644 --- a/vpr7_x2p/libarchfpga/SRC/physical_types.h +++ b/vpr7_x2p/libarchfpga/SRC/physical_types.h @@ -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; diff --git a/vpr7_x2p/libarchfpga/SRC/read_xml_arch_file.c b/vpr7_x2p/libarchfpga/SRC/read_xml_arch_file.c index d852e07dd..55a05bba9 100644 --- a/vpr7_x2p/libarchfpga/SRC/read_xml_arch_file.c +++ b/vpr7_x2p/libarchfpga/SRC/read_xml_arch_file.c @@ -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, diff --git a/vpr7_x2p/libarchfpga/SRC/read_xml_spice.c b/vpr7_x2p/libarchfpga/SRC/read_xml_spice.c index 10c4b2bbe..c630dc37f 100644 --- a/vpr7_x2p/libarchfpga/SRC/read_xml_spice.c +++ b/vpr7_x2p/libarchfpga/SRC/read_xml_spice.c @@ -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; diff --git a/vpr7_x2p/libarchfpga/SRC/spice_types.h b/vpr7_x2p/libarchfpga/SRC/spice_types.h index 42ecbb3f2..26f30b164 100644 --- a/vpr7_x2p/libarchfpga/SRC/spice_types.h +++ b/vpr7_x2p/libarchfpga/SRC/spice_types.h @@ -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, diff --git a/vpr7_x2p/vpr/SRC/base/vpr_types.h b/vpr7_x2p/vpr/SRC/base/vpr_types.h index 4b039d5c8..820ee7126 100755 --- a/vpr7_x2p/vpr/SRC/base/vpr_types.h +++ b/vpr7_x2p/vpr/SRC/base/vpr_types.h @@ -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; diff --git a/vpr7_x2p/vpr/SRC/device/decoder_library_utils.cpp b/vpr7_x2p/vpr/SRC/device/decoder_library_utils.cpp index ca773819e..47ec9a9a9 100644 --- a/vpr7_x2p/vpr/SRC/device/decoder_library_utils.cpp +++ b/vpr7_x2p/vpr/SRC/device/decoder_library_utils.cpp @@ -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 diff --git a/vpr7_x2p/vpr/SRC/device/decoder_library_utils.h b/vpr7_x2p/vpr/SRC/device/decoder_library_utils.h index f0719f2e6..100f04da7 100644 --- a/vpr7_x2p/vpr/SRC/device/decoder_library_utils.h +++ b/vpr7_x2p/vpr/SRC/device/decoder_library_utils.h @@ -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, diff --git a/vpr7_x2p/vpr/SRC/device/mux_graph.cpp b/vpr7_x2p/vpr/SRC/device/mux_graph.cpp index 91105ddbf..608ffa4b5 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_graph.cpp +++ b/vpr7_x2p/vpr/SRC/device/mux_graph.cpp @@ -65,6 +65,14 @@ MuxGraph::mem_range MuxGraph::memories() const { return vtr::make_range(mem_ids_.begin(), mem_ids_.end()); } +std::vector MuxGraph::levels() const { + std::vector 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 diff --git a/vpr7_x2p/vpr/SRC/device/mux_graph.h b/vpr7_x2p/vpr/SRC/device/mux_graph.h index 856c7e0b1..ddb80e6f4 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_graph.h +++ b/vpr7_x2p/vpr/SRC/device/mux_graph.h @@ -62,6 +62,7 @@ class MuxGraph { std::vector non_input_nodes() const; edge_range edges() const; mem_range memories() const; + std::vector 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 edge_inv_mem_; /* if the edge is controlled by an inverted output of a memory bit */ vtr::vector mem_ids_; /* ids of configuration memories */ + vtr::vector mem_levels_; /* ids of configuration memories */ /* fast look-up */ typedef std::vector>> NodeLookup; mutable NodeLookup node_lookup_; /* [num_levels][num_types][num_nodes_per_level] */ + typedef std::vector> MemLookup; + mutable MemLookup mem_lookup_; /* [num_levels][num_mems_per_level] */ }; #endif diff --git a/vpr7_x2p/vpr/SRC/device/mux_library.h b/vpr7_x2p/vpr/SRC/device/mux_library.h index 93e004252..7e38f27b1 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_library.h +++ b/vpr7_x2p/vpr/SRC/device/mux_library.h @@ -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; diff --git a/vpr7_x2p/vpr/SRC/device/mux_utils.cpp b/vpr7_x2p/vpr/SRC/device/mux_utils.cpp index 3fafb1998..53e71f1f8 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_utils.cpp +++ b/vpr7_x2p/vpr/SRC/device/mux_utils.cpp @@ -3,10 +3,12 @@ * that are used to implement a multiplexer *************************************************/ #include +#include #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 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 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::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; +} diff --git a/vpr7_x2p/vpr/SRC/device/mux_utils.h b/vpr7_x2p/vpr/SRC/device/mux_utils.h index c61db23c8..9fa1f12ca 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_utils.h +++ b/vpr7_x2p/vpr/SRC/device/mux_utils.h @@ -37,4 +37,13 @@ std::vector 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 diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/bitstream_context.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/bitstream_context.h new file mode 100644 index 000000000..6ee011182 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/bitstream_context.h @@ -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 bit_ids_; + /* Bit line address of a bit in the Bitream: ONLY applicable to memory-decoders */ + vtr::vector bl_addr_; + /* Word line address of a bit in the Bitream: ONLY applicable to memory-decoders */ + vtr::vector wl_addr_; + /* value of a bit in the Bitream */ + vtr::vector bit_val_; +}; + +#endif + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/bitstream_context_fwd.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/bitstream_context_fwd.h new file mode 100644 index 000000000..29d85580e --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/bitstream_context_fwd.h @@ -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 ConfigBitId; + +class BitstreamContext; + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_bitstream_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_bitstream_utils.c index 844eb16e3..a4c87afa8 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_bitstream_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_bitstream_utils.c @@ -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: diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_bitstream_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_bitstream_utils.h index 2ce9546a5..e32bb520a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_bitstream_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_bitstream_utils.h @@ -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); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_mux_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_mux_utils.c index 5e031e0c3..40c60d776 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_mux_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_mux_utils.c @@ -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)); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp index 66a28eff3..d39d4961a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp @@ -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_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 _mux * 2. MUXes are named as _size ***********************************************/ -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& 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 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& 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 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& 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 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& 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& 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); +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h index dbf6abff5..6d7f9c88c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h @@ -9,21 +9,23 @@ #include +#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& 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& coordinate); + +std::string generate_routing_track_port_name(const t_rr_type& chan_type, + const vtr::Point& coordinate, + const size_t& track_id, + const PORTS& port_direction); + +std::string generate_switch_block_module_name(const vtr::Point& coordinate); + +std::string generate_grid_port_name(const vtr::Point& 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 diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_setup.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_setup.c index 90690e48d..d88a27658 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_setup.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_setup.c @@ -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, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c index bdc3bbfbb..9f73bc651 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c @@ -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, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h index 8a5a0a9e4..114d2d604 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h @@ -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, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/link_arch_circuit_lib.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/link_arch_circuit_lib.cpp index 342524903..8e1848932 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/link_arch_circuit_lib.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/link_arch_circuit_lib.cpp @@ -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", diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.cpp index 8743b2ebb..2a89a748c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.cpp @@ -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 */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.h index 5a9fcd507..297046059 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.h @@ -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> ports_; /* List of ports for each Module */ vtr::vector> port_types_; /* Type of ports */ vtr::vector> port_is_register_; /* If the port is a register, use for Verilog port definition. If enabled: reg */ + vtr::vector> 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 name_id_map_; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp index 7faf4a054..e442b0223 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp @@ -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 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 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 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 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 generate_cmos_mem_module_port2port_map(const ModuleManager& module_manager, + const ModuleId& mem_module, + const std::vector& config_bus_ports, + const std::vector& mem_output_bus_ports, + const e_sram_orgz& sram_orgz_type) { + std::map 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 generate_rram_mem_module_port2port_map(const ModuleManager& module_manager, + const ModuleId& mem_module, + const e_sram_orgz& sram_orgz_type) { + std::map 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 generate_mem_module_port2port_map(const ModuleManager& module_manager, + const ModuleId& mem_module, + const std::vector& config_bus_ports, + const std::vector& mem_output_bus_ports, + const e_spice_model_design_tech& mem_design_tech, + const e_sram_orgz& sram_orgz_type) { + std::map 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; +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h index c117b5a6c..bee3e7ff8 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h @@ -7,6 +7,9 @@ #define MODULE_MANAGER_UTILS_H /* Include other header files which are dependency on the function declared below */ +#include +#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 generate_mem_module_port2port_map(const ModuleManager& module_manager, + const ModuleId& mem_module, + const std::vector& config_bus_ports, + const std::vector& mem_output_bus_ports, + const e_spice_model_design_tech& mem_design_tech, + const e_sram_orgz& sram_orgz_type); + #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.cpp new file mode 100644 index 000000000..197da9c8b --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.cpp @@ -0,0 +1,94 @@ +/******************************************************************** + * This file includes most utilized function for rr_block data structures + *******************************************************************/ +#include +#include + +#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 find_switch_block_global_ports(const RRGSB& rr_gsb, + const CircuitLibrary& circuit_lib, + const std::vector& switch_lib) { + std::vector 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 global_ports; + /* Iterate over the model list, and add the global ports*/ + for (const auto& model : sub_models) { + std::vector 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; +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.h new file mode 100644 index 000000000..d49a55539 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.h @@ -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 +#include "physical_types.h" +#include "circuit_library.h" +#include "rr_blocks.h" + +std::vector find_switch_block_global_ports(const RRGSB& rr_gsb, + const CircuitLibrary& circuit_lib, + const std::vector& switch_lib); + +size_t find_switch_block_number_of_muxes(const RRGSB& rr_gsb); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/spice/spice_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/spice/spice_utils.c index d24a6bcba..a75da71a7 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/spice/spice_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/spice/spice_utils.c @@ -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: diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 19c80b25e..f35a024aa 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -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, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.c index 112335c0b..96aea8d43 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.c @@ -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 diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_decoder.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_decoder.c index 4204a24f5..410e5d366 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_decoder.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_decoder.c @@ -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, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_decoders.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_decoders.cpp index 47255c250..4e3a7c422 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_decoders.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_decoders.cpp @@ -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; +} + + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_decoders.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_decoders.h index 88877b9e0..8f4a52816 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_decoders.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_decoders.h @@ -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 diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c index db4de023d..0be59a137 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c @@ -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); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_global.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_global.c index 7bc682ad7..c6d563c37 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_global.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_global.c @@ -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"; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c index dba96bb84..72b250231 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c @@ -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); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp index 5adc9a558..5c7e27449 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp @@ -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 */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.cpp index cb6754cea..09c2501f3 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.cpp @@ -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 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 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 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 global_port_types; + global_port_types.push_back(SPICE_MODEL_PORT_CLOCK); + global_port_types.push_back(SPICE_MODEL_PORT_INPUT); + std::vector 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 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 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 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 global_port_types; + global_port_types.push_back(SPICE_MODEL_PORT_CLOCK); + global_port_types.push_back(SPICE_MODEL_PORT_INPUT); + std::vector 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 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 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 sram_bl_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_BL, true); std::vector 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 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 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 */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.h index 08ecc4ec3..eee29cb23 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_memory.h @@ -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); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp index 3244cce1b..0f4b10579 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp @@ -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 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 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 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 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 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 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 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)) { diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c index d124f3b05..d08f5eb15 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c @@ -1,7 +1,7 @@ -/***********************************/ -/* SPICE Modeling for VPR */ -/* Xifan TANG, EPFL/LSI */ -/***********************************/ +/********************************************************************* + * This file includes functions that are used for + * Verilog generation of FPGA routing architecture (global routing) + *********************************************************************/ #include #include #include @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include /* Include vpr structs*/ @@ -24,9 +26,12 @@ #include "route_common.h" #include "vpr_utils.h" +#include "vtr_assert.h" + /* Include SPICE support headers*/ #include "linkedlist.h" #include "rr_blocks.h" +#include "rr_blocks_utils.h" #include "fpga_x2p_types.h" #include "fpga_x2p_utils.h" #include "fpga_x2p_backannotate_utils.h" @@ -34,18 +39,451 @@ #include "fpga_x2p_pbtypes_utils.h" #include "fpga_x2p_bitstream_utils.h" #include "fpga_x2p_globals.h" +#include "fpga_x2p_naming.h" +#include "mux_utils.h" +#include "module_manager.h" +#include "module_manager_utils.h" /* Include Verilog support headers*/ #include "verilog_global.h" #include "verilog_utils.h" +#include "verilog_writer_utils.h" #include "verilog_routing.h" +/******************************************************************** + * Print local wires that are used for SRAM configuration + * This function is supposed to be used by Verilog generation + * of switch blocks + * It will count the number of switch blocks, which is the + * port width for local wires when Configuration chain is used + ********************************************************************/ +static +void print_verilog_switch_block_local_sram_wires(std::fstream& fp, + const RRGSB& rr_gsb, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model, + const e_sram_orgz sram_orgz_type, + const size_t& port_size) { + size_t local_port_size = port_size; + if (SPICE_SRAM_SCAN_CHAIN == sram_orgz_type) { + /* Plus 1 for the wire size to connect to the tail of the configuration chain */ + local_port_size = find_switch_block_number_of_muxes(rr_gsb) + 1; + } + print_verilog_local_sram_wires(fp, circuit_lib, sram_model, sram_orgz_type, local_port_size); +} + +/********************************************************************* + * Generate the Verilog module for a routing channel + * Routing track wire, which is 1-input and dual output + * This type of wires are used in the global routing architecture. + * One of the output is wired to another Switch block multiplexer, + * while the mid-output is wired to a Connection block multiplexer. + * + * | CLB | + * +------------+ + * ^ + * | + * +------------------------------+ + * | Connection block multiplexer | + * +------------------------------+ + * ^ + * | mid-output +-------------- + * +--------------------+ | + * input --->| Routing track wire |--------->| Switch Block + * +--------------------+ output | + * +-------------- + * + * IMPORTANT: This function is designed for outputting unique Verilog modules + * of routing channels + * + * TODO: This function should be adapted to the RRGraph object + *********************************************************************/ +static +void print_verilog_routing_unique_chan_subckt(ModuleManager& module_manager, + const std::string& verilog_dir, + const std::string& subckt_dir, + const size_t& rr_chan_subckt_id, + const RRChan& rr_chan) { + std::string fname_prefix; + + /* TODO: use a constexpr String arrary to replace this switch cases? */ + /* Find the prefix for the Verilog file name */ + switch (rr_chan.get_type()) { + case CHANX: + fname_prefix = std::string(chanx_verilog_file_name_prefix); + break; + case CHANY: + fname_prefix = std::string(chany_verilog_file_name_prefix); + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid Channel type! Should be CHANX or CHANY.\n", + __FILE__, __LINE__); + exit(1); + } + + std::string verilog_fname(subckt_dir + generate_routing_block_netlist_name(fname_prefix, rr_chan_subckt_id, std::string(verilog_netlist_file_postfix))); + /* TODO: remove the bak file when the file is ready */ + 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_verilog_file_header(fp, "Verilog modules for routing channel in X- and Y-direction"); + + /* Print preprocessing flags */ + print_verilog_include_defines_preproc_file(fp, verilog_dir); + + /* Create a Verilog Module based on the circuit model, and add to module manager */ + ModuleId module_id = module_manager.add_module(generate_routing_channel_module_name(rr_chan.get_type(), rr_chan_subckt_id)); + + /* Add ports to the module */ + /* For the LEFT side of a X-direction routing channel + * or the BOTTOM bottom side of a Y-direction routing channel + * Routing Resource Nodes in INC_DIRECTION are inputs of the module + * + * For the RIGHT side of a X-direction routing channel + * or the TOP bottom side of a Y-direction routing channel + * Routing Resource Nodes in INC_DIRECTION are outputs of the module + * + * An example of X-direction routing channel consisting of W routing nodes: + * +--------------------------+ + * nodeA(INC_DIRECTION)--->| in[0] out[0] |---> nodeA(INC_DIRECTION) + * nodeB(DEC_DIRECTION)<---| out[1] in[1] |<--- nodeB(DEC_DIRECTION) + * ... ... ... ... + * nodeX(INC_DIRECTION)--->| in[W-1] out[W-1] |---> nodeX(INC_DIRECTION) + * +--------------------------+ + * + * An example of Y-direction routing channel consisting of W routing nodes: + * + * nodeA nodeB nodeX + * (INC_DIRECTION) (DEC_DIRECTION) (DEC_DIRECTION) + * ^ | ... | + * | v v + * +------------------------------ ... -------+ + * | out[0] in[1] in[X] | + * | | + * | | + * | in[0] out[1] ... out[X] | + * +------------------------------ ... -------+ + * ^ | | + * | v v + * nodeA nodeB nodeX + * (INC_DIRECTION) (DEC_DIRECTION) (DEC_DIRECTION) + */ + /* Add ports at LEFT/BOTTOM side of the module */ + for (size_t itrack = 0; itrack < rr_chan.get_chan_width(); ++itrack) { + switch (rr_chan.get_node(itrack)->direction) { + case INC_DIRECTION: { + /* TODO: naming should be more flexible !!! */ + BasicPort input_port(std::string("in" + std::to_string(itrack)), 1); + module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT); + break; + } + case DEC_DIRECTION: { + /* TODO: naming should be more flexible !!! */ + BasicPort output_port(std::string("out" + std::to_string(itrack)), 1); + module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT); + break; + } + case BI_DIRECTION: + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File: %s [LINE%d]) Invalid direction of rr_node %s[%lu]_in/out[%lu]!\n", + __FILE__, __LINE__, + convert_chan_type_to_string(rr_chan.get_type()), + rr_chan_subckt_id, itrack); + exit(1); + } + } + /* Add ports at RIGHT/TOP side of the module */ + for (size_t itrack = 0; itrack < rr_chan.get_chan_width(); ++itrack) { + switch (rr_chan.get_node(itrack)->direction) { + case INC_DIRECTION: { + /* TODO: naming should be more flexible !!! */ + BasicPort output_port(std::string("out" + std::to_string(itrack)), 1); + module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT); + break; + } + case DEC_DIRECTION: { + /* TODO: naming should be more flexible !!! */ + BasicPort input_port(std::string("in" + std::to_string(itrack)), 1); + module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT); + break; + } + case BI_DIRECTION: + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File: %s [LINE%d]) Invalid direction of rr_node %s[%lu]_in/out[%lu]!\n", + __FILE__, __LINE__, + convert_chan_type_to_string(rr_chan.get_type()), + rr_chan_subckt_id, itrack); + exit(1); + } + } + /* Add middle-point output for connection box inputs */ + for (size_t itrack = 0; itrack < rr_chan.get_chan_width(); ++itrack) { + /* TODO: naming should be more flexible !!! */ + BasicPort mid_output_port(std::string("mid_out" + std::to_string(itrack)), 1); + module_manager.add_port(module_id, mid_output_port, ModuleManager::MODULE_OUTPUT_PORT); + } + + /* dump module definition + ports */ + print_verilog_module_declaration(fp, module_manager, module_id); + /* Finish dumping ports */ + + /* Print short-wire connection: + * + * in[i] ----------> out[i] + * | + * +-----> mid_out[i] + */ + for (size_t itrack = 0; itrack < rr_chan.get_chan_width(); ++itrack) { + /* short connecting inputs and outputs: + * length of metal wire and parasitics are handled by semi-custom flow + */ + BasicPort input_port(std::string("in" + std::to_string(itrack)), 1); + BasicPort output_port(std::string("out" + std::to_string(itrack)), 1); + BasicPort mid_output_port(std::string("mid_out" + std::to_string(itrack)), 1); + print_verilog_wire_connection(fp, output_port, input_port, false); + print_verilog_wire_connection(fp, mid_output_port, input_port, false); + } + + /* Put an end to the Verilog module */ + print_verilog_module_end(fp, module_manager.module_name(module_id)); + + /* Add an empty line as a splitter */ + fp << std::endl; + + /* Close file handler */ + fp.close(); + + /* Add fname to the linked list */ + /* Uncomment this when it is ready + routing_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(routing_verilog_subckt_file_path_head, verilog_fname.c_str()); + */ + + return; +} + +/********************************************************************* + * Generate the Verilog module for a routing channel + * Routing track wire, which is 1-input and dual output + * This type of wires are used in the global routing architecture. + * One of the output is wired to another Switch block multiplexer, + * while the mid-output is wired to a Connection block multiplexer. + * + * | CLB | + * +------------+ + * ^ + * | + * +------------------------------+ + * | Connection block multiplexer | + * +------------------------------+ + * ^ + * | mid-output +-------------- + * +--------------------+ | + * input --->| Routing track wire |--------->| Switch Block + * +--------------------+ output | + * +-------------- + * + * IMPORTANT: This function is designed for outputting non-unique Verilog modules + * of routing channels + * + * TODO: This function should be adapted to the RRGraph object + *********************************************************************/ +static +void print_verilog_routing_chan_subckt(ModuleManager& module_manager, + const std::string& verilog_dir, + const std::string& subckt_dir, + const vtr::Point& chan_coordinate, + const t_rr_type& chan_type, + int LL_num_rr_nodes, t_rr_node* LL_rr_node, + t_ivec*** LL_rr_node_indices) { + int chan_width = 0; + t_rr_node** chan_rr_nodes = NULL; + + std::string fname_prefix; + + /* TODO: use a constexpr String arrary to replace this switch cases? */ + /* Find the prefix for the Verilog file name */ + switch (chan_type) { + case CHANX: + fname_prefix = std::string(chanx_verilog_file_name_prefix); + break; + case CHANY: + fname_prefix = std::string(chany_verilog_file_name_prefix); + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid Channel type! Should be CHANX or CHANY.\n", + __FILE__, __LINE__); + exit(1); + } + + std::string verilog_fname(subckt_dir + generate_routing_block_netlist_name(fname_prefix, chan_coordinate, std::string(verilog_netlist_file_postfix))); + /* TODO: remove the bak file when the file is ready */ + 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_verilog_file_header(fp, "Verilog modules for routing channel in X- and Y-direction"); + + /* Print preprocessing flags */ + print_verilog_include_defines_preproc_file(fp, verilog_dir); + + /* Create a Verilog Module based on the circuit model, and add to module manager */ + ModuleId module_id = module_manager.add_module(generate_routing_channel_module_name(chan_type, chan_coordinate)); + + /* Collect rr_nodes for Tracks for chanx[ix][iy] */ + chan_rr_nodes = get_chan_rr_nodes(&chan_width, chan_type, chan_coordinate.x(), chan_coordinate.y(), + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + + /* Add ports to the module */ + /* For the LEFT side of a X-direction routing channel + * or the BOTTOM bottom side of a Y-direction routing channel + * Routing Resource Nodes in INC_DIRECTION are inputs of the module + * + * For the RIGHT side of a X-direction routing channel + * or the TOP bottom side of a Y-direction routing channel + * Routing Resource Nodes in INC_DIRECTION are outputs of the module + * + * An example of X-direction routing channel consisting of W routing nodes: + * +--------------------------+ + * nodeA(INC_DIRECTION)--->| in[0] out[0] |---> nodeA(INC_DIRECTION) + * nodeB(DEC_DIRECTION)<---| out[1] in[1] |<--- nodeB(DEC_DIRECTION) + * ... ... ... ... + * nodeX(INC_DIRECTION)--->| in[W-1] out[W-1] |---> nodeX(INC_DIRECTION) + * +--------------------------+ + * + * An example of Y-direction routing channel consisting of W routing nodes: + * + * nodeA nodeB nodeX + * (INC_DIRECTION) (DEC_DIRECTION) (DEC_DIRECTION) + * ^ | ... | + * | v v + * +------------------------------ ... -------+ + * | out[0] in[1] in[X] | + * | | + * | | + * | in[0] out[1] ... out[X] | + * +------------------------------ ... -------+ + * ^ | | + * | v v + * nodeA nodeB nodeX + * (INC_DIRECTION) (DEC_DIRECTION) (DEC_DIRECTION) + */ + /* Add ports at LEFT/BOTTOM side of the module */ + for (size_t itrack = 0; itrack < size_t(chan_width); ++itrack) { + switch (chan_rr_nodes[itrack]->direction) { + case INC_DIRECTION: { + /* TODO: naming should be more flexible !!! */ + BasicPort input_port(std::string("in" + std::to_string(itrack)), 1); + module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT); + break; + } + case DEC_DIRECTION: { + /* TODO: naming should be more flexible !!! */ + BasicPort output_port(std::string("out" + std::to_string(itrack)), 1); + module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT); + break; + } + case BI_DIRECTION: + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File: %s [LINE%d]) Invalid direction of rr_node %s[%lu][%lu]_in/out[%lu]!\n", + __FILE__, __LINE__, + convert_chan_type_to_string(chan_type), + chan_coordinate.x(), chan_coordinate.y(), itrack); + exit(1); + } + } + /* Add ports at RIGHT/TOP side of the module */ + for (size_t itrack = 0; itrack < size_t(chan_width); ++itrack) { + switch (chan_rr_nodes[itrack]->direction) { + case INC_DIRECTION: { + /* TODO: naming should be more flexible !!! */ + BasicPort output_port(std::string("out" + std::to_string(itrack)), 1); + module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT); + break; + } + case DEC_DIRECTION: { + /* TODO: naming should be more flexible !!! */ + BasicPort input_port(std::string("in" + std::to_string(itrack)), 1); + module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT); + break; + } + case BI_DIRECTION: + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File: %s [LINE%d]) Invalid direction of rr_node %s[%lu][%lu]_in/out[%lu]!\n", + __FILE__, __LINE__, + convert_chan_type_to_string(chan_type), + chan_coordinate.x(), chan_coordinate.y(), itrack); + exit(1); + } + } + /* Add middle-point output for connection box inputs */ + for (size_t itrack = 0; itrack < size_t(chan_width); ++itrack) { + /* TODO: naming should be more flexible !!! */ + BasicPort mid_output_port(std::string("mid_out" + std::to_string(itrack)), 1); + module_manager.add_port(module_id, mid_output_port, ModuleManager::MODULE_OUTPUT_PORT); + } + + /* dump module definition + ports */ + print_verilog_module_declaration(fp, module_manager, module_id); + /* Finish dumping ports */ + + /* Print short-wire connection: + * + * in[i] ----------> out[i] + * | + * +-----> mid_out[i] + */ + for (size_t itrack = 0; itrack < size_t(chan_width); ++itrack) { + /* short connecting inputs and outputs: + * length of metal wire and parasitics are handled by semi-custom flow + */ + BasicPort input_port(std::string("in" + std::to_string(itrack)), 1); + BasicPort output_port(std::string("out" + std::to_string(itrack)), 1); + BasicPort mid_output_port(std::string("mid_out" + std::to_string(itrack)), 1); + print_verilog_wire_connection(fp, output_port, input_port, false); + print_verilog_wire_connection(fp, mid_output_port, input_port, false); + } + + /* Put an end to the Verilog module */ + print_verilog_module_end(fp, module_manager.module_name(module_id)); + + /* Add an empty line as a splitter */ + fp << std::endl; + + /* Close file handler */ + fp.close(); + + /* Add fname to the linked list */ + /* Uncomment this when it is ready + routing_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(routing_verilog_subckt_file_path_head, verilog_fname.c_str()); + */ + + /* Free */ + my_free(chan_rr_nodes); + + return; +} + + static void dump_verilog_routing_chan_subckt(char* verilog_dir, char* subckt_dir, size_t rr_chan_subckt_id, - const RRChan& rr_chan, - bool is_explicit_mapping) { + const RRChan& rr_chan) { FILE* fp = NULL; char* fname = NULL; @@ -79,9 +517,11 @@ void dump_verilog_routing_chan_subckt(char* verilog_dir, gen_verilog_one_routing_channel_module_name(rr_chan.get_type(), rr_chan_subckt_id, -1)); fprintf(fp, "\n"); /* dump global ports */ + /* if (0 < dump_verilog_global_ports(fp, global_ports_head, TRUE, false)) { fprintf(fp, ",\n"); } + */ /* Inputs and outputs, * Rules for CHANX: * print left-hand ports(in) first, then right-hand ports(out) @@ -171,8 +611,7 @@ void dump_verilog_routing_chan_subckt(char* verilog_dir, 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, - int num_segment, - bool is_explicit_mapping) { + int num_segment) { int itrack, iseg, cost_index; int chan_width = 0; t_rr_node** chan_rr_nodes = NULL; @@ -217,9 +656,11 @@ void dump_verilog_routing_chan_subckt(char* verilog_dir, gen_verilog_one_routing_channel_module_name(chan_type, x, y)); fprintf(fp, "\n"); /* dump global ports */ + /* if (0 < dump_verilog_global_ports(fp, global_ports_head, TRUE, false)) { fprintf(fp, ",\n"); } + */ /* Inputs and outputs, * Rules for CHANX: * print left-hand ports(in) first, then right-hand ports(out) @@ -313,7 +754,6 @@ void dump_verilog_routing_chan_subckt(char* verilog_dir, void dump_verilog_grid_side_pin_with_given_index(FILE* fp, t_rr_type pin_type, int pin_index, int side, int x, int y, - int unique_x, int unique_y, /* If explicit, needs the coordinates of the mirror*/ boolean dump_port_type, bool is_explicit_mapping) { int height; @@ -361,7 +801,7 @@ void dump_verilog_grid_side_pin_with_given_index(FILE* fp, t_rr_type pin_type, is_explicit_mapping = false; /* Both cannot be true at the same time */ } if (true == is_explicit_mapping) { - fprintf(fp, ".%s(", gen_verilog_grid_one_pin_name(unique_x, unique_y, height, side, pin_index, TRUE)); + fprintf(fp, ".%s(", gen_verilog_grid_one_pin_name(x, y, height, side, pin_index, TRUE)); } fprintf(fp, "%s", gen_verilog_grid_one_pin_name(x, y, height, side, pin_index, TRUE)); if (true == is_explicit_mapping) { @@ -522,8 +962,7 @@ void dump_verilog_unique_switch_box_short_interc(FILE* fp, enum e_side chan_side, t_rr_node* cur_rr_node, int actual_fan_in, - t_rr_node* drive_rr_node, - bool is_explicit_mapping) { + t_rr_node* drive_rr_node) { /* Check the file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", @@ -566,7 +1005,6 @@ void dump_verilog_unique_switch_box_short_interc(FILE* fp, drive_rr_node->ptc_num, rr_sb.get_opin_node_grid_side(drive_rr_node), grid_x, grid_y, - 0, 0, /* No explicit mapping*/ FALSE, false); /* Do not dump the direction of the port! */ break; case CHANX: @@ -669,8 +1107,6 @@ void dump_verilog_switch_box_short_interc(FILE* fp, drive_rr_node->ptc_num, cur_sb_info->opin_rr_node_grid_side[side][index], grid_x, grid_y, - 0, /*Used in more recent version*/ - 0, /*Used in more recent version*/ FALSE, is_explicit_mapping); /* Do not dump the direction of the port! */ break; case CHANX: @@ -771,16 +1207,12 @@ void dump_verilog_switch_box_mux(t_sram_orgz_info* cur_sram_orgz_info, /* Find grid_x and grid_y */ grid_x = drive_rr_nodes[inode]->xlow; grid_y = drive_rr_nodes[inode]->ylow; /*Plus the offset in function fprint_grid_side_pin_with_given_index */ - //const RRGSB& unique_mirror = device_rr_gsb.get_cb_unique_module(cb_type, coordinator); /* Print a grid pin */ fprintf(fp, "assign %s_size%d_%d_inbus[%d] = ", verilog_model->prefix, mux_size, verilog_model->cnt, input_cnt); dump_verilog_grid_side_pin_with_given_index(fp, IPIN, drive_rr_nodes[inode]->ptc_num, cur_sb_info->opin_rr_node_grid_side[side][index], - grid_x, grid_y, - 0,/*Used in more recent version*/ - 0,/*Used in more recent version*/ - FALSE, is_explicit_mapping); + grid_x, grid_y, FALSE, is_explicit_mapping); fprintf(fp, ";\n"); input_cnt++; break; @@ -844,7 +1276,7 @@ void dump_verilog_switch_box_mux(t_sram_orgz_info* cur_sram_orgz_info, verilog_model->prefix, mux_size, verilog_model->cnt); /* Dump global ports */ - if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, FALSE, FALSE, my_bool_to_boolean(is_explicit_mapping), TRUE)) { + if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, FALSE, FALSE, my_bool_to_boolean(is_explicit_mapping))) { fprintf(fp, ",\n"); } if (true == is_explicit_mapping) { @@ -989,7 +1421,7 @@ void dump_verilog_unique_switch_box_mux(t_sram_orgz_info* cur_sram_orgz_info, int cur_bl, cur_wl; t_spice_model* mem_model = NULL; char* mem_subckt_name = NULL; - int num_input_port, num_output_port, num_sram_port; + int num_input_port, num_output_port; /* Check the file handler*/ if (NULL == fp) { @@ -1037,9 +1469,7 @@ void dump_verilog_unique_switch_box_mux(t_sram_orgz_info* cur_sram_orgz_info, verilog_model->prefix, mux_size, verilog_model->cnt, input_cnt); dump_verilog_grid_side_pin_with_given_index(fp, IPIN, drive_rr_nodes[inode]->ptc_num, rr_sb.get_opin_node_grid_side(drive_rr_nodes[inode]), - grid_x, grid_y, - 0,0,/*No explicit mapping */ - FALSE, false); + grid_x, grid_y, FALSE, false); fprintf(fp, ";\n"); input_cnt++; break; @@ -1103,7 +1533,7 @@ void dump_verilog_unique_switch_box_mux(t_sram_orgz_info* cur_sram_orgz_info, verilog_model->prefix, mux_size, verilog_model->cnt); /* Dump global ports */ - if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, FALSE, FALSE, my_bool_to_boolean(is_explicit_mapping), TRUE)) { + if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, FALSE, FALSE, my_bool_to_boolean(is_explicit_mapping))) { fprintf(fp, ",\n"); } @@ -1477,13 +1907,11 @@ void dump_verilog_unique_switch_box_interc(t_sram_orgz_info* cur_sram_orgz_info, if (0 == num_drive_rr_nodes) { /* Print a special direct connection*/ dump_verilog_unique_switch_box_short_interc(fp, rr_sb, chan_side, cur_rr_node, - num_drive_rr_nodes, cur_rr_node, - is_explicit_mapping); + num_drive_rr_nodes, cur_rr_node); } else if (1 == num_drive_rr_nodes) { /* Print a direct connection*/ dump_verilog_unique_switch_box_short_interc(fp, rr_sb, chan_side, cur_rr_node, - num_drive_rr_nodes, drive_rr_nodes[DEFAULT_SWITCH_ID], - is_explicit_mapping); + num_drive_rr_nodes, drive_rr_nodes[DEFAULT_SWITCH_ID]); } else if (1 < num_drive_rr_nodes) { /* Print the multiplexer, fan_in >= 2 */ dump_verilog_unique_switch_box_mux(cur_sram_orgz_info, fp, rr_sb, chan_side, cur_rr_node, @@ -1720,287 +2148,409 @@ void update_routing_connection_box_conf_bits(t_sram_orgz_info* cur_sram_orgz_inf return; } - -/* Dump port list of a subckt describing a side of a switch block - * Only output ports will be printed on the specified side - * Only input ports will be printed on the other sides - */ +/********************************************************************* + * Generate a port for a routing track of a swtich block + ********************************************************************/ static -void dump_verilog_routing_switch_box_unique_side_subckt_portmap(FILE* fp, - const RRGSB& rr_sb, - enum e_side sb_side, - size_t seg_id, - boolean dump_port_type, - bool is_explicit_mapping) { - /* Check file handler*/ - if (NULL == fp) { - vpr_printf(TIO_MESSAGE_ERROR, - "(FILE:%s,LINE[%d])Invalid file handler!\n", - __FILE__, __LINE__); - exit(1); - } +BasicPort generate_verilog_unique_switch_box_chan_port(const RRGSB& rr_sb, + const e_side& chan_side, + t_rr_node* cur_rr_node, + const PORTS& cur_rr_node_direction) { + /* Get the index in sb_info of cur_rr_node */ + int index = rr_sb.get_node_index(cur_rr_node, chan_side, cur_rr_node_direction); + /* Make sure this node is included in this sb_info */ + VTR_ASSERT((-1 != index)&&(NUM_SIDES != chan_side)); - /* Create a side manager */ - Side sb_side_manager(sb_side); + DeviceCoordinator chan_rr_node_coordinator = rr_sb.get_side_block_coordinator(chan_side); - for (size_t side = 0; side < rr_sb.get_num_sides(); ++side) { - Side side_manager(side); - /* Print ports */ - fprintf(fp, "//----- Inputs/outputs of %s side -----\n", side_manager.c_str()); - DeviceCoordinator port_coordinator = rr_sb.get_side_block_coordinator(side_manager.get_side()); - - for (size_t itrack = 0; itrack < rr_sb.get_chan_width(side_manager.get_side()); ++itrack) { - switch (rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)) { - case OUT_PORT: - /* if this is the specified side, we only consider output ports */ - if (sb_side_manager.get_side() != side_manager.get_side()) { - break; - } - /* Bypass unwanted segments */ - if (seg_id != rr_sb.get_chan_node_segment(side_manager.get_side(), itrack)) { - continue; - } - fprintf(fp, " "); - if (TRUE == dump_port_type) { - fprintf(fp, "output "); - is_explicit_mapping = false; /* Both cannot be true together */ - } - if (true == is_explicit_mapping) { - fprintf(fp, ".%s(", - gen_verilog_routing_channel_one_pin_name(rr_sb.get_chan_node(side_manager.get_side(), itrack), - port_coordinator.get_x(), port_coordinator.get_y(), itrack, - rr_sb.get_chan_node_direction(side_manager.get_side(), itrack))); - } - fprintf(fp, "%s", - gen_verilog_routing_channel_one_pin_name(rr_sb.get_chan_node(side_manager.get_side(), itrack), - port_coordinator.get_x(), port_coordinator.get_y(), itrack, - rr_sb.get_chan_node_direction(side_manager.get_side(), itrack))); - if (true == is_explicit_mapping) { - fprintf(fp, ")"); - } - fprintf(fp, ",\n"); - break; - case IN_PORT: - /* if this is not the specified side, we only consider input ports */ - if (sb_side_manager.get_side() == side_manager.get_side()) { - break; - } - fprintf(fp, " "); - if (TRUE == dump_port_type) { - fprintf(fp, "input "); - } - if (true == is_explicit_mapping) { - fprintf(fp, ".%s(", - gen_verilog_routing_channel_one_pin_name(rr_sb.get_chan_node(side_manager.get_side(), itrack), - port_coordinator.get_x(), port_coordinator.get_y(), itrack, - rr_sb.get_chan_node_direction(side_manager.get_side(), itrack))); - } - fprintf(fp, "%s", - gen_verilog_routing_channel_one_pin_name(rr_sb.get_chan_node(side_manager.get_side(), itrack), - port_coordinator.get_x(), port_coordinator.get_y(), itrack, - rr_sb.get_chan_node_direction(side_manager.get_side(), itrack))); - if (true == is_explicit_mapping) { - fprintf(fp, ")"); - } - fprintf(fp, ",\n"); - break; - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File: %s [LINE%d]) Invalid direction of chan[%d][%d]_track[%d]!\n", - __FILE__, __LINE__, rr_sb.get_sb_x(), rr_sb.get_sb_y(), itrack); - exit(1); - } - } - - /* Dump OPINs of adjacent CLBs */ - //const RRGSB& unique_mirror = device_rr_gsb.get_cb_unique_module(port_coordinator); - for (size_t inode = 0; inode < rr_sb.get_num_opin_nodes(side_manager.get_side()); ++inode) { - fprintf(fp, " "); - dump_verilog_grid_side_pin_with_given_index(fp, OPIN, /* This is an input of a SB */ - rr_sb.get_opin_node(side_manager.get_side(), inode)->ptc_num, - rr_sb.get_opin_node_grid_side(side_manager.get_side(), inode), - rr_sb.get_opin_node(side_manager.get_side(), inode)->xlow, - rr_sb.get_opin_node(side_manager.get_side(), inode)->ylow, - rr_sb.get_opin_node(side_manager.get_side(), inode)->xlow, - rr_sb.get_opin_node(side_manager.get_side(), inode)->ylow, - dump_port_type, is_explicit_mapping); /* Dump the direction of the port ! */ - if (FALSE == dump_port_type) { - fprintf(fp, ",\n"); - } - } - } - - return; + vtr::Point chan_port_coord(chan_rr_node_coordinator.get_x(), chan_rr_node_coordinator.get_y()); + std::string chan_port_name = generate_routing_track_port_name(rr_sb.get_chan_node(chan_side, index)->type, + chan_port_coord, index, + rr_sb.get_chan_node_direction(chan_side, index)); + return BasicPort(chan_port_name, 1); /* Every track has a port size of 1 */ } - -/* Task: Print the subckt of a side of a Switch Box. - * For TOP side: - * 1. Channel Y [x][y+1] inputs - * 2. Grid[x][y+1] Right side outputs pins - * 3. Grid[x+1][y+1] Left side output pins - * For RIGHT side: - * 1. Channel X [x+1][y] inputs - * 2. Grid[x+1][y+1] Bottom side output pins - * 3. Grid[x+1][y] Top side output pins - * For BOTTOM side: - * 1. Channel Y [x][y] outputs - * 2. Grid[x][y] Right side output pins - * 3. Grid[x+1][y] Left side output pins - * For LEFT side: - * 1. Channel X [x][y] outputs - * 2. Grid[x][y] Top side output pins - * 3. Grid[x][y+1] Bottom side output pins - * - * -------------- -------------- - * | | | | - * | Grid | ChanY | Grid | - * | [x][y+1] | [x][y+1] | [x+1][y+1] | - * | | | | - * -------------- -------------- - * ---------- - * ChanX | Switch | ChanX - * [x][y] | Box | [x+1][y] - * | [x][y] | - * ---------- - * -------------- -------------- - * | | | | - * | Grid | ChanY | Grid | - * | [x][y] | [x][y] | [x+1][y] | - * | | | | - * -------------- -------------- - */ +/********************************************************************* + * Generate an input port for routing multiplexer inside the switch block + * In addition to give the Routing Resource node of the input + * Users should provide the side of input, which is different case by case: + * 1. When the input is a pin of a CLB/Logic Block, the input_side should + * be the side of the node on its grid! + * For example, the input pin is on the top side of a switch block + * but on the right side of a switch block + * +--------+ + * | | + * | Grid |---+ + * | | | + * +--------+ v input_pin + * +----------------+ + * | Switch Block | + * +----------------+ + * 2. When the input is a routing track, the input_side should be + * the side of the node locating on the switch block + ********************************************************************/ static -void dump_verilog_routing_switch_box_unique_side_module(t_sram_orgz_info* cur_sram_orgz_info, - char* verilog_dir, char* subckt_dir, - size_t module_id, size_t seg_id, - const RRGSB& rr_sb, enum e_side side, - bool is_explicit_mapping) { - FILE* fp = NULL; - char* fname = NULL; - Side side_manager(side); - - /* Get the channel width on this side, if it is zero, we return */ - if (0 == rr_sb.get_chan_width(side)) { - return; +BasicPort generate_switch_block_input_port(const RRGSB& rr_sb, + const e_side& input_side, + t_rr_node* input_rr_node) { + BasicPort input_port; + /* Generate the input port object */ + switch (input_rr_node->type) { + /* case SOURCE: */ + case OPIN: { + /* Find the coordinator (grid_x and grid_y) for the input port */ + vtr::Point input_port_coord(input_rr_node->xlow, input_rr_node->ylow); + std::string input_port_name = generate_grid_side_port_name(input_port_coord, + input_side, + input_rr_node->ptc_num); + input_port.set_name(input_port_name); + input_port.set_width(1); /* Every grid output has a port size of 1 */ + break; + } + case CHANX: + case CHANY: { + input_port = generate_verilog_unique_switch_box_chan_port(rr_sb, input_side, input_rr_node, IN_PORT); + break; + } + default: /* SOURCE, IPIN, SINK are invalid*/ + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n", + __FILE__, __LINE__); + exit(1); } - /* Count the number of configuration bits to be consumed by this Switch block */ - int num_conf_bits = count_verilog_switch_box_side_conf_bits(cur_sram_orgz_info, rr_sb, side, seg_id); - /* Count the number of reserved configuration bits to be consumed by this Switch block */ - int num_reserved_conf_bits = count_verilog_switch_box_side_reserved_conf_bits(cur_sram_orgz_info, rr_sb, side, seg_id); - /* Estimate the sram_verilog_model->cnt */ - int cur_num_sram = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info); - int esti_sram_cnt = cur_num_sram + num_conf_bits; + return input_port; +} - /* Create file name */ - std::string fname_prefix(sb_verilog_file_name_prefix); - fname_prefix += side_manager.c_str(); +/********************************************************************* + * Generate a list of input ports for routing multiplexer inside the switch block + ********************************************************************/ +static +std::vector generate_switch_block_input_ports(const RRGSB& rr_sb, + const std::vector& input_rr_nodes) { + std::vector input_ports; - std::string file_description("Unique module for Switch Block side: "); - file_description += side_manager.c_str(); - file_description += "seg"; - file_description += std::to_string(seg_id); - - /* Create file handler */ - fp = verilog_create_one_subckt_file(subckt_dir, file_description.c_str(), - fname_prefix.c_str(), module_id, seg_id, &fname); - - /* Print preprocessing flags */ - verilog_include_defines_preproc_file(fp, verilog_dir); - - /* Comment lines */ - fprintf(fp, - "//----- Verilog Module of Unique Switch Box[%lu][%lu] at Side %s, Segment id: %lu -----\n", - rr_sb.get_sb_x(), rr_sb.get_sb_y(), side_manager.c_str(), seg_id); - /* Print the definition of subckt*/ - fprintf(fp, "module %s ( \n", rr_sb.gen_sb_verilog_side_module_name(side, seg_id)); - /* dump global ports */ - if (0 < dump_verilog_global_ports(fp, global_ports_head, TRUE, false)) { - fprintf(fp, ",\n"); - } - - dump_verilog_routing_switch_box_unique_side_subckt_portmap(fp, rr_sb, side, - seg_id, TRUE, - false); - - /* Put down configuration port */ - /* output of each configuration bit */ - /* Reserved sram ports */ - dump_verilog_reserved_sram_ports(fp, cur_sram_orgz_info, - 0, - num_reserved_conf_bits - 1, - VERILOG_PORT_INPUT); - if (0 < num_reserved_conf_bits) { - fprintf(fp, ",\n"); - } - /* Normal sram ports */ - dump_verilog_sram_ports(fp, cur_sram_orgz_info, - cur_num_sram, - esti_sram_cnt - 1, - VERILOG_PORT_INPUT); - - /* Dump ports only visible during formal verification*/ - if (0 < num_conf_bits) { - fprintf(fp, "\n"); - fprintf(fp, "`ifdef %s\n", verilog_formal_verification_preproc_flag); - fprintf(fp, ",\n"); - dump_verilog_formal_verification_sram_ports(fp, cur_sram_orgz_info, - cur_num_sram, - esti_sram_cnt - 1, - VERILOG_PORT_INPUT, false); - fprintf(fp, "\n"); - fprintf(fp, "`endif\n"); - } - fprintf(fp, "); \n"); - - /* Local wires for memory configurations */ - dump_verilog_sram_config_bus_internal_wires(fp, cur_sram_orgz_info, - cur_num_sram, - esti_sram_cnt - 1); - - /* Put down all the multiplexers */ - fprintf(fp, "//----- %s side Multiplexers -----\n", - side_manager.c_str()); - for (size_t itrack = 0; itrack < rr_sb.get_chan_width(side_manager.get_side()); ++itrack) { - assert((CHANX == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type) - ||(CHANY == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type)); - /* We care INC_DIRECTION tracks at this side*/ - if (OUT_PORT == rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)) { - /* Bypass unwanted segments */ - if (seg_id != rr_sb.get_chan_node_segment(side_manager.get_side(), itrack)) { - continue; - } - dump_verilog_unique_switch_box_interc(cur_sram_orgz_info, fp, rr_sb, - side_manager.get_side(), - itrack, is_explicit_mapping); + for (auto input_rr_node : input_rr_nodes) { + enum e_side input_pin_side = NUM_SIDES; + switch (input_rr_node->type) { + case OPIN: + input_pin_side = rr_sb.get_opin_node_grid_side(input_rr_node); + break; + case CHANX: + case CHANY: { + /* The input could be at any side of the switch block, find it */ + int index = -1; + rr_sb.get_node_side_and_index(input_rr_node, IN_PORT, &input_pin_side, &index); + VTR_ASSERT(NUM_SIDES != input_pin_side); + break; } + default: /* SOURCE, IPIN, SINK are invalid*/ + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n", + __FILE__, __LINE__); + exit(1); + } + input_ports.push_back(generate_switch_block_input_port(rr_sb, input_pin_side, input_rr_node)); } - - fprintf(fp, "endmodule\n"); - /* Comment lines */ - fprintf(fp, - "//----- END Verilog Module of Switch Box[%lu][%lu] Side %s -----\n\n", - rr_sb.get_sb_x(), rr_sb.get_sb_y(), side_manager.c_str()); + return input_ports; +} + +/********************************************************************* + * Print a short interconneciton in switch box + * There are two cases should be noticed. + * 1. The actual fan-in of cur_rr_node is 0. In this case, + the cur_rr_node need to be short connected to itself which is on the opposite side of this switch + * 2. The actual fan-in of cur_rr_node is 0. In this case, + * The cur_rr_node need to connected to the drive_rr_node + ********************************************************************/ +static +void print_verilog_unique_switch_box_short_interc(std::fstream& fp, + const RRGSB& rr_sb, + const e_side& chan_side, + t_rr_node* cur_rr_node, + t_rr_node* drive_rr_node) { + /* Check the file handler*/ + check_file_handler(fp); + + /* Find the name of output port */ + BasicPort output_port = generate_verilog_unique_switch_box_chan_port(rr_sb, chan_side, cur_rr_node, OUT_PORT); + enum e_side input_pin_side = chan_side; + + /* Generate the input port object */ + switch (drive_rr_node->type) { + case OPIN: + input_pin_side = rr_sb.get_opin_node_grid_side(drive_rr_node); + break; + case CHANX: + case CHANY: { + /* This should be an input in the data structure of RRGSB */ + if (cur_rr_node == drive_rr_node) { + /* To be strict, the input should locate on the opposite side. + * Use the else part if this may change in some architecture. + */ + Side side_manager(chan_side); + input_pin_side = side_manager.get_opposite(); + } else { + /* The input could be at any side of the switch block, find it */ + int index = -1; + rr_sb.get_node_side_and_index(drive_rr_node, IN_PORT, &input_pin_side, &index); + } + break; + } + default: /* SOURCE, IPIN, SINK are invalid*/ + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n", + __FILE__, __LINE__); + exit(1); + } + /* Find the name of input port */ + BasicPort input_port = generate_switch_block_input_port(rr_sb, input_pin_side, drive_rr_node); + + /* Print the wire connection in Verilog format */ + print_verilog_comment(fp, std::string("----- Short connection " + output_port.get_name() + " -----")); + print_verilog_wire_connection(fp, output_port, input_port, false); + fp << std::endl; +} + +/********************************************************************* + * Print a Verilog instance of a routing multiplexer as well as + * associated memory modules for a connection inside a switch block + ********************************************************************/ +static +void print_verilog_unique_switch_box_mux(ModuleManager& module_manager, + std::fstream& fp, + t_sram_orgz_info* cur_sram_orgz_info, + const ModuleId& sb_module, + const RRGSB& rr_sb, + const CircuitLibrary& circuit_lib, + const MuxLibrary& mux_lib, + const std::vector& rr_switches, + const e_side& chan_side, + t_rr_node* cur_rr_node, + const std::vector& drive_rr_nodes, + const size_t& switch_index, + const bool& use_explicit_mapping) { + /* Check the file handler*/ + check_file_handler(fp); /* Check */ - assert(esti_sram_cnt == get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info)); + /* Check current rr_node is CHANX or CHANY*/ + VTR_ASSERT((CHANX == cur_rr_node->type)||(CHANY == cur_rr_node->type)); - /* Close file handler */ - fclose(fp); + /* Get the circuit model id of the routing multiplexer */ + CircuitModelId mux_model = rr_switches[switch_index].circuit_model; - /* Add fname to the linked list */ - routing_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(routing_verilog_subckt_file_path_head, fname); + /* Find the input size of the implementation of a routing multiplexer */ + size_t datapath_mux_size = drive_rr_nodes.size(); - /* Free chan_rr_nodes */ - my_free(fname); + /* Get the multiplexing graph from the Mux Library */ + MuxId mux_id = mux_lib.mux_graph(mux_model, datapath_mux_size); + const MuxGraph& mux_graph = mux_lib.mux_graph(mux_id); - return; + /* Find the module name of the multiplexer and try to find it in the module manager */ + std::string mux_module_name = generate_mux_subckt_name(circuit_lib, mux_model, datapath_mux_size, std::string("")); + ModuleId mux_module = module_manager.find_module(mux_module_name); + VTR_ASSERT (true == module_manager.valid_module_id(mux_module)); + + /* Get the MUX instance id from the module manager */ + size_t mux_instance_id = module_manager.num_instance(sb_module, mux_module); + + /* Print the input bus for the inputs of a multiplexer + * We use the datapath input size (mux_size) to name the bus + * just to following the naming convention when the tool is built + * The bus port size should be the input size of multiplexer implementation + */ + BasicPort inbus_port; + inbus_port.set_name(generate_mux_input_bus_port_name(circuit_lib, mux_model, datapath_mux_size, mux_instance_id)); + inbus_port.set_width(datapath_mux_size); + + /* Generate input ports that are wired to the input bus of the routing multiplexer */ + std::vector mux_input_ports = generate_switch_block_input_ports(rr_sb, drive_rr_nodes); + /* Connect input ports to bus */ + print_verilog_comment(fp, std::string("----- BEGIN A local bus wire for multiplexer inputs -----")); + fp << generate_verilog_local_wire(inbus_port, mux_input_ports) << std::endl; + print_verilog_comment(fp, std::string("----- END A local bus wire for multiplexer inputs -----")); + fp << std::endl; + + /* Find the number of reserved configuration bits for the routing multiplexer */ + size_t mux_num_reserved_config_bits = find_mux_num_reserved_config_bits(circuit_lib, mux_model, mux_graph); + + /* Find the number of configuration bits for the routing multiplexer */ + size_t mux_num_config_bits = find_mux_num_config_bits(circuit_lib, mux_model, mux_graph, cur_sram_orgz_info->type); + + /* Print the configuration bus for the routing multiplexers */ + print_verilog_comment(fp, std::string("----- BEGIN Local wires to group configuration ports -----")); + print_verilog_mux_config_bus(fp, circuit_lib, mux_model, cur_sram_orgz_info->type, + datapath_mux_size, mux_instance_id, + mux_num_reserved_config_bits, mux_num_config_bits); + print_verilog_comment(fp, std::string("----- END Local wires to group configuration ports -----")); + fp << std::endl; + + /* Dump ports visible only during formal verification */ + print_verilog_comment(fp, std::string("----- BEGIN Local wires used in only formal verification purpose -----")); + print_verilog_preprocessing_flag(fp, std::string(verilog_formal_verification_preproc_flag)); + /* Print the SRAM configuration ports for formal verification */ + /* TODO: align with the port width of formal verification port of SB module */ + print_verilog_formal_verification_mux_sram_ports_wiring(fp, circuit_lib, mux_model, + datapath_mux_size, mux_instance_id, mux_num_config_bits); + print_verilog_endif(fp); + print_verilog_comment(fp, std::string("----- END Local wires used in only formal verification purpose -----")); + fp << std::endl; + + /* Instanciate the MUX Module */ + /* Create port-to-port map */ + std::map mux_port2port_name_map; + + /* Link input bus port to Switch Block inputs */ + std::vector mux_model_input_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_INPUT, true); + VTR_ASSERT(1 == mux_model_input_ports.size()); + /* Use the port name convention in the circuit library */ + mux_port2port_name_map[circuit_lib.port_lib_name(mux_model_input_ports[0])] = inbus_port; + + /* Link output port to Switch Block outputs */ + std::vector mux_model_output_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_OUTPUT, true); + VTR_ASSERT(1 == mux_model_output_ports.size()); + /* Use the port name convention in the circuit library */ + mux_port2port_name_map[circuit_lib.port_lib_name(mux_model_output_ports[0])] = generate_verilog_unique_switch_box_chan_port(rr_sb, chan_side, cur_rr_node, OUT_PORT); + + /* Link SRAM port to different configuraton port for the routing multiplexer + * Different design technology requires different configuration bus! + */ + std::vector mux_model_sram_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_SRAM, true); + VTR_ASSERT( 1 == mux_model_sram_ports.size() ); + /* For the regular SRAM port, module port use the same name */ + std::string mux_module_sram_port_name = circuit_lib.port_lib_name(mux_model_sram_ports[0]); + BasicPort mux_config_port(generate_mux_sram_port_name(circuit_lib, mux_model, datapath_mux_size, mux_instance_id, SPICE_MODEL_PORT_INPUT), + mux_num_config_bits); + mux_port2port_name_map[mux_module_sram_port_name] = mux_config_port; + + /* For the inverted SRAM port */ + std::string mux_module_sram_inv_port_name = circuit_lib.port_lib_name(mux_model_sram_ports[0]) + std::string("_inv"); + BasicPort mux_config_inv_port(generate_mux_sram_port_name(circuit_lib, mux_model, datapath_mux_size, mux_instance_id, SPICE_MODEL_PORT_OUTPUT), + mux_num_config_bits); + mux_port2port_name_map[mux_module_sram_inv_port_name] = mux_config_inv_port; + + /* Print an instance of the MUX Module */ + print_verilog_comment(fp, std::string("----- BEGIN Instanciation of a routing multiplexer -----")); + print_verilog_module_instance(fp, module_manager, sb_module, mux_module, mux_port2port_name_map, use_explicit_mapping); + print_verilog_comment(fp, std::string("----- END Instanciation of a routing multiplexer -----")); + 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(sb_module, mux_module); + + /* Instanciate memory modules */ + /* Find the name and module id of the memory module */ + std::string mem_module_name = generate_mux_subckt_name(circuit_lib, mux_model, datapath_mux_size, std::string(verilog_mem_posfix)); + ModuleId mem_module = module_manager.find_module(mem_module_name); + VTR_ASSERT (true == module_manager.valid_module_id(mem_module)); + + /* Create port-to-port map */ + std::map mem_port2port_name_map; + + /* TODO: Make the port2port map generation more generic!!! */ + std::vector config_ports; + config_ports.push_back(BasicPort(generate_local_config_bus_port_name(), mux_instance_id - 1, mux_instance_id)); + std::vector mem_output_ports; + mem_output_ports.push_back(mux_config_port); + mem_output_ports.push_back(mux_config_inv_port); + mem_port2port_name_map = generate_mem_module_port2port_map(module_manager, mem_module, + config_ports, + mem_output_ports, + circuit_lib.design_tech_type(mux_model), + cur_sram_orgz_info->type); + + /* Print an instance of the MUX Module */ + print_verilog_comment(fp, std::string("----- BEGIN Instanciation of memory cells for a routing multiplexer -----")); + print_verilog_module_instance(fp, module_manager, sb_module, mem_module, mem_port2port_name_map, use_explicit_mapping); + print_verilog_comment(fp, std::string("----- END Instanciation of memory cells for a routing multiplexer -----")); + 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(sb_module, mem_module); + + /* Create the path of the input of multiplexer in the hierarchy + * TODO: this MUST be deprecated later because module manager is created to handle these problems!!! + */ + std::string mux_input_hie_path = std::string(rr_sb.gen_sb_verilog_instance_name()) + std::string("/") + + mux_module_name + std::string("_") + + std::to_string(mux_instance_id) + std::string("_/in"); + cur_rr_node->name_mux = my_strdup(mux_input_hie_path.c_str()); } -/* Task: Print the subckt of a Switch Box. - * Call the four submodules dumped in function: unique_side_module + +/********************************************************************* + * Print the Verilog modules for a interconnection inside switch block + * The interconnection could be either a wire or a routing multiplexer, + * which depends on the fan-in of the rr_nodes in the switch block + ********************************************************************/ +static +void print_verilog_unique_switch_box_interc(ModuleManager& module_manager, + std::fstream& fp, + t_sram_orgz_info* cur_sram_orgz_info, + const ModuleId& sb_module, + const RRGSB& rr_sb, + const CircuitLibrary& circuit_lib, + const MuxLibrary& mux_lib, + const std::vector& rr_switches, + const e_side& chan_side, + const size_t& chan_node_id, + const bool& use_explicit_mapping) { + std::vector drive_rr_nodes; + + /* Get the node */ + t_rr_node* cur_rr_node = rr_sb.get_chan_node(chan_side, chan_node_id); + + /* Determine if the interc lies inside a channel wire, that is interc between segments */ + if (false == rr_sb.is_sb_node_passing_wire(chan_side, chan_node_id)) { + for (int i = 0; i < cur_rr_node->num_drive_rr_nodes; ++i) { + drive_rr_nodes.push_back(cur_rr_node->drive_rr_nodes[i]); + } + /* Special: if there are zero-driver nodes. We skip here */ + if (0 == drive_rr_nodes.size()) { + return; + } + } + + if (0 == drive_rr_nodes.size()) { + /* Print a special direct connection*/ + print_verilog_unique_switch_box_short_interc(fp, rr_sb, chan_side, cur_rr_node, + cur_rr_node); + } else if (1 == drive_rr_nodes.size()) { + /* Print a direct connection*/ + print_verilog_unique_switch_box_short_interc(fp, rr_sb, chan_side, cur_rr_node, + drive_rr_nodes[DEFAULT_SWITCH_ID]); + } else if (1 < drive_rr_nodes.size()) { + /* Print the multiplexer, fan_in >= 2 */ + print_verilog_unique_switch_box_mux(module_manager, fp, cur_sram_orgz_info, + sb_module, rr_sb, circuit_lib, mux_lib, + rr_switches, chan_side, cur_rr_node, + drive_rr_nodes, + cur_rr_node->drive_switches[DEFAULT_SWITCH_ID], + use_explicit_mapping); + } /*Nothing should be done else*/ +} + +/********************************************************************* + * Generate the Verilog module for a Switch Box. + * A Switch Box module consists of following ports: + * 1. Channel Y [x][y] inputs + * 2. Channel X [x+1][y] inputs + * 3. Channel Y [x][y-1] outputs + * 4. Channel X [x][y] outputs + * 5. Grid[x][y+1] Right side outputs pins + * 6. Grid[x+1][y+1] Left side output pins + * 7. Grid[x+1][y+1] Bottom side output pins + * 8. Grid[x+1][y] Top side output pins + * 9. Grid[x+1][y] Left side output pins + * 10. Grid[x][y] Right side output pins + * 11. Grid[x][y] Top side output pins + * 12. Grid[x][y+1] Bottom side output pins + * + * Location of a Switch Box in FPGA fabric: * * -------------- -------------- * | | | | @@ -2019,15 +2569,45 @@ void dump_verilog_routing_switch_box_unique_side_module(t_sram_orgz_info* cur_sr * | [x][y] | [x][y] | [x+1][y] | * | | | | * -------------- -------------- - */ + * + * Switch Block pin location map + * + * Grid[x][y+1] ChanY[x][y+1] Grid[x+1][y+1] + * right_pins inputs/outputs left_pins + * | ^ | + * | | | + * v v v + * +-----------------------------------------------+ + * | | + * Grid[x][y+1] | | Grid[x+1][y+1] + * bottom_pins---->| |<---- bottom_pins + * | | + * ChanX[x][y] | Switch Box [x][y] | ChanX[x+1][y] + * inputs/outputs<--->| |<---> inputs/outputs + * | | + * Grid[x][y+1] | | Grid[x+1][y+1] + * top_pins---->| |<---- top_pins + * | | + * +-----------------------------------------------+ + * ^ ^ ^ + * | | | + * | v | + * Grid[x][y] ChanY[x][y] Grid[x+1][y] + * right_pins inputs/outputs left_pins + * + * + ********************************************************************/ static -void dump_verilog_routing_switch_box_unique_module(t_sram_orgz_info* cur_sram_orgz_info, - char* verilog_dir, char* subckt_dir, - const RRGSB& rr_sb, - bool is_explicit_mapping) { - FILE* fp = NULL; - char* fname = NULL; - +void print_verilog_routing_switch_box_unique_module(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const MuxLibrary& mux_lib, + const std::vector& rr_switches, + t_sram_orgz_info* cur_sram_orgz_info, + const std::string& verilog_dir, + const std::string& subckt_dir, + const RRGSB& rr_sb, + const bool& is_explicit_mapping) { + /* TODO: move this part to another function where we count the conf bits for all the switch blocks !!!*/ /* Count the number of configuration bits to be consumed by this Switch block */ int num_conf_bits = count_verilog_switch_box_conf_bits(cur_sram_orgz_info, rr_sb); /* Count the number of reserved configuration bits to be consumed by this Switch block */ @@ -2035,45 +2615,58 @@ void dump_verilog_routing_switch_box_unique_module(t_sram_orgz_info* cur_sram_or /* Estimate the sram_verilog_model->cnt */ int cur_num_sram = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info); RRGSB rr_gsb = rr_sb; /* IMPORTANT: this copy will be removed when the config ports are initialized when created!!! */ - rr_gsb.set_sb_num_reserved_conf_bits(num_reserved_conf_bits); - rr_gsb.set_sb_conf_bits_lsb(cur_num_sram); - rr_gsb.set_sb_conf_bits_msb(cur_num_sram + num_conf_bits - 1); + rr_gsb.set_sb_num_reserved_conf_bits(size_t(num_reserved_conf_bits)); + rr_gsb.set_sb_conf_bits_lsb(size_t(cur_num_sram)); + rr_gsb.set_sb_conf_bits_msb(size_t(cur_num_sram + num_conf_bits - 1)); - /* Create file handler */ - fp = verilog_create_one_subckt_file(subckt_dir, "Unique Switch Block ", - sb_verilog_file_name_prefix, rr_gsb.get_sb_x(), rr_gsb.get_sb_y(), &fname); + /* Create the netlist */ + vtr::Point gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); + std::string verilog_fname(subckt_dir + generate_routing_block_netlist_name(sb_verilog_file_name_prefix, gsb_coordinate, std::string(verilog_netlist_file_postfix))); + /* TODO: remove the bak file when the file is ready */ + 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_verilog_file_header(fp, std::string("Verilog modules for Unique Switch Blocks[" + std::to_string(rr_gsb.get_sb_x()) + "]["+ std::to_string(rr_gsb.get_sb_y()) + "]")); /* Print preprocessing flags */ - verilog_include_defines_preproc_file(fp, verilog_dir); + print_verilog_include_defines_preproc_file(fp, verilog_dir); - /* Comment lines */ - fprintf(fp, "//----- Verilog Module of Unique Switch Box[%lu][%lu] -----\n", rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); - /* Print the definition of subckt*/ - fprintf(fp, "module %s ( \n", rr_gsb.gen_sb_verilog_module_name()); - /* dump global ports */ - if (0 < dump_verilog_global_ports(fp, global_ports_head, TRUE, false)) { - fprintf(fp, ",\n"); + /* Create a Verilog Module based on the circuit model, and add to module manager */ + ModuleId module_id = module_manager.add_module(generate_switch_block_module_name(gsb_coordinate)); + + /* Add ports to the module */ + /* Global ports: + * In the circuit_library, find all the circuit models that may be included in the Switch Block + * Collect the global ports from the circuit_models and merge with the same name + */ + std::vector global_ports = find_switch_block_global_ports(rr_gsb, circuit_lib, rr_switches); + for (const auto& port : global_ports) { + BasicPort module_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + module_manager.add_port(module_id, module_port, ModuleManager::MODULE_GLOBAL_PORT); } - + /* Add routing channel ports at each side of the GSB */ for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { Side side_manager(side); - /* Print ports */ - fprintf(fp, "//----- Channel Inputs/outputs of %s side -----\n", side_manager.c_str()); DeviceCoordinator port_coordinator = rr_gsb.get_side_block_coordinator(side_manager.get_side()); for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) { + vtr::Point port_coord(port_coordinator.get_x(), port_coordinator.get_y()); + std::string port_name = generate_routing_track_port_name(rr_gsb.get_chan_node(side_manager.get_side(), itrack)->type, + port_coord, itrack, + rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)); + BasicPort module_port(port_name, 1); /* Every track has a port size of 1 */ + switch (rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) { - case OUT_PORT: - fprintf(fp, " output %s,\n", - gen_verilog_routing_channel_one_pin_name(rr_gsb.get_chan_node(side_manager.get_side(), itrack), - port_coordinator.get_x(), port_coordinator.get_y(), itrack, - rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack))); + case OUT_PORT: + module_manager.add_port(module_id, module_port, ModuleManager::MODULE_OUTPUT_PORT); break; case IN_PORT: - fprintf(fp, " input %s,\n", - gen_verilog_routing_channel_one_pin_name(rr_gsb.get_chan_node(side_manager.get_side(), itrack), - port_coordinator.get_x(), port_coordinator.get_y(), itrack, - rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack))); + module_manager.add_port(module_id, module_port, ModuleManager::MODULE_INPUT_PORT); break; default: vpr_printf(TIO_MESSAGE_ERROR, @@ -2083,156 +2676,87 @@ void dump_verilog_routing_switch_box_unique_module(t_sram_orgz_info* cur_sram_or } } /* Dump OPINs of adjacent CLBs */ - fprintf(fp, "//----- Grid Inputs/outputs of %s side -----\n", side_manager.c_str()); for (size_t inode = 0; inode < rr_gsb.get_num_opin_nodes(side_manager.get_side()); ++inode) { - fprintf(fp, " "); - dump_verilog_grid_side_pin_with_given_index(fp, OPIN, /* This is an input of a SB */ - rr_gsb.get_opin_node(side_manager.get_side(), inode)->ptc_num, - rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode), - rr_gsb.get_opin_node(side_manager.get_side(), inode)->xlow, - rr_gsb.get_opin_node(side_manager.get_side(), inode)->ylow, - 0,0, /*No explicit mapping */ - TRUE, false); /* Dump the direction of the port ! */ + vtr::Point port_coord(rr_gsb.get_opin_node(side_manager.get_side(), inode)->xlow, + rr_gsb.get_opin_node(side_manager.get_side(), inode)->ylow); + std::string port_name = generate_grid_side_port_name(port_coord, + rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode), + rr_gsb.get_opin_node(side_manager.get_side(), inode)->ptc_num); + BasicPort module_port(port_name, 1); /* Every grid output has a port size of 1 */ + /* Grid outputs are inputs of switch blocks */ + module_manager.add_port(module_id, module_port, ModuleManager::MODULE_INPUT_PORT); } } - /* Put down configuration port */ - /* output of each configuration bit */ + /* Add configuration ports */ /* Reserved sram ports */ - fprintf(fp, "//----- Reserved SRAM Ports -----\n"); if (0 < rr_gsb.get_sb_num_reserved_conf_bits()) { - dump_verilog_reserved_sram_ports(fp, cur_sram_orgz_info, - rr_gsb.get_sb_reserved_conf_bits_lsb(), - rr_gsb.get_sb_reserved_conf_bits_msb(), - VERILOG_PORT_INPUT); - fprintf(fp, ",\n"); + /* Check: this SRAM organization type must be memory-bank ! */ + VTR_ASSERT( SPICE_SRAM_MEMORY_BANK == cur_sram_orgz_info->type ); + /* Generate a list of ports */ + add_reserved_sram_ports_to_module_manager(module_manager, module_id, + rr_gsb.get_sb_num_reserved_conf_bits()); } + + /* TODO: this should be added to the cur_sram_orgz_info !!! */ + t_spice_model* mem_model = NULL; + get_sram_orgz_info_mem_model(cur_sram_orgz_info, & mem_model); + CircuitModelId sram_model = circuit_lib.model(mem_model->name); + VTR_ASSERT(CircuitModelId::INVALID() != sram_model); + /* Normal sram ports */ - fprintf(fp, "//----- Regular SRAM Ports -----\n"); - dump_verilog_sram_ports(fp, cur_sram_orgz_info, - rr_gsb.get_sb_conf_bits_lsb(), - rr_gsb.get_sb_conf_bits_msb(), - VERILOG_PORT_INPUT); - - /* Dump ports only visible during formal verification*/ if (0 < rr_gsb.get_sb_num_conf_bits()) { - fprintf(fp, "\n"); - fprintf(fp, "//----- SRAM Ports for formal verification -----\n"); - fprintf(fp, "`ifdef %s\n", verilog_formal_verification_preproc_flag); - fprintf(fp, ",\n"); - dump_verilog_formal_verification_sram_ports(fp, cur_sram_orgz_info, - rr_gsb.get_sb_conf_bits_lsb(), - rr_gsb.get_sb_conf_bits_msb(), - VERILOG_PORT_INPUT, - false); - fprintf(fp, "\n"); - fprintf(fp, "`endif\n"); + add_sram_ports_to_module_manager(module_manager, module_id, + circuit_lib, sram_model, cur_sram_orgz_info->type, + rr_gsb.get_sb_num_conf_bits()); + /* Add ports only visible during formal verification to the module */ + add_formal_verification_sram_ports_to_module_manager(module_manager, module_id, circuit_lib, sram_model, + std::string(verilog_formal_verification_preproc_flag), + rr_gsb.get_sb_num_conf_bits()); } - fprintf(fp, "); \n"); + /* Print module definition + ports */ + print_verilog_module_declaration(fp, module_manager, module_id); + /* Finish printing ports */ + + print_verilog_comment(fp, std::string("---- BEGIN local wires for SRAM data ports ----")); /* Local wires for memory configurations */ - dump_verilog_sram_config_bus_internal_wires(fp, cur_sram_orgz_info, - rr_gsb.get_sb_conf_bits_lsb(), - rr_gsb.get_sb_conf_bits_msb()); + print_verilog_switch_block_local_sram_wires(fp, rr_gsb, circuit_lib, sram_model, cur_sram_orgz_info->type, + rr_gsb.get_sb_num_conf_bits()); + print_verilog_comment(fp, std::string("---- END local wires for SRAM data ports ----")); - /* Call submodules */ - int cur_sram_lsb = cur_num_sram; - int cur_sram_msb = cur_num_sram; + /* TODO: Print routing multiplexers */ for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { Side side_manager(side); - fprintf(fp, "//----- %s side Submodule -----\n", - side_manager.c_str()); - - /* Get the channel width on this side, if it is zero, we return */ - if (0 == rr_gsb.get_chan_width(side_manager.get_side())) { - fprintf(fp, "//----- %s side has zero channel width, module dump skipped -----\n", - side_manager.c_str()); - continue; - } - - /* get segment ids */ - std::vector seg_ids = rr_gsb.get_chan(side_manager.get_side()).get_segment_ids(); - for (size_t iseg = 0; iseg < seg_ids.size(); ++iseg) { - fprintf(fp, "//----- %s side Submodule with Segment id: %lu -----\n", - side_manager.c_str(), seg_ids[iseg]); - - /* Count the number of configuration bits to be consumed by this Switch block */ - int side_num_conf_bits = count_verilog_switch_box_side_conf_bits(cur_sram_orgz_info, rr_gsb, side_manager.get_side(), seg_ids[iseg]); - /* Count the number of reserved configuration bits to be consumed by this Switch block */ - int side_num_reserved_conf_bits = count_verilog_switch_box_side_reserved_conf_bits(cur_sram_orgz_info, rr_gsb, side_manager.get_side(), seg_ids[iseg]); - - /* Cache the sram counter */ - cur_sram_msb = cur_sram_lsb + side_num_conf_bits - 1; - - /* Instanciate the subckt*/ - fprintf(fp, - "%s %s ( \n", - rr_gsb.gen_sb_verilog_side_module_name(side_manager.get_side(), seg_ids[iseg]), - rr_gsb.gen_sb_verilog_side_instance_name(side_manager.get_side(), seg_ids[iseg])); - /* dump global ports */ - if (0 < dump_verilog_global_ports(fp, global_ports_head, FALSE, is_explicit_mapping)) { - fprintf(fp, ",\n"); - } - - dump_verilog_routing_switch_box_unique_side_subckt_portmap(fp, rr_gsb, side_manager.get_side(), seg_ids[iseg], FALSE, is_explicit_mapping); - - /* Put down configuration port */ - /* output of each configuration bit */ - /* Reserved sram ports */ - dump_verilog_reserved_sram_ports(fp, cur_sram_orgz_info, - 0, - side_num_reserved_conf_bits - 1, - VERILOG_PORT_CONKT); - if (0 < side_num_reserved_conf_bits) { - fprintf(fp, ",\n"); - } - /* Normal sram ports */ - dump_verilog_sram_local_ports(fp, cur_sram_orgz_info, - cur_sram_lsb, - cur_sram_msb, - VERILOG_PORT_CONKT, is_explicit_mapping); - - /* Dump ports only visible during formal verification*/ - if (0 < side_num_conf_bits) { - fprintf(fp, "\n"); - fprintf(fp, "`ifdef %s\n", verilog_formal_verification_preproc_flag); - fprintf(fp, ",\n"); - dump_verilog_formal_verification_sram_ports(fp, cur_sram_orgz_info, - cur_sram_lsb, - cur_sram_msb, - VERILOG_PORT_CONKT, - false); - fprintf(fp, "\n"); - fprintf(fp, "`endif\n"); - } - fprintf(fp, "); \n"); - - /* Update sram_lsb */ - cur_sram_lsb = cur_sram_msb + 1; + print_verilog_comment(fp, std::string("----- " + side_manager.to_string() + " side Routing Multiplexers -----")); + for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) { + /* We care INC_DIRECTION tracks at this side*/ + if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) { + print_verilog_unique_switch_box_interc(module_manager, fp, cur_sram_orgz_info, module_id, rr_sb, + circuit_lib, mux_lib, rr_switches, + side_manager.get_side(), + itrack, is_explicit_mapping); + } } } - /* checker */ - assert(cur_sram_msb == cur_num_sram + num_conf_bits - 1); + + /* Put an end to the Verilog module */ + print_verilog_module_end(fp, module_manager.module_name(module_id)); + + /* Add an empty line as a splitter */ + fp << std::endl; - fprintf(fp, "endmodule\n"); - - /* Comment lines */ - fprintf(fp, "//----- END Verilog Module of Switch Box[%lu][%lu] -----\n\n", rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); - /* Close file handler */ - fclose(fp); + fp.close(); /* Add fname to the linked list */ - routing_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(routing_verilog_subckt_file_path_head, fname); - - /* Free chan_rr_nodes */ - my_free(fname); + /* + routing_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(routing_verilog_subckt_file_path_head, verilog_fname.c_str()); + */ return; } - - /* Task: Print the subckt of a Switch Box. * A Switch Box subckt consists of following ports: * 1. Channel Y [x][y] inputs @@ -2298,7 +2822,7 @@ void dump_verilog_routing_switch_box_unique_subckt(t_sram_orgz_info* cur_sram_or /* Print the definition of subckt*/ fprintf(fp, "module %s ( \n", rr_gsb.gen_sb_verilog_module_name()); /* dump global ports */ - if (0 < dump_verilog_global_ports(fp, global_ports_head, TRUE, false)) { + if (0 < dump_verilog_global_ports(fp, global_ports_head, TRUE, is_explicit_mapping)) { fprintf(fp, ",\n"); } @@ -2337,9 +2861,7 @@ void dump_verilog_routing_switch_box_unique_subckt(t_sram_orgz_info* cur_sram_or rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode), rr_gsb.get_opin_node(side_manager.get_side(), inode)->xlow, rr_gsb.get_opin_node(side_manager.get_side(), inode)->ylow, - rr_gsb.get_opin_node(side_manager.get_side(), inode)->xlow, - rr_gsb.get_opin_node(side_manager.get_side(), inode)->ylow, - TRUE, false); /* Dump the direction of the port ! */ + TRUE, is_explicit_mapping); /* Dump the direction of the port ! */ } } @@ -2367,7 +2889,7 @@ void dump_verilog_routing_switch_box_unique_subckt(t_sram_orgz_info* cur_sram_or dump_verilog_formal_verification_sram_ports(fp, cur_sram_orgz_info, rr_gsb.get_sb_conf_bits_lsb(), rr_gsb.get_sb_conf_bits_msb(), - VERILOG_PORT_INPUT, false); + VERILOG_PORT_INPUT, is_explicit_mapping); fprintf(fp, "\n"); fprintf(fp, "`endif\n"); } @@ -2541,8 +3063,6 @@ void dump_verilog_routing_switch_box_subckt(t_sram_orgz_info* cur_sram_orgz_info cur_sb_info->opin_rr_node_grid_side[side][inode], cur_sb_info->opin_rr_node[side][inode]->xlow, cur_sb_info->opin_rr_node[side][inode]->ylow, - 0,/*used in more recent version*/ - 0,/*used in more recent version*/ TRUE, is_explicit_mapping); /* Dump the direction of the port ! */ } } @@ -2570,7 +3090,7 @@ void dump_verilog_routing_switch_box_subckt(t_sram_orgz_info* cur_sram_orgz_info dump_verilog_formal_verification_sram_ports(fp, cur_sram_orgz_info, cur_sb_info->conf_bits_lsb, cur_sb_info->conf_bits_msb - 1, - VERILOG_PORT_INPUT, false); + VERILOG_PORT_INPUT, is_explicit_mapping); fprintf(fp, "\n"); fprintf(fp, "`endif\n"); } @@ -2791,7 +3311,6 @@ void dump_verilog_connection_box_short_interc(FILE* fp, rr_gsb.get_ipin_node(side, index)->ptc_num, rr_gsb.get_ipin_node_grid_side(side, index), xlow, ylow, /* Coordinator of Grid */ - 0,0, /*No explicit mapping */ FALSE, false); /* Do not specify the direction of this pin */ /* End */ @@ -2802,10 +3321,10 @@ void dump_verilog_connection_box_short_interc(FILE* fp, /* SRC rr_node is the IPIN of a grid.*/ +static void dump_verilog_connection_box_short_interc(FILE* fp, t_cb* cur_cb_info, - t_rr_node* src_rr_node, - bool is_explicit_mapping) { + t_rr_node* src_rr_node) { t_rr_node* drive_rr_node = NULL; int iedge, check_flag; int xlow, ylow, height, side, index; @@ -2869,7 +3388,6 @@ void dump_verilog_connection_box_short_interc(FILE* fp, cur_cb_info->ipin_rr_node[side][index]->ptc_num, cur_cb_info->ipin_rr_node_grid_side[side][index], xlow, ylow, /* Coordinator of Grid */ - 0,0, /*No explicit mapping */ FALSE, false); /* Do not specify the direction of this pin */ /* End */ @@ -2996,7 +3514,7 @@ void dump_verilog_connection_box_mux(t_sram_orgz_info* cur_sram_orgz_info, verilog_model->prefix, mux_size, verilog_model->cnt); /* Dump global ports */ - if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, FALSE, FALSE, my_bool_to_boolean(is_explicit_mapping), TRUE)) { + if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, FALSE, FALSE, my_bool_to_boolean(is_explicit_mapping))) { fprintf(fp, ",\n"); } @@ -3027,7 +3545,6 @@ void dump_verilog_connection_box_mux(t_sram_orgz_info* cur_sram_orgz_info, rr_gsb.get_ipin_node(side, index)->ptc_num, rr_gsb.get_ipin_node_grid_side(side, index), xlow, ylow, /* Coordinator of Grid */ - 0,0, /*No explicit mapping*/ FALSE, false); /* Do not specify the direction of port */ if (true == is_explicit_mapping) { fprintf(fp, ")"); @@ -3244,7 +3761,7 @@ void dump_verilog_connection_box_mux(t_sram_orgz_info* cur_sram_orgz_info, verilog_model->prefix, mux_size, verilog_model->cnt); /* Dump global ports */ - if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, FALSE, FALSE, my_bool_to_boolean(is_explicit_mapping), TRUE)) { + if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, FALSE, FALSE, my_bool_to_boolean(is_explicit_mapping))) { fprintf(fp, ",\n"); } @@ -3275,8 +3792,6 @@ void dump_verilog_connection_box_mux(t_sram_orgz_info* cur_sram_orgz_info, cur_cb_info->ipin_rr_node[side][index]->ptc_num, cur_cb_info->ipin_rr_node_grid_side[side][index], xlow, ylow, /* Coordinator of Grid */ - 0,/*No explicit mapping*/ - 0,/*No explicit mapping*/ FALSE, false); /* Do not specify the direction of port */ if (true == is_explicit_mapping) { fprintf(fp, ")"); @@ -3415,7 +3930,7 @@ void dump_verilog_connection_box_interc(t_sram_orgz_info* cur_sram_orgz_info, if (1 == src_rr_node->fan_in) { /* Print a direct connection*/ - dump_verilog_connection_box_short_interc(fp, cur_cb_info, src_rr_node, is_explicit_mapping); + dump_verilog_connection_box_short_interc(fp, cur_cb_info, src_rr_node); } else if (1 < src_rr_node->fan_in) { /* Print the multiplexer, fan_in >= 2 */ dump_verilog_connection_box_mux(cur_sram_orgz_info, fp, cur_cb_info, @@ -3606,8 +4121,6 @@ void dump_verilog_routing_connection_box_unique_module(t_sram_orgz_info* cur_sra rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode), rr_gsb.get_ipin_node(cb_ipin_side, inode)->xlow, rr_gsb.get_ipin_node(cb_ipin_side, inode)->ylow, - 0,/*No explicit mapping */ - 0,/*No explicit mapping */ TRUE, false); } @@ -3811,7 +4324,6 @@ void dump_verilog_routing_connection_box_subckt(t_sram_orgz_info* cur_sram_orgz_ assert((1 == side_cnt)||(2 == side_cnt)); side_cnt = 0; - //const RRGSB& unique_mirror = device_rr_gsb.get_cb_unique_module(cb_type, coordinator); /* Print the ports of grids*/ /* only check ipin_rr_nodes of cur_cb_info */ for (side = 0; side < cur_cb_info->num_sides; side++) { @@ -3829,8 +4341,6 @@ void dump_verilog_routing_connection_box_subckt(t_sram_orgz_info* cur_sram_orgz_ cur_cb_info->ipin_rr_node_grid_side[side][inode], cur_cb_info->ipin_rr_node[side][inode]->xlow, cur_cb_info->ipin_rr_node[side][inode]->ylow, - 0,/*Used in more recent version*/ - 0,/*Used in more recent version*/ TRUE, is_explicit_mapping); } @@ -3862,7 +4372,7 @@ void dump_verilog_routing_connection_box_subckt(t_sram_orgz_info* cur_sram_orgz_ dump_verilog_formal_verification_sram_ports(fp, cur_sram_orgz_info, cur_cb_info->conf_bits_lsb, cur_cb_info->conf_bits_msb - 1, - VERILOG_PORT_INPUT, false); + VERILOG_PORT_INPUT, is_explicit_mapping); fprintf(fp, "\n"); fprintf(fp, "`endif\n"); } @@ -3923,21 +4433,62 @@ void dump_verilog_routing_connection_box_subckt(t_sram_orgz_info* cur_sram_orgz_ return; } -/* Top Function*/ -/* Build the routing resource SPICE sub-circuits*/ -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) { - assert(UNI_DIRECTIONAL == routing_arch->directionality); +/********************************************************************* + * Generate the port name for a Grid + *********************************************************************/ +std::string generate_grid_side_port_name(const vtr::Point& coordinate, + const e_side& side, + const size_t& pin_id) { + /* Output the pins on the side*/ + int height = get_grid_pin_height(coordinate.x(), coordinate.y(), (int)pin_id); + if (1 != grid[coordinate.x()][coordinate.y()].type->pinloc[height][side][pin_id]) { + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Fail to generate a grid pin (x=%lu, y=%lu, height=%lu, side=%s, index=%d)\n", + __FILE__, __LINE__, + coordinate.x(), coordinate.y(), height, convert_side_index_to_string(side), pin_id); + exit(1); + } + return generate_grid_port_name(coordinate, (size_t)height, side, pin_id, true); +} + +/********************************************************************* + * Top-level function: + * Build the Verilog modules for global routing architecture + * 1. Routing channels + * 2. Switch blocks + * 3. Connection blocks + * + * This function supports two styles in Verilog generation: + * 1. Explicit port mapping + * 2. Inexplicit port mapping + * + * This function also supports high hierarchical Verilog generation + * (when the compact_routing_hierarchy is set true) + * In this mode, Verilog generation will be done for only those + * unique modules in terms of internal logics + *********************************************************************/ +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, /* To be replaced by RRGraph object */ + t_ivec*** LL_rr_node_indices, + t_rr_indexed_data* LL_rr_indexed_data, + const t_fpga_spice_opts& FPGA_SPICE_Opts) { + VTR_ASSERT (UNI_DIRECTIONAL == routing_arch.directionality); boolean compact_routing_hierarchy = FPGA_SPICE_Opts.compact_routing_hierarchy; boolean explicit_port_mapping = FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog; + + /* Create a vector of switch infs. TODO: this should be replaced switch objects!!! */ + std::vector rr_switches; + for (short i = 0; i < routing_arch.num_switch; ++i) { + rr_switches.push_back(switch_inf[i]); + } + /* Two major tasks: * 1. Generate sub-circuits for Routing Channels * 2. Generate sub-circuits for Switch Boxes @@ -3962,13 +4513,19 @@ void dump_verilog_routing_resources(t_sram_orgz_info* cur_sram_orgz_info, /* X - channels [1...nx][0..ny]*/ for (size_t ichan = 0; ichan < device_rr_chan.get_num_modules(CHANX); ++ichan) { dump_verilog_routing_chan_subckt(verilog_dir, subckt_dir, - ichan, device_rr_chan.get_module(CHANX, ichan), explicit_port_mapping); + ichan, device_rr_chan.get_module(CHANX, ichan)); + + print_verilog_routing_unique_chan_subckt(module_manager, std::string(verilog_dir), std::string(subckt_dir), + ichan, device_rr_chan.get_module(CHANX, ichan)); } /* Y - channels [1...ny][0..nx]*/ vpr_printf(TIO_MESSAGE_INFO, "Writing Y-direction Channels...\n"); for (size_t ichan = 0; ichan < device_rr_chan.get_num_modules(CHANY); ++ichan) { dump_verilog_routing_chan_subckt(verilog_dir, subckt_dir, - ichan, device_rr_chan.get_module(CHANY, ichan), explicit_port_mapping); + ichan, device_rr_chan.get_module(CHANY, ichan)); + + print_verilog_routing_unique_chan_subckt(module_manager, std::string(verilog_dir), std::string(subckt_dir), + ichan, device_rr_chan.get_module(CHANY, ichan)); } } else { /* Output the full array of routing channels */ @@ -3977,7 +4534,11 @@ void dump_verilog_routing_resources(t_sram_orgz_info* cur_sram_orgz_info, for (int ix = 1; ix < (nx + 1); ix++) { dump_verilog_routing_chan_subckt(verilog_dir, subckt_dir, ix, iy, CHANX, LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices, LL_rr_indexed_data, - arch.num_segments, explicit_port_mapping); + arch.num_segments); + + vtr::Point chan_coordinate((size_t)ix, (size_t)iy); + print_verilog_routing_chan_subckt(module_manager, std::string(verilog_dir), std::string(subckt_dir), chan_coordinate, CHANX, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); } } /* Y - channels [1...ny][0..nx]*/ @@ -3986,7 +4547,11 @@ void dump_verilog_routing_resources(t_sram_orgz_info* cur_sram_orgz_info, for (int iy = 1; iy < (ny + 1); iy++) { dump_verilog_routing_chan_subckt(verilog_dir, subckt_dir, ix, iy, CHANY, LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices, LL_rr_indexed_data, - arch.num_segments, explicit_port_mapping); + arch.num_segments); + + vtr::Point chan_coordinate((size_t)ix, (size_t)iy); + print_verilog_routing_chan_subckt(module_manager, std::string(verilog_dir), std::string(subckt_dir), chan_coordinate, CHANY, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); } } } @@ -3996,28 +4561,16 @@ void dump_verilog_routing_resources(t_sram_orgz_info* cur_sram_orgz_info, /* Create a snapshot on sram_orgz_info */ t_sram_orgz_info* stamped_sram_orgz_info = snapshot_sram_orgz_info(cur_sram_orgz_info); - /* Output unique side modules - for (size_t side = 0; side < device_rr_gsb.get_max_num_sides(); ++side) { - Side side_manager(side); - for (size_t iseg = 0; iseg < device_rr_gsb.get_num_segments(); ++iseg) { - for (size_t isb = 0; isb < device_rr_gsb.get_num_sb_unique_submodule(side_manager.get_side(), iseg); ++isb) { - const RRGSB& unique_mirror = device_rr_gsb.get_sb_unique_submodule(isb, side_manager.get_side(), iseg); - size_t seg_id = device_rr_gsb.get_segment_id(iseg); - dump_verilog_routing_switch_box_unique_side_module(cur_sram_orgz_info, verilog_dir, subckt_dir, isb, seg_id, unique_mirror, side_manager.get_side(), explicit_port_mapping); - } - } - } - */ - /* Output unique modules */ for (size_t isb = 0; isb < device_rr_gsb.get_num_sb_unique_module(); ++isb) { const RRGSB& unique_mirror = device_rr_gsb.get_sb_unique_module(isb); - /* - dump_verilog_routing_switch_box_unique_module(cur_sram_orgz_info, verilog_dir, - subckt_dir, unique_mirror, explicit_port_mapping); - */ dump_verilog_routing_switch_box_unique_subckt(cur_sram_orgz_info, verilog_dir, subckt_dir, unique_mirror, explicit_port_mapping); + print_verilog_routing_switch_box_unique_module(module_manager, arch.spice->circuit_lib, mux_lib, + rr_switches, + cur_sram_orgz_info, std::string(verilog_dir), + std::string(subckt_dir), unique_mirror, + explicit_port_mapping); } /* Restore sram_orgz_info to the base */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.h index 24b805a6b..1e12d0b45 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.h @@ -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& 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 diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c index 2e92482b0..3a2723ec2 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c @@ -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)); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_netlist_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_netlist_utils.c index 8e52d6f5a..1da674e78 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_netlist_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_netlist_utils.c @@ -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) { diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c index 186cb5f68..1a34c7921 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c @@ -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: diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h index 84b456203..ab5a98d2f 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h @@ -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, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp index ca832260b..4b93c2cd2 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp @@ -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 " 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& 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 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 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 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); +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h index a3d8e7206..c95bfbb18 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h @@ -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 diff --git a/vpr7_x2p/vpr/SRC/util/vpr_utils.c b/vpr7_x2p/vpr/SRC/util/vpr_utils.c index 93ef9fe24..049eef7c5 100755 --- a/vpr7_x2p/vpr/SRC/util/vpr_utils.c +++ b/vpr7_x2p/vpr/SRC/util/vpr_utils.c @@ -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;