Merge remote-tracking branch 'lnis_origin/dev' into ganesh_dev
This commit is contained in:
commit
c1bef00079
|
@ -231,7 +231,7 @@ SRAMs
|
|||
.. note:: The support SRAM modules should have a BL and a WL when the memory-bank-style configuration circuit is declared. Note that the WL should be the write/read enable signal, while BL is the data input.
|
||||
|
||||
Logic gates
|
||||
-----
|
||||
-----------
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
|
|
|
@ -98,3 +98,5 @@ Transistor level
|
|||
* **is_config_enable:** can be either ``true`` or ``false``. Only valid when ``is_global`` is true. Specify if this port controls a configuration-enable signal. This port is only enabled during FPGA configuration, and always disabled during FPGA operation. All the ``config_enable`` ports are connected to global configuration-enable voltage stimuli in testbenches.
|
||||
|
||||
.. note:: Different types of ``circuit_model`` have different XML syntax, with which users can highly customize their circuit topologies. See refer to examples of ``circuit_model`` for more details.
|
||||
|
||||
.. note:: Note that we have a list of reserved port names, which indicate the usage of these ports when building FPGA fabrics. Please do not use ``mem_out``, ``mem_inv``, ``bl``, ``wl``, ``blb``, ``wlb``, ``ccff_head`` and ``ccff_tail``.
|
||||
|
|
|
@ -1,4 +1,38 @@
|
|||
Bistream Output File Format
|
||||
============================
|
||||
|
||||
**Under Construction**
|
||||
FPGA-Bitstream can generate two types of bitstreams:
|
||||
* Generic bitstreams, where configuration bits are organized out-of-order in a database. We output the generic bitstream to a XML format, which is easy to debug. As shown in the following XML code, configuration bits are organized block by block, where each block could be a LUT, a routing multiplexer `etc`. Each ``bitstream_block`` includes two sets of information:
|
||||
- ``hierarchy`` represents the location of this block in FPGA fabric.
|
||||
- ``bitstream`` represents the configuration bits affiliated to this block.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<bitstream_block index="0">
|
||||
<hierarchy>
|
||||
<instance level="0" name="fpga_top"/>
|
||||
<instance level="1" name="grid_clb_1_1"/>
|
||||
<instance level="2" name="fle_0"/>
|
||||
<instance level="3" name="lut4_0"/>
|
||||
</hierarchy>
|
||||
<bitstream>
|
||||
<bit memory_port="mem_out[0]" value="1"/>
|
||||
<bit memory_port="mem_out[1]" value="0"/>
|
||||
<bit memory_port="mem_out[2]" value="1"/>
|
||||
<bit memory_port="mem_out[3]" value="0"/>
|
||||
<bit memory_port="mem_out[4]" value="1"/>
|
||||
<bit memory_port="mem_out[5]" value="0"/>
|
||||
<bit memory_port="mem_out[6]" value="1"/>
|
||||
<bit memory_port="mem_out[7]" value="0"/>
|
||||
<bit memory_port="mem_out[8]" value="1"/>
|
||||
<bit memory_port="mem_out[9]" value="0"/>
|
||||
<bit memory_port="mem_out[10]" value="1"/>
|
||||
<bit memory_port="mem_out[11]" value="0"/>
|
||||
<bit memory_port="mem_out[12]" value="1"/>
|
||||
<bit memory_port="mem_out[13]" value="0"/>
|
||||
<bit memory_port="mem_out[14]" value="1"/>
|
||||
<bit memory_port="mem_out[15]" value="0"/>
|
||||
</bitstream>
|
||||
</bitstream_block>
|
||||
|
||||
* Fabric-dependent bitstreams, where configuration bits are organized to be loadable to the configuration protocols of FPGAs. The bitstream just sets an order to the configuration bits in the database, without duplicating the database. OpenFPGA framework provides a fabric-dependent bitstream generator which is aligned to our Verilog netlists. The fabric-dependent bitstream can be found in autogenerated Verilog testbenches.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
FPGA-Bitstream
|
||||
=============
|
||||
==============
|
||||
|
||||
.. _fpga_bitstream:
|
||||
User Manual for FPGA Bitstream Generator
|
||||
|
|
|
@ -5,20 +5,8 @@ If the --fpga_verilog_print_modelsim_autodeck option is selected, it is possible
|
|||
|
||||
The point of the verification step is to check that the FPGA reproduces the right function. As illustrated in :numref:`fig_ModelSim`, inside of the red rectangle is the programming of the FPGA. Each prog clock cycle corresponds to one bit added to the scan-chain. Inside of the blue rectangle, we see that the prog clock is set to 0 and the operating clock is toggled. Two outputs are shown, benchmark and FPGA, and by checking the value on both of them, we know if the functionality is respected.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.. _fig_ModelSim:
|
||||
|
||||
.. figure:: ./figures/Verification_step.pdf
|
||||
:scale: 100%
|
||||
:alt: Functional Verification using ModelSim
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ This motivates us to generate the Verilog code of the architecture to enable a s
|
|||
|
||||
In this manual, we present FPGA-Verilog. This extension enables the generation of a fully functional Verilog code enabling a deeper understanding of the architectures of the FPGAs. We introduce different options to this module to do the verification of the system. This will be presented in more depth in the FPGA-Bitstream section.
|
||||
|
||||
The technical details can be found in our TVLSI'19 paper :cite:`XTang_TVLSI_2019`.
|
||||
The technical details can be found in our TVLSI'19 paper :cite:`XTang_TVLSI_2019` and FPL'19 paper :cite:`XTang_FPL_2019`.
|
||||
|
||||
FPGA-Bitstream
|
||||
--------------
|
||||
|
@ -34,3 +34,5 @@ FPGA-Bitstream
|
|||
To have the right functionality on top of the FPGA generated, it is necessary to have a Bitstream generation which programs the FPGA. For this reason, we generate a Bitstream and some testbenches in parallel which allow the user to do some functional verification of the system to make sure that the functionality is respected. This includes three different testbenches. First, the FPGA is configured then the clock runs with random patterns are generated to test the functionality. Secondly, the FPGA can be configured in parallel to the testbench itself to do a comparison of the signals and check the validity. Finally, the configuration can be skipped to directly have access to the functioning of the system and reduce the processing time.
|
||||
|
||||
This will be explained in more depth in the FPGA-Bitstream section.
|
||||
|
||||
The technical details can be found in our TVLSI'19 paper :cite:`XTang_TVLSI_2019` and FPL'19 paper :cite:`XTang_FPL_2019`.
|
||||
|
|
|
@ -14,19 +14,6 @@ doi={10.1109/ICCD.2015.7357183},
|
|||
ISSN={},
|
||||
month={Oct},}
|
||||
|
||||
@ARTICLE{XTang_JETCAS_2018,
|
||||
author={X. Tang and E. Giacomin and G. De Micheli and P. Gaillardon},
|
||||
journal={IEEE Journal on Emerging and Selected Topics in Circuits and Systems},
|
||||
title={Post-P amp;R Performance and Power Analysis for RRAM-Based FPGAs},
|
||||
year={2018},
|
||||
volume={8},
|
||||
number={3},
|
||||
pages={639-650},
|
||||
keywords={Field programmable gate arrays;Random access memory;Analytical models;Delays;Resistance;Routing;Programmable logic arrays;resistive ram;simulation;system modeling;integrated circuit reliability},
|
||||
doi={10.1109/JETCAS.2018.2847600},
|
||||
ISSN={2156-3357},
|
||||
month={Sept},}
|
||||
|
||||
@book{VBetz_Book_1999,
|
||||
editor = {Betz, Vaughn and Rose, Jonathan and Marquardt, Alexander},
|
||||
title = {Architecture and CAD for Deep-Submicron FPGAs},
|
||||
|
@ -36,31 +23,6 @@ month={Sept},}
|
|||
address = {Norwell, MA, USA},
|
||||
}
|
||||
|
||||
@article{XTang_TCAS1_2016,
|
||||
title={{A Study on the Programming Structures for RRAM-based FPGA Architectures}},
|
||||
author={X. Tang and Kim, Gain and Gaillardon, Pierre-Emmanuel and De Micheli, Giovanni},
|
||||
journal={IEEE Transactions on Circuits and Systems I: Regular Papers},
|
||||
volume={63},
|
||||
number={4},
|
||||
pages={503--516},
|
||||
year={2016},
|
||||
publisher={IEEE}
|
||||
}
|
||||
|
||||
|
||||
@ARTICLE{XTang_TCAS1_2017,
|
||||
author={X. Tang and E. Giacomin and G. De Micheli and P. E. Gaillardon},
|
||||
journal={IEEE Transactions on Circuits and Systems I: Regular Papers},
|
||||
title={{Circuit Designs of High-Performance and Low-Power RRAM-Based Multiplexers Based on 4T(ransistor)1R(RAM) Programming Structure}},
|
||||
year={2017},
|
||||
volume={64},
|
||||
number={5},
|
||||
pages={1173-1186},
|
||||
keywords={Delays;Logic gates;Multiplexing;Programming;Resistance;Routing;Transistors;Circuit design;high-performance;low-power;multiplexer;resistive memory},
|
||||
doi={10.1109/TCSI.2016.2638542},
|
||||
ISSN={1549-8328},
|
||||
month={May},}
|
||||
|
||||
@inproceedings{JLuu_FPGA_2011,
|
||||
author = {Luu, Jason and Anderson, Jason Helge and Rose, Jonathan Scott},
|
||||
title = {{Architecture Description and Packing for Logic Blocks with Hierarchy, Modes and Complex Interconnect}},
|
||||
|
@ -119,3 +81,17 @@ month={Sept},}
|
|||
ISSN={1063-8210},
|
||||
month={March},
|
||||
}
|
||||
|
||||
@INPROCEEDINGS{XTang_FPL_2019,
|
||||
author={X. {Tang} and E. {Giacomin} and A. {Alacchi} and B. {Chauviere} and P. {Gaillardon}},
|
||||
booktitle={2019 29th International Conference on Field Programmable Logic and Applications (FPL)},
|
||||
title={OpenFPGA: An Opensource Framework Enabling Rapid Prototyping of Customizable FPGAs},
|
||||
year={2019},
|
||||
volume={},
|
||||
number={},
|
||||
pages={367-374},
|
||||
keywords={field programmable gate arrays;logic design;reconfigurable architectures;software prototyping;OpenFPGA;FPGA architectures;semicustom design;XML-to-Prototype design flow;Verilog netlists;FPGA fabric;XML language;VTR framework;production-ready layouts;fully-optimized commercial products;data processing applications;Field Programmable Gate Arrays;programmable accelerators;computing systems;Verilog-to-Bitstream generator;Field programmable gate arrays;Computer architecture;Hardware design languages;XML;Microprocessors;Layout;Libraries;FPGA;Verilog generator;Bitstream generation;Semi Custom Designed FPGA},
|
||||
doi={10.1109/FPL.2019.00065},
|
||||
ISSN={1946-147X},
|
||||
month={Sep.},}
|
||||
|
||||
|
|
|
@ -19,6 +19,12 @@ check_execution_path (){
|
|||
fi
|
||||
}
|
||||
|
||||
run-task-with-modelsim () {
|
||||
echo "Script as to be run as \"run-task-with-modelsim task_name --maxthreads nb_threads other_run-modelsim_options\""
|
||||
$PYTHON_EXEC $OPENFPGA_SCRIPT_PATH/run_fpga_task.py $1 $2 $3
|
||||
$PYTHON_EXEC $OPENFPGA_SCRIPT_PATH/run_modelsim.py "$@"
|
||||
}
|
||||
|
||||
run-task () {
|
||||
$PYTHON_EXEC $OPENFPGA_SCRIPT_PATH/run_fpga_task.py "$@"
|
||||
}
|
||||
|
@ -76,4 +82,4 @@ fi
|
|||
TaskList=$(ls -tdalh ${OPENFPGA_TASK_PATH}/* | awk '{system("basename " $9)}' | awk '{printf("%s ",$1)}')
|
||||
complete -W "${TaskList}" goto-task
|
||||
complete -W "${TaskList}" run-task
|
||||
complete -W "${TaskList}" run-modelsim
|
||||
complete -W "${TaskList}" run-modelsim
|
||||
|
|
|
@ -1,42 +1,42 @@
|
|||
//-----------------------------------------------------
|
||||
// Design Name : dual_port_ram_32x512
|
||||
// Design Name : dual_port_ram
|
||||
// File Name : dpram.v
|
||||
// Function : Dual port RAM 32x512
|
||||
// Coder : Aurelien Alacchi
|
||||
// Function : Dual port RAM 32x1024
|
||||
// Coder : Aurelien
|
||||
//-----------------------------------------------------
|
||||
|
||||
module dual_port_ram_32x512 (
|
||||
module dpram (
|
||||
input clk,
|
||||
input wen,
|
||||
input ren,
|
||||
input[0:8] waddr,
|
||||
input[0:8] raddr,
|
||||
input[0:9] waddr,
|
||||
input[0:9] raddr,
|
||||
input[0:31] d_in,
|
||||
output[0:31] d_out );
|
||||
|
||||
dual_port_sram_32x512 memory_0 (
|
||||
.wclk (clk),
|
||||
.wen (wen),
|
||||
.waddr (waddr),
|
||||
.data_in (d_in),
|
||||
.rclk (clk),
|
||||
.ren (ren),
|
||||
.raddr (raddr),
|
||||
.d_out (d_out) );
|
||||
dual_port_sram memory_0 (
|
||||
.wclk (clk),
|
||||
.wen (wen),
|
||||
.waddr (waddr),
|
||||
.data_in (d_in),
|
||||
.rclk (clk),
|
||||
.ren (ren),
|
||||
.raddr (raddr),
|
||||
.d_out (d_out) );
|
||||
|
||||
endmodule
|
||||
|
||||
module dual_port_sram_32x512 (
|
||||
module dual_port_sram (
|
||||
input wclk,
|
||||
input wen,
|
||||
input[0:8] waddr,
|
||||
input[0:9] waddr,
|
||||
input[0:31] data_in,
|
||||
input rclk,
|
||||
input ren,
|
||||
input[0:8] raddr,
|
||||
input[0:9] raddr,
|
||||
output[0:31] d_out );
|
||||
|
||||
reg[0:31] ram[0:511];
|
||||
reg[0:31] ram[0:1023];
|
||||
reg[0:31] internal;
|
||||
|
||||
assign d_out = internal;
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
//-----------------------------------------------------
|
||||
// Design Name : dual_port_ram_tb
|
||||
// File Name : memory_wrapper_tb.v
|
||||
// Function : Dual port RAM 64x2048
|
||||
// Coder : Aurelien
|
||||
//-----------------------------------------------------
|
||||
`timescale 1 ns/1 ps
|
||||
|
||||
module dpram_tb ();
|
||||
reg clk;
|
||||
reg wen;
|
||||
reg ren;
|
||||
reg[0:9] waddr;
|
||||
reg[0:9] raddr;
|
||||
reg[0:31] d_in;
|
||||
wire[0:31] d_out;
|
||||
|
||||
integer count;
|
||||
integer lim_max = 1023;
|
||||
|
||||
dpram memory_0 (
|
||||
.clk (clk),
|
||||
.wen (wen),
|
||||
.waddr (waddr),
|
||||
.d_in (d_in),
|
||||
.ren (ren),
|
||||
.raddr (raddr),
|
||||
.d_out (d_out) );
|
||||
|
||||
initial begin
|
||||
clk <= 1'b0;
|
||||
ren <= 1'b0;
|
||||
wen <= 1'b0;
|
||||
raddr <= 10'h000;
|
||||
waddr <= 10'h000;
|
||||
d_in <= 32'h00000000;
|
||||
for(count = 0; count < lim_max; count = count +1) begin
|
||||
#5
|
||||
wen <= 1'b1;
|
||||
clk <= !clk;
|
||||
if(clk) begin
|
||||
waddr <= waddr + 1;
|
||||
end
|
||||
end
|
||||
wen <= 1'b0;
|
||||
for(count = 0; count < lim_max; count = count +1) begin
|
||||
#5
|
||||
ren <= 1'b1;
|
||||
clk <= !clk;
|
||||
if(clk) begin
|
||||
raddr <= raddr + 1;
|
||||
end
|
||||
end
|
||||
$finish;
|
||||
end
|
||||
|
||||
always@(negedge clk) begin
|
||||
d_in <= $random;
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,36 @@
|
|||
bram $__MY_DPRAM
|
||||
init 0
|
||||
abits 10
|
||||
dbits 32
|
||||
groups 2
|
||||
ports 1 1
|
||||
wrmode 1 0
|
||||
enable 1 1
|
||||
transp 0 0
|
||||
clocks 1 1
|
||||
clkpol 1 1
|
||||
endbram
|
||||
|
||||
bram $__MY_SPRAM
|
||||
init 0
|
||||
abits 10
|
||||
dbits 32
|
||||
groups 2
|
||||
ports 1 1
|
||||
wrmode 1 0
|
||||
enable 1 0
|
||||
transp 0 0
|
||||
clocks 1 1
|
||||
clkpol 1 1
|
||||
endbram
|
||||
|
||||
match $__MY_DPRAM
|
||||
min efficiency 0
|
||||
make_transp
|
||||
or_next_if_better
|
||||
endmatch
|
||||
|
||||
match $__MY_SPRAM
|
||||
min efficiency 0
|
||||
make_transp
|
||||
endmatch
|
|
@ -0,0 +1,44 @@
|
|||
module $__MY_DPRAM (
|
||||
output[31:0] B1DATA,
|
||||
input CLK1,
|
||||
input[9:0] B1ADDR,
|
||||
input[9:0] A1ADDR,
|
||||
input[31:0] A1DATA,
|
||||
input A1EN,
|
||||
input B1EN );
|
||||
|
||||
generate
|
||||
dpram #() _TECHMAP_REPLACE_ (
|
||||
.clk (CLK1),
|
||||
.wen (A1EN),
|
||||
.waddr (A1ADDR),
|
||||
.d_in (A1DATA),
|
||||
.ren (B1EN),
|
||||
.raddr (B1ADDR),
|
||||
.d_out (B1DATA) );
|
||||
endgenerate
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
|
||||
module $__MY_SPRAM (
|
||||
output[31:0] B1DATA,
|
||||
input CLK1,
|
||||
input[9:0] B1ADDR,
|
||||
input[9:0] A1ADDR,
|
||||
input[31:0] A1DATA,
|
||||
input A1EN );
|
||||
|
||||
generate
|
||||
dpram #() _TECHMAP_REPLACE_ (
|
||||
.clk (CLK1),
|
||||
.wen (A1EN),
|
||||
.waddr (A1ADDR),
|
||||
.d_in (A1DATA),
|
||||
.ren (1'b1),
|
||||
.raddr (A1ADDR),
|
||||
.d_out (B1DATA) );
|
||||
endgenerate
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,62 @@
|
|||
module dpram (
|
||||
input clk,
|
||||
input wen,
|
||||
input ren,
|
||||
input[9:0] waddr,
|
||||
input[9:0] raddr,
|
||||
input[31:0] d_in,
|
||||
output[31:0] d_out );
|
||||
|
||||
dual_port_sram memory_0 (
|
||||
.wclk (clk),
|
||||
.wen (wen),
|
||||
.waddr (waddr),
|
||||
.data_in (d_in),
|
||||
.rclk (clk),
|
||||
.ren (ren),
|
||||
.raddr (raddr),
|
||||
.d_out (d_out) );
|
||||
|
||||
endmodule
|
||||
|
||||
module dual_port_sram (
|
||||
input wclk,
|
||||
input wen,
|
||||
input[9:0] waddr,
|
||||
input[31:0] data_in,
|
||||
input rclk,
|
||||
input ren,
|
||||
input[9:0] raddr,
|
||||
output[31:0] d_out );
|
||||
|
||||
reg[31:0] ram[1023:0];
|
||||
reg[31:0] internal;
|
||||
|
||||
assign d_out = internal;
|
||||
|
||||
always @(posedge wclk) begin
|
||||
if(wen) begin
|
||||
ram[waddr] <= data_in;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge rclk) begin
|
||||
if(ren) begin
|
||||
internal <= ram[raddr];
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module adder(
|
||||
input cin,
|
||||
input a,
|
||||
input b,
|
||||
output cout,
|
||||
output sumout );
|
||||
|
||||
|
||||
assign sumout = a ^ b ^ cin;
|
||||
assign cout = (a & b) | ((a | b) & cin);
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,164 @@
|
|||
//////////////////////////
|
||||
// arithmetic //
|
||||
//////////////////////////
|
||||
|
||||
module \$alu (A, B, CI, BI, X, Y, CO);
|
||||
|
||||
parameter A_SIGNED = 0;
|
||||
parameter B_SIGNED = 0;
|
||||
parameter A_WIDTH = 1;
|
||||
parameter B_WIDTH = 1;
|
||||
parameter Y_WIDTH = 1;
|
||||
|
||||
input [A_WIDTH-1:0] A;
|
||||
input [B_WIDTH-1:0] B;
|
||||
output [Y_WIDTH:0] X, Y;
|
||||
|
||||
input CI, BI;
|
||||
output [Y_WIDTH:0] CO;
|
||||
|
||||
wire [Y_WIDTH-1:0] AA, BB;
|
||||
wire [1024:0] _TECHMAP_DO_ = "splitnets CARRY; clean";
|
||||
|
||||
generate
|
||||
if (A_SIGNED && B_SIGNED) begin:BLOCK1
|
||||
assign AA = $signed(A), BB = BI ? ~$signed(B) : $signed(B);
|
||||
end else begin:BLOCK2
|
||||
assign AA = $unsigned(A), BB = BI ? ~$unsigned(B) : $unsigned(B);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
wire [Y_WIDTH: 0 ] CARRY;
|
||||
assign CARRY[0] = CI;
|
||||
|
||||
genvar i;
|
||||
generate for (i = 0; i < Y_WIDTH - 1; i = i+1) begin:gen3
|
||||
adder my_adder (
|
||||
.cin (CARRY[i]),
|
||||
.cout (CARRY[i+1]),
|
||||
.a (AA[i]),
|
||||
.b (BB[i]),
|
||||
.sumout (Y[i])
|
||||
);
|
||||
end endgenerate
|
||||
|
||||
generate if ((Y_WIDTH -1) % 20 == 0) begin:gen4
|
||||
assign Y[Y_WIDTH-1] = CARRY[Y_WIDTH-1];
|
||||
end else begin:gen5
|
||||
adder my_adder (
|
||||
.cin (CARRY[Y_WIDTH - 1]),
|
||||
.cout (CARRY[Y_WIDTH]),
|
||||
.a (1'b0),
|
||||
.b (1'b0),
|
||||
.sumout (Y[Y_WIDTH -1])
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
endmodule
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
||||
module \$fa (A, B, C, X, Y);
|
||||
|
||||
parameter A_SIGNED = 0;
|
||||
parameter B_SIGNED = 0;
|
||||
parameter A_WIDTH = 1;
|
||||
parameter B_WIDTH = 1;
|
||||
parameter Y_WIDTH = 1;
|
||||
|
||||
input [A_WIDTH-1:0] A;
|
||||
input [B_WIDTH-1:0] B;
|
||||
input C;
|
||||
output [Y_WIDTH:0] X, Y;
|
||||
|
||||
wire [Y_WIDTH-1:0] AA, BB;
|
||||
wire [1024:0] _TECHMAP_DO_ = "splitnets CARRY; clean";
|
||||
|
||||
generate
|
||||
if (A_SIGNED && B_SIGNED) begin:BLOCK1
|
||||
assign AA = $signed(A), BB = $signed(B);
|
||||
end else begin:BLOCK2
|
||||
assign AA = $unsigned(A), BB = $unsigned(B);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
wire [Y_WIDTH: 0 ] CARRY;
|
||||
assign CARRY[0] = C;
|
||||
|
||||
genvar i;
|
||||
generate for (i = 0; i < Y_WIDTH - 1; i = i+1) begin:gen3
|
||||
adder my_adder (
|
||||
.cin (CARRY[i]),
|
||||
.cout (CARRY[i+1]),
|
||||
.a (AA[i]),
|
||||
.b (BB[i]),
|
||||
.sumout (Y[i])
|
||||
);
|
||||
end endgenerate
|
||||
|
||||
generate if ((Y_WIDTH -1) % 20 == 0) begin:gen4
|
||||
assign Y[Y_WIDTH-1] = CARRY[Y_WIDTH-1];
|
||||
end else begin:gen5
|
||||
adder my_adder (
|
||||
.cin (CARRY[Y_WIDTH - 1]),
|
||||
.cout (CARRY[Y_WIDTH]),
|
||||
.a (1'b0),
|
||||
.b (1'b0),
|
||||
.sumout (Y[Y_WIDTH -1])
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
endmodule
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
||||
module \$add (A, B, Y);
|
||||
|
||||
parameter A_SIGNED = 0;
|
||||
parameter B_SIGNED = 0;
|
||||
parameter A_WIDTH = 1;
|
||||
parameter B_WIDTH = 1;
|
||||
parameter Y_WIDTH = 1;
|
||||
|
||||
input [A_WIDTH-1:0] A;
|
||||
input [B_WIDTH-1:0] B;
|
||||
output [Y_WIDTH:0] Y;
|
||||
|
||||
wire [Y_WIDTH-1:0] AA, BB;
|
||||
wire [1024:0] _TECHMAP_DO_ = "splitnets CARRY; clean";
|
||||
|
||||
generate
|
||||
if (A_SIGNED && B_SIGNED) begin:BLOCK1
|
||||
assign AA = $signed(A), BB = $signed(B);
|
||||
end else begin:BLOCK2
|
||||
assign AA = $unsigned(A), BB = $unsigned(B);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
wire [Y_WIDTH: 0 ] CARRY;
|
||||
assign CARRY[0] = 1'b0;
|
||||
|
||||
genvar i;
|
||||
generate for (i = 0; i < Y_WIDTH - 1; i = i+1) begin:gen3
|
||||
adder my_adder (
|
||||
.cin (CARRY[i]),
|
||||
.cout (CARRY[i+1]),
|
||||
.a (AA[i]),
|
||||
.b (BB[i]),
|
||||
.sumout (Y[i])
|
||||
);
|
||||
end endgenerate
|
||||
|
||||
generate if ((Y_WIDTH -1) % 20 == 0) begin:gen4
|
||||
assign Y[Y_WIDTH-1] = CARRY[Y_WIDTH-1];
|
||||
end else begin:gen5
|
||||
adder my_adder (
|
||||
.cin (CARRY[Y_WIDTH - 1]),
|
||||
.cout (CARRY[Y_WIDTH]),
|
||||
.a (1'b0),
|
||||
.b (1'b0),
|
||||
.sumout (Y[Y_WIDTH -1])
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
endmodule
|
|
@ -0,0 +1,41 @@
|
|||
# Yosys synthesis script for alu4
|
||||
# read Verilog
|
||||
read_verilog /full_path/design.v #can be repeated if project has many files
|
||||
read_verilog -lib /full_path/cells_sim.v # file we provide
|
||||
|
||||
hierarchy -check -top top_module
|
||||
proc
|
||||
|
||||
flatten
|
||||
tribuf -logic
|
||||
|
||||
synth -run coarse
|
||||
opt -fast
|
||||
|
||||
memory -nomap
|
||||
opt_clean
|
||||
|
||||
|
||||
memory_bram -rules /full_OpenFPGA_path/openfpga_flow/misc/OpenFPGA_lib/brams.txt
|
||||
techmap -map /full_OpenFPGA_path/openfpga_flow/misc/OpenFPGA_lib/brams_map.v
|
||||
opt -fast -mux_undef -undriven -fine
|
||||
memory_map
|
||||
|
||||
# Technology mapping
|
||||
#proc
|
||||
techmap -D NO_LUT -map /full_OpenFPGA_path/openfpga_flow/misc/OpenFPGA_lib/fpga_techmap.v -map +/adff2dff.v
|
||||
|
||||
# Synthesis
|
||||
synth -top top_module -flatten -run fine
|
||||
clean
|
||||
|
||||
# LUT mapping
|
||||
abc -lut 6
|
||||
|
||||
# Check
|
||||
synth -run check
|
||||
|
||||
# Clean and output blif
|
||||
opt_clean -purge
|
||||
write_blif design.blif
|
||||
write_verilog design.v
|
|
@ -0,0 +1,59 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# 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_template.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.blif
|
||||
|
||||
[SYNTHESIS_PARAM]
|
||||
bench0_top = test_modes
|
||||
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.act
|
||||
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.v
|
||||
|
||||
#[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_verilog_explicit_mapping=
|
||||
#vpr_fpga_x2p_compact_routing_hierarchy=
|
||||
vpr_fpga_x2p_duplicate_grid_pin=
|
||||
end_flow_with_test=
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# 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 = 200*60
|
||||
fpga_flow=yosys_vpr
|
||||
|
||||
[ARCHITECTURES]
|
||||
#arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml
|
||||
#arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k4_N4_sram_chain_FC_behavioral_verilog_template.xml
|
||||
arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/adder/adder.v
|
||||
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/arbiter/arbiter.v
|
||||
bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/bar/bar.v
|
||||
bench3=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/cavlc/cavlc.v
|
||||
bench4=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/ctrl/ctrl.v
|
||||
bench5=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/dec/dec.v
|
||||
bench6=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/div/div.v
|
||||
# This benchmark is failing -> debug ongoing
|
||||
#bench7=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/hyp/hyp.v
|
||||
bench8=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/i2c/i2c.v
|
||||
bench9=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/int2float/int2float.v
|
||||
bench10=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/log2/log2.v
|
||||
bench11=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/max/max.v
|
||||
# This benchmark is commented because of its runtime
|
||||
#bench12=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/mem_ctrl/mem_ctrl.v
|
||||
bench13=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/multiplier/multiplier.v
|
||||
bench14=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/priority/priority.v
|
||||
bench15=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/router/router.v
|
||||
bench16=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/sin/sin.v
|
||||
bench17=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/sqrt/sqrt.v
|
||||
bench18=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/square/square.v
|
||||
bench19=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/epfl/voter/voter.v
|
||||
|
||||
[SYNTHESIS_PARAM]
|
||||
bench0_top = adder
|
||||
bench1_top = arbiter
|
||||
bench2_top = bar
|
||||
bench3_top = cavlc
|
||||
bench4_top = ctrl
|
||||
bench5_top = dec
|
||||
bench6_top = div
|
||||
#bench7_top = hyp
|
||||
bench8_top = i2c
|
||||
bench9_top = int2float
|
||||
bench10_top = log2
|
||||
bench11_top = max
|
||||
bench12_top = mem_ctrl
|
||||
bench13_top = multiplier
|
||||
bench14_top = priority
|
||||
bench15_top = router
|
||||
bench16_top = sin
|
||||
bench17_top = sqrt
|
||||
bench18_top = square
|
||||
bench19_top = voter
|
||||
|
||||
#[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_verilog_explicit_mapping=
|
||||
vpr_fpga_x2p_compact_routing_hierarchy=
|
||||
# If you wish to run Modelsim verification in batch, turn on the ini file outputting
|
||||
vpr_fpga_verilog_print_simulation_ini=
|
||||
# If you wish to run Modelsim verification in batch, turn off running iVerilog at the end of the flow
|
||||
#end_flow_with_test=
|
||||
|
|
@ -65,6 +65,7 @@ struct s_TokenPair OptionBaseTokenList[] = {
|
|||
{ "fpga_x2p_sim_window_size", OT_FPGA_X2P_SIM_WINDOW_SIZE }, /* Window size in determining number of clock cycles in simulation */
|
||||
{ "fpga_x2p_compact_routing_hierarchy", OT_FPGA_X2P_COMPACT_ROUTING_HIERARCHY }, /* use a compact routing hierarchy in SPICE/Verilog generation */
|
||||
{ "fpga_x2p_output_sb_xml", OT_FPGA_X2P_OUTPUT_SB_XML }, /* use a compact routing hierarchy in SPICE/Verilog generation */
|
||||
{ "fpga_x2p_duplicate_grid_pin", OT_FPGA_X2P_DUPLICATE_GRID_PIN }, /* Duplicate the pins at each side of a grid when generating SPICE and Verilog netlists */
|
||||
/* Xifan TANG: FPGA SPICE Support */
|
||||
{ "fpga_spice", OT_FPGA_SPICE },/* Xifan TANG: SPICE Model Support, turn on the functionality*/
|
||||
{ "fpga_spice_dir", OT_FPGA_SPICE_DIR },/* Xifan TANG: SPICE Model Support, directory of spice netlists*/
|
||||
|
|
|
@ -82,6 +82,7 @@ enum e_OptionBaseToken {
|
|||
OT_FPGA_X2P_SIM_WINDOW_SIZE, /* Window size in determining number of clock cycles in simulation */
|
||||
OT_FPGA_X2P_COMPACT_ROUTING_HIERARCHY, /* use a compact routing hierarchy in SPICE/Verilog generation */
|
||||
OT_FPGA_X2P_OUTPUT_SB_XML, /* output switch blocks to XML files */
|
||||
OT_FPGA_X2P_DUPLICATE_GRID_PIN, /* Duplicate the pins at each side of a grid when generating SPICE and Verilog netlists */
|
||||
/* Xifan TANG: FPGA SPICE Support */
|
||||
OT_FPGA_SPICE, /* Xifan TANG: FPGA SPICE Model Support */
|
||||
OT_FPGA_SPICE_DIR, /* Xifan TANG: FPGA SPICE Model Support */
|
||||
|
|
|
@ -491,6 +491,8 @@ ProcessOption(INP char **Args, INOUTP t_options * Options) {
|
|||
case OT_FPGA_X2P_OUTPUT_SB_XML:
|
||||
/* Read the file prefix to output SB XML files */
|
||||
return ReadString(Args, &Options->sb_xml_dir);
|
||||
case OT_FPGA_X2P_DUPLICATE_GRID_PIN:
|
||||
return Args;
|
||||
/* Xifan TANG: FPGA SPICE Model Options*/
|
||||
case OT_FPGA_SPICE:
|
||||
return Args;
|
||||
|
|
|
@ -1275,6 +1275,12 @@ static void SetupFpgaSpiceOpts(t_options Options,
|
|||
fpga_spice_opts->sb_xml_dir = Options.sb_xml_dir;
|
||||
}
|
||||
|
||||
/* Check if user wants to duplicate the pin at each side of grids */
|
||||
fpga_spice_opts->duplicate_grid_pin = FALSE;
|
||||
if (Options.Count[OT_FPGA_X2P_DUPLICATE_GRID_PIN]) {
|
||||
fpga_spice_opts->duplicate_grid_pin = TRUE;
|
||||
}
|
||||
|
||||
/* Decide if we need to do FPGA-SPICE */
|
||||
fpga_spice_opts->do_fpga_spice = FALSE;
|
||||
if (( TRUE == fpga_spice_opts->SpiceOpts.do_spice)
|
||||
|
|
|
@ -175,6 +175,7 @@ void vpr_print_usage(void) {
|
|||
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_x2p_sim_window_size <float>\n");
|
||||
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_x2p_compact_routing_hierarchy\n");
|
||||
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_x2p_output_sb_xml <directory_path_output_switch_block_XML>\n");
|
||||
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_x2p_duplicate_grid_pin\n");
|
||||
vpr_printf(TIO_MESSAGE_INFO, "SPICE Support Options:\n");
|
||||
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_spice\n");
|
||||
vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_spice_dir <directory_path_output_spice_netlists>\n");
|
||||
|
|
|
@ -1302,6 +1302,7 @@ struct s_fpga_spice_opts {
|
|||
t_bitstream_gen_opts BitstreamGenOpts; /* Xifan Bitsteam Generator */
|
||||
|
||||
boolean compact_routing_hierarchy; /* use compact routing hierarchy */
|
||||
boolean duplicate_grid_pin; /* Duplicate pins at each side of the grid */
|
||||
|
||||
/* Signal Density */
|
||||
float signal_density_weight;
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
rm tags
|
||||
ctags -R shell_main.c main.c ./* ../../libarchfpga/SRC/* ../../pcre/SRC/*.[ch]
|
||||
ctags -R shell_main.c main.c ./* ../../libarchfpga/SRC/* ../../libpcre/SRC/*.[ch] ../../../libs/libvtrutil/src/*
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const RRGSB& rr_gsb,
|
||||
|
@ -77,9 +76,9 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp,
|
|||
port_coord.set_x(unique_mirror.get_cb_x(cb_type));
|
||||
port_coord.set_y(unique_mirror.get_cb_y(cb_type));
|
||||
}
|
||||
std::string port_name = generate_routing_track_port_name(cb_type,
|
||||
port_coord, itrack,
|
||||
IN_PORT);
|
||||
std::string port_name = generate_cb_module_track_port_name(cb_type,
|
||||
itrack,
|
||||
IN_PORT);
|
||||
|
||||
/* Ensure we have this port in the module! */
|
||||
ModulePortId module_port = module_manager.find_module_port(cb_module, port_name);
|
||||
|
@ -108,9 +107,9 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp,
|
|||
port_coord.set_x(unique_mirror.get_cb_x(cb_type));
|
||||
port_coord.set_y(unique_mirror.get_cb_y(cb_type));
|
||||
}
|
||||
std::string port_name = generate_routing_track_port_name(cb_type,
|
||||
port_coord, itrack,
|
||||
OUT_PORT);
|
||||
std::string port_name = generate_cb_module_track_port_name(cb_type,
|
||||
itrack,
|
||||
OUT_PORT);
|
||||
|
||||
/* Ensure we have this port in the module! */
|
||||
ModulePortId module_port = module_manager.find_module_port(cb_module, port_name);
|
||||
|
@ -145,10 +144,8 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp,
|
|||
}
|
||||
|
||||
vtr::Point<size_t> port_coord(ipin_node->xlow, ipin_node->ylow);
|
||||
std::string port_name = generate_grid_side_port_name(grids,
|
||||
port_coord,
|
||||
rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode),
|
||||
ipin_node->ptc_num);
|
||||
std::string port_name = generate_cb_module_grid_port_name(cb_ipin_side,
|
||||
ipin_node->ptc_num);
|
||||
|
||||
/* Find the port in unique mirror! */
|
||||
if (true == compact_routing_hierarchy) {
|
||||
|
@ -158,10 +155,8 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp,
|
|||
t_rr_node* unique_mirror_ipin_node = unique_mirror.get_ipin_node(cb_ipin_side, inode);
|
||||
port_coord.set_x(unique_mirror_ipin_node->xlow);
|
||||
port_coord.set_y(unique_mirror_ipin_node->ylow);
|
||||
port_name = generate_grid_side_port_name(grids,
|
||||
port_coord,
|
||||
unique_mirror.get_ipin_node_grid_side(cb_ipin_side, inode),
|
||||
unique_mirror_ipin_node->ptc_num);
|
||||
port_name = generate_cb_module_grid_port_name(cb_ipin_side,
|
||||
unique_mirror_ipin_node->ptc_num);
|
||||
}
|
||||
|
||||
/* Ensure we have this port in the module! */
|
||||
|
@ -204,9 +199,9 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp,
|
|||
port_coord.set_x(unique_mirror.get_cb_x(cb_type));
|
||||
port_coord.set_y(unique_mirror.get_cb_y(cb_type));
|
||||
}
|
||||
std::string port_name = generate_routing_track_port_name(cb_type,
|
||||
port_coord, itrack,
|
||||
OUT_PORT);
|
||||
std::string port_name = generate_cb_module_track_port_name(cb_type,
|
||||
itrack,
|
||||
OUT_PORT);
|
||||
|
||||
/* Ensure we have this port in the module! */
|
||||
ModulePortId module_port = module_manager.find_module_port(cb_module, port_name);
|
||||
|
@ -227,7 +222,6 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp,
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_analysis_sdc_disable_unused_cb_ports(std::fstream& fp,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
|
@ -246,7 +240,7 @@ void print_analysis_sdc_disable_unused_cb_ports(std::fstream& fp,
|
|||
continue;
|
||||
}
|
||||
|
||||
print_analysis_sdc_disable_cb_unused_resources(fp, grids,
|
||||
print_analysis_sdc_disable_cb_unused_resources(fp,
|
||||
module_manager,
|
||||
L_device_rr_gsb,
|
||||
rr_gsb,
|
||||
|
@ -261,16 +255,15 @@ void print_analysis_sdc_disable_unused_cb_ports(std::fstream& fp,
|
|||
* and disable unused ports for each of them
|
||||
*******************************************************************/
|
||||
void print_analysis_sdc_disable_unused_cbs(std::fstream& fp,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
|
||||
print_analysis_sdc_disable_unused_cb_ports(fp, grids, module_manager,
|
||||
print_analysis_sdc_disable_unused_cb_ports(fp, module_manager,
|
||||
L_device_rr_gsb,
|
||||
CHANX, compact_routing_hierarchy);
|
||||
|
||||
print_analysis_sdc_disable_unused_cb_ports(fp, grids, module_manager,
|
||||
print_analysis_sdc_disable_unused_cb_ports(fp, module_manager,
|
||||
L_device_rr_gsb,
|
||||
CHANY, compact_routing_hierarchy);
|
||||
}
|
||||
|
@ -283,7 +276,6 @@ void print_analysis_sdc_disable_unused_cbs(std::fstream& fp,
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_analysis_sdc_disable_sb_unused_resources(std::fstream& fp,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const RRGSB& rr_gsb,
|
||||
|
@ -327,9 +319,9 @@ void print_analysis_sdc_disable_sb_unused_resources(std::fstream& fp,
|
|||
t_rr_node* chan_node = rr_gsb.get_chan_node(side_manager.get_side(), itrack);
|
||||
|
||||
vtr::Point<size_t> port_coord(port_coordinate.get_x(), port_coordinate.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));
|
||||
std::string port_name = generate_sb_module_track_port_name(rr_gsb.get_chan_node(side_manager.get_side(), itrack)->type,
|
||||
side_manager.get_side(), itrack,
|
||||
rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack));
|
||||
|
||||
if (true == compact_routing_hierarchy) {
|
||||
/* Note: use GSB coordinate when inquire for unique modules!!! */
|
||||
|
@ -338,9 +330,9 @@ void print_analysis_sdc_disable_sb_unused_resources(std::fstream& fp,
|
|||
DeviceCoordinator unique_port_coordinate = unique_mirror.get_side_block_coordinator(side_manager.get_side());
|
||||
port_coord.set_x(unique_port_coordinate.get_x());
|
||||
port_coord.set_y(unique_port_coordinate.get_y());
|
||||
port_name = generate_routing_track_port_name(unique_mirror.get_chan_node(side_manager.get_side(), itrack)->type,
|
||||
port_coord, itrack,
|
||||
unique_mirror.get_chan_node_direction(side_manager.get_side(), itrack));
|
||||
port_name = generate_sb_module_track_port_name(unique_mirror.get_chan_node(side_manager.get_side(), itrack)->type,
|
||||
side_manager.get_side(), itrack,
|
||||
unique_mirror.get_chan_node_direction(side_manager.get_side(), itrack));
|
||||
}
|
||||
|
||||
/* Ensure we have this port in the module! */
|
||||
|
@ -375,9 +367,9 @@ void print_analysis_sdc_disable_sb_unused_resources(std::fstream& fp,
|
|||
vtr::Point<size_t> 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(grids, port_coord,
|
||||
rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode),
|
||||
opin_node->ptc_num);
|
||||
std::string port_name = generate_sb_module_grid_port_name(side_manager.get_side(),
|
||||
rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode),
|
||||
opin_node->ptc_num);
|
||||
|
||||
if (true == compact_routing_hierarchy) {
|
||||
/* Note: use GSB coordinate when inquire for unique modules!!! */
|
||||
|
@ -386,9 +378,9 @@ void print_analysis_sdc_disable_sb_unused_resources(std::fstream& fp,
|
|||
port_coord.set_x(unique_mirror.get_opin_node(side_manager.get_side(), inode)->xlow);
|
||||
port_coord.set_y(unique_mirror.get_opin_node(side_manager.get_side(), inode)->ylow);
|
||||
|
||||
port_name = generate_grid_side_port_name(grids, port_coord,
|
||||
unique_mirror.get_opin_node_grid_side(side_manager.get_side(), inode),
|
||||
unique_mirror.get_opin_node(side_manager.get_side(), inode)->ptc_num);
|
||||
port_name = generate_sb_module_grid_port_name(side_manager.get_side(),
|
||||
unique_mirror.get_opin_node_grid_side(side_manager.get_side(), inode),
|
||||
unique_mirror.get_opin_node(side_manager.get_side(), inode)->ptc_num);
|
||||
}
|
||||
|
||||
|
||||
|
@ -440,9 +432,9 @@ void print_analysis_sdc_disable_sb_unused_resources(std::fstream& fp,
|
|||
vtr::Point<size_t> 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(grids, port_coord,
|
||||
rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode),
|
||||
opin_node->ptc_num);
|
||||
std::string port_name = generate_sb_module_grid_port_name(side_manager.get_side(),
|
||||
rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode),
|
||||
opin_node->ptc_num);
|
||||
|
||||
if (true == compact_routing_hierarchy) {
|
||||
/* Note: use GSB coordinate when inquire for unique modules!!! */
|
||||
|
@ -451,9 +443,9 @@ void print_analysis_sdc_disable_sb_unused_resources(std::fstream& fp,
|
|||
port_coord.set_x(unique_mirror.get_opin_node(side_manager.get_side(), inode)->xlow);
|
||||
port_coord.set_y(unique_mirror.get_opin_node(side_manager.get_side(), inode)->ylow);
|
||||
|
||||
port_name = generate_grid_side_port_name(grids, port_coord,
|
||||
unique_mirror.get_opin_node_grid_side(side_manager.get_side(), inode),
|
||||
unique_mirror.get_opin_node(side_manager.get_side(), inode)->ptc_num);
|
||||
port_name = generate_sb_module_grid_port_name(side_manager.get_side(),
|
||||
unique_mirror.get_opin_node_grid_side(side_manager.get_side(), inode),
|
||||
unique_mirror.get_opin_node(side_manager.get_side(), inode)->ptc_num);
|
||||
}
|
||||
|
||||
|
||||
|
@ -484,9 +476,9 @@ void print_analysis_sdc_disable_sb_unused_resources(std::fstream& fp,
|
|||
t_rr_node* chan_node = rr_gsb.get_chan_node(side_manager.get_side(), itrack);
|
||||
|
||||
vtr::Point<size_t> port_coord(port_coordinate.get_x(), port_coordinate.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));
|
||||
std::string port_name = generate_sb_module_track_port_name(rr_gsb.get_chan_node(side_manager.get_side(), itrack)->type,
|
||||
side_manager.get_side(), itrack,
|
||||
rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack));
|
||||
|
||||
if (true == compact_routing_hierarchy) {
|
||||
/* Note: use GSB coordinate when inquire for unique modules!!! */
|
||||
|
@ -496,9 +488,9 @@ void print_analysis_sdc_disable_sb_unused_resources(std::fstream& fp,
|
|||
port_coord.set_x(unique_port_coordinate.get_x());
|
||||
port_coord.set_y(unique_port_coordinate.get_y());
|
||||
|
||||
port_name = generate_routing_track_port_name(unique_mirror.get_chan_node(side_manager.get_side(), itrack)->type,
|
||||
port_coord, itrack,
|
||||
unique_mirror.get_chan_node_direction(side_manager.get_side(), itrack));
|
||||
port_name = generate_sb_module_track_port_name(unique_mirror.get_chan_node(side_manager.get_side(), itrack)->type,
|
||||
side_manager.get_side(), itrack,
|
||||
unique_mirror.get_chan_node_direction(side_manager.get_side(), itrack));
|
||||
}
|
||||
|
||||
|
||||
|
@ -522,7 +514,6 @@ void print_analysis_sdc_disable_sb_unused_resources(std::fstream& fp,
|
|||
* and disable unused ports for each of them
|
||||
*******************************************************************/
|
||||
void print_analysis_sdc_disable_unused_sbs(std::fstream& fp,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
|
@ -538,7 +529,7 @@ void print_analysis_sdc_disable_unused_sbs(std::fstream& fp,
|
|||
*/
|
||||
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
|
||||
|
||||
print_analysis_sdc_disable_sb_unused_resources(fp, grids,
|
||||
print_analysis_sdc_disable_sb_unused_resources(fp,
|
||||
module_manager,
|
||||
L_device_rr_gsb,
|
||||
rr_gsb,
|
||||
|
|
|
@ -8,13 +8,11 @@
|
|||
#include "vpr_types.h"
|
||||
|
||||
void print_analysis_sdc_disable_unused_cbs(std::fstream& fp,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const bool& compact_routing_hierarchy);
|
||||
|
||||
void print_analysis_sdc_disable_unused_sbs(std::fstream& fp,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const bool& compact_routing_hierarchy);
|
||||
|
|
|
@ -244,13 +244,13 @@ void print_analysis_sdc(const std::string& sdc_dir,
|
|||
|
||||
|
||||
/* Disable timing for unused routing resources in connection blocks */
|
||||
print_analysis_sdc_disable_unused_cbs(fp, L_grids,
|
||||
print_analysis_sdc_disable_unused_cbs(fp,
|
||||
module_manager,
|
||||
L_device_rr_gsb,
|
||||
compact_routing_hierarchy);
|
||||
|
||||
/* Disable timing for unused routing resources in switch blocks */
|
||||
print_analysis_sdc_disable_unused_sbs(fp, L_grids,
|
||||
print_analysis_sdc_disable_unused_sbs(fp,
|
||||
module_manager,
|
||||
L_device_rr_gsb,
|
||||
compact_routing_hierarchy);
|
||||
|
|
|
@ -43,7 +43,6 @@ void print_pnr_sdc_constrain_sb_mux_timing(std::fstream& fp,
|
|||
const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const e_side& output_node_side,
|
||||
t_rr_node* output_rr_node) {
|
||||
|
@ -70,7 +69,6 @@ void print_pnr_sdc_constrain_sb_mux_timing(std::fstream& fp,
|
|||
std::vector<ModulePortId> module_input_ports = find_switch_block_module_input_ports(module_manager,
|
||||
sb_module,
|
||||
rr_gsb,
|
||||
grids,
|
||||
input_rr_nodes);
|
||||
|
||||
/* Find timing constraints for each path (edge) */
|
||||
|
@ -103,7 +101,6 @@ void print_pnr_sdc_constrain_sb_mux_timing(std::fstream& fp,
|
|||
static
|
||||
void print_pnr_sdc_constrain_sb_timing(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const RRGSB& rr_gsb) {
|
||||
|
||||
|
@ -141,7 +138,7 @@ void print_pnr_sdc_constrain_sb_timing(const std::string& sdc_dir,
|
|||
print_pnr_sdc_constrain_sb_mux_timing(fp,
|
||||
module_manager, sb_module,
|
||||
rr_gsb,
|
||||
grids, switches,
|
||||
switches,
|
||||
side_manager.get_side(),
|
||||
chan_rr_node);
|
||||
}
|
||||
|
@ -157,7 +154,6 @@ void print_pnr_sdc_constrain_sb_timing(const std::string& sdc_dir,
|
|||
*******************************************************************/
|
||||
void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb) {
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
|
@ -174,7 +170,7 @@ void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_di
|
|||
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
|
||||
print_pnr_sdc_constrain_sb_timing(sdc_dir,
|
||||
module_manager,
|
||||
grids, switches,
|
||||
switches,
|
||||
rr_gsb);
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +190,6 @@ void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_di
|
|||
*******************************************************************/
|
||||
void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb) {
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
|
@ -207,7 +202,7 @@ void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_di
|
|||
const RRGSB& rr_gsb = L_device_rr_gsb.get_sb_unique_module(isb);
|
||||
print_pnr_sdc_constrain_sb_timing(sdc_dir,
|
||||
module_manager,
|
||||
grids, switches,
|
||||
switches,
|
||||
rr_gsb);
|
||||
}
|
||||
|
||||
|
@ -230,7 +225,6 @@ void print_pnr_sdc_constrain_cb_mux_timing(std::fstream& fp,
|
|||
const ModuleId& cb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
t_rr_node* output_rr_node) {
|
||||
/* Validate file stream */
|
||||
|
@ -251,7 +245,7 @@ void print_pnr_sdc_constrain_cb_mux_timing(std::fstream& fp,
|
|||
ModulePortId module_output_port = find_connection_block_module_ipin_port(module_manager,
|
||||
cb_module,
|
||||
rr_gsb,
|
||||
grids, output_rr_node);
|
||||
output_rr_node);
|
||||
|
||||
/* Find the module port corresponding to the fan-in rr_nodes of the output rr_node */
|
||||
std::vector<t_rr_node*> input_rr_nodes;
|
||||
|
@ -295,7 +289,6 @@ void print_pnr_sdc_constrain_cb_timing(const std::string& sdc_dir,
|
|||
const ModuleManager& module_manager,
|
||||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches) {
|
||||
/* Create the netlist */
|
||||
vtr::Point<size_t> gsb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||
|
@ -327,7 +320,7 @@ void print_pnr_sdc_constrain_cb_timing(const std::string& sdc_dir,
|
|||
print_pnr_sdc_constrain_cb_mux_timing(fp,
|
||||
module_manager, cb_module,
|
||||
rr_gsb, cb_type,
|
||||
grids, switches,
|
||||
switches,
|
||||
ipin_rr_node);
|
||||
}
|
||||
}
|
||||
|
@ -344,7 +337,6 @@ static
|
|||
void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const t_rr_type& cb_type) {
|
||||
/* Build unique X-direction connection block modules */
|
||||
|
@ -364,7 +356,7 @@ void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_di
|
|||
module_manager,
|
||||
rr_gsb,
|
||||
cb_type,
|
||||
grids, switches);
|
||||
switches);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -377,7 +369,6 @@ void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_di
|
|||
void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches) {
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Generating SDC for constrain Connection Block timing for P&R flow...");
|
||||
|
@ -387,13 +378,11 @@ void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_di
|
|||
|
||||
print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, module_manager,
|
||||
L_device_rr_gsb,
|
||||
grids,
|
||||
switches,
|
||||
CHANX);
|
||||
|
||||
print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, module_manager,
|
||||
L_device_rr_gsb,
|
||||
grids,
|
||||
switches,
|
||||
CHANY);
|
||||
|
||||
|
@ -412,7 +401,6 @@ void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_di
|
|||
*******************************************************************/
|
||||
void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb) {
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
|
@ -428,7 +416,7 @@ void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_di
|
|||
module_manager,
|
||||
unique_mirror,
|
||||
CHANX,
|
||||
grids, switches);
|
||||
switches);
|
||||
}
|
||||
|
||||
/* Print SDC for unique Y-direction connection block modules */
|
||||
|
@ -438,7 +426,7 @@ void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_di
|
|||
module_manager,
|
||||
unique_mirror,
|
||||
CHANY,
|
||||
grids, switches);
|
||||
switches);
|
||||
}
|
||||
|
||||
/* End time count */
|
||||
|
|
|
@ -9,25 +9,21 @@
|
|||
|
||||
void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb);
|
||||
|
||||
void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb);
|
||||
|
||||
void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches);
|
||||
|
||||
void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb);
|
||||
|
||||
|
|
|
@ -387,7 +387,6 @@ void print_pnr_sdc_compact_routing_disable_switch_block_outputs(const std::strin
|
|||
*******************************************************************/
|
||||
void print_pnr_sdc(const SdcOption& sdc_options,
|
||||
const float& critical_path_delay,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const ModuleManager& module_manager,
|
||||
|
@ -426,8 +425,8 @@ void print_pnr_sdc(const SdcOption& sdc_options,
|
|||
} else {
|
||||
VTR_ASSERT_SAFE (false == compact_routing_hierarchy);
|
||||
print_pnr_sdc_flatten_routing_disable_switch_block_outputs(sdc_options.sdc_dir(),
|
||||
module_manager,
|
||||
L_device_rr_gsb);
|
||||
module_manager,
|
||||
L_device_rr_gsb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -436,13 +435,13 @@ void print_pnr_sdc(const SdcOption& sdc_options,
|
|||
if (true == compact_routing_hierarchy) {
|
||||
print_pnr_sdc_compact_routing_constrain_sb_timing(sdc_options.sdc_dir(),
|
||||
module_manager,
|
||||
grids, switches,
|
||||
switches,
|
||||
L_device_rr_gsb);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE (false == compact_routing_hierarchy);
|
||||
print_pnr_sdc_flatten_routing_constrain_sb_timing(sdc_options.sdc_dir(),
|
||||
module_manager,
|
||||
grids, switches,
|
||||
switches,
|
||||
L_device_rr_gsb);
|
||||
}
|
||||
}
|
||||
|
@ -452,7 +451,6 @@ void print_pnr_sdc(const SdcOption& sdc_options,
|
|||
if (true == compact_routing_hierarchy) {
|
||||
print_pnr_sdc_compact_routing_constrain_cb_timing(sdc_options.sdc_dir(),
|
||||
module_manager,
|
||||
grids,
|
||||
switches,
|
||||
L_device_rr_gsb);
|
||||
} else {
|
||||
|
@ -460,7 +458,6 @@ void print_pnr_sdc(const SdcOption& sdc_options,
|
|||
print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_options.sdc_dir(),
|
||||
module_manager,
|
||||
L_device_rr_gsb,
|
||||
grids,
|
||||
switches);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
void print_pnr_sdc(const SdcOption& sdc_options,
|
||||
const float& critical_path_delay,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const ModuleManager& module_manager,
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
*******************************************************************/
|
||||
void fpga_sdc_generator(const SdcOption& sdc_options,
|
||||
const float& critical_path_delay,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& rr_switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const std::vector<t_logical_block>& L_logical_blocks,
|
||||
|
@ -32,7 +31,7 @@ void fpga_sdc_generator(const SdcOption& sdc_options,
|
|||
|
||||
if (true == sdc_options.generate_sdc_pnr()) {
|
||||
print_pnr_sdc(sdc_options, critical_path_delay,
|
||||
grids, rr_switches, L_device_rr_gsb,
|
||||
rr_switches, L_device_rr_gsb,
|
||||
module_manager, mux_lib,
|
||||
circuit_lib, global_ports,
|
||||
compact_routing_hierarchy);
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
void fpga_sdc_generator(const SdcOption& sdc_options,
|
||||
const float& critical_path_delay,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& rr_switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const std::vector<t_logical_block>& L_logical_blocks,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <vector>
|
||||
|
||||
/* Include vpr structs*/
|
||||
#include "vtr_assert.h"
|
||||
#include "util.h"
|
||||
#include "physical_types.h"
|
||||
#include "vpr_types.h"
|
||||
|
@ -137,9 +138,17 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup,
|
|||
|
||||
/* Xifan TANG: Synthesizable verilog dumping */
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_syn_verilog) {
|
||||
/* Create a local SRAM organization info
|
||||
* TODO: This should be deprecated in future */
|
||||
VTR_ASSERT(NULL != Arch.sram_inf.verilog_sram_inf_orgz); /* Check !*/
|
||||
t_spice_model* sram_verilog_model = Arch.sram_inf.verilog_sram_inf_orgz->spice_model;
|
||||
/* initialize the SRAM organization information struct */
|
||||
t_sram_orgz_info* sram_verilog_orgz_info = alloc_one_sram_orgz_info();
|
||||
init_sram_orgz_info(sram_verilog_orgz_info, Arch.sram_inf.verilog_sram_inf_orgz->type, sram_verilog_model, nx + 2, ny + 2);
|
||||
|
||||
vpr_fpga_verilog(module_manager, bitstream_manager, fabric_bitstream, mux_lib,
|
||||
L_logical_blocks, device_size, grids, L_blocks,
|
||||
vpr_setup, Arch, vpr_setup.FileNameOpts.CircuitName);
|
||||
L_logical_blocks, device_size, grids, L_blocks, device_rr_gsb,
|
||||
vpr_setup, Arch, std::string(vpr_setup.FileNameOpts.CircuitName), sram_verilog_orgz_info);
|
||||
}
|
||||
|
||||
|
||||
|
@ -154,12 +163,15 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup,
|
|||
sdc_options.set_generate_sdc_pnr(TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_sdc_pnr);
|
||||
sdc_options.set_generate_sdc_analysis(TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_sdc_analysis);
|
||||
|
||||
/* Create directory to contain the SDC files */
|
||||
create_dir_path(sdc_options.sdc_dir().c_str());
|
||||
|
||||
if (true == sdc_options.generate_sdc()) {
|
||||
std::vector<CircuitPortId> global_ports = find_circuit_library_global_ports(Arch.spice->circuit_lib);
|
||||
/* TODO: the critical path delay unit should be explicit! */
|
||||
fpga_sdc_generator(sdc_options,
|
||||
Arch.spice->spice_params.stimulate_params.vpr_crit_path_delay / 1e-9,
|
||||
grids, rr_switches, device_rr_gsb,
|
||||
rr_switches, device_rr_gsb,
|
||||
L_logical_blocks, device_size, grids, L_blocks,
|
||||
module_manager, mux_lib,
|
||||
Arch.spice->circuit_lib, global_ports,
|
||||
|
|
|
@ -244,6 +244,8 @@ std::string generate_routing_channel_module_name(const t_rr_type& chan_type,
|
|||
/*********************************************************************
|
||||
* Generate the port name for a routing track with a given coordinate
|
||||
* and port direction
|
||||
* This function is mainly used in naming routing tracks in the top-level netlists
|
||||
* where we do need unique names (with coordinates) for each routing tracks
|
||||
*********************************************************************/
|
||||
std::string generate_routing_track_port_name(const t_rr_type& chan_type,
|
||||
const vtr::Point<size_t>& coordinate,
|
||||
|
@ -281,6 +283,99 @@ std::string generate_routing_track_port_name(const t_rr_type& chan_type,
|
|||
return port_name;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for a routing track in a Switch Block module
|
||||
* This function is created to ease the PnR for each unique routing module
|
||||
* So it is mainly used when creating non-top-level modules!
|
||||
* Note that this function does not include any port coordinate
|
||||
* Instead, we use the relative location of the pins in the context of routing modules
|
||||
* so that each module can be instanciated across the fabric
|
||||
* Even though, port direction must be provided!
|
||||
*********************************************************************/
|
||||
std::string generate_sb_module_track_port_name(const t_rr_type& chan_type,
|
||||
const e_side& module_side,
|
||||
const size_t& track_id,
|
||||
const PORTS& port_direction) {
|
||||
/* Channel must be either CHANX or CHANY */
|
||||
VTR_ASSERT( (CHANX == chan_type) || (CHANY == chan_type) );
|
||||
|
||||
/* Create a map between chan_type and module_prefix */
|
||||
std::map<t_rr_type, std::string> module_prefix_map;
|
||||
/* TODO: use a constexpr string to replace the fixed name? */
|
||||
module_prefix_map[CHANX] = std::string("chanx");
|
||||
module_prefix_map[CHANY] = std::string("chany");
|
||||
|
||||
std::string port_name = module_prefix_map[chan_type];
|
||||
port_name += std::string("_");
|
||||
|
||||
Side side_manager(module_side);
|
||||
port_name += std::string(side_manager.to_string());
|
||||
port_name += 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 port name for a routing track in a Connection Block module
|
||||
* This function is created to ease the PnR for each unique routing module
|
||||
* So it is mainly used when creating non-top-level modules!
|
||||
* Note that this function does not include any port coordinate
|
||||
* Instead, we use the relative location of the pins in the context of routing modules
|
||||
* so that each module can be instanciated across the fabric
|
||||
* Even though, port direction must be provided!
|
||||
*********************************************************************/
|
||||
std::string generate_cb_module_track_port_name(const t_rr_type& chan_type,
|
||||
const size_t& track_id,
|
||||
const PORTS& port_direction) {
|
||||
/* Channel must be either CHANX or CHANY */
|
||||
VTR_ASSERT( (CHANX == chan_type) || (CHANY == chan_type) );
|
||||
|
||||
/* Create a map between chan_type and module_prefix */
|
||||
std::map<t_rr_type, std::string> module_prefix_map;
|
||||
/* TODO: use a constexpr string to replace the fixed name? */
|
||||
module_prefix_map[CHANX] = std::string("chanx");
|
||||
module_prefix_map[CHANY] = std::string("chany");
|
||||
|
||||
std::string port_name = module_prefix_map[chan_type];
|
||||
port_name += std::string("_");
|
||||
|
||||
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 middle output port name for a routing track
|
||||
* with a given coordinate
|
||||
|
@ -339,9 +434,9 @@ std::string generate_connection_block_module_name(const t_rr_type& cb_type,
|
|||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for a Grid
|
||||
* TODO: add more comments about why we need different names for
|
||||
* top and non-top netlists
|
||||
* Generate the port name for a grid in top-level netlists, i.e., full FPGA fabric
|
||||
* This function will generate a full port name including coordinates
|
||||
* so that each pin in top-level netlists is unique!
|
||||
*********************************************************************/
|
||||
std::string generate_grid_port_name(const vtr::Point<size_t>& coordinate,
|
||||
const size_t& height,
|
||||
|
@ -374,6 +469,50 @@ std::string generate_grid_port_name(const vtr::Point<size_t>& coordinate,
|
|||
return port_name;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for a grid with duplication
|
||||
* This function will generate two types of port names.
|
||||
* One with a postfix of "upper"
|
||||
* The other with a postfix of "lower"
|
||||
*********************************************************************/
|
||||
std::string generate_grid_duplicated_port_name(const size_t& height,
|
||||
const e_side& side,
|
||||
const size_t& pin_id,
|
||||
const bool& upper_port) {
|
||||
/* For non-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("_");
|
||||
|
||||
if (true == upper_port) {
|
||||
port_name += std::string("upper");
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(false == upper_port);
|
||||
port_name += std::string("lower");
|
||||
}
|
||||
|
||||
return port_name;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for a grid in the context of a module
|
||||
* To keep a short and simple name, this function will not
|
||||
* include any grid coorindate information!
|
||||
*********************************************************************/
|
||||
std::string generate_grid_module_port_name(const size_t& pin_id) {
|
||||
/* For non-top netlist */
|
||||
std::string port_name = std::string("grid_");
|
||||
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 Grid
|
||||
* This is a wrapper function for generate_port_name()
|
||||
|
@ -396,6 +535,72 @@ std::string generate_grid_side_port_name(const std::vector<std::vector<t_grid_ti
|
|||
return generate_grid_port_name(coordinate, height, side, pin_id, true);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name of a grid pin for a routing module,
|
||||
* which could be a switch block or a connection block
|
||||
* Note that to ensure unique grid port name in the context of a routing module,
|
||||
* we need a prefix which denotes the relative location of the port in the routing module
|
||||
*
|
||||
* The prefix is created by considering the the grid coordinate
|
||||
* and switch block coordinate
|
||||
* Detailed rules in conversion is as follows:
|
||||
*
|
||||
* top_left top_right
|
||||
* +------------------------+
|
||||
* left_top | | right_top
|
||||
* | Switch Block |
|
||||
* | [x][y] |
|
||||
* | |
|
||||
* | |
|
||||
* left_right | | right_bottom
|
||||
* +------------------------+
|
||||
* bottom_left bottom_right
|
||||
*
|
||||
* +--------------------------------------------------------
|
||||
* | Grid Coordinate | Pin side of grid | module side
|
||||
* +--------------------------------------------------------
|
||||
* | [x][y+1] | right | top_left
|
||||
* +--------------------------------------------------------
|
||||
* | [x][y+1] | bottom | left_top
|
||||
* +--------------------------------------------------------
|
||||
* | [x+1][y+1] | left | top_right
|
||||
* +--------------------------------------------------------
|
||||
* | [x+1][y+1] | bottom | right_top
|
||||
* +--------------------------------------------------------
|
||||
* | [x][y] | top | left_right
|
||||
* +--------------------------------------------------------
|
||||
* | [x][y] | right | bottom_left
|
||||
* +--------------------------------------------------------
|
||||
* | [x+1][y] | top | right_bottom
|
||||
* +--------------------------------------------------------
|
||||
* | [x+1][y] | left | bottom_right
|
||||
* +--------------------------------------------------------
|
||||
*
|
||||
*********************************************************************/
|
||||
std::string generate_sb_module_grid_port_name(const e_side& sb_side,
|
||||
const e_side& grid_side,
|
||||
const size_t& pin_id) {
|
||||
Side sb_side_manager(sb_side);
|
||||
Side grid_side_manager(grid_side);
|
||||
/* Relative location is opposite to the side in grid context */
|
||||
grid_side_manager.set_opposite();
|
||||
std::string prefix = sb_side_manager.to_string() + std::string("_") + grid_side_manager.to_string();
|
||||
return prefix + std::string("_") + generate_grid_module_port_name(pin_id);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name of a grid pin for a routing module,
|
||||
* which could be a switch block or a connection block
|
||||
* Note that to ensure unique grid port name in the context of a routing module,
|
||||
* we need a prefix which denotes the relative location of the port in the routing module
|
||||
*********************************************************************/
|
||||
std::string generate_cb_module_grid_port_name(const e_side& cb_side,
|
||||
const size_t& pin_id) {
|
||||
Side side_manager(cb_side);
|
||||
std::string prefix = side_manager.to_string();
|
||||
return prefix + std::string("_") + generate_grid_module_port_name(pin_id);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* 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
|
||||
|
|
|
@ -69,6 +69,15 @@ std::string generate_routing_track_port_name(const t_rr_type& chan_type,
|
|||
const size_t& track_id,
|
||||
const PORTS& port_direction);
|
||||
|
||||
std::string generate_sb_module_track_port_name(const t_rr_type& chan_type,
|
||||
const e_side& module_side,
|
||||
const size_t& track_id,
|
||||
const PORTS& port_direction);
|
||||
|
||||
std::string generate_cb_module_track_port_name(const t_rr_type& chan_type,
|
||||
const size_t& track_id,
|
||||
const PORTS& port_direction);
|
||||
|
||||
std::string generate_routing_track_middle_output_port_name(const t_rr_type& chan_type,
|
||||
const vtr::Point<size_t>& coordinate,
|
||||
const size_t& track_id);
|
||||
|
@ -112,10 +121,19 @@ std::string generate_grid_port_name(const vtr::Point<size_t>& coordinate,
|
|||
const size_t& pin_id,
|
||||
const bool& for_top_netlist);
|
||||
|
||||
std::string generate_grid_side_port_name(const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const vtr::Point<size_t>& coordinate,
|
||||
const e_side& side,
|
||||
const size_t& pin_id);
|
||||
std::string generate_grid_duplicated_port_name(const size_t& height,
|
||||
const e_side& side,
|
||||
const size_t& pin_id,
|
||||
const bool& upper_port);
|
||||
|
||||
std::string generate_grid_module_port_name(const size_t& pin_id);
|
||||
|
||||
std::string generate_sb_module_grid_port_name(const e_side& sb_side,
|
||||
const e_side& grid_side,
|
||||
const size_t& pin_id);
|
||||
|
||||
std::string generate_cb_module_grid_port_name(const e_side& cb_side,
|
||||
const size_t& pin_id);
|
||||
|
||||
std::string generate_reserved_sram_port_name(const e_spice_model_port_type& port_type);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/********************************************************************
|
||||
* Most utilized functions in FPGA X2P framework
|
||||
*******************************************************************/
|
||||
#include <sys/stat.h>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -54,8 +55,8 @@ std::string find_path_file_name(const std::string& file_name) {
|
|||
if (found != std::string::npos) {
|
||||
return file_name.substr(found + 1);
|
||||
}
|
||||
/* Not found, return an empty string */
|
||||
return std::string();
|
||||
/* Not found. The input is the file name! Return the original string */
|
||||
return file_name;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
@ -133,3 +134,43 @@ std::vector<size_t> my_itobin_vec(const size_t& in_int, const size_t& bin_len) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Create a directory with a given path
|
||||
********************************************************************/
|
||||
bool create_dir_path(const char* dir_path) {
|
||||
/* Give up if the path is empty */
|
||||
if (NULL == dir_path) {
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"dir_path is empty and nothing is created.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Try to create a directory */
|
||||
int ret = mkdir(dir_path, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH);
|
||||
|
||||
/* Analyze the return flag and output status */
|
||||
switch (ret) {
|
||||
case 0:
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Create directory(%s)...successfully.\n",
|
||||
dir_path);
|
||||
return true;
|
||||
case -1:
|
||||
if (EEXIST == errno) {
|
||||
vpr_printf(TIO_MESSAGE_WARNING,
|
||||
"Directory(%s) already exists. Will overwrite contents\n",
|
||||
dir_path);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"Create directory(%s)...Failed!\n",
|
||||
dir_path);
|
||||
exit(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ std::string find_path_file_name(const std::string& file_name);
|
|||
|
||||
std::vector<size_t> my_itobin_vec(const size_t& in_int, const size_t& bin_len);
|
||||
|
||||
bool create_dir_path(const char* dir_path);
|
||||
|
||||
/* Old functions */
|
||||
|
||||
char* my_gettime();
|
||||
|
|
|
@ -843,6 +843,7 @@ int RRGSB::get_node_index(t_rr_node* node,
|
|||
&&(node_direction == chan_node_direction_[side_manager.to_size_t()][inode])) {
|
||||
cnt++;
|
||||
ret = inode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -851,6 +852,7 @@ int RRGSB::get_node_index(t_rr_node* node,
|
|||
if (node == ipin_node_[side_manager.to_size_t()][inode]) {
|
||||
cnt++;
|
||||
ret = inode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -859,11 +861,14 @@ int RRGSB::get_node_index(t_rr_node* node,
|
|||
if (node == opin_node_[side_manager.to_size_t()][inode]) {
|
||||
cnt++;
|
||||
ret = inode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid cur_rr_node type! Should be [CHANX|CHANY|IPIN|OPIN]\n", __FILE__, __LINE__);
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])Invalid cur_rr_node type! Should be [CHANX|CHANY|IPIN|OPIN]\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -105,16 +105,17 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup,
|
|||
|
||||
/* Build grid and programmable block modules */
|
||||
build_grid_modules(module_manager, arch.spice->circuit_lib, mux_lib,
|
||||
arch.sram_inf.verilog_sram_inf_orgz->type, sram_model);
|
||||
arch.sram_inf.verilog_sram_inf_orgz->type, sram_model,
|
||||
TRUE == vpr_setup.FPGA_SPICE_Opts.duplicate_grid_pin);
|
||||
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy) {
|
||||
build_unique_routing_modules(module_manager, L_device_rr_gsb, arch.spice->circuit_lib,
|
||||
arch.sram_inf.verilog_sram_inf_orgz->type, sram_model, grids,
|
||||
arch.sram_inf.verilog_sram_inf_orgz->type, sram_model,
|
||||
vpr_setup.RoutingArch, rr_switches);
|
||||
} else {
|
||||
VTR_ASSERT(FALSE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy);
|
||||
build_flatten_routing_modules(module_manager, L_device_rr_gsb, arch.spice->circuit_lib,
|
||||
arch.sram_inf.verilog_sram_inf_orgz->type, sram_model, grids,
|
||||
arch.sram_inf.verilog_sram_inf_orgz->type, sram_model,
|
||||
vpr_setup.RoutingArch, rr_switches);
|
||||
}
|
||||
|
||||
|
@ -124,7 +125,8 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup,
|
|||
device_size, grids, L_device_rr_gsb,
|
||||
clb2clb_directs,
|
||||
arch.sram_inf.verilog_sram_inf_orgz->type, sram_model,
|
||||
TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy);
|
||||
TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy,
|
||||
TRUE == vpr_setup.FPGA_SPICE_Opts.duplicate_grid_pin);
|
||||
|
||||
/* Now a critical correction has to be done!
|
||||
* In the module construction, we always use prefix of ports because they are binded
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
/********************************************************************
|
||||
* This file includes functions that are used to add duplicated
|
||||
* pins to each side of a grid
|
||||
*
|
||||
* These functions are located in this file, being separated from
|
||||
* the default functions in build_grid_module.cpp
|
||||
* This allows us to keep new features easy to be maintained.
|
||||
*
|
||||
* Please follow this rules when creating new features!
|
||||
*******************************************************************/
|
||||
/* External library headers */
|
||||
#include "vtr_assert.h"
|
||||
|
||||
/* FPGA-X2P headers */
|
||||
#include "fpga_x2p_naming.h"
|
||||
|
||||
/* Module builder headers */
|
||||
#include "build_grid_module_utils.h"
|
||||
#include "build_grid_module_duplicated_pins.h"
|
||||
|
||||
/* Global variables should be the last to include */
|
||||
#include "globals.h"
|
||||
|
||||
/********************************************************************
|
||||
* This function adds pb_type ports to top-level grid module with duplication
|
||||
* For each pin at each side, we create two pins which are short-wired
|
||||
* They are driven by the same pin, e.g., pinA in the child module
|
||||
* But in this top module, we will create two pins, each of which indicates
|
||||
* the physical location of pin.
|
||||
* Take the following example:
|
||||
* One is called pinA_upper which is located close to the top side of this grid
|
||||
* The other is called pinA_lower which is located close to the bottom side of this grid
|
||||
*
|
||||
* Similarly, we duplicate pins at TOP, RIGHT, BOTTOM and LEFT sides.
|
||||
* For LEFT side, upper and lower pins carry the indication in physical location as RIGHT side.
|
||||
* For TOP and BOTTOM side, upper pin is located close to the left side of a grid, while lower
|
||||
* pin is located close to the right side of a grid
|
||||
*
|
||||
* pinB_upper pinB_lower
|
||||
* ^ ^
|
||||
* | |
|
||||
* ---------------+
|
||||
* |--->pinA_upper
|
||||
* |
|
||||
* Grid |
|
||||
* |
|
||||
* |--->pinA_lower
|
||||
* ---------------+
|
||||
*******************************************************************/
|
||||
void add_grid_module_duplicated_pb_type_ports(ModuleManager& module_manager,
|
||||
const ModuleId& grid_module,
|
||||
t_type_ptr grid_type_descriptor,
|
||||
const e_side& border_side) {
|
||||
/* Ensure that we have a valid grid_type_descriptor */
|
||||
VTR_ASSERT(NULL != grid_type_descriptor);
|
||||
|
||||
/* Find the pin side for I/O grids*/
|
||||
std::vector<e_side> grid_pin_sides;
|
||||
/* For I/O grids, we care only one side
|
||||
* Otherwise, we will iterate all the 4 sides
|
||||
*/
|
||||
if (IO_TYPE == grid_type_descriptor) {
|
||||
grid_pin_sides.push_back(find_grid_module_pin_side(grid_type_descriptor, border_side));
|
||||
} else {
|
||||
grid_pin_sides = {TOP, RIGHT, BOTTOM, LEFT};
|
||||
}
|
||||
|
||||
/* Create a map between pin class type and grid pin direction */
|
||||
std::map<e_pin_type, ModuleManager::e_module_port_type> pin_type2type_map;
|
||||
pin_type2type_map[RECEIVER] = ModuleManager::MODULE_INPUT_PORT;
|
||||
pin_type2type_map[DRIVER] = ModuleManager::MODULE_OUTPUT_PORT;
|
||||
|
||||
/* Iterate over sides, height and pins */
|
||||
for (const e_side& side : grid_pin_sides) {
|
||||
for (int iheight = 0; iheight < grid_type_descriptor->height; ++iheight) {
|
||||
for (int ipin = 0; ipin < grid_type_descriptor->num_pins; ++ipin) {
|
||||
if (1 != grid_type_descriptor->pinloc[iheight][side][ipin]) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here, it means this pin is on this side */
|
||||
int class_id = grid_type_descriptor->pin_class[ipin];
|
||||
e_pin_type pin_class_type = grid_type_descriptor->class_inf[class_id].type;
|
||||
/* Generate the pin name */
|
||||
if (RECEIVER == pin_class_type) {
|
||||
/* For each RECEIVER PIN, we do not duplicate */
|
||||
vtr::Point<size_t> dummy_coordinate;
|
||||
std::string port_name = generate_grid_port_name(dummy_coordinate, iheight, side, ipin, false);
|
||||
BasicPort grid_port(port_name, 0, 0);
|
||||
/* Add the port to the module */
|
||||
module_manager.add_port(grid_module, grid_port, pin_type2type_map[pin_class_type]);
|
||||
} else {
|
||||
/* For each DRIVER pin, we create two copies.
|
||||
* One with a postfix of upper, indicating it is located on the upper part of a side
|
||||
* The other with a postfix of lower, indicating it is located on the lower part of a side
|
||||
*/
|
||||
VTR_ASSERT(DRIVER == pin_class_type);
|
||||
std::string upper_port_name = generate_grid_duplicated_port_name(iheight, side, ipin, true);
|
||||
BasicPort grid_upper_port(upper_port_name, 0, 0);
|
||||
/* Add the port to the module */
|
||||
module_manager.add_port(grid_module, grid_upper_port, pin_type2type_map[pin_class_type]);
|
||||
|
||||
std::string lower_port_name = generate_grid_duplicated_port_name(iheight, side, ipin, false);
|
||||
BasicPort grid_lower_port(lower_port_name, 0, 0);
|
||||
/* Add the port to the module */
|
||||
module_manager.add_port(grid_module, grid_lower_port, pin_type2type_map[pin_class_type]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add module nets to connect a port of child pb_module
|
||||
* to the duplicated pins of grid module
|
||||
* Note: This function SHOULD be ONLY applied to pb_graph output pins
|
||||
* of the child module.
|
||||
* For each such pin, we connect it to two outputs of the grid module
|
||||
* one is named after "upper", and the other is named after "lower"
|
||||
*******************************************************************/
|
||||
static
|
||||
void add_grid_module_net_connect_duplicated_pb_graph_pin(ModuleManager& module_manager,
|
||||
const ModuleId& grid_module,
|
||||
const ModuleId& child_module,
|
||||
const size_t& child_instance,
|
||||
t_type_ptr grid_type_descriptor,
|
||||
t_pb_graph_pin* pb_graph_pin,
|
||||
const e_side& border_side,
|
||||
const enum e_spice_pin2pin_interc_type& pin2pin_interc_type) {
|
||||
/* Make sure this is ONLY applied to output pins */
|
||||
VTR_ASSERT(OUTPUT2OUTPUT_INTERC == pin2pin_interc_type);
|
||||
|
||||
/* Find the pin side for I/O grids*/
|
||||
std::vector<e_side> grid_pin_sides;
|
||||
/* For I/O grids, we care only one side
|
||||
* Otherwise, we will iterate all the 4 sides
|
||||
*/
|
||||
if (IO_TYPE == grid_type_descriptor) {
|
||||
grid_pin_sides.push_back(find_grid_module_pin_side(grid_type_descriptor, border_side));
|
||||
} else {
|
||||
grid_pin_sides.push_back(TOP);
|
||||
grid_pin_sides.push_back(RIGHT);
|
||||
grid_pin_sides.push_back(BOTTOM);
|
||||
grid_pin_sides.push_back(LEFT);
|
||||
}
|
||||
|
||||
/* num_pins/capacity = the number of pins that each type_descriptor has.
|
||||
* Capacity defines the number of type_descriptors in each grid
|
||||
* so the pin index at grid level = pin_index_in_type_descriptor
|
||||
* + type_descriptor_index_in_capacity * num_pins_per_type_descriptor
|
||||
*/
|
||||
size_t grid_pin_index = pb_graph_pin->pin_count_in_cluster
|
||||
+ child_instance * grid_type_descriptor->num_pins / grid_type_descriptor->capacity;
|
||||
int pin_height = grid_type_descriptor->pin_height[grid_pin_index];
|
||||
for (const e_side& side : grid_pin_sides) {
|
||||
if (1 != grid_type_descriptor->pinloc[pin_height][side][grid_pin_index]) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here, it means this pin is on this side */
|
||||
/* Create a net to connect the grid pin to child module pin */
|
||||
ModuleNetId net = module_manager.create_module_net(grid_module);
|
||||
/* Find the upper port in grid_module */
|
||||
std::string grid_upper_port_name = generate_grid_duplicated_port_name(pin_height, side, grid_pin_index, true);
|
||||
ModulePortId grid_module_upper_port_id = module_manager.find_module_port(grid_module, grid_upper_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_module_upper_port_id));
|
||||
|
||||
/* Find the lower port in grid_module */
|
||||
std::string grid_lower_port_name = generate_grid_duplicated_port_name(pin_height, side, grid_pin_index, false);
|
||||
ModulePortId grid_module_lower_port_id = module_manager.find_module_port(grid_module, grid_lower_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_module_lower_port_id));
|
||||
|
||||
/* Grid port always has only 1 pin, it is assumed when adding these ports to the module
|
||||
* if you need a change, please also change the port adding codes
|
||||
*/
|
||||
size_t grid_module_pin_id = 0;
|
||||
/* Find the port in child module */
|
||||
std::string child_module_port_name = generate_pb_type_port_name(pb_graph_pin->port);
|
||||
ModulePortId child_module_port_id = module_manager.find_module_port(child_module, child_module_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(child_module, child_module_port_id));
|
||||
size_t child_module_pin_id = pb_graph_pin->pin_number;
|
||||
|
||||
/* Add net sources and sinks:
|
||||
* For output-to-output connection,
|
||||
* net_source is pb_graph_pin,
|
||||
* while net_sinks are grid upper pin and grid lower pin
|
||||
*/
|
||||
module_manager.add_module_net_source(grid_module, net, child_module, child_instance, child_module_port_id, child_module_pin_id);
|
||||
module_manager.add_module_net_sink(grid_module, net, grid_module, 0, grid_module_upper_port_id, grid_module_pin_id);
|
||||
module_manager.add_module_net_sink(grid_module, net, grid_module, 0, grid_module_lower_port_id, grid_module_pin_id);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add module nets to connect a port of child pb_module
|
||||
* to the duplicated ports of grid module
|
||||
*******************************************************************/
|
||||
void add_grid_module_nets_connect_duplicated_pb_type_ports(ModuleManager& module_manager,
|
||||
const ModuleId& grid_module,
|
||||
const ModuleId& child_module,
|
||||
const size_t& child_instance,
|
||||
t_type_ptr grid_type_descriptor,
|
||||
const e_side& border_side) {
|
||||
/* Ensure that we have a valid grid_type_descriptor */
|
||||
VTR_ASSERT(NULL != grid_type_descriptor);
|
||||
t_pb_graph_node* top_pb_graph_node = grid_type_descriptor->pb_graph_head;
|
||||
VTR_ASSERT(NULL != top_pb_graph_node);
|
||||
|
||||
for (int iport = 0; iport < top_pb_graph_node->num_input_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < top_pb_graph_node->num_input_pins[iport]; ++ipin) {
|
||||
add_grid_module_net_connect_pb_graph_pin(module_manager, grid_module,
|
||||
child_module, child_instance,
|
||||
grid_type_descriptor,
|
||||
&(top_pb_graph_node->input_pins[iport][ipin]),
|
||||
border_side,
|
||||
INPUT2INPUT_INTERC);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (int iport = 0; iport < top_pb_graph_node->num_output_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < top_pb_graph_node->num_output_pins[iport]; ++ipin) {
|
||||
add_grid_module_net_connect_duplicated_pb_graph_pin(module_manager, grid_module,
|
||||
child_module, child_instance,
|
||||
grid_type_descriptor,
|
||||
&(top_pb_graph_node->output_pins[iport][ipin]),
|
||||
border_side,
|
||||
OUTPUT2OUTPUT_INTERC);
|
||||
}
|
||||
}
|
||||
|
||||
for (int iport = 0; iport < top_pb_graph_node->num_clock_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < top_pb_graph_node->num_clock_pins[iport]; ++ipin) {
|
||||
add_grid_module_net_connect_pb_graph_pin(module_manager, grid_module,
|
||||
child_module, child_instance,
|
||||
grid_type_descriptor,
|
||||
&(top_pb_graph_node->clock_pins[iport][ipin]),
|
||||
border_side,
|
||||
INPUT2INPUT_INTERC);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef BUILD_GRID_MODULE_DUPLICATED_PINS_H
|
||||
#define BUILD_GRID_MODULE_DUPLICATED_PINS_H
|
||||
|
||||
#include "module_manager.h"
|
||||
#include "sides.h"
|
||||
#include "vpr_types.h"
|
||||
|
||||
void add_grid_module_duplicated_pb_type_ports(ModuleManager& module_manager,
|
||||
const ModuleId& grid_module,
|
||||
t_type_ptr grid_type_descriptor,
|
||||
const e_side& border_side);
|
||||
|
||||
void add_grid_module_nets_connect_duplicated_pb_type_ports(ModuleManager& module_manager,
|
||||
const ModuleId& grid_module,
|
||||
const ModuleId& child_module,
|
||||
const size_t& child_instance,
|
||||
t_type_ptr grid_type_descriptor,
|
||||
const e_side& border_side);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,106 @@
|
|||
/********************************************************************
|
||||
* This file includes most utilized functions for grid module builders
|
||||
*******************************************************************/
|
||||
/* External library headers */
|
||||
#include "vtr_assert.h"
|
||||
|
||||
/* FPGA-X2P headers */
|
||||
#include "fpga_x2p_naming.h"
|
||||
|
||||
/* Module builder headers */
|
||||
#include "build_grid_module_utils.h"
|
||||
|
||||
/* Global variables should be the last to include */
|
||||
#include "globals.h"
|
||||
|
||||
/********************************************************************
|
||||
* Find the side where I/O pins locate on a grid I/O block
|
||||
* 1. I/O grids on the top side of FPGA only have ports on its bottom side
|
||||
* 2. I/O grids on the right side of FPGA only have ports on its left side
|
||||
* 3. I/O grids on the bottom side of FPGA only have ports on its top side
|
||||
* 4. I/O grids on the left side of FPGA only have ports on its right side
|
||||
*******************************************************************/
|
||||
e_side find_grid_module_pin_side(t_type_ptr grid_type_descriptor,
|
||||
const e_side& border_side) {
|
||||
VTR_ASSERT(IO_TYPE == grid_type_descriptor);
|
||||
Side side_manager(border_side);
|
||||
return side_manager.get_opposite();
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add module nets to connect a port of child pb_module
|
||||
* to the grid module
|
||||
*******************************************************************/
|
||||
void add_grid_module_net_connect_pb_graph_pin(ModuleManager& module_manager,
|
||||
const ModuleId& grid_module,
|
||||
const ModuleId& child_module,
|
||||
const size_t& child_instance,
|
||||
t_type_ptr grid_type_descriptor,
|
||||
t_pb_graph_pin* pb_graph_pin,
|
||||
const e_side& border_side,
|
||||
const enum e_spice_pin2pin_interc_type& pin2pin_interc_type) {
|
||||
/* Find the pin side for I/O grids*/
|
||||
std::vector<e_side> grid_pin_sides;
|
||||
/* For I/O grids, we care only one side
|
||||
* Otherwise, we will iterate all the 4 sides
|
||||
*/
|
||||
if (IO_TYPE == grid_type_descriptor) {
|
||||
grid_pin_sides.push_back(find_grid_module_pin_side(grid_type_descriptor, border_side));
|
||||
} else {
|
||||
grid_pin_sides.push_back(TOP);
|
||||
grid_pin_sides.push_back(RIGHT);
|
||||
grid_pin_sides.push_back(BOTTOM);
|
||||
grid_pin_sides.push_back(LEFT);
|
||||
}
|
||||
|
||||
/* num_pins/capacity = the number of pins that each type_descriptor has.
|
||||
* Capacity defines the number of type_descriptors in each grid
|
||||
* so the pin index at grid level = pin_index_in_type_descriptor
|
||||
* + type_descriptor_index_in_capacity * num_pins_per_type_descriptor
|
||||
*/
|
||||
size_t grid_pin_index = pb_graph_pin->pin_count_in_cluster
|
||||
+ child_instance * grid_type_descriptor->num_pins / grid_type_descriptor->capacity;
|
||||
int pin_height = grid_type_descriptor->pin_height[grid_pin_index];
|
||||
for (const e_side& side : grid_pin_sides) {
|
||||
if (1 != grid_type_descriptor->pinloc[pin_height][side][grid_pin_index]) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here, it means this pin is on this side */
|
||||
/* Create a net to connect the grid pin to child module pin */
|
||||
ModuleNetId net = module_manager.create_module_net(grid_module);
|
||||
/* Find the port in grid_module */
|
||||
vtr::Point<size_t> dummy_coordinate;
|
||||
std::string grid_port_name = generate_grid_port_name(dummy_coordinate, pin_height, side, grid_pin_index, false);
|
||||
ModulePortId grid_module_port_id = module_manager.find_module_port(grid_module, grid_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_module_port_id));
|
||||
/* Grid port always has only 1 pin, it is assumed when adding these ports to the module
|
||||
* if you need a change, please also change the port adding codes
|
||||
*/
|
||||
size_t grid_module_pin_id = 0;
|
||||
/* Find the port in child module */
|
||||
std::string child_module_port_name = generate_pb_type_port_name(pb_graph_pin->port);
|
||||
ModulePortId child_module_port_id = module_manager.find_module_port(child_module, child_module_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(child_module, child_module_port_id));
|
||||
size_t child_module_pin_id = pb_graph_pin->pin_number;
|
||||
/* Add net sources and sinks:
|
||||
* For input-to-input connection, net_source is grid pin, while net_sink is pb_graph_pin
|
||||
* For output-to-output connection, net_source is pb_graph_pin, while net_sink is grid pin
|
||||
*/
|
||||
switch (pin2pin_interc_type) {
|
||||
case INPUT2INPUT_INTERC:
|
||||
module_manager.add_module_net_source(grid_module, net, grid_module, 0, grid_module_port_id, grid_module_pin_id);
|
||||
module_manager.add_module_net_sink(grid_module, net, child_module, child_instance, child_module_port_id, child_module_pin_id);
|
||||
break;
|
||||
case OUTPUT2OUTPUT_INTERC:
|
||||
module_manager.add_module_net_source(grid_module, net, child_module, child_instance, child_module_port_id, child_module_pin_id);
|
||||
module_manager.add_module_net_sink(grid_module, net, grid_module, 0, grid_module_port_id, grid_module_pin_id);
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) Invalid pin-to-pin interconnection type!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef BUILD_GRID_MODULE_UTILS_H
|
||||
#define BUILD_GRID_MODULE_UTILS_H
|
||||
|
||||
#include "vpr_types.h"
|
||||
#include "sides.h"
|
||||
#include "spice_types.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
e_side find_grid_module_pin_side(t_type_ptr grid_type_descriptor,
|
||||
const e_side& border_side);
|
||||
|
||||
void add_grid_module_net_connect_pb_graph_pin(ModuleManager& module_manager,
|
||||
const ModuleId& grid_module,
|
||||
const ModuleId& child_module,
|
||||
const size_t& child_instance,
|
||||
t_type_ptr grid_type_descriptor,
|
||||
t_pb_graph_pin* pb_graph_pin,
|
||||
const e_side& border_side,
|
||||
const enum e_spice_pin2pin_interc_type& pin2pin_interc_type);
|
||||
|
||||
|
||||
#endif
|
|
@ -27,24 +27,10 @@
|
|||
|
||||
/* Header files for Verilog generator */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_utils.h"
|
||||
#include "build_grid_module_utils.h"
|
||||
#include "build_grid_module_duplicated_pins.h"
|
||||
#include "build_grid_modules.h"
|
||||
|
||||
/********************************************************************
|
||||
* Find the side where I/O pins locate on a grid I/O block
|
||||
* 1. I/O grids on the top side of FPGA only have ports on its bottom side
|
||||
* 2. I/O grids on the right side of FPGA only have ports on its left side
|
||||
* 3. I/O grids on the bottom side of FPGA only have ports on its top side
|
||||
* 4. I/O grids on the left side of FPGA only have ports on its right side
|
||||
*******************************************************************/
|
||||
static
|
||||
e_side find_grid_module_pin_side(t_type_ptr grid_type_descriptor,
|
||||
const e_side& border_side) {
|
||||
VTR_ASSERT(IO_TYPE == grid_type_descriptor);
|
||||
Side side_manager(border_side);
|
||||
return side_manager.get_opposite();
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add ports/pins to a grid module
|
||||
* This function will iterate over all the pins that are defined
|
||||
|
@ -100,85 +86,6 @@ void add_grid_module_pb_type_ports(ModuleManager& module_manager,
|
|||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add module nets to connect a port of child pb_module
|
||||
* to the grid module
|
||||
*******************************************************************/
|
||||
static
|
||||
void add_grid_module_net_connect_pb_graph_pin(ModuleManager& module_manager,
|
||||
const ModuleId& grid_module,
|
||||
const ModuleId& child_module,
|
||||
const size_t& child_instance,
|
||||
t_type_ptr grid_type_descriptor,
|
||||
t_pb_graph_pin* pb_graph_pin,
|
||||
const e_side& border_side,
|
||||
const enum e_spice_pin2pin_interc_type& pin2pin_interc_type) {
|
||||
/* Find the pin side for I/O grids*/
|
||||
std::vector<e_side> grid_pin_sides;
|
||||
/* For I/O grids, we care only one side
|
||||
* Otherwise, we will iterate all the 4 sides
|
||||
*/
|
||||
if (IO_TYPE == grid_type_descriptor) {
|
||||
grid_pin_sides.push_back(find_grid_module_pin_side(grid_type_descriptor, border_side));
|
||||
} else {
|
||||
grid_pin_sides.push_back(TOP);
|
||||
grid_pin_sides.push_back(RIGHT);
|
||||
grid_pin_sides.push_back(BOTTOM);
|
||||
grid_pin_sides.push_back(LEFT);
|
||||
}
|
||||
|
||||
/* num_pins/capacity = the number of pins that each type_descriptor has.
|
||||
* Capacity defines the number of type_descriptors in each grid
|
||||
* so the pin index at grid level = pin_index_in_type_descriptor
|
||||
* + type_descriptor_index_in_capacity * num_pins_per_type_descriptor
|
||||
*/
|
||||
size_t grid_pin_index = pb_graph_pin->pin_count_in_cluster
|
||||
+ child_instance * grid_type_descriptor->num_pins / grid_type_descriptor->capacity;
|
||||
int pin_height = grid_type_descriptor->pin_height[grid_pin_index];
|
||||
for (const e_side& side : grid_pin_sides) {
|
||||
if (1 != grid_type_descriptor->pinloc[pin_height][side][grid_pin_index]) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here, it means this pin is on this side */
|
||||
/* Create a net to connect the grid pin to child module pin */
|
||||
ModuleNetId net = module_manager.create_module_net(grid_module);
|
||||
/* Find the port in grid_module */
|
||||
vtr::Point<size_t> dummy_coordinate;
|
||||
std::string grid_port_name = generate_grid_port_name(dummy_coordinate, pin_height, side, grid_pin_index, false);
|
||||
ModulePortId grid_module_port_id = module_manager.find_module_port(grid_module, grid_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_module_port_id));
|
||||
/* Grid port always has only 1 pin, it is assumed when adding these ports to the module
|
||||
* if you need a change, please also change the port adding codes
|
||||
*/
|
||||
size_t grid_module_pin_id = 0;
|
||||
/* Find the port in child module */
|
||||
std::string child_module_port_name = generate_pb_type_port_name(pb_graph_pin->port);
|
||||
ModulePortId child_module_port_id = module_manager.find_module_port(child_module, child_module_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(child_module, child_module_port_id));
|
||||
size_t child_module_pin_id = pb_graph_pin->pin_number;
|
||||
/* Add net sources and sinks:
|
||||
* For input-to-input connection, net_source is grid pin, while net_sink is pb_graph_pin
|
||||
* For output-to-output connection, net_source is pb_graph_pin, while net_sink is grid pin
|
||||
*/
|
||||
switch (pin2pin_interc_type) {
|
||||
case INPUT2INPUT_INTERC:
|
||||
module_manager.add_module_net_source(grid_module, net, grid_module, 0, grid_module_port_id, grid_module_pin_id);
|
||||
module_manager.add_module_net_sink(grid_module, net, child_module, child_instance, child_module_port_id, child_module_pin_id);
|
||||
break;
|
||||
case OUTPUT2OUTPUT_INTERC:
|
||||
module_manager.add_module_net_source(grid_module, net, child_module, child_instance, child_module_port_id, child_module_pin_id);
|
||||
module_manager.add_module_net_sink(grid_module, net, grid_module, 0, grid_module_port_id, grid_module_pin_id);
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) Invalid pin-to-pin interconnection type!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Add module nets to connect ports/pins of a grid module
|
||||
* to its child modules
|
||||
|
@ -1004,7 +911,8 @@ void build_grid_module(ModuleManager& module_manager,
|
|||
const e_sram_orgz& sram_orgz_type,
|
||||
const CircuitModelId& sram_model,
|
||||
t_type_ptr phy_block_type,
|
||||
const e_side& border_side) {
|
||||
const e_side& border_side,
|
||||
const bool& duplicate_grid_pin) {
|
||||
/* Check code: if this is an IO block, the border side MUST be valid */
|
||||
if (IO_TYPE == phy_block_type) {
|
||||
VTR_ASSERT(NUM_SIDES != border_side);
|
||||
|
@ -1054,14 +962,28 @@ void build_grid_module(ModuleManager& module_manager,
|
|||
}
|
||||
|
||||
/* Add grid ports(pins) to the module */
|
||||
add_grid_module_pb_type_ports(module_manager, grid_module,
|
||||
phy_block_type, border_side);
|
||||
|
||||
/* Add module nets to connect the pb_type ports to sub modules */
|
||||
for (const size_t& child_instance : module_manager.child_module_instances(grid_module, pb_module)) {
|
||||
add_grid_module_nets_connect_pb_type_ports(module_manager, grid_module,
|
||||
pb_module, child_instance,
|
||||
phy_block_type, border_side);
|
||||
if (false == duplicate_grid_pin) {
|
||||
/* Default way to add these ports by following the definition in pb_types */
|
||||
add_grid_module_pb_type_ports(module_manager, grid_module,
|
||||
phy_block_type, border_side);
|
||||
/* Add module nets to connect the pb_type ports to sub modules */
|
||||
for (const size_t& child_instance : module_manager.child_module_instances(grid_module, pb_module)) {
|
||||
add_grid_module_nets_connect_pb_type_ports(module_manager, grid_module,
|
||||
pb_module, child_instance,
|
||||
phy_block_type, border_side);
|
||||
}
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(true == duplicate_grid_pin);
|
||||
/* TODO: Add these ports with duplication */
|
||||
add_grid_module_duplicated_pb_type_ports(module_manager, grid_module,
|
||||
phy_block_type, border_side);
|
||||
|
||||
/* TODO: Add module nets to connect the duplicated pb_type ports to sub modules */
|
||||
for (const size_t& child_instance : module_manager.child_module_instances(grid_module, pb_module)) {
|
||||
add_grid_module_nets_connect_duplicated_pb_type_ports(module_manager, grid_module,
|
||||
pb_module, child_instance,
|
||||
phy_block_type, border_side);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add global ports to the pb_module:
|
||||
|
@ -1113,7 +1035,8 @@ void build_grid_modules(ModuleManager& module_manager,
|
|||
const CircuitLibrary& circuit_lib,
|
||||
const MuxLibrary& mux_lib,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const CircuitModelId& sram_model) {
|
||||
const CircuitModelId& sram_model,
|
||||
const bool& duplicate_grid_pin) {
|
||||
/* Start time count */
|
||||
clock_t t_start = clock();
|
||||
|
||||
|
@ -1132,7 +1055,8 @@ void build_grid_modules(ModuleManager& module_manager,
|
|||
build_grid_module(module_manager, mux_lib, circuit_lib,
|
||||
sram_orgz_type, sram_model,
|
||||
&type_descriptors[itype],
|
||||
side_manager.get_side());
|
||||
side_manager.get_side(),
|
||||
duplicate_grid_pin);
|
||||
}
|
||||
continue;
|
||||
} else if (FILL_TYPE == &type_descriptors[itype]) {
|
||||
|
@ -1140,14 +1064,16 @@ void build_grid_modules(ModuleManager& module_manager,
|
|||
build_grid_module(module_manager, mux_lib, circuit_lib,
|
||||
sram_orgz_type, sram_model,
|
||||
&type_descriptors[itype],
|
||||
NUM_SIDES);
|
||||
NUM_SIDES,
|
||||
duplicate_grid_pin);
|
||||
continue;
|
||||
} else {
|
||||
/* For heterogenenous blocks */
|
||||
build_grid_module(module_manager, mux_lib, circuit_lib,
|
||||
sram_orgz_type, sram_model,
|
||||
&type_descriptors[itype],
|
||||
NUM_SIDES);
|
||||
NUM_SIDES,
|
||||
duplicate_grid_pin);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ void build_grid_modules(ModuleManager& module_manager,
|
|||
const CircuitLibrary& circuit_lib,
|
||||
const MuxLibrary& mux_lib,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const CircuitModelId& sram_model);
|
||||
const CircuitModelId& sram_model,
|
||||
const bool& duplicate_grid_pin);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,9 +30,9 @@ ModulePortId find_switch_block_module_chan_port(const ModuleManager& module_mana
|
|||
DeviceCoordinator chan_rr_node_coordinator = rr_gsb.get_side_block_coordinator(chan_side);
|
||||
|
||||
vtr::Point<size_t> 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_gsb.get_chan_node(chan_side, index)->type,
|
||||
chan_port_coord, index,
|
||||
rr_gsb.get_chan_node_direction(chan_side, index));
|
||||
std::string chan_port_name = generate_sb_module_track_port_name(rr_gsb.get_chan_node(chan_side, index)->type,
|
||||
chan_side, index,
|
||||
rr_gsb.get_chan_node_direction(chan_side, index));
|
||||
|
||||
/* Must find a valid port id in the Switch Block module */
|
||||
ModulePortId chan_port_id = module_manager.find_module_port(sb_module, chan_port_name);
|
||||
|
@ -62,7 +62,6 @@ ModulePortId find_switch_block_module_chan_port(const ModuleManager& module_mana
|
|||
ModulePortId find_switch_block_module_input_port(const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const e_side& input_side,
|
||||
t_rr_node* input_rr_node) {
|
||||
/* Deposit an invalid value */
|
||||
|
@ -73,10 +72,14 @@ ModulePortId find_switch_block_module_input_port(const ModuleManager& module_man
|
|||
case OPIN: {
|
||||
/* Find the coordinator (grid_x and grid_y) for the input port */
|
||||
vtr::Point<size_t> input_port_coord(input_rr_node->xlow, input_rr_node->ylow);
|
||||
std::string input_port_name = generate_grid_side_port_name(grids,
|
||||
input_port_coord,
|
||||
input_side,
|
||||
input_rr_node->ptc_num);
|
||||
|
||||
/* Find the side where the grid pin locates in the grid */
|
||||
enum e_side grid_pin_side = rr_gsb.get_opin_node_grid_side(input_rr_node);
|
||||
VTR_ASSERT(NUM_SIDES != grid_pin_side);
|
||||
|
||||
std::string input_port_name = generate_sb_module_grid_port_name(input_side,
|
||||
grid_pin_side,
|
||||
input_rr_node->ptc_num);
|
||||
/* Must find a valid port id in the Switch Block module */
|
||||
input_port_id = module_manager.find_module_port(sb_module, input_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, input_port_id));
|
||||
|
@ -104,31 +107,19 @@ ModulePortId find_switch_block_module_input_port(const ModuleManager& module_man
|
|||
std::vector<ModulePortId> find_switch_block_module_input_ports(const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_rr_node*>& input_rr_nodes) {
|
||||
std::vector<ModulePortId> input_ports;
|
||||
|
||||
for (auto input_rr_node : input_rr_nodes) {
|
||||
/* Find the side where the input locates in the Switch Block */
|
||||
enum e_side input_pin_side = NUM_SIDES;
|
||||
switch (input_rr_node->type) {
|
||||
case OPIN:
|
||||
input_pin_side = rr_gsb.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_gsb.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(find_switch_block_module_input_port(module_manager, sb_module, rr_gsb, grids, input_pin_side, input_rr_node));
|
||||
/* The input could be at any side of the switch block, find it */
|
||||
int index = -1;
|
||||
rr_gsb.get_node_side_and_index(input_rr_node, IN_PORT, &input_pin_side, &index);
|
||||
VTR_ASSERT(NUM_SIDES != input_pin_side);
|
||||
VTR_ASSERT(-1 != index);
|
||||
|
||||
input_ports.push_back(find_switch_block_module_input_port(module_manager, sb_module, rr_gsb, input_pin_side, input_rr_node));
|
||||
}
|
||||
|
||||
return input_ports;
|
||||
|
@ -152,9 +143,9 @@ ModulePortId find_connection_block_module_chan_port(const ModuleManager& module_
|
|||
vtr::Point<size_t> port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||
int chan_node_track_id = rr_gsb.get_cb_chan_node_index(cb_type, chan_rr_node);
|
||||
/* Create a port description for the middle output */
|
||||
std::string input_port_name = generate_routing_track_port_name(cb_type,
|
||||
port_coord, chan_node_track_id,
|
||||
IN_PORT);
|
||||
std::string input_port_name = generate_cb_module_track_port_name(cb_type,
|
||||
chan_node_track_id,
|
||||
IN_PORT);
|
||||
/* Must find a valid port id in the Switch Block module */
|
||||
input_port_id = module_manager.find_module_port(cb_module, input_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, input_port_id));
|
||||
|
@ -176,7 +167,6 @@ ModulePortId find_connection_block_module_chan_port(const ModuleManager& module_
|
|||
ModulePortId find_connection_block_module_ipin_port(const ModuleManager& module_manager,
|
||||
const ModuleId& cb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
t_rr_node* src_rr_node) {
|
||||
|
||||
/* Ensure the src_rr_node is an input pin of a CLB */
|
||||
|
@ -189,10 +179,8 @@ ModulePortId find_connection_block_module_ipin_port(const ModuleManager& module_
|
|||
rr_gsb.get_node_side_and_index(src_rr_node, OUT_PORT, &cb_ipin_side, &cb_ipin_index);
|
||||
/* We need to be sure that drive_rr_node is part of the CB */
|
||||
VTR_ASSERT((-1 != cb_ipin_index)&&(NUM_SIDES != cb_ipin_side));
|
||||
std::string port_name = generate_grid_side_port_name(grids,
|
||||
port_coord,
|
||||
rr_gsb.get_ipin_node_grid_side(cb_ipin_side, cb_ipin_index),
|
||||
rr_gsb.get_ipin_node(cb_ipin_side, cb_ipin_index)->ptc_num);
|
||||
std::string port_name = generate_cb_module_grid_port_name(cb_ipin_side,
|
||||
rr_gsb.get_ipin_node(cb_ipin_side, cb_ipin_index)->ptc_num);
|
||||
|
||||
/* Must find a valid port id in the Switch Block module */
|
||||
ModulePortId ipin_port_id = module_manager.find_module_port(cb_module, port_name);
|
||||
|
|
|
@ -17,14 +17,12 @@ ModulePortId find_switch_block_module_chan_port(const ModuleManager& module_mana
|
|||
ModulePortId find_switch_block_module_input_port(const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const e_side& input_side,
|
||||
t_rr_node* input_rr_node);
|
||||
|
||||
std::vector<ModulePortId> find_switch_block_module_input_ports(const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_rr_node*>& input_rr_nodes);
|
||||
|
||||
ModulePortId find_connection_block_module_chan_port(const ModuleManager& module_manager,
|
||||
|
@ -36,7 +34,6 @@ ModulePortId find_connection_block_module_chan_port(const ModuleManager& module_
|
|||
ModulePortId find_connection_block_module_ipin_port(const ModuleManager& module_manager,
|
||||
const ModuleId& cb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
t_rr_node* src_rr_node);
|
||||
|
||||
std::vector<ModulePortId> find_connection_block_module_input_ports(const ModuleManager& module_manager,
|
||||
|
|
|
@ -42,17 +42,18 @@ void build_switch_block_module_short_interc(ModuleManager& module_manager,
|
|||
const e_side& chan_side,
|
||||
t_rr_node* cur_rr_node,
|
||||
t_rr_node* drive_rr_node,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::map<ModulePortId, ModuleNetId>& input_port_to_module_nets) {
|
||||
/* Find the name of output port */
|
||||
ModulePortId output_port_id = find_switch_block_module_chan_port(module_manager, sb_module, rr_gsb, chan_side, cur_rr_node, OUT_PORT);
|
||||
enum e_side input_pin_side = chan_side;
|
||||
int index = -1;
|
||||
|
||||
/* Generate the input port object */
|
||||
switch (drive_rr_node->type) {
|
||||
case OPIN:
|
||||
input_pin_side = rr_gsb.get_opin_node_grid_side(drive_rr_node);
|
||||
case OPIN: {
|
||||
rr_gsb.get_node_side_and_index(drive_rr_node, IN_PORT, &input_pin_side, &index);
|
||||
break;
|
||||
}
|
||||
case CHANX:
|
||||
case CHANY: {
|
||||
/* This should be an input in the data structure of RRGSB */
|
||||
|
@ -64,7 +65,6 @@ void build_switch_block_module_short_interc(ModuleManager& module_manager,
|
|||
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_gsb.get_node_side_and_index(drive_rr_node, IN_PORT, &input_pin_side, &index);
|
||||
}
|
||||
break;
|
||||
|
@ -76,7 +76,7 @@ void build_switch_block_module_short_interc(ModuleManager& module_manager,
|
|||
exit(1);
|
||||
}
|
||||
/* Find the name of input port */
|
||||
ModulePortId input_port_id = find_switch_block_module_input_port(module_manager, sb_module, rr_gsb, grids, input_pin_side, drive_rr_node);
|
||||
ModulePortId input_port_id = find_switch_block_module_input_port(module_manager, sb_module, rr_gsb, input_pin_side, drive_rr_node);
|
||||
|
||||
/* The input port and output port must match in size */
|
||||
BasicPort input_port = module_manager.module_port(sb_module, input_port_id);
|
||||
|
@ -101,7 +101,6 @@ void build_switch_block_mux_module(ModuleManager& module_manager,
|
|||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& rr_switches,
|
||||
const e_side& chan_side,
|
||||
const size_t& chan_node_id,
|
||||
|
@ -135,7 +134,7 @@ void build_switch_block_mux_module(ModuleManager& module_manager,
|
|||
module_manager.set_child_instance_name(sb_module, mux_module, mux_instance_id, mux_instance_name);
|
||||
|
||||
/* Generate input ports that are wired to the input bus of the routing multiplexer */
|
||||
std::vector<ModulePortId> sb_input_port_ids = find_switch_block_module_input_ports(module_manager, sb_module, rr_gsb, grids, drive_rr_nodes);
|
||||
std::vector<ModulePortId> sb_input_port_ids = find_switch_block_module_input_ports(module_manager, sb_module, rr_gsb, drive_rr_nodes);
|
||||
|
||||
/* Link input bus port to Switch Block inputs */
|
||||
std::vector<CircuitPortId> mux_model_input_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
|
@ -209,7 +208,6 @@ void build_switch_block_interc_modules(ModuleManager& module_manager,
|
|||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& rr_switches,
|
||||
const e_side& chan_side,
|
||||
const size_t& chan_node_id,
|
||||
|
@ -234,20 +232,19 @@ void build_switch_block_interc_modules(ModuleManager& module_manager,
|
|||
/* Print a special direct connection*/
|
||||
build_switch_block_module_short_interc(module_manager, sb_module,
|
||||
rr_gsb, chan_side, cur_rr_node,
|
||||
cur_rr_node, grids,
|
||||
cur_rr_node,
|
||||
input_port_to_module_nets);
|
||||
} else if (1 == drive_rr_nodes.size()) {
|
||||
/* Print a direct connection*/
|
||||
build_switch_block_module_short_interc(module_manager, sb_module,
|
||||
rr_gsb, chan_side, cur_rr_node,
|
||||
drive_rr_nodes[DEFAULT_SWITCH_ID],
|
||||
grids,
|
||||
input_port_to_module_nets);
|
||||
} else if (1 < drive_rr_nodes.size()) {
|
||||
/* Print the multiplexer, fan_in >= 2 */
|
||||
build_switch_block_mux_module(module_manager,
|
||||
sb_module, rr_gsb, circuit_lib,
|
||||
grids, rr_switches, chan_side, chan_node_id, cur_rr_node,
|
||||
rr_switches, chan_side, chan_node_id, cur_rr_node,
|
||||
drive_rr_nodes,
|
||||
cur_rr_node->drive_switches[DEFAULT_SWITCH_ID],
|
||||
input_port_to_module_nets);
|
||||
|
@ -322,7 +319,6 @@ void build_switch_block_interc_modules(ModuleManager& module_manager,
|
|||
static
|
||||
void build_switch_block_module(ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& rr_switches,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const CircuitModelId& sram_model,
|
||||
|
@ -341,9 +337,9 @@ void build_switch_block_module(ModuleManager& module_manager,
|
|||
|
||||
for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) {
|
||||
vtr::Point<size_t> 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));
|
||||
std::string port_name = generate_sb_module_track_port_name(rr_gsb.get_chan_node(side_manager.get_side(), itrack)->type,
|
||||
side_manager.get_side(), 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)) {
|
||||
|
@ -369,9 +365,9 @@ void build_switch_block_module(ModuleManager& module_manager,
|
|||
for (size_t inode = 0; inode < rr_gsb.get_num_opin_nodes(side_manager.get_side()); ++inode) {
|
||||
vtr::Point<size_t> 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(grids, 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);
|
||||
std::string port_name = generate_sb_module_grid_port_name(side_manager.get_side(),
|
||||
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 */
|
||||
ModulePortId input_port_id = module_manager.add_port(sb_module, module_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
|
@ -391,7 +387,7 @@ void build_switch_block_module(ModuleManager& module_manager,
|
|||
if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) {
|
||||
build_switch_block_interc_modules(module_manager,
|
||||
sb_module, rr_gsb,
|
||||
circuit_lib, grids, rr_switches,
|
||||
circuit_lib, rr_switches,
|
||||
side_manager.get_side(),
|
||||
itrack,
|
||||
input_port_to_module_nets);
|
||||
|
@ -440,7 +436,6 @@ void build_connection_block_module_short_interc(ModuleManager& module_manager,
|
|||
const ModuleId& cb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
t_rr_node* src_rr_node,
|
||||
const std::map<ModulePortId, ModuleNetId>& input_port_to_module_nets) {
|
||||
/* Ensure we have only one 1 driver node */
|
||||
|
@ -463,7 +458,7 @@ void build_connection_block_module_short_interc(ModuleManager& module_manager,
|
|||
ModulePortId input_port_id = find_connection_block_module_chan_port(module_manager, cb_module, rr_gsb, cb_type, drive_rr_node);
|
||||
|
||||
/* Create port description for input pin of a CLB */
|
||||
ModulePortId ipin_port_id = find_connection_block_module_ipin_port(module_manager, cb_module, rr_gsb, grids, src_rr_node);
|
||||
ModulePortId ipin_port_id = find_connection_block_module_ipin_port(module_manager, cb_module, rr_gsb, src_rr_node);
|
||||
|
||||
/* The input port and output port must match in size */
|
||||
BasicPort input_port = module_manager.module_port(cb_module, input_port_id);
|
||||
|
@ -489,7 +484,6 @@ void build_connection_block_mux_module(ModuleManager& module_manager,
|
|||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& rr_switches,
|
||||
const e_side& cb_ipin_side,
|
||||
const size_t& ipin_index,
|
||||
|
@ -556,7 +550,7 @@ void build_connection_block_mux_module(ModuleManager& module_manager,
|
|||
ModulePortId mux_output_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_model_output_ports[0]));
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(mux_module, mux_output_port_id));
|
||||
BasicPort mux_output_port = module_manager.module_port(mux_module, mux_output_port_id);
|
||||
ModulePortId cb_output_port_id = find_connection_block_module_ipin_port(module_manager, cb_module, rr_gsb, grids, cur_rr_node);
|
||||
ModulePortId cb_output_port_id = find_connection_block_module_ipin_port(module_manager, cb_module, rr_gsb, cur_rr_node);
|
||||
BasicPort cb_output_port = module_manager.module_port(cb_module, cb_output_port_id);
|
||||
|
||||
/* Check port size should match */
|
||||
|
@ -606,7 +600,6 @@ void build_connection_block_interc_modules(ModuleManager& module_manager,
|
|||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& rr_switches,
|
||||
const e_side& cb_ipin_side,
|
||||
const size_t& ipin_index,
|
||||
|
@ -616,13 +609,13 @@ void build_connection_block_interc_modules(ModuleManager& module_manager,
|
|||
return; /* This port has no driver, skip it */
|
||||
} else if (1 == src_rr_node->fan_in) {
|
||||
/* Print a direct connection */
|
||||
build_connection_block_module_short_interc(module_manager, cb_module, rr_gsb, cb_type, grids, src_rr_node, input_port_to_module_nets);
|
||||
build_connection_block_module_short_interc(module_manager, cb_module, rr_gsb, cb_type, src_rr_node, input_port_to_module_nets);
|
||||
|
||||
} else if (1 < src_rr_node->fan_in) {
|
||||
/* Print the multiplexer, fan_in >= 2 */
|
||||
build_connection_block_mux_module(module_manager,
|
||||
cb_module, rr_gsb, cb_type,
|
||||
circuit_lib, grids, rr_switches,
|
||||
circuit_lib, rr_switches,
|
||||
cb_ipin_side, ipin_index,
|
||||
input_port_to_module_nets);
|
||||
} /*Nothing should be done else*/
|
||||
|
@ -685,7 +678,6 @@ void build_connection_block_interc_modules(ModuleManager& module_manager,
|
|||
static
|
||||
void build_connection_block_module(ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& rr_switches,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const CircuitModelId& sram_model,
|
||||
|
@ -702,17 +694,17 @@ void build_connection_block_module(ModuleManager& module_manager,
|
|||
*/
|
||||
for (size_t itrack = 0; itrack < rr_gsb.get_cb_chan_width(cb_type); ++itrack) {
|
||||
vtr::Point<size_t> port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||
std::string port_name = generate_routing_track_port_name(cb_type,
|
||||
port_coord, itrack,
|
||||
IN_PORT);
|
||||
std::string port_name = generate_cb_module_track_port_name(cb_type,
|
||||
itrack,
|
||||
IN_PORT);
|
||||
BasicPort module_port(port_name, 1); /* Every track has a port size of 1 */
|
||||
module_manager.add_port(cb_module, module_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
}
|
||||
for (size_t itrack = 0; itrack < rr_gsb.get_cb_chan_width(cb_type); ++itrack) {
|
||||
vtr::Point<size_t> port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||
std::string port_name = generate_routing_track_port_name(cb_type,
|
||||
port_coord, itrack,
|
||||
OUT_PORT);
|
||||
std::string port_name = generate_cb_module_track_port_name(cb_type,
|
||||
itrack,
|
||||
OUT_PORT);
|
||||
BasicPort module_port(port_name, 1); /* Every track has a port size of 1 */
|
||||
module_manager.add_port(cb_module, module_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||
}
|
||||
|
@ -724,10 +716,8 @@ void build_connection_block_module(ModuleManager& module_manager,
|
|||
for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) {
|
||||
t_rr_node* ipin_node = rr_gsb.get_ipin_node(cb_ipin_side, inode);
|
||||
vtr::Point<size_t> port_coord(ipin_node->xlow, ipin_node->ylow);
|
||||
std::string port_name = generate_grid_side_port_name(grids,
|
||||
port_coord,
|
||||
rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode),
|
||||
ipin_node->ptc_num);
|
||||
std::string port_name = generate_cb_module_grid_port_name(cb_ipin_side,
|
||||
ipin_node->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(cb_module, module_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||
|
@ -747,16 +737,16 @@ void build_connection_block_module(ModuleManager& module_manager,
|
|||
for (size_t itrack = 0; itrack < rr_gsb.get_cb_chan_width(cb_type); ++itrack) {
|
||||
vtr::Point<size_t> port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||
/* Create a port description for the input */
|
||||
std::string input_port_name = generate_routing_track_port_name(cb_type,
|
||||
port_coord, itrack,
|
||||
IN_PORT);
|
||||
std::string input_port_name = generate_cb_module_track_port_name(cb_type,
|
||||
itrack,
|
||||
IN_PORT);
|
||||
ModulePortId input_port_id = module_manager.find_module_port(cb_module, input_port_name);
|
||||
BasicPort input_port = module_manager.module_port(cb_module, input_port_id);
|
||||
|
||||
/* Create a port description for the output */
|
||||
std::string output_port_name = generate_routing_track_port_name(cb_type,
|
||||
port_coord, itrack,
|
||||
OUT_PORT);
|
||||
std::string output_port_name = generate_cb_module_track_port_name(cb_type,
|
||||
itrack,
|
||||
OUT_PORT);
|
||||
ModulePortId output_port_id = module_manager.find_module_port(cb_module, output_port_name);
|
||||
BasicPort output_port = module_manager.module_port(cb_module, output_port_id);
|
||||
|
||||
|
@ -782,7 +772,7 @@ void build_connection_block_module(ModuleManager& module_manager,
|
|||
for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) {
|
||||
build_connection_block_interc_modules(module_manager,
|
||||
cb_module, rr_gsb, cb_type,
|
||||
circuit_lib, grids, rr_switches,
|
||||
circuit_lib, rr_switches,
|
||||
cb_ipin_side, inode,
|
||||
input_port_to_module_nets);
|
||||
}
|
||||
|
@ -830,7 +820,6 @@ static
|
|||
void build_flatten_connection_block_modules(ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& rr_switches,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const CircuitModelId& sram_model,
|
||||
|
@ -850,7 +839,7 @@ void build_flatten_connection_block_modules(ModuleManager& module_manager,
|
|||
}
|
||||
build_connection_block_module(module_manager,
|
||||
circuit_lib,
|
||||
grids, rr_switches,
|
||||
rr_switches,
|
||||
sram_orgz_type, sram_model,
|
||||
rr_gsb, cb_type);
|
||||
}
|
||||
|
@ -871,7 +860,6 @@ void build_flatten_routing_modules(ModuleManager& module_manager,
|
|||
const CircuitLibrary& circuit_lib,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const CircuitModelId& sram_model,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const t_det_routing_arch& routing_arch,
|
||||
const std::vector<t_switch_inf>& rr_switches) {
|
||||
/* Start time count */
|
||||
|
@ -891,7 +879,7 @@ void build_flatten_routing_modules(ModuleManager& module_manager,
|
|||
for (size_t iy = 0; iy < sb_range.get_y(); ++iy) {
|
||||
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
|
||||
build_switch_block_module(module_manager, circuit_lib,
|
||||
grids, rr_switches,
|
||||
rr_switches,
|
||||
sram_orgz_type, sram_model,
|
||||
rr_gsb);
|
||||
}
|
||||
|
@ -899,13 +887,13 @@ void build_flatten_routing_modules(ModuleManager& module_manager,
|
|||
|
||||
build_flatten_connection_block_modules(module_manager, L_device_rr_gsb,
|
||||
circuit_lib,
|
||||
grids, rr_switches,
|
||||
rr_switches,
|
||||
sram_orgz_type, sram_model,
|
||||
CHANX);
|
||||
|
||||
build_flatten_connection_block_modules(module_manager, L_device_rr_gsb,
|
||||
circuit_lib,
|
||||
grids, rr_switches,
|
||||
rr_switches,
|
||||
sram_orgz_type, sram_model,
|
||||
CHANY);
|
||||
|
||||
|
@ -934,7 +922,6 @@ void build_unique_routing_modules(ModuleManager& module_manager,
|
|||
const CircuitLibrary& circuit_lib,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const CircuitModelId& sram_model,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const t_det_routing_arch& routing_arch,
|
||||
const std::vector<t_switch_inf>& rr_switches) {
|
||||
/* Start time count */
|
||||
|
@ -950,7 +937,7 @@ void build_unique_routing_modules(ModuleManager& module_manager,
|
|||
for (size_t isb = 0; isb < L_device_rr_gsb.get_num_sb_unique_module(); ++isb) {
|
||||
const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(isb);
|
||||
build_switch_block_module(module_manager, circuit_lib,
|
||||
grids, rr_switches,
|
||||
rr_switches,
|
||||
sram_orgz_type, sram_model,
|
||||
unique_mirror);
|
||||
}
|
||||
|
@ -961,7 +948,7 @@ void build_unique_routing_modules(ModuleManager& module_manager,
|
|||
|
||||
build_connection_block_module(module_manager,
|
||||
circuit_lib,
|
||||
grids, rr_switches,
|
||||
rr_switches,
|
||||
sram_orgz_type, sram_model,
|
||||
unique_mirror, CHANX);
|
||||
}
|
||||
|
@ -972,7 +959,7 @@ void build_unique_routing_modules(ModuleManager& module_manager,
|
|||
|
||||
build_connection_block_module(module_manager,
|
||||
circuit_lib,
|
||||
grids, rr_switches,
|
||||
rr_switches,
|
||||
sram_orgz_type, sram_model,
|
||||
unique_mirror, CHANY);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ void build_flatten_routing_modules(ModuleManager& module_manager,
|
|||
const CircuitLibrary& circuit_lib,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const CircuitModelId& sram_model,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const t_det_routing_arch& routing_arch,
|
||||
const std::vector<t_switch_inf>& rr_switches);
|
||||
|
||||
|
@ -25,7 +24,6 @@ void build_unique_routing_modules(ModuleManager& module_manager,
|
|||
const CircuitLibrary& circuit_lib,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const CircuitModelId& sram_model,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const t_det_routing_arch& routing_arch,
|
||||
const std::vector<t_switch_inf>& rr_switches);
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "fpga_x2p_utils.h"
|
||||
#include "fpga_x2p_pbtypes_utils.h"
|
||||
#include "module_manager_utils.h"
|
||||
#include "build_top_module_utils.h"
|
||||
#include "build_top_module_connection.h"
|
||||
#include "build_top_module_memory.h"
|
||||
#include "build_top_module_directs.h"
|
||||
|
||||
|
@ -24,78 +26,6 @@
|
|||
#include "build_module_graph_utils.h"
|
||||
#include "build_top_module.h"
|
||||
|
||||
/********************************************************************
|
||||
* Generate the name for a grid block, by considering
|
||||
* 1. if it locates on the border with given device size
|
||||
* 2. its type
|
||||
*
|
||||
* This function is mainly used in the top-level module generation
|
||||
*******************************************************************/
|
||||
static
|
||||
std::string generate_grid_block_module_name_in_top_module(const std::string& prefix,
|
||||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const vtr::Point<size_t>& grid_coordinate) {
|
||||
/* Determine if the grid locates at the border */
|
||||
e_side border_side = find_grid_border_side(device_size, grid_coordinate);
|
||||
|
||||
return generate_grid_block_module_name(prefix, std::string(grids[grid_coordinate.x()][grid_coordinate.y()].type->name),
|
||||
IO_TYPE == grids[grid_coordinate.x()][grid_coordinate.y()].type, border_side);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Find the cb_type of a GSB in the top-level module
|
||||
* depending on the side of SB
|
||||
* TOP/BOTTOM side: CHANY
|
||||
* RIGHT/LEFT side: CHANX
|
||||
*******************************************************************/
|
||||
static
|
||||
t_rr_type find_top_module_cb_type_by_sb_side(const e_side& sb_side) {
|
||||
VTR_ASSERT(NUM_SIDES != sb_side);
|
||||
|
||||
if ((TOP == sb_side) || (BOTTOM == sb_side)) {
|
||||
return CHANY;
|
||||
}
|
||||
|
||||
VTR_ASSERT((RIGHT == sb_side) || (LEFT == sb_side));
|
||||
return CHANX;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Find the GSB coordinate for a CB in the top-level module
|
||||
* depending on the side of a SB
|
||||
* TODO: use vtr::Point<size_t> to replace DeviceCoordinator
|
||||
*******************************************************************/
|
||||
static
|
||||
DeviceCoordinator find_top_module_gsb_coordinate_by_sb_side(const RRGSB& rr_gsb,
|
||||
const e_side& sb_side) {
|
||||
VTR_ASSERT(NUM_SIDES != sb_side);
|
||||
|
||||
DeviceCoordinator gsb_coordinate;
|
||||
|
||||
if ((TOP == sb_side) || (LEFT == sb_side)) {
|
||||
gsb_coordinate.set_x(rr_gsb.get_x());
|
||||
gsb_coordinate.set_y(rr_gsb.get_y());
|
||||
return gsb_coordinate;
|
||||
}
|
||||
|
||||
VTR_ASSERT((RIGHT == sb_side) || (BOTTOM == sb_side));
|
||||
|
||||
/* RIGHT side: x + 1 */
|
||||
if (RIGHT == sb_side) {
|
||||
gsb_coordinate.set_x(rr_gsb.get_x() + 1);
|
||||
gsb_coordinate.set_y(rr_gsb.get_y());
|
||||
}
|
||||
|
||||
/* BOTTOM side: y - 1 */
|
||||
if (BOTTOM == sb_side) {
|
||||
gsb_coordinate.set_x(rr_gsb.get_x());
|
||||
gsb_coordinate.set_y(rr_gsb.get_y() - 1);
|
||||
}
|
||||
|
||||
return gsb_coordinate;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add a instance of a grid module to the top module
|
||||
*******************************************************************/
|
||||
|
@ -343,499 +273,6 @@ std::vector<std::vector<size_t>> add_top_module_connection_block_instances(Modul
|
|||
return cb_instance_ids;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add module nets to connect a GSB to adjacent grid ports/pins
|
||||
* as well as connection blocks
|
||||
* This function will create nets for the following types of connections
|
||||
* between grid output pins of Switch block and adjacent grids
|
||||
* In this case, the net source is the grid pin, while the net sink
|
||||
* is the switch block pin
|
||||
*
|
||||
* +------------+ +------------+
|
||||
* | | | |
|
||||
* | Grid | | Grid |
|
||||
* | [x][y+1] | | [x+1][y+1] |
|
||||
* | | | |
|
||||
* +------------+ +------------+
|
||||
* | |
|
||||
* | +------------+ |
|
||||
* +------>| |<-----+
|
||||
* | Switch |
|
||||
* | Block |
|
||||
* +------>| [x][y] |<-----+
|
||||
* | +------------+ |
|
||||
* | |
|
||||
* | |
|
||||
* +------------+ +------------+
|
||||
* | | | |
|
||||
* | Grid | | Grid |
|
||||
* | [x][y] | | [x+1][y] |
|
||||
* | | | |
|
||||
* +------------+ +------------+
|
||||
*
|
||||
*******************************************************************/
|
||||
static
|
||||
void add_top_module_nets_connect_grids_and_sb(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<size_t>>& sb_instance_ids,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
|
||||
/* We could have two different coordinators, one is the instance, the other is the module */
|
||||
vtr::Point<size_t> instance_sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
|
||||
DeviceCoordinator module_gsb_coordinate(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
|
||||
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
|
||||
if (true == compact_routing_hierarchy) {
|
||||
DeviceCoordinator gsb_coord(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(gsb_coord);
|
||||
module_gsb_coordinate.set_x(unique_mirror.get_x());
|
||||
module_gsb_coordinate.set_y(unique_mirror.get_y());
|
||||
}
|
||||
|
||||
/* This is the source cb that is added to the top module */
|
||||
const RRGSB& module_sb = L_device_rr_gsb.get_gsb(module_gsb_coordinate);
|
||||
vtr::Point<size_t> module_sb_coordinate(module_sb.get_sb_x(), module_sb.get_sb_y());
|
||||
|
||||
/* Collect sink-related information */
|
||||
std::string sink_sb_module_name = generate_switch_block_module_name(module_sb_coordinate);
|
||||
ModuleId sink_sb_module = module_manager.find_module(sink_sb_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(sink_sb_module));
|
||||
size_t sink_sb_instance = sb_instance_ids[instance_sb_coordinate.x()][instance_sb_coordinate.y()];
|
||||
|
||||
/* Connect grid output pins (OPIN) to switch block grid pins */
|
||||
for (size_t side = 0; side < module_sb.get_num_sides(); ++side) {
|
||||
Side side_manager(side);
|
||||
for (size_t inode = 0; inode < module_sb.get_num_opin_nodes(side_manager.get_side()); ++inode) {
|
||||
/* Collect source-related information */
|
||||
/* Generate the grid module name by considering if it locates on the border */
|
||||
vtr::Point<size_t> grid_coordinate(rr_gsb.get_opin_node(side_manager.get_side(), inode)->xlow, (rr_gsb.get_opin_node(side_manager.get_side(), inode)->ylow));
|
||||
std::string src_grid_module_name = generate_grid_block_module_name_in_top_module(std::string(GRID_MODULE_NAME_PREFIX), device_size, grids, grid_coordinate);
|
||||
ModuleId src_grid_module = module_manager.find_module(src_grid_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(src_grid_module));
|
||||
size_t src_grid_instance = grid_instance_ids[grid_coordinate.x()][grid_coordinate.y()];
|
||||
size_t src_grid_pin_index = rr_gsb.get_opin_node(side_manager.get_side(), inode)->ptc_num;
|
||||
size_t src_grid_pin_height = find_grid_pin_height(grids, grid_coordinate, src_grid_pin_index);
|
||||
std::string src_grid_port_name = generate_grid_port_name(grid_coordinate, src_grid_pin_height, rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode), src_grid_pin_index, false);
|
||||
ModulePortId src_grid_port_id = module_manager.find_module_port(src_grid_module, src_grid_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(src_grid_module, src_grid_port_id));
|
||||
BasicPort src_grid_port = module_manager.module_port(src_grid_module, src_grid_port_id);
|
||||
|
||||
/* Collect sink-related information */
|
||||
vtr::Point<size_t> sink_sb_port_coord(module_sb.get_opin_node(side_manager.get_side(), inode)->xlow,
|
||||
module_sb.get_opin_node(side_manager.get_side(), inode)->ylow);
|
||||
std::string sink_sb_port_name = generate_grid_side_port_name(grids, sink_sb_port_coord,
|
||||
module_sb.get_opin_node_grid_side(side_manager.get_side(), inode),
|
||||
src_grid_pin_index);
|
||||
ModulePortId sink_sb_port_id = module_manager.find_module_port(sink_sb_module, sink_sb_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(sink_sb_module, sink_sb_port_id));
|
||||
BasicPort sink_sb_port = module_manager.module_port(sink_sb_module, sink_sb_port_id);
|
||||
|
||||
/* Source and sink port should match in size */
|
||||
VTR_ASSERT(src_grid_port.get_width() == sink_sb_port.get_width());
|
||||
|
||||
/* Create a net for each pin */
|
||||
for (size_t pin_id = 0; pin_id < src_grid_port.pins().size(); ++pin_id) {
|
||||
ModuleNetId net = module_manager.create_module_net(top_module);
|
||||
/* Configure the net source */
|
||||
module_manager.add_module_net_source(top_module, net, src_grid_module, src_grid_instance, src_grid_port_id, src_grid_port.pins()[pin_id]);
|
||||
/* Configure the net sink */
|
||||
module_manager.add_module_net_sink(top_module, net, sink_sb_module, sink_sb_instance, sink_sb_port_id, sink_sb_port.pins()[pin_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will create nets for the connections
|
||||
* between grid input pins and connection blocks
|
||||
* In this case, the net source is the connection block pin,
|
||||
* while the net sink is the grid input
|
||||
*
|
||||
* +------------+ +------------------+ +------------+
|
||||
* | | | | | |
|
||||
* | Grid |<-----| Connection Block |----->| Grid |
|
||||
* | [x][y+1] | | Y-direction | | [x+1][y+1] |
|
||||
* | | | [x][y+1] | | |
|
||||
* +------------+ +------------------+ +------------+
|
||||
* ^
|
||||
* |
|
||||
* +------------+ +------------------+
|
||||
* | Connection | | |
|
||||
* | Block | | Switch Block |
|
||||
* | X-direction| | [x][y] |
|
||||
* | [x][y] | | |
|
||||
* +------------+ +------------------+
|
||||
* |
|
||||
* v
|
||||
* +------------+
|
||||
* | |
|
||||
* | Grid |
|
||||
* | [x][y] |
|
||||
* | |
|
||||
* +------------+
|
||||
*
|
||||
*
|
||||
* Relationship between source connection block and its unique module
|
||||
* Take an example of a CBY
|
||||
*
|
||||
* grid_pin name should follow unique module of Grid[x][y+1]
|
||||
* cb_pin name should follow unique module of CBY[x][y+1]
|
||||
*
|
||||
* However, instace id should follow the origin Grid and Connection block
|
||||
*
|
||||
*
|
||||
* +------------+ +------------------+
|
||||
* | | | |
|
||||
* | Grid |<------------| Connection Block |
|
||||
* | [x][y+1] | | Y-direction |
|
||||
* | | | [x][y+1] |
|
||||
* +------------+ +------------------+
|
||||
* ^
|
||||
* || unique mirror
|
||||
* +------------+ +------------------+
|
||||
* | | | |
|
||||
* | Grid |<------------| Connection Block |
|
||||
* | [i][j+1] | | Y-direction |
|
||||
* | | | [i][j+1] |
|
||||
* +------------+ +------------------+
|
||||
*
|
||||
*******************************************************************/
|
||||
static
|
||||
void add_top_module_nets_connect_grids_and_cb(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
const std::vector<std::vector<size_t>>& cb_instance_ids,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
/* We could have two different coordinators, one is the instance, the other is the module */
|
||||
vtr::Point<size_t> instance_cb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||
DeviceCoordinator module_gsb_coordinate(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
|
||||
/* Skip those Connection blocks that do not exist */
|
||||
if (false == rr_gsb.is_cb_exist(cb_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip if the cb does not contain any configuration bits! */
|
||||
if (true == connection_block_contain_only_routing_tracks(rr_gsb, cb_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
|
||||
if (true == compact_routing_hierarchy) {
|
||||
DeviceCoordinator gsb_coord(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, gsb_coord);
|
||||
module_gsb_coordinate.set_x(unique_mirror.get_x());
|
||||
module_gsb_coordinate.set_y(unique_mirror.get_y());
|
||||
}
|
||||
|
||||
/* This is the source cb that is added to the top module */
|
||||
const RRGSB& module_cb = L_device_rr_gsb.get_gsb(module_gsb_coordinate);
|
||||
vtr::Point<size_t> module_cb_coordinate(module_cb.get_cb_x(cb_type), module_cb.get_cb_y(cb_type));
|
||||
|
||||
/* Collect source-related information */
|
||||
std::string src_cb_module_name = generate_connection_block_module_name(cb_type, module_cb_coordinate);
|
||||
ModuleId src_cb_module = module_manager.find_module(src_cb_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(src_cb_module));
|
||||
/* Instance id should follow the instance cb coordinate */
|
||||
size_t src_cb_instance = cb_instance_ids[instance_cb_coordinate.x()][instance_cb_coordinate.y()];
|
||||
|
||||
/* Iterate over the output pins of the Connection Block */
|
||||
std::vector<enum e_side> cb_ipin_sides = module_cb.get_cb_ipin_sides(cb_type);
|
||||
for (size_t iside = 0; iside < cb_ipin_sides.size(); ++iside) {
|
||||
enum e_side cb_ipin_side = cb_ipin_sides[iside];
|
||||
for (size_t inode = 0; inode < module_cb.get_num_ipin_nodes(cb_ipin_side); ++inode) {
|
||||
/* Collect source-related information */
|
||||
t_rr_node* module_ipin_node = module_cb.get_ipin_node(cb_ipin_side, inode);
|
||||
vtr::Point<size_t> cb_src_port_coord(module_ipin_node->xlow, module_ipin_node->ylow);
|
||||
std::string src_cb_port_name = generate_grid_side_port_name(grids, cb_src_port_coord,
|
||||
module_cb.get_ipin_node_grid_side(cb_ipin_side, inode),
|
||||
module_ipin_node->ptc_num);
|
||||
ModulePortId src_cb_port_id = module_manager.find_module_port(src_cb_module, src_cb_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(src_cb_module, src_cb_port_id));
|
||||
BasicPort src_cb_port = module_manager.module_port(src_cb_module, src_cb_port_id);
|
||||
|
||||
/* Collect sink-related information */
|
||||
/* Note that we use the instance cb pin here!!!
|
||||
* because it has the correct coordinator for the grid!!!
|
||||
*/
|
||||
t_rr_node* instance_ipin_node = rr_gsb.get_ipin_node(cb_ipin_side, inode);
|
||||
vtr::Point<size_t> grid_coordinate(instance_ipin_node->xlow, instance_ipin_node->ylow);
|
||||
std::string sink_grid_module_name = generate_grid_block_module_name_in_top_module(std::string(GRID_MODULE_NAME_PREFIX), device_size, grids, grid_coordinate);
|
||||
ModuleId sink_grid_module = module_manager.find_module(sink_grid_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(sink_grid_module));
|
||||
size_t sink_grid_instance = grid_instance_ids[grid_coordinate.x()][grid_coordinate.y()];
|
||||
size_t sink_grid_pin_index = instance_ipin_node->ptc_num;
|
||||
size_t sink_grid_pin_height = find_grid_pin_height(grids, grid_coordinate, sink_grid_pin_index);
|
||||
std::string sink_grid_port_name = generate_grid_port_name(grid_coordinate, sink_grid_pin_height, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode), sink_grid_pin_index, false);
|
||||
ModulePortId sink_grid_port_id = module_manager.find_module_port(sink_grid_module, sink_grid_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(sink_grid_module, sink_grid_port_id));
|
||||
BasicPort sink_grid_port = module_manager.module_port(sink_grid_module, sink_grid_port_id);
|
||||
|
||||
/* Source and sink port should match in size */
|
||||
VTR_ASSERT(src_cb_port.get_width() == sink_grid_port.get_width());
|
||||
|
||||
/* Create a net for each pin */
|
||||
for (size_t pin_id = 0; pin_id < src_cb_port.pins().size(); ++pin_id) {
|
||||
ModuleNetId net = module_manager.create_module_net(top_module);
|
||||
/* Configure the net source */
|
||||
module_manager.add_module_net_source(top_module, net, src_cb_module, src_cb_instance, src_cb_port_id, src_cb_port.pins()[pin_id]);
|
||||
/* Configure the net sink */
|
||||
module_manager.add_module_net_sink(top_module, net, sink_grid_module, sink_grid_instance, sink_grid_port_id, sink_grid_port.pins()[pin_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will create nets for the connections
|
||||
* between connection block and switch block pins
|
||||
* Two cases should be considered:
|
||||
* a. The switch block pin denotes an input of a routing track
|
||||
* The net source is an output of a routing track of connection block
|
||||
* while the net sink is an input of a routing track of switch block
|
||||
* b. The switch block pin denotes an output of a routing track
|
||||
* The net source is an output of routing track of switch block
|
||||
* while the net sink is an input of a routing track of connection block
|
||||
*
|
||||
* +------------+ +------------------+ +------------+
|
||||
* | | | | | |
|
||||
* | Grid | | Connection Block | | Grid |
|
||||
* | [x][y+1] | | Y-direction | | [x+1][y+1] |
|
||||
* | | | [x][y+1] | | |
|
||||
* +------------+ +------------------+ +------------+
|
||||
* | ^
|
||||
* v |
|
||||
* +------------+ +------------------+ +------------+
|
||||
* | Connection |----->| |----->| Connection |
|
||||
* | Block | | Switch Block | | Block |
|
||||
* | X-direction|<-----| [x][y] |<-----| X-direction|
|
||||
* | [x][y] | | | | [x+1][y] |
|
||||
* +------------+ +------------------+ +------------+
|
||||
* | ^
|
||||
* v |
|
||||
* +------------+ +------------------+ +------------+
|
||||
* | | | | | |
|
||||
* | Grid | | Connection Block | | Grid |
|
||||
* | [x][y] | | Y-direction | | [x][y+1] |
|
||||
* | | | [x][y] | | |
|
||||
* +------------+ +------------------+ +------------+
|
||||
*
|
||||
* Here, to achieve the purpose, we can simply iterate over the
|
||||
* four sides of switch block and make connections to adjancent
|
||||
* connection blocks
|
||||
*
|
||||
*******************************************************************/
|
||||
static
|
||||
void add_top_module_nets_connect_sb_and_cb(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<size_t>>& sb_instance_ids,
|
||||
const std::map<t_rr_type, std::vector<std::vector<size_t>>>& cb_instance_ids,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
/* We could have two different coordinators, one is the instance, the other is the module */
|
||||
vtr::Point<size_t> instance_sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
|
||||
DeviceCoordinator module_gsb_sb_coordinate(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
|
||||
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
|
||||
if (true == compact_routing_hierarchy) {
|
||||
DeviceCoordinator gsb_coord(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(gsb_coord);
|
||||
module_gsb_sb_coordinate.set_x(unique_mirror.get_x());
|
||||
module_gsb_sb_coordinate.set_y(unique_mirror.get_y());
|
||||
}
|
||||
|
||||
/* This is the source cb that is added to the top module */
|
||||
const RRGSB& module_sb = L_device_rr_gsb.get_gsb(module_gsb_sb_coordinate);
|
||||
vtr::Point<size_t> module_sb_coordinate(module_sb.get_sb_x(), module_sb.get_sb_y());
|
||||
std::string sb_module_name = generate_switch_block_module_name(module_sb_coordinate);
|
||||
ModuleId sb_module_id = module_manager.find_module(sb_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(sb_module_id));
|
||||
size_t sb_instance = sb_instance_ids[instance_sb_coordinate.x()][instance_sb_coordinate.y()];
|
||||
|
||||
/* Connect grid output pins (OPIN) to switch block grid pins */
|
||||
for (size_t side = 0; side < module_sb.get_num_sides(); ++side) {
|
||||
Side side_manager(side);
|
||||
/* Iterate over the routing tracks on this side */
|
||||
DeviceCoordinator port_coordinator = module_sb.get_side_block_coordinator(side_manager.get_side());
|
||||
/* Early skip: if there is no routing tracks at this side */
|
||||
if (0 == module_sb.get_chan_width(side_manager.get_side())) {
|
||||
continue;
|
||||
}
|
||||
/* Find the Connection Block module */
|
||||
/* We find the original connection block and then spot its unique mirror!
|
||||
* Do NOT use module_sb here!!!
|
||||
*/
|
||||
t_rr_type cb_type = find_top_module_cb_type_by_sb_side(side_manager.get_side());
|
||||
DeviceCoordinator instance_gsb_cb_coordinate = find_top_module_gsb_coordinate_by_sb_side(rr_gsb, side_manager.get_side());
|
||||
DeviceCoordinator module_gsb_cb_coordinate = find_top_module_gsb_coordinate_by_sb_side(rr_gsb, side_manager.get_side());
|
||||
|
||||
/* Skip those Connection blocks that do not exist:
|
||||
* 1. The CB does not exist in the device level! We should skip!
|
||||
* 2. The CB does exist but we need to make sure if the GSB includes such CBs
|
||||
* For TOP and LEFT side, check the existence using RRGSB method is_cb_exist()
|
||||
* FOr RIGHT and BOTTOM side, find the adjacent RRGSB and then use is_cb_exist()
|
||||
*/
|
||||
if ( TOP == side_manager.get_side() || LEFT == side_manager.get_side() ) {
|
||||
if ( false == rr_gsb.is_cb_exist(cb_type)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( RIGHT == side_manager.get_side() || BOTTOM == side_manager.get_side() ) {
|
||||
const RRGSB& adjacent_gsb = L_device_rr_gsb.get_gsb(module_gsb_cb_coordinate);
|
||||
if ( false == adjacent_gsb.is_cb_exist(cb_type)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
|
||||
if (true == compact_routing_hierarchy) {
|
||||
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, module_gsb_cb_coordinate);
|
||||
module_gsb_cb_coordinate.set_x(unique_mirror.get_x());
|
||||
module_gsb_cb_coordinate.set_y(unique_mirror.get_y());
|
||||
}
|
||||
|
||||
const RRGSB& module_cb = L_device_rr_gsb.get_gsb(module_gsb_cb_coordinate);
|
||||
vtr::Point<size_t> module_cb_coordinate(module_cb.get_cb_x(cb_type), module_cb.get_cb_y(cb_type));
|
||||
std::string cb_module_name = generate_connection_block_module_name(cb_type, module_cb_coordinate);
|
||||
ModuleId cb_module_id = module_manager.find_module(cb_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(cb_module_id));
|
||||
const RRGSB& instance_cb = L_device_rr_gsb.get_gsb(instance_gsb_cb_coordinate);
|
||||
vtr::Point<size_t> instance_cb_coordinate(instance_cb.get_cb_x(cb_type), instance_cb.get_cb_y(cb_type));
|
||||
size_t cb_instance = cb_instance_ids.at(cb_type)[instance_cb_coordinate.x()][instance_cb_coordinate.y()];
|
||||
|
||||
for (size_t itrack = 0; itrack < module_sb.get_chan_width(side_manager.get_side()); ++itrack) {
|
||||
vtr::Point<size_t> sb_port_coord(port_coordinator.get_x(), port_coordinator.get_y());
|
||||
std::string sb_port_name = generate_routing_track_port_name(module_sb.get_chan_node(side_manager.get_side(), itrack)->type,
|
||||
sb_port_coord, itrack,
|
||||
module_sb.get_chan_node_direction(side_manager.get_side(), itrack));
|
||||
/* Prepare SB-related port information */
|
||||
ModulePortId sb_port_id = module_manager.find_module_port(sb_module_id, sb_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module_id, sb_port_id));
|
||||
BasicPort sb_port = module_manager.module_port(sb_module_id, sb_port_id);
|
||||
|
||||
/* Prepare CB-related port information */
|
||||
PORTS cb_port_direction = OUT_PORT;
|
||||
/* The cb port direction should be opposite to the sb port !!! */
|
||||
if (OUT_PORT == module_sb.get_chan_node_direction(side_manager.get_side(), itrack)) {
|
||||
cb_port_direction = IN_PORT;
|
||||
} else {
|
||||
VTR_ASSERT(IN_PORT == module_sb.get_chan_node_direction(side_manager.get_side(), itrack));
|
||||
}
|
||||
vtr::Point<size_t> cb_port_coord(module_cb.get_cb_x(cb_type), module_cb.get_cb_y(cb_type));
|
||||
std::string cb_port_name = generate_routing_track_port_name(cb_type,
|
||||
cb_port_coord, itrack,
|
||||
cb_port_direction);
|
||||
ModulePortId cb_port_id = module_manager.find_module_port(cb_module_id, cb_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module_id, cb_port_id));
|
||||
BasicPort cb_port = module_manager.module_port(cb_module_id, cb_port_id);
|
||||
|
||||
/* Source and sink port should match in size */
|
||||
VTR_ASSERT(cb_port.get_width() == sb_port.get_width());
|
||||
|
||||
/* Create a net for each pin */
|
||||
for (size_t pin_id = 0; pin_id < cb_port.pins().size(); ++pin_id) {
|
||||
ModuleNetId net = module_manager.create_module_net(top_module);
|
||||
/* Configure the net source and sink:
|
||||
* If sb port is an output (source), cb port is an input (sink)
|
||||
* If sb port is an input (sink), cb port is an output (source)
|
||||
*/
|
||||
if (OUT_PORT == module_sb.get_chan_node_direction(side_manager.get_side(), itrack)) {
|
||||
module_manager.add_module_net_sink(top_module, net, cb_module_id, cb_instance, cb_port_id, cb_port.pins()[pin_id]);
|
||||
module_manager.add_module_net_source(top_module, net, sb_module_id, sb_instance, sb_port_id, sb_port.pins()[pin_id]);
|
||||
} else {
|
||||
VTR_ASSERT(IN_PORT == module_sb.get_chan_node_direction(side_manager.get_side(), itrack));
|
||||
module_manager.add_module_net_source(top_module, net, cb_module_id, cb_instance, cb_port_id, cb_port.pins()[pin_id]);
|
||||
module_manager.add_module_net_sink(top_module, net, sb_module_id, sb_instance, sb_port_id, sb_port.pins()[pin_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add module nets to connect the grid ports/pins to Connection Blocks
|
||||
* and Switch Blocks
|
||||
* To make it easy, this function will iterate over all the General
|
||||
* Switch Blocks (GSBs), through which we can obtain the coordinates
|
||||
* of all the grids, connection blocks and switch blocks that are
|
||||
* supposed to be connected tightly.
|
||||
*
|
||||
* As such, we have completed all the connection for each grid.
|
||||
* There is no need to iterate over the grids
|
||||
*
|
||||
* +-------------------------+ +---------------------------------+
|
||||
* | | | Y-direction CB |
|
||||
* | Grid[x][y+1] | | [x][y + 1] |
|
||||
* | | +---------------------------------+
|
||||
* +-------------------------+
|
||||
* TOP SIDE
|
||||
* +-------------+ +---------------------------------+
|
||||
* | | | OPIN_NODE CHAN_NODES OPIN_NODES |
|
||||
* | | | |
|
||||
* | | | OPIN_NODES OPIN_NODES |
|
||||
* | X-direction | | |
|
||||
* | CB | LEFT SIDE | Switch Block | RIGHT SIDE
|
||||
* | [x][y] | | [x][y] |
|
||||
* | | | |
|
||||
* | | | CHAN_NODES CHAN_NODES |
|
||||
* | | | |
|
||||
* | | | OPIN_NODES OPIN_NODES |
|
||||
* | | | |
|
||||
* | | | OPIN_NODE CHAN_NODES OPIN_NODES |
|
||||
* +-------------+ +---------------------------------+
|
||||
* BOTTOM SIDE
|
||||
*******************************************************************/
|
||||
static
|
||||
void add_top_module_nets_connect_grids_and_gsbs(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const std::vector<std::vector<size_t>>& sb_instance_ids,
|
||||
const std::map<t_rr_type, std::vector<std::vector<size_t>>>& cb_instance_ids,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
DeviceCoordinator gsb_range = L_device_rr_gsb.get_gsb_range();
|
||||
for (size_t ix = 0; ix < gsb_range.get_x(); ++ix) {
|
||||
for (size_t iy = 0; iy < gsb_range.get_y(); ++iy) {
|
||||
vtr::Point<size_t> gsb_coordinate(ix, iy);
|
||||
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
|
||||
/* Connect the grid pins of the GSB to adjacent grids */
|
||||
add_top_module_nets_connect_grids_and_sb(module_manager, top_module,
|
||||
device_size, grids, grid_instance_ids,
|
||||
L_device_rr_gsb, rr_gsb, sb_instance_ids,
|
||||
compact_routing_hierarchy);
|
||||
|
||||
add_top_module_nets_connect_grids_and_cb(module_manager, top_module,
|
||||
device_size, grids, grid_instance_ids,
|
||||
L_device_rr_gsb, rr_gsb, CHANX, cb_instance_ids.at(CHANX),
|
||||
compact_routing_hierarchy);
|
||||
|
||||
add_top_module_nets_connect_grids_and_cb(module_manager, top_module,
|
||||
device_size, grids, grid_instance_ids,
|
||||
L_device_rr_gsb, rr_gsb, CHANY, cb_instance_ids.at(CHANY),
|
||||
compact_routing_hierarchy);
|
||||
|
||||
add_top_module_nets_connect_sb_and_cb(module_manager, top_module,
|
||||
L_device_rr_gsb, rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||
compact_routing_hierarchy);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print the top-level module for the FPGA fabric in Verilog format
|
||||
* This function will
|
||||
|
@ -855,7 +292,8 @@ void build_top_module(ModuleManager& module_manager,
|
|||
const std::vector<t_clb_to_clb_directs>& clb2clb_directs,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const CircuitModelId& sram_model,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
const bool& compact_routing_hierarchy,
|
||||
const bool& duplicate_grid_pin) {
|
||||
/* Start time count */
|
||||
clock_t t_start = clock();
|
||||
|
||||
|
@ -881,7 +319,7 @@ void build_top_module(ModuleManager& module_manager,
|
|||
add_top_module_nets_connect_grids_and_gsbs(module_manager, top_module,
|
||||
device_size, grids, grid_instance_ids,
|
||||
L_device_rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||
compact_routing_hierarchy);
|
||||
compact_routing_hierarchy, duplicate_grid_pin);
|
||||
/* Add inter-CLB direct connections */
|
||||
add_top_module_nets_clb2clb_direct_connections(module_manager, top_module, circuit_lib,
|
||||
device_size, grids, grid_instance_ids,
|
||||
|
|
|
@ -20,6 +20,7 @@ void build_top_module(ModuleManager& module_manager,
|
|||
const std::vector<t_clb_to_clb_directs>& clb2clb_directs,
|
||||
const e_sram_orgz& sram_orgz_type,
|
||||
const CircuitModelId& sram_model,
|
||||
const bool& compact_routing_hierarchy);
|
||||
const bool& compact_routing_hierarchy,
|
||||
const bool& duplicate_grid_pin);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,636 @@
|
|||
/********************************************************************
|
||||
* This file include most utilized functions for building connections
|
||||
* inside the module graph for FPGA fabric
|
||||
*******************************************************************/
|
||||
/* External library headers */
|
||||
#include "vtr_assert.h"
|
||||
|
||||
/* FPGA-X2P headers */
|
||||
#include "fpga_x2p_reserved_words.h"
|
||||
#include "fpga_x2p_naming.h"
|
||||
#include "fpga_x2p_pbtypes_utils.h"
|
||||
#include "rr_blocks_utils.h"
|
||||
|
||||
/* Module builder headers */
|
||||
#include "build_top_module_utils.h"
|
||||
#include "build_top_module_connection.h"
|
||||
|
||||
/********************************************************************
|
||||
* Add module nets to connect a GSB to adjacent grid ports/pins
|
||||
* as well as connection blocks
|
||||
* This function will create nets for the following types of connections
|
||||
* between grid output pins of Switch block and adjacent grids
|
||||
* In this case, the net source is the grid pin, while the net sink
|
||||
* is the switch block pin
|
||||
*
|
||||
* +------------+ +------------+
|
||||
* | | | |
|
||||
* | Grid | | Grid |
|
||||
* | [x][y+1] | | [x+1][y+1] |
|
||||
* | |----+ +----| |
|
||||
* +------------+ | | +------------+
|
||||
* | v v |
|
||||
* | +------------+ |
|
||||
* +------>| |<-----+
|
||||
* | Switch |
|
||||
* | Block |
|
||||
* +------>| [x][y] |<-----+
|
||||
* | +------------+ |
|
||||
* | ^ ^ |
|
||||
* | | | |
|
||||
* +------------+ | | +------------+
|
||||
* | |----+ +-----| |
|
||||
* | Grid | | Grid |
|
||||
* | [x][y] | | [x+1][y] |
|
||||
* | | | |
|
||||
* +------------+ +------------+
|
||||
|
||||
*
|
||||
*******************************************************************/
|
||||
static
|
||||
void add_top_module_nets_connect_grids_and_sb(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<size_t>>& sb_instance_ids,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
|
||||
/* We could have two different coordinators, one is the instance, the other is the module */
|
||||
vtr::Point<size_t> instance_sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
|
||||
DeviceCoordinator module_gsb_coordinate(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
|
||||
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
|
||||
if (true == compact_routing_hierarchy) {
|
||||
DeviceCoordinator gsb_coord(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(gsb_coord);
|
||||
module_gsb_coordinate.set_x(unique_mirror.get_x());
|
||||
module_gsb_coordinate.set_y(unique_mirror.get_y());
|
||||
}
|
||||
|
||||
/* This is the source cb that is added to the top module */
|
||||
const RRGSB& module_sb = L_device_rr_gsb.get_gsb(module_gsb_coordinate);
|
||||
vtr::Point<size_t> module_sb_coordinate(module_sb.get_sb_x(), module_sb.get_sb_y());
|
||||
|
||||
/* Collect sink-related information */
|
||||
std::string sink_sb_module_name = generate_switch_block_module_name(module_sb_coordinate);
|
||||
ModuleId sink_sb_module = module_manager.find_module(sink_sb_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(sink_sb_module));
|
||||
size_t sink_sb_instance = sb_instance_ids[instance_sb_coordinate.x()][instance_sb_coordinate.y()];
|
||||
|
||||
/* Connect grid output pins (OPIN) to switch block grid pins */
|
||||
for (size_t side = 0; side < module_sb.get_num_sides(); ++side) {
|
||||
Side side_manager(side);
|
||||
for (size_t inode = 0; inode < module_sb.get_num_opin_nodes(side_manager.get_side()); ++inode) {
|
||||
/* Collect source-related information */
|
||||
/* Generate the grid module name by considering if it locates on the border */
|
||||
vtr::Point<size_t> grid_coordinate(rr_gsb.get_opin_node(side_manager.get_side(), inode)->xlow, (rr_gsb.get_opin_node(side_manager.get_side(), inode)->ylow));
|
||||
std::string src_grid_module_name = generate_grid_block_module_name_in_top_module(std::string(GRID_MODULE_NAME_PREFIX), device_size, grids, grid_coordinate);
|
||||
ModuleId src_grid_module = module_manager.find_module(src_grid_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(src_grid_module));
|
||||
size_t src_grid_instance = grid_instance_ids[grid_coordinate.x()][grid_coordinate.y()];
|
||||
size_t src_grid_pin_index = rr_gsb.get_opin_node(side_manager.get_side(), inode)->ptc_num;
|
||||
size_t src_grid_pin_height = find_grid_pin_height(grids, grid_coordinate, src_grid_pin_index);
|
||||
std::string src_grid_port_name = generate_grid_port_name(grid_coordinate, src_grid_pin_height, rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode), src_grid_pin_index, false);
|
||||
ModulePortId src_grid_port_id = module_manager.find_module_port(src_grid_module, src_grid_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(src_grid_module, src_grid_port_id));
|
||||
BasicPort src_grid_port = module_manager.module_port(src_grid_module, src_grid_port_id);
|
||||
|
||||
/* Collect sink-related information */
|
||||
vtr::Point<size_t> sink_sb_port_coord(module_sb.get_opin_node(side_manager.get_side(), inode)->xlow,
|
||||
module_sb.get_opin_node(side_manager.get_side(), inode)->ylow);
|
||||
std::string sink_sb_port_name = generate_sb_module_grid_port_name(side_manager.get_side(),
|
||||
module_sb.get_opin_node_grid_side(side_manager.get_side(), inode),
|
||||
src_grid_pin_index);
|
||||
ModulePortId sink_sb_port_id = module_manager.find_module_port(sink_sb_module, sink_sb_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(sink_sb_module, sink_sb_port_id));
|
||||
BasicPort sink_sb_port = module_manager.module_port(sink_sb_module, sink_sb_port_id);
|
||||
|
||||
/* Source and sink port should match in size */
|
||||
VTR_ASSERT(src_grid_port.get_width() == sink_sb_port.get_width());
|
||||
|
||||
/* Create a net for each pin */
|
||||
for (size_t pin_id = 0; pin_id < src_grid_port.pins().size(); ++pin_id) {
|
||||
ModuleNetId net = module_manager.create_module_net(top_module);
|
||||
/* Configure the net source */
|
||||
module_manager.add_module_net_source(top_module, net, src_grid_module, src_grid_instance, src_grid_port_id, src_grid_port.pins()[pin_id]);
|
||||
/* Configure the net sink */
|
||||
module_manager.add_module_net_sink(top_module, net, sink_sb_module, sink_sb_instance, sink_sb_port_id, sink_sb_port.pins()[pin_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add module nets to connect a GSB to adjacent grid ports/pins
|
||||
* as well as connection blocks
|
||||
* This function will create nets for the following types of connections
|
||||
* between grid output pins of Switch block and adjacent grids
|
||||
* In this case, the net source is the grid pin, while the net sink
|
||||
* is the switch block pin
|
||||
*
|
||||
* In particular, this function considers the duplicated output pins of grids
|
||||
* when creating the connecting nets.
|
||||
* The follow figure shows the different pin postfix to be considered when
|
||||
* connecting the grid pins to SB inputs
|
||||
*
|
||||
* +------------+ +------------+
|
||||
* | | | |
|
||||
* | Grid | | Grid |
|
||||
* | [x][y+1] |lower lower| [x+1][y+1] |
|
||||
* | |----+ +----| |
|
||||
* +------------+ | | +------------+
|
||||
* |lower v v |upper
|
||||
* | +------------+ |
|
||||
* +------>| |<-----+
|
||||
* | Switch |
|
||||
* | Block |
|
||||
* +------>| [x][y] |<-----+
|
||||
* | +------------+ |
|
||||
* | ^ ^ |
|
||||
* |lower | | |upper
|
||||
* +------------+ | | +------------+
|
||||
* | |----+ +-----| |
|
||||
* | Grid |upper upper | Grid |
|
||||
* | [x][y] | | [x+1][y] |
|
||||
* | | | |
|
||||
* +------------+ +------------+
|
||||
*
|
||||
*******************************************************************/
|
||||
static
|
||||
void add_top_module_nets_connect_grids_and_sb_with_duplicated_pins(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<size_t>>& sb_instance_ids,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
|
||||
/* We could have two different coordinators, one is the instance, the other is the module */
|
||||
vtr::Point<size_t> instance_sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
|
||||
DeviceCoordinator module_gsb_coordinate(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
|
||||
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
|
||||
if (true == compact_routing_hierarchy) {
|
||||
DeviceCoordinator gsb_coord(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(gsb_coord);
|
||||
module_gsb_coordinate.set_x(unique_mirror.get_x());
|
||||
module_gsb_coordinate.set_y(unique_mirror.get_y());
|
||||
}
|
||||
|
||||
/* This is the source cb that is added to the top module */
|
||||
const RRGSB& module_sb = L_device_rr_gsb.get_gsb(module_gsb_coordinate);
|
||||
vtr::Point<size_t> module_sb_coordinate(module_sb.get_sb_x(), module_sb.get_sb_y());
|
||||
|
||||
/* Collect sink-related information */
|
||||
std::string sink_sb_module_name = generate_switch_block_module_name(module_sb_coordinate);
|
||||
ModuleId sink_sb_module = module_manager.find_module(sink_sb_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(sink_sb_module));
|
||||
size_t sink_sb_instance = sb_instance_ids[instance_sb_coordinate.x()][instance_sb_coordinate.y()];
|
||||
|
||||
/* Create a truth table for the postfix to be used regarding to the different side of switch blocks */
|
||||
std::map<e_side, bool> sb_side2postfix_map;
|
||||
/* Boolean variable "true" indicates the upper postfix in naming functions
|
||||
* Boolean variable "false" indicates the lower postfix in naming functions
|
||||
*/
|
||||
sb_side2postfix_map[TOP] = false;
|
||||
sb_side2postfix_map[RIGHT] = true;
|
||||
sb_side2postfix_map[BOTTOM] = true;
|
||||
sb_side2postfix_map[LEFT] = false;
|
||||
|
||||
/* Connect grid output pins (OPIN) to switch block grid pins */
|
||||
for (size_t side = 0; side < module_sb.get_num_sides(); ++side) {
|
||||
Side side_manager(side);
|
||||
for (size_t inode = 0; inode < module_sb.get_num_opin_nodes(side_manager.get_side()); ++inode) {
|
||||
/* Collect source-related information */
|
||||
/* Generate the grid module name by considering if it locates on the border */
|
||||
vtr::Point<size_t> grid_coordinate(rr_gsb.get_opin_node(side_manager.get_side(), inode)->xlow, (rr_gsb.get_opin_node(side_manager.get_side(), inode)->ylow));
|
||||
std::string src_grid_module_name = generate_grid_block_module_name_in_top_module(std::string(GRID_MODULE_NAME_PREFIX), device_size, grids, grid_coordinate);
|
||||
ModuleId src_grid_module = module_manager.find_module(src_grid_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(src_grid_module));
|
||||
size_t src_grid_instance = grid_instance_ids[grid_coordinate.x()][grid_coordinate.y()];
|
||||
size_t src_grid_pin_index = rr_gsb.get_opin_node(side_manager.get_side(), inode)->ptc_num;
|
||||
size_t src_grid_pin_height = find_grid_pin_height(grids, grid_coordinate, src_grid_pin_index);
|
||||
std::string src_grid_port_name = generate_grid_duplicated_port_name(src_grid_pin_height, rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode), src_grid_pin_index, sb_side2postfix_map[side_manager.get_side()]);
|
||||
ModulePortId src_grid_port_id = module_manager.find_module_port(src_grid_module, src_grid_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(src_grid_module, src_grid_port_id));
|
||||
BasicPort src_grid_port = module_manager.module_port(src_grid_module, src_grid_port_id);
|
||||
|
||||
/* Collect sink-related information */
|
||||
vtr::Point<size_t> sink_sb_port_coord(module_sb.get_opin_node(side_manager.get_side(), inode)->xlow,
|
||||
module_sb.get_opin_node(side_manager.get_side(), inode)->ylow);
|
||||
std::string sink_sb_port_name = generate_sb_module_grid_port_name(side_manager.get_side(),
|
||||
module_sb.get_opin_node_grid_side(side_manager.get_side(), inode),
|
||||
src_grid_pin_index);
|
||||
ModulePortId sink_sb_port_id = module_manager.find_module_port(sink_sb_module, sink_sb_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(sink_sb_module, sink_sb_port_id));
|
||||
BasicPort sink_sb_port = module_manager.module_port(sink_sb_module, sink_sb_port_id);
|
||||
|
||||
/* Source and sink port should match in size */
|
||||
VTR_ASSERT(src_grid_port.get_width() == sink_sb_port.get_width());
|
||||
|
||||
/* Create a net for each pin */
|
||||
for (size_t pin_id = 0; pin_id < src_grid_port.pins().size(); ++pin_id) {
|
||||
ModuleNetId net = module_manager.create_module_net(top_module);
|
||||
/* Configure the net source */
|
||||
module_manager.add_module_net_source(top_module, net, src_grid_module, src_grid_instance, src_grid_port_id, src_grid_port.pins()[pin_id]);
|
||||
/* Configure the net sink */
|
||||
module_manager.add_module_net_sink(top_module, net, sink_sb_module, sink_sb_instance, sink_sb_port_id, sink_sb_port.pins()[pin_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will create nets for the connections
|
||||
* between grid input pins and connection blocks
|
||||
* In this case, the net source is the connection block pin,
|
||||
* while the net sink is the grid input
|
||||
*
|
||||
* +------------+ +------------------+ +------------+
|
||||
* | | | | | |
|
||||
* | Grid |<-----| Connection Block |----->| Grid |
|
||||
* | [x][y+1] | | Y-direction | | [x+1][y+1] |
|
||||
* | | | [x][y+1] | | |
|
||||
* +------------+ +------------------+ +------------+
|
||||
* ^
|
||||
* |
|
||||
* +------------+ +------------------+
|
||||
* | Connection | | |
|
||||
* | Block | | Switch Block |
|
||||
* | X-direction| | [x][y] |
|
||||
* | [x][y] | | |
|
||||
* +------------+ +------------------+
|
||||
* |
|
||||
* v
|
||||
* +------------+
|
||||
* | |
|
||||
* | Grid |
|
||||
* | [x][y] |
|
||||
* | |
|
||||
* +------------+
|
||||
*
|
||||
*
|
||||
* Relationship between source connection block and its unique module
|
||||
* Take an example of a CBY
|
||||
*
|
||||
* grid_pin name should follow unique module of Grid[x][y+1]
|
||||
* cb_pin name should follow unique module of CBY[x][y+1]
|
||||
*
|
||||
* However, instace id should follow the origin Grid and Connection block
|
||||
*
|
||||
*
|
||||
* +------------+ +------------------+
|
||||
* | | | |
|
||||
* | Grid |<------------| Connection Block |
|
||||
* | [x][y+1] | | Y-direction |
|
||||
* | | | [x][y+1] |
|
||||
* +------------+ +------------------+
|
||||
* ^
|
||||
* || unique mirror
|
||||
* +------------+ +------------------+
|
||||
* | | | |
|
||||
* | Grid |<------------| Connection Block |
|
||||
* | [i][j+1] | | Y-direction |
|
||||
* | | | [i][j+1] |
|
||||
* +------------+ +------------------+
|
||||
*
|
||||
*******************************************************************/
|
||||
static
|
||||
void add_top_module_nets_connect_grids_and_cb(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
const std::vector<std::vector<size_t>>& cb_instance_ids,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
/* We could have two different coordinators, one is the instance, the other is the module */
|
||||
vtr::Point<size_t> instance_cb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||
DeviceCoordinator module_gsb_coordinate(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
|
||||
/* Skip those Connection blocks that do not exist */
|
||||
if (false == rr_gsb.is_cb_exist(cb_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip if the cb does not contain any configuration bits! */
|
||||
if (true == connection_block_contain_only_routing_tracks(rr_gsb, cb_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
|
||||
if (true == compact_routing_hierarchy) {
|
||||
DeviceCoordinator gsb_coord(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, gsb_coord);
|
||||
module_gsb_coordinate.set_x(unique_mirror.get_x());
|
||||
module_gsb_coordinate.set_y(unique_mirror.get_y());
|
||||
}
|
||||
|
||||
/* This is the source cb that is added to the top module */
|
||||
const RRGSB& module_cb = L_device_rr_gsb.get_gsb(module_gsb_coordinate);
|
||||
vtr::Point<size_t> module_cb_coordinate(module_cb.get_cb_x(cb_type), module_cb.get_cb_y(cb_type));
|
||||
|
||||
/* Collect source-related information */
|
||||
std::string src_cb_module_name = generate_connection_block_module_name(cb_type, module_cb_coordinate);
|
||||
ModuleId src_cb_module = module_manager.find_module(src_cb_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(src_cb_module));
|
||||
/* Instance id should follow the instance cb coordinate */
|
||||
size_t src_cb_instance = cb_instance_ids[instance_cb_coordinate.x()][instance_cb_coordinate.y()];
|
||||
|
||||
/* Iterate over the output pins of the Connection Block */
|
||||
std::vector<enum e_side> cb_ipin_sides = module_cb.get_cb_ipin_sides(cb_type);
|
||||
for (size_t iside = 0; iside < cb_ipin_sides.size(); ++iside) {
|
||||
enum e_side cb_ipin_side = cb_ipin_sides[iside];
|
||||
for (size_t inode = 0; inode < module_cb.get_num_ipin_nodes(cb_ipin_side); ++inode) {
|
||||
/* Collect source-related information */
|
||||
t_rr_node* module_ipin_node = module_cb.get_ipin_node(cb_ipin_side, inode);
|
||||
vtr::Point<size_t> cb_src_port_coord(module_ipin_node->xlow, module_ipin_node->ylow);
|
||||
std::string src_cb_port_name = generate_cb_module_grid_port_name(cb_ipin_side,
|
||||
module_ipin_node->ptc_num);
|
||||
ModulePortId src_cb_port_id = module_manager.find_module_port(src_cb_module, src_cb_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(src_cb_module, src_cb_port_id));
|
||||
BasicPort src_cb_port = module_manager.module_port(src_cb_module, src_cb_port_id);
|
||||
|
||||
/* Collect sink-related information */
|
||||
/* Note that we use the instance cb pin here!!!
|
||||
* because it has the correct coordinator for the grid!!!
|
||||
*/
|
||||
t_rr_node* instance_ipin_node = rr_gsb.get_ipin_node(cb_ipin_side, inode);
|
||||
vtr::Point<size_t> grid_coordinate(instance_ipin_node->xlow, instance_ipin_node->ylow);
|
||||
std::string sink_grid_module_name = generate_grid_block_module_name_in_top_module(std::string(GRID_MODULE_NAME_PREFIX), device_size, grids, grid_coordinate);
|
||||
ModuleId sink_grid_module = module_manager.find_module(sink_grid_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(sink_grid_module));
|
||||
size_t sink_grid_instance = grid_instance_ids[grid_coordinate.x()][grid_coordinate.y()];
|
||||
size_t sink_grid_pin_index = instance_ipin_node->ptc_num;
|
||||
size_t sink_grid_pin_height = find_grid_pin_height(grids, grid_coordinate, sink_grid_pin_index);
|
||||
std::string sink_grid_port_name = generate_grid_port_name(grid_coordinate, sink_grid_pin_height, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode), sink_grid_pin_index, false);
|
||||
ModulePortId sink_grid_port_id = module_manager.find_module_port(sink_grid_module, sink_grid_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(sink_grid_module, sink_grid_port_id));
|
||||
BasicPort sink_grid_port = module_manager.module_port(sink_grid_module, sink_grid_port_id);
|
||||
|
||||
/* Source and sink port should match in size */
|
||||
VTR_ASSERT(src_cb_port.get_width() == sink_grid_port.get_width());
|
||||
|
||||
/* Create a net for each pin */
|
||||
for (size_t pin_id = 0; pin_id < src_cb_port.pins().size(); ++pin_id) {
|
||||
ModuleNetId net = module_manager.create_module_net(top_module);
|
||||
/* Configure the net source */
|
||||
module_manager.add_module_net_source(top_module, net, src_cb_module, src_cb_instance, src_cb_port_id, src_cb_port.pins()[pin_id]);
|
||||
/* Configure the net sink */
|
||||
module_manager.add_module_net_sink(top_module, net, sink_grid_module, sink_grid_instance, sink_grid_port_id, sink_grid_port.pins()[pin_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will create nets for the connections
|
||||
* between connection block and switch block pins
|
||||
* Two cases should be considered:
|
||||
* a. The switch block pin denotes an input of a routing track
|
||||
* The net source is an output of a routing track of connection block
|
||||
* while the net sink is an input of a routing track of switch block
|
||||
* b. The switch block pin denotes an output of a routing track
|
||||
* The net source is an output of routing track of switch block
|
||||
* while the net sink is an input of a routing track of connection block
|
||||
*
|
||||
* +------------+ +------------------+ +------------+
|
||||
* | | | | | |
|
||||
* | Grid | | Connection Block | | Grid |
|
||||
* | [x][y+1] | | Y-direction | | [x+1][y+1] |
|
||||
* | | | [x][y+1] | | |
|
||||
* +------------+ +------------------+ +------------+
|
||||
* | ^
|
||||
* v |
|
||||
* +------------+ +------------------+ +------------+
|
||||
* | Connection |----->| |----->| Connection |
|
||||
* | Block | | Switch Block | | Block |
|
||||
* | X-direction|<-----| [x][y] |<-----| X-direction|
|
||||
* | [x][y] | | | | [x+1][y] |
|
||||
* +------------+ +------------------+ +------------+
|
||||
* | ^
|
||||
* v |
|
||||
* +------------+ +------------------+ +------------+
|
||||
* | | | | | |
|
||||
* | Grid | | Connection Block | | Grid |
|
||||
* | [x][y] | | Y-direction | | [x][y+1] |
|
||||
* | | | [x][y] | | |
|
||||
* +------------+ +------------------+ +------------+
|
||||
*
|
||||
* Here, to achieve the purpose, we can simply iterate over the
|
||||
* four sides of switch block and make connections to adjancent
|
||||
* connection blocks
|
||||
*
|
||||
*******************************************************************/
|
||||
static
|
||||
void add_top_module_nets_connect_sb_and_cb(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<size_t>>& sb_instance_ids,
|
||||
const std::map<t_rr_type, std::vector<std::vector<size_t>>>& cb_instance_ids,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
/* We could have two different coordinators, one is the instance, the other is the module */
|
||||
vtr::Point<size_t> instance_sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
|
||||
DeviceCoordinator module_gsb_sb_coordinate(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
|
||||
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
|
||||
if (true == compact_routing_hierarchy) {
|
||||
DeviceCoordinator gsb_coord(rr_gsb.get_x(), rr_gsb.get_y());
|
||||
const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(gsb_coord);
|
||||
module_gsb_sb_coordinate.set_x(unique_mirror.get_x());
|
||||
module_gsb_sb_coordinate.set_y(unique_mirror.get_y());
|
||||
}
|
||||
|
||||
/* This is the source cb that is added to the top module */
|
||||
const RRGSB& module_sb = L_device_rr_gsb.get_gsb(module_gsb_sb_coordinate);
|
||||
vtr::Point<size_t> module_sb_coordinate(module_sb.get_sb_x(), module_sb.get_sb_y());
|
||||
std::string sb_module_name = generate_switch_block_module_name(module_sb_coordinate);
|
||||
ModuleId sb_module_id = module_manager.find_module(sb_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(sb_module_id));
|
||||
size_t sb_instance = sb_instance_ids[instance_sb_coordinate.x()][instance_sb_coordinate.y()];
|
||||
|
||||
/* Connect grid output pins (OPIN) to switch block grid pins */
|
||||
for (size_t side = 0; side < module_sb.get_num_sides(); ++side) {
|
||||
Side side_manager(side);
|
||||
/* Iterate over the routing tracks on this side */
|
||||
/* Early skip: if there is no routing tracks at this side */
|
||||
if (0 == module_sb.get_chan_width(side_manager.get_side())) {
|
||||
continue;
|
||||
}
|
||||
/* Find the Connection Block module */
|
||||
/* We find the original connection block and then spot its unique mirror!
|
||||
* Do NOT use module_sb here!!!
|
||||
*/
|
||||
t_rr_type cb_type = find_top_module_cb_type_by_sb_side(side_manager.get_side());
|
||||
DeviceCoordinator instance_gsb_cb_coordinate = find_top_module_gsb_coordinate_by_sb_side(rr_gsb, side_manager.get_side());
|
||||
DeviceCoordinator module_gsb_cb_coordinate = find_top_module_gsb_coordinate_by_sb_side(rr_gsb, side_manager.get_side());
|
||||
|
||||
/* Skip those Connection blocks that do not exist:
|
||||
* 1. The CB does not exist in the device level! We should skip!
|
||||
* 2. The CB does exist but we need to make sure if the GSB includes such CBs
|
||||
* For TOP and LEFT side, check the existence using RRGSB method is_cb_exist()
|
||||
* FOr RIGHT and BOTTOM side, find the adjacent RRGSB and then use is_cb_exist()
|
||||
*/
|
||||
if ( TOP == side_manager.get_side() || LEFT == side_manager.get_side() ) {
|
||||
if ( false == rr_gsb.is_cb_exist(cb_type)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( RIGHT == side_manager.get_side() || BOTTOM == side_manager.get_side() ) {
|
||||
const RRGSB& adjacent_gsb = L_device_rr_gsb.get_gsb(module_gsb_cb_coordinate);
|
||||
if ( false == adjacent_gsb.is_cb_exist(cb_type)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we use compact routing hierarchy, we should find the unique module of CB, which is added to the top module */
|
||||
if (true == compact_routing_hierarchy) {
|
||||
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, module_gsb_cb_coordinate);
|
||||
module_gsb_cb_coordinate.set_x(unique_mirror.get_x());
|
||||
module_gsb_cb_coordinate.set_y(unique_mirror.get_y());
|
||||
}
|
||||
|
||||
const RRGSB& module_cb = L_device_rr_gsb.get_gsb(module_gsb_cb_coordinate);
|
||||
vtr::Point<size_t> module_cb_coordinate(module_cb.get_cb_x(cb_type), module_cb.get_cb_y(cb_type));
|
||||
std::string cb_module_name = generate_connection_block_module_name(cb_type, module_cb_coordinate);
|
||||
ModuleId cb_module_id = module_manager.find_module(cb_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(cb_module_id));
|
||||
const RRGSB& instance_cb = L_device_rr_gsb.get_gsb(instance_gsb_cb_coordinate);
|
||||
vtr::Point<size_t> instance_cb_coordinate(instance_cb.get_cb_x(cb_type), instance_cb.get_cb_y(cb_type));
|
||||
size_t cb_instance = cb_instance_ids.at(cb_type)[instance_cb_coordinate.x()][instance_cb_coordinate.y()];
|
||||
|
||||
for (size_t itrack = 0; itrack < module_sb.get_chan_width(side_manager.get_side()); ++itrack) {
|
||||
std::string sb_port_name = generate_sb_module_track_port_name(module_sb.get_chan_node(side_manager.get_side(), itrack)->type,
|
||||
side_manager.get_side(), itrack,
|
||||
module_sb.get_chan_node_direction(side_manager.get_side(), itrack));
|
||||
/* Prepare SB-related port information */
|
||||
ModulePortId sb_port_id = module_manager.find_module_port(sb_module_id, sb_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module_id, sb_port_id));
|
||||
BasicPort sb_port = module_manager.module_port(sb_module_id, sb_port_id);
|
||||
|
||||
/* Prepare CB-related port information */
|
||||
PORTS cb_port_direction = OUT_PORT;
|
||||
/* The cb port direction should be opposite to the sb port !!! */
|
||||
if (OUT_PORT == module_sb.get_chan_node_direction(side_manager.get_side(), itrack)) {
|
||||
cb_port_direction = IN_PORT;
|
||||
} else {
|
||||
VTR_ASSERT(IN_PORT == module_sb.get_chan_node_direction(side_manager.get_side(), itrack));
|
||||
}
|
||||
std::string cb_port_name = generate_cb_module_track_port_name(cb_type,
|
||||
itrack,
|
||||
cb_port_direction);
|
||||
ModulePortId cb_port_id = module_manager.find_module_port(cb_module_id, cb_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module_id, cb_port_id));
|
||||
BasicPort cb_port = module_manager.module_port(cb_module_id, cb_port_id);
|
||||
|
||||
/* Source and sink port should match in size */
|
||||
VTR_ASSERT(cb_port.get_width() == sb_port.get_width());
|
||||
|
||||
/* Create a net for each pin */
|
||||
for (size_t pin_id = 0; pin_id < cb_port.pins().size(); ++pin_id) {
|
||||
ModuleNetId net = module_manager.create_module_net(top_module);
|
||||
/* Configure the net source and sink:
|
||||
* If sb port is an output (source), cb port is an input (sink)
|
||||
* If sb port is an input (sink), cb port is an output (source)
|
||||
*/
|
||||
if (OUT_PORT == module_sb.get_chan_node_direction(side_manager.get_side(), itrack)) {
|
||||
module_manager.add_module_net_sink(top_module, net, cb_module_id, cb_instance, cb_port_id, cb_port.pins()[pin_id]);
|
||||
module_manager.add_module_net_source(top_module, net, sb_module_id, sb_instance, sb_port_id, sb_port.pins()[pin_id]);
|
||||
} else {
|
||||
VTR_ASSERT(IN_PORT == module_sb.get_chan_node_direction(side_manager.get_side(), itrack));
|
||||
module_manager.add_module_net_source(top_module, net, cb_module_id, cb_instance, cb_port_id, cb_port.pins()[pin_id]);
|
||||
module_manager.add_module_net_sink(top_module, net, sb_module_id, sb_instance, sb_port_id, sb_port.pins()[pin_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add module nets to connect the grid ports/pins to Connection Blocks
|
||||
* and Switch Blocks
|
||||
* To make it easy, this function will iterate over all the General
|
||||
* Switch Blocks (GSBs), through which we can obtain the coordinates
|
||||
* of all the grids, connection blocks and switch blocks that are
|
||||
* supposed to be connected tightly.
|
||||
*
|
||||
* As such, we have completed all the connection for each grid.
|
||||
* There is no need to iterate over the grids
|
||||
*
|
||||
* +-------------------------+ +---------------------------------+
|
||||
* | | | Y-direction CB |
|
||||
* | Grid[x][y+1] | | [x][y + 1] |
|
||||
* | | +---------------------------------+
|
||||
* +-------------------------+
|
||||
* TOP SIDE
|
||||
* +-------------+ +---------------------------------+
|
||||
* | | | OPIN_NODE CHAN_NODES OPIN_NODES |
|
||||
* | | | |
|
||||
* | | | OPIN_NODES OPIN_NODES |
|
||||
* | X-direction | | |
|
||||
* | CB | LEFT SIDE | Switch Block | RIGHT SIDE
|
||||
* | [x][y] | | [x][y] |
|
||||
* | | | |
|
||||
* | | | CHAN_NODES CHAN_NODES |
|
||||
* | | | |
|
||||
* | | | OPIN_NODES OPIN_NODES |
|
||||
* | | | |
|
||||
* | | | OPIN_NODE CHAN_NODES OPIN_NODES |
|
||||
* +-------------+ +---------------------------------+
|
||||
* BOTTOM SIDE
|
||||
*******************************************************************/
|
||||
void add_top_module_nets_connect_grids_and_gsbs(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const std::vector<std::vector<size_t>>& sb_instance_ids,
|
||||
const std::map<t_rr_type, std::vector<std::vector<size_t>>>& cb_instance_ids,
|
||||
const bool& compact_routing_hierarchy,
|
||||
const bool& duplicate_grid_pin) {
|
||||
DeviceCoordinator gsb_range = L_device_rr_gsb.get_gsb_range();
|
||||
for (size_t ix = 0; ix < gsb_range.get_x(); ++ix) {
|
||||
for (size_t iy = 0; iy < gsb_range.get_y(); ++iy) {
|
||||
vtr::Point<size_t> gsb_coordinate(ix, iy);
|
||||
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
|
||||
/* Connect the grid pins of the GSB to adjacent grids */
|
||||
if (false == duplicate_grid_pin) {
|
||||
add_top_module_nets_connect_grids_and_sb(module_manager, top_module,
|
||||
device_size, grids, grid_instance_ids,
|
||||
L_device_rr_gsb, rr_gsb, sb_instance_ids,
|
||||
compact_routing_hierarchy);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(true == duplicate_grid_pin);
|
||||
add_top_module_nets_connect_grids_and_sb_with_duplicated_pins(module_manager, top_module,
|
||||
device_size, grids, grid_instance_ids,
|
||||
L_device_rr_gsb, rr_gsb, sb_instance_ids,
|
||||
compact_routing_hierarchy);
|
||||
}
|
||||
|
||||
add_top_module_nets_connect_grids_and_cb(module_manager, top_module,
|
||||
device_size, grids, grid_instance_ids,
|
||||
L_device_rr_gsb, rr_gsb, CHANX, cb_instance_ids.at(CHANX),
|
||||
compact_routing_hierarchy);
|
||||
|
||||
add_top_module_nets_connect_grids_and_cb(module_manager, top_module,
|
||||
device_size, grids, grid_instance_ids,
|
||||
L_device_rr_gsb, rr_gsb, CHANY, cb_instance_ids.at(CHANY),
|
||||
compact_routing_hierarchy);
|
||||
|
||||
add_top_module_nets_connect_sb_and_cb(module_manager, top_module,
|
||||
L_device_rr_gsb, rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||
compact_routing_hierarchy);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef BUILD_TOP_MODULE_CONNECTION_H
|
||||
#define BUILD_TOP_MODULE_CONNECTION_H
|
||||
|
||||
#include <vector>
|
||||
#include "vtr_geometry.h"
|
||||
#include "vpr_types.h"
|
||||
#include "rr_blocks.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
void add_top_module_nets_connect_grids_and_gsbs(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const std::vector<std::vector<size_t>>& sb_instance_ids,
|
||||
const std::map<t_rr_type, std::vector<std::vector<size_t>>>& cb_instance_ids,
|
||||
const bool& compact_routing_hierarchy,
|
||||
const bool& duplicate_grid_pin);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,86 @@
|
|||
/********************************************************************
|
||||
* This file include most utilized functions for building the module
|
||||
* graph for FPGA fabric
|
||||
*******************************************************************/
|
||||
/* External library headers */
|
||||
#include "vtr_assert.h"
|
||||
|
||||
/* FPGA-X2P headers */
|
||||
#include "device_coordinator.h"
|
||||
#include "fpga_x2p_naming.h"
|
||||
#include "rr_blocks.h"
|
||||
|
||||
/* Module builder headers */
|
||||
#include "build_top_module_utils.h"
|
||||
|
||||
/* Global variables should be the last to include */
|
||||
#include "globals.h"
|
||||
|
||||
/********************************************************************
|
||||
* Generate the name for a grid block, by considering
|
||||
* 1. if it locates on the border with given device size
|
||||
* 2. its type
|
||||
*
|
||||
* This function is mainly used in the top-level module generation
|
||||
*******************************************************************/
|
||||
std::string generate_grid_block_module_name_in_top_module(const std::string& prefix,
|
||||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const vtr::Point<size_t>& grid_coordinate) {
|
||||
/* Determine if the grid locates at the border */
|
||||
e_side border_side = find_grid_border_side(device_size, grid_coordinate);
|
||||
|
||||
return generate_grid_block_module_name(prefix, std::string(grids[grid_coordinate.x()][grid_coordinate.y()].type->name),
|
||||
IO_TYPE == grids[grid_coordinate.x()][grid_coordinate.y()].type, border_side);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Find the cb_type of a GSB in the top-level module
|
||||
* depending on the side of SB
|
||||
* TOP/BOTTOM side: CHANY
|
||||
* RIGHT/LEFT side: CHANX
|
||||
*******************************************************************/
|
||||
t_rr_type find_top_module_cb_type_by_sb_side(const e_side& sb_side) {
|
||||
VTR_ASSERT(NUM_SIDES != sb_side);
|
||||
|
||||
if ((TOP == sb_side) || (BOTTOM == sb_side)) {
|
||||
return CHANY;
|
||||
}
|
||||
|
||||
VTR_ASSERT((RIGHT == sb_side) || (LEFT == sb_side));
|
||||
return CHANX;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Find the GSB coordinate for a CB in the top-level module
|
||||
* depending on the side of a SB
|
||||
* TODO: use vtr::Point<size_t> to replace DeviceCoordinator
|
||||
*******************************************************************/
|
||||
DeviceCoordinator find_top_module_gsb_coordinate_by_sb_side(const RRGSB& rr_gsb,
|
||||
const e_side& sb_side) {
|
||||
VTR_ASSERT(NUM_SIDES != sb_side);
|
||||
|
||||
DeviceCoordinator gsb_coordinate;
|
||||
|
||||
if ((TOP == sb_side) || (LEFT == sb_side)) {
|
||||
gsb_coordinate.set_x(rr_gsb.get_x());
|
||||
gsb_coordinate.set_y(rr_gsb.get_y());
|
||||
return gsb_coordinate;
|
||||
}
|
||||
|
||||
VTR_ASSERT((RIGHT == sb_side) || (BOTTOM == sb_side));
|
||||
|
||||
/* RIGHT side: x + 1 */
|
||||
if (RIGHT == sb_side) {
|
||||
gsb_coordinate.set_x(rr_gsb.get_x() + 1);
|
||||
gsb_coordinate.set_y(rr_gsb.get_y());
|
||||
}
|
||||
|
||||
/* BOTTOM side: y - 1 */
|
||||
if (BOTTOM == sb_side) {
|
||||
gsb_coordinate.set_x(rr_gsb.get_x());
|
||||
gsb_coordinate.set_y(rr_gsb.get_y() - 1);
|
||||
}
|
||||
|
||||
return gsb_coordinate;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef BUILD_TOP_MODULE_UTILS_H
|
||||
#define BUILD_TOP_MODULE_UTILS_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "vtr_geometry.h"
|
||||
#include "vpr_types.h"
|
||||
#include "sides.h"
|
||||
|
||||
std::string generate_grid_block_module_name_in_top_module(const std::string& prefix,
|
||||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const vtr::Point<size_t>& grid_coordinate);
|
||||
|
||||
t_rr_type find_top_module_cb_type_by_sb_side(const e_side& sb_side);
|
||||
|
||||
DeviceCoordinator find_top_module_gsb_coordinate_by_sb_side(const RRGSB& rr_gsb,
|
||||
const e_side& sb_side);
|
||||
|
||||
#endif
|
|
@ -50,11 +50,12 @@ void shell_execute_fpga_verilog(t_shell_env* env, t_opt_info* opts) {
|
|||
if (FALSE == shell_setup_fpga_verilog(env, opts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
vpr_fpga_verilog(env->module_manager, env->bitstream_manager, env->fabric_bitstream,
|
||||
env->mux_lib, env->logical_blocks, env->device_size, env->grids, env->blocks,
|
||||
env->device_rr_gsb,
|
||||
env->vpr_setup, env->arch,
|
||||
env->vpr_setup.FileNameOpts.CircuitName);
|
||||
std::string(env->vpr_setup.FileNameOpts.CircuitName), &(env->sram_orgz_info));
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "vtr_geometry.h"
|
||||
#include "vpr_types.h"
|
||||
#include "mux_library.h"
|
||||
#include "rr_blocks.h"
|
||||
#include "module_manager.h"
|
||||
#include "bitstream_manager.h"
|
||||
|
||||
|
@ -45,6 +46,8 @@ struct s_shell_env {
|
|||
vtr::Point<size_t> device_size;
|
||||
std::vector<std::vector<t_grid_tile>> grids;
|
||||
std::vector<t_block> blocks;
|
||||
DeviceRRGSB device_rr_gsb;
|
||||
t_sram_orgz_info sram_orgz_info;
|
||||
t_arch arch;
|
||||
t_vpr_setup vpr_setup;
|
||||
t_shell_cmd* cmd;
|
||||
|
|
|
@ -1,552 +0,0 @@
|
|||
/***********************************/
|
||||
/* Synthesizable Verilog Dumping */
|
||||
/* Xifan TANG, EPFL/LSI */
|
||||
/***********************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
/* Include vpr structs*/
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_geometry.h"
|
||||
#include "util.h"
|
||||
#include "physical_types.h"
|
||||
#include "vpr_types.h"
|
||||
#include "globals.h"
|
||||
#include "rr_graph.h"
|
||||
#include "vpr_utils.h"
|
||||
#include "path_delay.h"
|
||||
#include "stats.h"
|
||||
#include "route_common.h"
|
||||
|
||||
/* Include FPGA-SPICE utils */
|
||||
#include "read_xml_spice_util.h"
|
||||
#include "linkedlist.h"
|
||||
#include "fpga_x2p_types.h"
|
||||
#include "fpga_x2p_utils.h"
|
||||
#include "fpga_x2p_pbtypes_utils.h"
|
||||
#include "fpga_x2p_backannotate_utils.h"
|
||||
#include "fpga_x2p_globals.h"
|
||||
#include "fpga_bitstream.h"
|
||||
|
||||
#include "module_manager.h"
|
||||
#include "mux_library.h"
|
||||
#include "mux_library_builder.h"
|
||||
#include "circuit_library_utils.h"
|
||||
|
||||
/* Include SynVerilog headers */
|
||||
#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_grid.h"
|
||||
#include "verilog_routing.h"
|
||||
#include "verilog_top_module.h"
|
||||
#include "verilog_compact_netlist.h"
|
||||
#include "verilog_top_testbench.h"
|
||||
#include "verilog_autocheck_top_testbench.h"
|
||||
#include "verilog_formal_random_top_testbench.h"
|
||||
#include "verilog_preconfig_top_module.h"
|
||||
#include "verilog_verification_top_netlist.h"
|
||||
#include "verilog_modelsim_autodeck.h"
|
||||
#include "verilog_report_timing.h"
|
||||
#include "verilog_sdc.h"
|
||||
#include "verilog_formality_autodeck.h"
|
||||
#include "verilog_sdc_pb_types.h"
|
||||
#include "verilog_auxiliary_netlists.h"
|
||||
#include "simulation_info_writer.h"
|
||||
|
||||
#include "verilog_api.h"
|
||||
|
||||
/***** Subroutines *****/
|
||||
/* Alloc array that records Configuration bits for :
|
||||
* (1) Switch blocks
|
||||
* (2) Connection boxes
|
||||
* TODO: Can be improved in alloc strategy to be more memory efficient!
|
||||
*/
|
||||
static
|
||||
void alloc_global_routing_conf_bits() {
|
||||
int i;
|
||||
|
||||
/* Alloc array for Switch blocks */
|
||||
num_conf_bits_sb = (int**)my_malloc((nx+1)*sizeof(int*));
|
||||
for (i = 0; i < (nx + 1); i++) {
|
||||
num_conf_bits_sb[i] = (int*)my_calloc((ny+1), sizeof(int));
|
||||
}
|
||||
|
||||
/* Alloc array for Connection blocks */
|
||||
num_conf_bits_cbx = (int**)my_malloc((nx+1)*sizeof(int*));
|
||||
for (i = 0; i < (nx + 1); i++) {
|
||||
num_conf_bits_cbx[i] = (int*)my_calloc((ny+1), sizeof(int));
|
||||
}
|
||||
|
||||
num_conf_bits_cby = (int**)my_malloc((nx+1)*sizeof(int*));
|
||||
for (i = 0; i < (nx + 1); i++) {
|
||||
num_conf_bits_cby[i] = (int*)my_calloc((ny+1), sizeof(int));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
void free_global_routing_conf_bits() {
|
||||
int i;
|
||||
|
||||
/* Free array for Switch blocks */
|
||||
for (i = 0; i < (nx + 1); i++) {
|
||||
my_free(num_conf_bits_sb[i]);
|
||||
}
|
||||
my_free(num_conf_bits_sb);
|
||||
|
||||
/* Free array for Connection box */
|
||||
for (i = 0; i < (nx + 1); i++) {
|
||||
my_free(num_conf_bits_cbx[i]);
|
||||
}
|
||||
my_free(num_conf_bits_cbx);
|
||||
|
||||
for (i = 0; i < (nx + 1); i++) {
|
||||
my_free(num_conf_bits_cby[i]);
|
||||
}
|
||||
my_free(num_conf_bits_cby);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Top-level function*/
|
||||
void vpr_fpga_verilog(ModuleManager& module_manager,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const std::vector<ConfigBitId>& fabric_bitstream,
|
||||
const MuxLibrary& mux_lib,
|
||||
const std::vector<t_logical_block>& L_logical_blocks,
|
||||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& L_grids,
|
||||
const std::vector<t_block>& L_blocks,
|
||||
t_vpr_setup vpr_setup,
|
||||
t_arch Arch,
|
||||
char* circuit_name) {
|
||||
/* Timer */
|
||||
clock_t t_start;
|
||||
clock_t t_end;
|
||||
float run_time_sec;
|
||||
|
||||
int num_clocks = Arch.spice->spice_params.stimulate_params.num_clocks;
|
||||
/* int vpr_crit_path_delay = Arch.spice->spice_params.stimulate_params.vpr_crit_path_delay; */
|
||||
|
||||
/* Directory paths */
|
||||
char* verilog_dir_formatted = NULL;
|
||||
char* src_dir_path = NULL;
|
||||
char* submodule_dir_path= NULL;
|
||||
char* lb_dir_path = NULL;
|
||||
char* rr_dir_path = NULL;
|
||||
char* tcl_dir_path = NULL;
|
||||
char* sdc_dir_path = NULL;
|
||||
char* msim_dir_path = NULL;
|
||||
char* fm_dir_path = NULL;
|
||||
char* top_netlist_file = NULL;
|
||||
char* top_netlist_path = NULL;
|
||||
char* blif_testbench_file_name = NULL;
|
||||
char* blif_testbench_file_path = NULL;
|
||||
char* bitstream_file_name = NULL;
|
||||
char* bitstream_file_path = NULL;
|
||||
|
||||
char* chomped_parent_dir = NULL;
|
||||
char* chomped_circuit_name = NULL;
|
||||
|
||||
t_sram_orgz_info* sram_verilog_orgz_info = NULL;
|
||||
|
||||
/* 0. basic units: inverter, buffers and pass-gate logics, */
|
||||
/* Check if the routing architecture we support*/
|
||||
if (UNI_DIRECTIONAL != vpr_setup.RoutingArch.directionality) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "FPGA synthesizable Verilog dumping only support uni-directional routing architecture!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* We don't support mrFPGA */
|
||||
#ifdef MRFPGA_H
|
||||
if (is_mrFPGA) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "FPGA synthesizable verilog dumping do not support mrFPGA!\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
assert ( TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_syn_verilog);
|
||||
|
||||
/* VerilogGenerator formally starts*/
|
||||
vpr_printf(TIO_MESSAGE_INFO, "\nFPGA synthesizable verilog generator starts...\n");
|
||||
|
||||
/* Start time count */
|
||||
t_start = clock();
|
||||
|
||||
/* Format the directory paths */
|
||||
split_path_prog_name(circuit_name, '/', &chomped_parent_dir, &chomped_circuit_name);
|
||||
|
||||
if (NULL != vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.syn_verilog_dump_dir) {
|
||||
verilog_dir_formatted = format_dir_path(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.syn_verilog_dump_dir);
|
||||
} else {
|
||||
verilog_dir_formatted = format_dir_path(my_strcat(format_dir_path(chomped_parent_dir), default_verilog_dir_name));
|
||||
}
|
||||
|
||||
/* SRC directory */
|
||||
src_dir_path = format_dir_path(my_strcat(verilog_dir_formatted, default_src_dir_name));
|
||||
/* lb directory */
|
||||
lb_dir_path = my_strcat(src_dir_path, default_lb_dir_name);
|
||||
/* routing resources directory */
|
||||
rr_dir_path = my_strcat(src_dir_path, default_rr_dir_name);
|
||||
/* submodule_dir_path */
|
||||
submodule_dir_path = my_strcat(src_dir_path, default_submodule_dir_name);
|
||||
/* SDC_dir_path */
|
||||
sdc_dir_path = my_strcat(verilog_dir_formatted, default_sdc_dir_name);
|
||||
/* tcl_dir_path */
|
||||
tcl_dir_path = my_strcat(verilog_dir_formatted, default_tcl_dir_name);
|
||||
/* msim_dir_path */
|
||||
msim_dir_path = my_strcat(verilog_dir_formatted, default_msim_dir_name);
|
||||
/* fm_dir_path */
|
||||
fm_dir_path = my_strcat(verilog_dir_formatted, default_snpsfm_dir_name);
|
||||
/* Top netlists dir_path */
|
||||
top_netlist_file = my_strcat(chomped_circuit_name, verilog_top_postfix);
|
||||
top_netlist_path = my_strcat(src_dir_path, top_netlist_file);
|
||||
/* Report timing directory */
|
||||
if (NULL == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.report_timing_path) {
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.report_timing_path = my_strcat(verilog_dir_formatted, default_report_timing_rpt_dir_name);
|
||||
}
|
||||
|
||||
/* Create directories */
|
||||
create_dir_path(verilog_dir_formatted);
|
||||
create_dir_path(src_dir_path);
|
||||
create_dir_path(lb_dir_path);
|
||||
create_dir_path(rr_dir_path);
|
||||
create_dir_path(sdc_dir_path);
|
||||
create_dir_path(tcl_dir_path);
|
||||
create_dir_path(fm_dir_path);
|
||||
create_dir_path(msim_dir_path);
|
||||
create_dir_path(submodule_dir_path);
|
||||
|
||||
/* assign the global variable of SRAM model */
|
||||
assert(NULL != Arch.sram_inf.verilog_sram_inf_orgz); /* Check !*/
|
||||
sram_verilog_model = Arch.sram_inf.verilog_sram_inf_orgz->spice_model;
|
||||
/* initialize the SRAM organization information struct */
|
||||
sram_verilog_orgz_info = alloc_one_sram_orgz_info();
|
||||
init_sram_orgz_info(sram_verilog_orgz_info, Arch.sram_inf.verilog_sram_inf_orgz->type, sram_verilog_model, nx + 2, ny + 2);
|
||||
|
||||
/* Check all the SRAM port is using the correct SRAM SPICE MODEL */
|
||||
config_spice_models_sram_port_spice_model(Arch.spice->num_spice_model,
|
||||
Arch.spice->spice_models,
|
||||
Arch.sram_inf.verilog_sram_inf_orgz->spice_model);
|
||||
config_circuit_models_sram_port_to_default_sram_model(Arch.spice->circuit_lib, Arch.sram_inf.verilog_sram_inf_orgz->circuit_model);
|
||||
|
||||
/* Assign global variables of input and output pads */
|
||||
iopad_verilog_model = find_iopad_spice_model(Arch.spice->num_spice_model, Arch.spice->spice_models);
|
||||
assert(NULL != iopad_verilog_model);
|
||||
|
||||
/* zero the counter of each spice_model */
|
||||
zero_spice_models_cnt(Arch.spice->num_spice_model, Arch.spice->spice_models);
|
||||
|
||||
/* Initialize the user-defined verilog netlists to be included */
|
||||
init_list_include_verilog_netlists(Arch.spice);
|
||||
|
||||
/* Initial global variables about configuration bits */
|
||||
alloc_global_routing_conf_bits();
|
||||
|
||||
/* Initialize the number of configuration bits of all the grids */
|
||||
vpr_printf(TIO_MESSAGE_INFO, "Count the number of configuration bits, IO pads in each logic block...\n");
|
||||
/* init_grids_num_conf_bits(sram_verilog_orgz_type); */
|
||||
//init_grids_num_conf_bits(sram_verilog_orgz_info);
|
||||
init_pb_types_num_conf_bits(sram_verilog_orgz_info);
|
||||
//init_grids_num_iopads();
|
||||
init_pb_types_num_iopads();
|
||||
/* init_grids_num_mode_bits(); */
|
||||
|
||||
/* Print Verilog files containing preprocessing flags */
|
||||
print_verilog_preprocessing_flags_netlist(std::string(src_dir_path),
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
|
||||
|
||||
print_verilog_simulation_preprocessing_flags(std::string(src_dir_path),
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
|
||||
/*
|
||||
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 */
|
||||
print_verilog_routing_resources(module_manager, 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);
|
||||
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy) {
|
||||
print_verilog_unique_routing_modules(module_manager, device_rr_gsb,
|
||||
vpr_setup.RoutingArch,
|
||||
std::string(src_dir_path), std::string(rr_dir_path),
|
||||
TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
||||
} else {
|
||||
VTR_ASSERT(FALSE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy);
|
||||
print_verilog_flatten_routing_modules(module_manager, device_rr_gsb,
|
||||
vpr_setup.RoutingArch,
|
||||
std::string(src_dir_path), std::string(rr_dir_path),
|
||||
TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
||||
}
|
||||
|
||||
|
||||
/* Dump logic blocks
|
||||
* Branches to go:
|
||||
* 1. a compact output
|
||||
* 2. a full-size output
|
||||
*/
|
||||
print_compact_verilog_logic_blocks(sram_verilog_orgz_info, src_dir_path,
|
||||
lb_dir_path, Arch,
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
||||
|
||||
print_verilog_grids(module_manager,
|
||||
std::string(src_dir_path), std::string(lb_dir_path),
|
||||
TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
||||
|
||||
/* 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);
|
||||
|
||||
print_verilog_top_module(module_manager,
|
||||
std::string(vpr_setup.FileNameOpts.ArchFile),
|
||||
std::string(src_dir_path),
|
||||
TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
||||
|
||||
/* TODO: This is the old function, which will be deprecated when refactoring is done */
|
||||
dump_compact_verilog_top_netlist(sram_verilog_orgz_info, chomped_circuit_name,
|
||||
top_netlist_path, src_dir_path, submodule_dir_path, lb_dir_path, rr_dir_path,
|
||||
num_rr_nodes, rr_node, rr_node_indices,
|
||||
num_clocks,
|
||||
vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy,
|
||||
*(Arch.spice), vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
||||
|
||||
/* Dump SDC constraints */
|
||||
/* Output SDC to contrain the P&R flow
|
||||
*/
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_sdc_pnr) {
|
||||
verilog_generate_sdc_pnr(sram_verilog_orgz_info, sdc_dir_path,
|
||||
Arch, &vpr_setup.RoutingArch,
|
||||
num_rr_nodes, rr_node, rr_node_indices, rr_indexed_data,
|
||||
nx, ny, device_rr_gsb,
|
||||
vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy);
|
||||
}
|
||||
|
||||
/* dump verilog testbench only for input blif */
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_input_blif_testbench) {
|
||||
blif_testbench_file_name = my_strcat(chomped_circuit_name, blif_testbench_verilog_file_postfix);
|
||||
blif_testbench_file_path = my_strcat(src_dir_path, blif_testbench_file_name);
|
||||
dump_verilog_input_blif_testbench(chomped_circuit_name, blif_testbench_file_path, src_dir_path,
|
||||
*(Arch.spice));
|
||||
/* Free */
|
||||
my_free(blif_testbench_file_name);
|
||||
my_free(blif_testbench_file_path);
|
||||
}
|
||||
|
||||
/* Free sram_orgz_info:
|
||||
* Free the allocated sram_orgz_info before, we start bitstream generation !
|
||||
*/
|
||||
free_sram_orgz_info(sram_verilog_orgz_info,
|
||||
sram_verilog_orgz_info->type);
|
||||
|
||||
/* Force enable bitstream generator when we need to output Verilog top testbench*/
|
||||
if ((TRUE == vpr_setup.FPGA_SPICE_Opts.BitstreamGenOpts.gen_bitstream)
|
||||
|| (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_top_testbench)
|
||||
|| (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_autocheck_top_testbench)
|
||||
|| (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_formal_verification_top_netlist)) {
|
||||
vpr_setup.FPGA_SPICE_Opts.BitstreamGenOpts.gen_bitstream = TRUE;
|
||||
}
|
||||
|
||||
/* Generate bitstream if required, and also Dump bitstream file */
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.BitstreamGenOpts.gen_bitstream) {
|
||||
bitstream_file_name = my_strcat(chomped_circuit_name, fpga_spice_bitstream_output_file_postfix);
|
||||
bitstream_file_path = my_strcat(src_dir_path, bitstream_file_name);
|
||||
/* Run bitstream generation */
|
||||
vpr_fpga_generate_bitstream(vpr_setup, Arch, circuit_name, bitstream_file_path, &sram_verilog_orgz_info);
|
||||
my_free(bitstream_file_name);
|
||||
my_free(bitstream_file_path);
|
||||
}
|
||||
|
||||
/* Collect global ports from the circuit library
|
||||
* TODO: move outside this function
|
||||
*/
|
||||
std::vector<CircuitPortId> global_ports = find_circuit_library_global_ports(Arch.spice->circuit_lib);
|
||||
|
||||
/* dump verilog testbench only for top-level: ONLY valid when bitstream is generated! */
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_top_testbench) {
|
||||
std::string top_testbench_file_path = std::string(src_dir_path)
|
||||
+ std::string(chomped_circuit_name)
|
||||
+ std::string(top_testbench_verilog_file_postfix);
|
||||
/* TODO: this is an old function, to be shadowed */
|
||||
dump_verilog_top_testbench(sram_verilog_orgz_info, chomped_circuit_name, top_testbench_file_path.c_str(),
|
||||
src_dir_path, *(Arch.spice));
|
||||
}
|
||||
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_formal_verification_top_netlist) {
|
||||
std::string formal_verification_top_netlist_file_path = std::string(src_dir_path)
|
||||
+ std::string(chomped_circuit_name)
|
||||
+ std::string(formal_verification_verilog_file_postfix);
|
||||
/* TODO: this is an old function, to be shadowed */
|
||||
dump_verilog_formal_verification_top_netlist(sram_verilog_orgz_info, chomped_circuit_name,
|
||||
std::string(formal_verification_top_netlist_file_path + std::string(".bak")).c_str(), src_dir_path);
|
||||
/* TODO: new function: to be tested */
|
||||
print_verilog_preconfig_top_module(module_manager, bitstream_manager,
|
||||
Arch.spice->circuit_lib, global_ports, L_logical_blocks,
|
||||
device_size, L_grids, L_blocks,
|
||||
std::string(chomped_circuit_name), formal_verification_top_netlist_file_path,
|
||||
std::string(src_dir_path));
|
||||
|
||||
/* Output script for formality */
|
||||
write_formality_script(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts,
|
||||
fm_dir_path,
|
||||
src_dir_path,
|
||||
chomped_circuit_name,
|
||||
*(Arch.spice));
|
||||
|
||||
/* Print out top-level testbench using random vectors */
|
||||
std::string random_top_testbench_file_path = std::string(src_dir_path)
|
||||
+ std::string(chomped_circuit_name)
|
||||
+ std::string(random_top_testbench_verilog_file_postfix);
|
||||
print_verilog_random_top_testbench(std::string(chomped_circuit_name), random_top_testbench_file_path,
|
||||
std::string(src_dir_path), L_logical_blocks,
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, Arch.spice->spice_params);
|
||||
}
|
||||
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_simulation_ini) {
|
||||
/* Print exchangeable files which contains simulation settings */
|
||||
std::string simulation_ini_file_name;
|
||||
if (NULL != vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.simulation_ini_path) {
|
||||
simulation_ini_file_name = std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.simulation_ini_path);
|
||||
}
|
||||
print_verilog_simulation_info(simulation_ini_file_name,
|
||||
std::string(format_dir_path(chomped_parent_dir)),
|
||||
std::string(chomped_circuit_name),
|
||||
std::string(src_dir_path),
|
||||
bitstream_manager.bits().size(),
|
||||
Arch.spice->spice_params.meas_params.sim_num_clock_cycle,
|
||||
Arch.spice->spice_params.stimulate_params.prog_clock_freq,
|
||||
Arch.spice->spice_params.stimulate_params.op_clock_freq);
|
||||
}
|
||||
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_autocheck_top_testbench) {
|
||||
std::string autocheck_top_testbench_file_path = std::string(src_dir_path)
|
||||
+ std::string(chomped_circuit_name)
|
||||
+ std::string(autocheck_top_testbench_verilog_file_postfix);
|
||||
/* TODO: this is an old function, to be shadowed */
|
||||
/*
|
||||
dump_verilog_autocheck_top_testbench(sram_verilog_orgz_info, chomped_circuit_name,
|
||||
autocheck_top_testbench_file_path.c_str(), src_dir_path,
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, *(Arch.spice));
|
||||
*/
|
||||
/* TODO: new function: to be tested */
|
||||
print_verilog_top_testbench(module_manager, bitstream_manager, fabric_bitstream,
|
||||
sram_verilog_orgz_info->type,
|
||||
Arch.spice->circuit_lib, global_ports,
|
||||
L_logical_blocks, device_size, L_grids, L_blocks,
|
||||
std::string(chomped_circuit_name),
|
||||
autocheck_top_testbench_file_path,
|
||||
std::string(src_dir_path),
|
||||
Arch.spice->spice_params);
|
||||
}
|
||||
|
||||
/* Output Modelsim Autodeck scripts */
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_modelsim_autodeck) {
|
||||
dump_verilog_modelsim_autodeck(sram_verilog_orgz_info,
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts,
|
||||
*(Arch.spice),
|
||||
Arch.spice->spice_params.meas_params.sim_num_clock_cycle,
|
||||
msim_dir_path,
|
||||
chomped_circuit_name,
|
||||
src_dir_path);
|
||||
}
|
||||
|
||||
/* Output SDC to contrain the mapped FPGA in timing-analysis purpose
|
||||
*/
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_sdc_analysis) {
|
||||
verilog_generate_sdc_analysis(sram_verilog_orgz_info, sdc_dir_path,
|
||||
Arch,
|
||||
num_rr_nodes, rr_node, rr_node_indices,
|
||||
nx, ny, grid, block, device_rr_gsb,
|
||||
vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy);
|
||||
}
|
||||
/* Output routing report_timing script :
|
||||
*/
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_report_timing_tcl) {
|
||||
verilog_generate_report_timing(sram_verilog_orgz_info, tcl_dir_path,
|
||||
Arch, &vpr_setup.RoutingArch,
|
||||
num_rr_nodes, rr_node, rr_node_indices,
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts,
|
||||
vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy);
|
||||
}
|
||||
|
||||
if ((TRUE == vpr_setup.FPGA_SPICE_Opts.BitstreamGenOpts.gen_bitstream)
|
||||
|| (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_top_testbench)
|
||||
|| (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_autocheck_top_testbench)
|
||||
|| (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_formal_verification_top_netlist)) {
|
||||
/* Free sram_orgz_info:
|
||||
* Free the allocated sram_orgz_info before, we start bitstream generation !
|
||||
*/
|
||||
free_sram_orgz_info(sram_verilog_orgz_info,
|
||||
sram_verilog_orgz_info->type);
|
||||
}
|
||||
|
||||
/* Print a Verilog file including all the netlists that have been generated */
|
||||
std::string ref_verilog_benchmark_file_name;
|
||||
if (NULL != vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file) {
|
||||
ref_verilog_benchmark_file_name = std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file);
|
||||
}
|
||||
print_include_netlists(std::string(src_dir_path),
|
||||
std::string(chomped_circuit_name),
|
||||
ref_verilog_benchmark_file_name,
|
||||
Arch.spice->circuit_lib);
|
||||
|
||||
vpr_printf(TIO_MESSAGE_INFO, "Outputted %lu Verilog modules in total.\n", module_manager.num_modules());
|
||||
|
||||
/* End time count */
|
||||
t_end = clock();
|
||||
|
||||
run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
|
||||
vpr_printf(TIO_MESSAGE_INFO, "Synthesizable verilog dumping took %g seconds\n", run_time_sec);
|
||||
|
||||
/* Free global array */
|
||||
free_global_routing_conf_bits();
|
||||
|
||||
/* Free */
|
||||
my_free(verilog_dir_formatted);
|
||||
my_free(src_dir_path);
|
||||
my_free(lb_dir_path);
|
||||
my_free(rr_dir_path);
|
||||
my_free(msim_dir_path);
|
||||
my_free(fm_dir_path);
|
||||
my_free(sdc_dir_path);
|
||||
my_free(tcl_dir_path);
|
||||
my_free(top_netlist_file);
|
||||
my_free(top_netlist_path);
|
||||
my_free(submodule_dir_path);
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
/********************************************************************
|
||||
* This file include top-level function of FPGA-Verilog
|
||||
********************************************************************/
|
||||
/* Standard header files */
|
||||
#include <ctime>
|
||||
|
||||
/* External library header files */
|
||||
#include "util.h"
|
||||
#include "vtr_assert.h"
|
||||
#include "circuit_library_utils.h"
|
||||
|
||||
/* FPGA-X2P header files */
|
||||
#include "fpga_x2p_utils.h"
|
||||
#include "rr_blocks.h"
|
||||
|
||||
/* FPGA-Verilog header files */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_submodules.h"
|
||||
#include "verilog_routing.h"
|
||||
#include "verilog_submodules.h"
|
||||
#include "verilog_grid.h"
|
||||
#include "verilog_routing.h"
|
||||
#include "verilog_top_module.h"
|
||||
#include "verilog_top_testbench.h"
|
||||
#include "verilog_formal_random_top_testbench.h"
|
||||
#include "verilog_preconfig_top_module.h"
|
||||
#include "simulation_info_writer.h"
|
||||
#include "verilog_auxiliary_netlists.h"
|
||||
|
||||
/* Header file for this source file */
|
||||
#include "verilog_api.h"
|
||||
|
||||
/********************************************************************
|
||||
* Top-level function of FPGA-Verilog
|
||||
* This function will generate
|
||||
* 1. primitive modules required by the full fabric
|
||||
* which are LUTs, routing multiplexer, logic gates, transmission-gates etc.
|
||||
* 2. Routing modules, which are Switch Blocks (SBs) and Connection Blocks (CBs)
|
||||
* 3. Logic block modules, which are Configuration Logic Blocks (CLBs)
|
||||
* 4. FPGA module, which are the full FPGA fabric with configuration protocol
|
||||
* 5. A wrapper module, which encapsulate the FPGA module in a Verilog module which have the same port as the input benchmark
|
||||
* 6. Testbench, where a FPGA module is configured with a bitstream and then driven by input vectors
|
||||
* 7. Pre-configured testbench, which can skip the configuration phase and pre-configure the FPGA module. This testbench is created for quick verification and formal verification purpose.
|
||||
* 8. Verilog netlist including preprocessing flags and all the Verilog netlists that have been generated
|
||||
********************************************************************/
|
||||
void vpr_fpga_verilog(ModuleManager& module_manager,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const std::vector<ConfigBitId>& fabric_bitstream,
|
||||
const MuxLibrary& mux_lib,
|
||||
const std::vector<t_logical_block>& L_logical_blocks,
|
||||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& L_grids,
|
||||
const std::vector<t_block>& L_blocks,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const t_vpr_setup& vpr_setup,
|
||||
const t_arch& Arch,
|
||||
const std::string& circuit_name,
|
||||
t_sram_orgz_info* sram_verilog_orgz_info) {
|
||||
/* Start time count */
|
||||
clock_t t_start = clock();
|
||||
|
||||
/* 0. basic units: inverter, buffers and pass-gate logics, */
|
||||
/* Check if the routing architecture we support*/
|
||||
if (UNI_DIRECTIONAL != vpr_setup.RoutingArch.directionality) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"FPGA-Verilog only supports uni-directional routing architecture!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* We don't support mrFPGA */
|
||||
#ifdef MRFPGA_H
|
||||
if (is_mrFPGA) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"FPGA-Verilog does not support mrFPGA!\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Verilog generator formally starts*/
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"\nFPGA-Verilog starts...\n");
|
||||
|
||||
/* Format the directory paths */
|
||||
std::string chomped_parent_dir = find_path_dir_name(circuit_name);
|
||||
std::string chomped_circuit_name = find_path_file_name(circuit_name);
|
||||
|
||||
std::string verilog_dir_formatted;
|
||||
if (NULL != vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.syn_verilog_dump_dir) {
|
||||
verilog_dir_formatted = format_dir_path(std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.syn_verilog_dump_dir));
|
||||
} else {
|
||||
verilog_dir_formatted = format_dir_path(format_dir_path(chomped_parent_dir) + std::string(default_verilog_dir_name));
|
||||
}
|
||||
|
||||
/* Create directories */
|
||||
create_dir_path(verilog_dir_formatted.c_str());
|
||||
|
||||
/* SRC directory to contain all the netlists */
|
||||
std::string src_dir_path = format_dir_path(verilog_dir_formatted + std::string(default_src_dir_name));
|
||||
create_dir_path(src_dir_path.c_str());
|
||||
|
||||
/* Sub directory under SRC directory to contain all the primitive block netlists */
|
||||
std::string submodule_dir_path = src_dir_path + std::string(default_submodule_dir_name);
|
||||
create_dir_path(submodule_dir_path.c_str());
|
||||
|
||||
/* Sub directory under SRC directory to contain all the logic block netlists */
|
||||
std::string lb_dir_path = src_dir_path + std::string(default_lb_dir_name);
|
||||
create_dir_path(lb_dir_path.c_str());
|
||||
|
||||
/* Sub directory under SRC directory to contain all the routing block netlists */
|
||||
std::string rr_dir_path = src_dir_path + std::string(default_rr_dir_name);
|
||||
create_dir_path(rr_dir_path.c_str());
|
||||
|
||||
/* Ensure all the SRAM port is using the correct circuit model */
|
||||
config_circuit_models_sram_port_to_default_sram_model(Arch.spice->circuit_lib, Arch.sram_inf.verilog_sram_inf_orgz->circuit_model);
|
||||
|
||||
/* Print Verilog files containing preprocessing flags */
|
||||
print_verilog_preprocessing_flags_netlist(std::string(src_dir_path),
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
|
||||
|
||||
print_verilog_simulation_preprocessing_flags(std::string(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!!!
|
||||
*/
|
||||
print_verilog_submodules(module_manager, mux_lib, sram_verilog_orgz_info, src_dir_path.c_str(), submodule_dir_path.c_str(),
|
||||
Arch, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
|
||||
|
||||
/* Generate routing blocks */
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy) {
|
||||
print_verilog_unique_routing_modules(module_manager, L_device_rr_gsb,
|
||||
vpr_setup.RoutingArch,
|
||||
src_dir_path, rr_dir_path,
|
||||
TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
||||
} else {
|
||||
VTR_ASSERT(FALSE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy);
|
||||
print_verilog_flatten_routing_modules(module_manager, L_device_rr_gsb,
|
||||
vpr_setup.RoutingArch,
|
||||
src_dir_path, rr_dir_path,
|
||||
TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
||||
}
|
||||
|
||||
/* Generate grids */
|
||||
print_verilog_grids(module_manager,
|
||||
src_dir_path, lb_dir_path,
|
||||
TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
||||
|
||||
/* Generate FPGA fabric */
|
||||
print_verilog_top_module(module_manager,
|
||||
std::string(vpr_setup.FileNameOpts.ArchFile),
|
||||
src_dir_path,
|
||||
TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
||||
|
||||
/* Collect global ports from the circuit library
|
||||
* TODO: move outside this function
|
||||
*/
|
||||
std::vector<CircuitPortId> global_ports = find_circuit_library_global_ports(Arch.spice->circuit_lib);
|
||||
|
||||
/* Generate wrapper module for FPGA fabric (mapped by the input benchmark and pre-configured testbench for verification */
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_formal_verification_top_netlist) {
|
||||
std::string formal_verification_top_netlist_file_path = src_dir_path + chomped_circuit_name
|
||||
+ std::string(formal_verification_verilog_file_postfix);
|
||||
print_verilog_preconfig_top_module(module_manager, bitstream_manager,
|
||||
Arch.spice->circuit_lib, global_ports, L_logical_blocks,
|
||||
device_size, L_grids, L_blocks,
|
||||
std::string(chomped_circuit_name), formal_verification_top_netlist_file_path,
|
||||
std::string(src_dir_path));
|
||||
|
||||
/* Generate top-level testbench using random vectors */
|
||||
std::string random_top_testbench_file_path = src_dir_path + chomped_circuit_name
|
||||
+ std::string(random_top_testbench_verilog_file_postfix);
|
||||
print_verilog_random_top_testbench(chomped_circuit_name, random_top_testbench_file_path,
|
||||
src_dir_path, L_logical_blocks,
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, Arch.spice->spice_params);
|
||||
}
|
||||
|
||||
/* Generate exchangeable files which contains simulation settings */
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_simulation_ini) {
|
||||
std::string simulation_ini_file_name;
|
||||
if (NULL != vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.simulation_ini_path) {
|
||||
simulation_ini_file_name = std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.simulation_ini_path);
|
||||
}
|
||||
print_verilog_simulation_info(simulation_ini_file_name,
|
||||
format_dir_path(chomped_parent_dir),
|
||||
chomped_circuit_name,
|
||||
src_dir_path,
|
||||
bitstream_manager.bits().size(),
|
||||
Arch.spice->spice_params.meas_params.sim_num_clock_cycle,
|
||||
Arch.spice->spice_params.stimulate_params.prog_clock_freq,
|
||||
Arch.spice->spice_params.stimulate_params.op_clock_freq);
|
||||
}
|
||||
|
||||
/* Generate full testbench for verification, including configuration phase and operating phase */
|
||||
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_autocheck_top_testbench) {
|
||||
std::string autocheck_top_testbench_file_path = src_dir_path + chomped_circuit_name
|
||||
+ std::string(autocheck_top_testbench_verilog_file_postfix);
|
||||
print_verilog_top_testbench(module_manager, bitstream_manager, fabric_bitstream,
|
||||
sram_verilog_orgz_info->type,
|
||||
Arch.spice->circuit_lib, global_ports,
|
||||
L_logical_blocks, device_size, L_grids, L_blocks,
|
||||
chomped_circuit_name,
|
||||
autocheck_top_testbench_file_path,
|
||||
src_dir_path,
|
||||
Arch.spice->spice_params);
|
||||
}
|
||||
|
||||
/* Generate a Verilog file including all the netlists that have been generated */
|
||||
std::string ref_verilog_benchmark_file_name;
|
||||
if (NULL != vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file) {
|
||||
ref_verilog_benchmark_file_name = std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file);
|
||||
}
|
||||
print_include_netlists(src_dir_path,
|
||||
chomped_circuit_name,
|
||||
ref_verilog_benchmark_file_name,
|
||||
Arch.spice->circuit_lib);
|
||||
|
||||
/* Given a brief stats on how many Verilog modules have been written to files */
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Outputted %lu Verilog modules in total\n",
|
||||
module_manager.num_modules());
|
||||
|
||||
/* End time count */
|
||||
clock_t t_end = clock();
|
||||
|
||||
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"FPGA-Verilog took %g seconds\n",
|
||||
run_time_sec);
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
#ifndef VERILOG_API_H
|
||||
#define VERILOG_API_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "vpr_types.h"
|
||||
#include "mux_library.h"
|
||||
#include "rr_blocks.h"
|
||||
#include "module_manager.h"
|
||||
#include "bitstream_manager.h"
|
||||
|
||||
|
@ -15,8 +17,10 @@ void vpr_fpga_verilog(ModuleManager& module_manager,
|
|||
const vtr::Point<size_t>& device_size,
|
||||
const std::vector<std::vector<t_grid_tile>>& L_grids,
|
||||
const std::vector<t_block>& L_blocks,
|
||||
t_vpr_setup vpr_setup,
|
||||
t_arch Arch,
|
||||
char* circuit_name);
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const t_vpr_setup& vpr_setup,
|
||||
const t_arch& Arch,
|
||||
const std::string& circuit_name,
|
||||
t_sram_orgz_info* sram_verilog_orgz_info);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,406 +0,0 @@
|
|||
/***********************************/
|
||||
/* Dump Synthesizable Veriolog */
|
||||
/* Xifan TANG, EPFL/LSI */
|
||||
/***********************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Include vpr structs*/
|
||||
#include "util.h"
|
||||
#include "physical_types.h"
|
||||
#include "vpr_types.h"
|
||||
#include "globals.h"
|
||||
#include "rr_graph.h"
|
||||
#include "route_common.h"
|
||||
#include "vpr_utils.h"
|
||||
|
||||
/* Include spice support headers*/
|
||||
#include "read_xml_spice_util.h"
|
||||
#include "linkedlist.h"
|
||||
#include "fpga_x2p_types.h"
|
||||
#include "fpga_x2p_utils.h"
|
||||
#include "fpga_x2p_pbtypes_utils.h"
|
||||
#include "fpga_x2p_backannotate_utils.h"
|
||||
#include "fpga_x2p_bitstream_utils.h"
|
||||
#include "fpga_x2p_globals.h"
|
||||
#include "fpga_bitstream.h"
|
||||
|
||||
/* Include verilog support headers*/
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_utils.h"
|
||||
#include "verilog_routing.h"
|
||||
#include "verilog_pbtypes.h"
|
||||
#include "verilog_decoder.h"
|
||||
#include "verilog_top_netlist_utils.h"
|
||||
#include "verilog_top_testbench.h"
|
||||
|
||||
#include "verilog_autocheck_top_testbench.h"
|
||||
|
||||
/* Local variables */
|
||||
static char* autocheck_testbench_reference_output_postfix = "_benchmark";
|
||||
static char* autocheck_testbench_verification_output_postfix = "_verification";
|
||||
static char* error_counter = "nb_error";
|
||||
|
||||
/* Local Subroutines declaration */
|
||||
|
||||
/******** Subroutines ***********/
|
||||
static
|
||||
void dump_verilog_top_auto_testbench_ports(FILE* fp,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* circuit_name,
|
||||
t_syn_verilog_opts fpga_verilog_opts){
|
||||
int num_array_bl, num_array_wl;
|
||||
int bl_decoder_size, wl_decoder_size;
|
||||
int iblock, iopad_idx;
|
||||
t_spice_model* mem_model = NULL;
|
||||
char* port_name = NULL;
|
||||
|
||||
get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
|
||||
|
||||
fprintf(fp, "`include \"%s\"\n", fpga_verilog_opts.reference_verilog_benchmark_file);
|
||||
|
||||
fprintf(fp, "module %s%s;\n", circuit_name, modelsim_autocheck_testbench_module_postfix);
|
||||
/* Local wires */
|
||||
/* 1. reset, set, clock signals */
|
||||
/* 2. iopad signals */
|
||||
|
||||
/* Connect to defined signals */
|
||||
/* set and reset signals */
|
||||
fprintf(fp, "\n");
|
||||
dump_verilog_top_testbench_global_ports(fp, global_ports_head, VERILOG_PORT_WIRE);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
/* TODO: dump each global signal as reg here */
|
||||
|
||||
/* Inputs and outputs of I/O pads */
|
||||
/* Inout Pads */
|
||||
assert(NULL != iopad_verilog_model);
|
||||
if ((NULL == iopad_verilog_model)
|
||||
||(iopad_verilog_model->cnt > 0)) {
|
||||
/* Malloc and assign port_name */
|
||||
port_name = (char*)my_malloc(sizeof(char)*(strlen(gio_inout_prefix) + strlen(iopad_verilog_model->prefix) + 1));
|
||||
sprintf(port_name, "%s%s", gio_inout_prefix, iopad_verilog_model->prefix);
|
||||
/* Dump a wired port */
|
||||
dump_verilog_generic_port(fp, VERILOG_PORT_WIRE,
|
||||
port_name, iopad_verilog_model->cnt - 1, 0);
|
||||
fprintf(fp, "; //--- FPGA inouts \n");
|
||||
/* Free port_name */
|
||||
my_free(port_name);
|
||||
/* Malloc and assign port_name */
|
||||
port_name = (char*)my_malloc(sizeof(char)*(strlen(gio_inout_prefix) + strlen(iopad_verilog_model->prefix) + strlen(top_tb_inout_reg_postfix) + 1));
|
||||
sprintf(port_name, "%s%s%s", gio_inout_prefix, iopad_verilog_model->prefix, top_tb_inout_reg_postfix);
|
||||
/* Dump a wired port */
|
||||
dump_verilog_generic_port(fp, VERILOG_PORT_REG,
|
||||
port_name, iopad_verilog_model->cnt - 1, 0);
|
||||
fprintf(fp, "; //--- reg for FPGA inouts \n");
|
||||
/* Free port_name */
|
||||
my_free(port_name);
|
||||
}
|
||||
|
||||
/* Add a signal to identify the configuration phase is finished */
|
||||
fprintf(fp, "reg [0:0] %s;\n", top_tb_config_done_port_name);
|
||||
/* Programming clock */
|
||||
fprintf(fp, "wire [0:0] %s;\n", top_tb_prog_clock_port_name);
|
||||
fprintf(fp, "reg [0:0] %s%s;\n", top_tb_prog_clock_port_name, top_tb_clock_reg_postfix);
|
||||
/* Operation clock */
|
||||
fprintf(fp, "wire [0:0] %s;\n", top_tb_op_clock_port_name);
|
||||
fprintf(fp, "reg [0:0] %s%s;\n", top_tb_op_clock_port_name, top_tb_clock_reg_postfix);
|
||||
/* Programming set and reset */
|
||||
fprintf(fp, "reg [0:0] %s;\n", top_tb_prog_reset_port_name);
|
||||
fprintf(fp, "reg [0:0] %s;\n", top_tb_prog_set_port_name);
|
||||
/* Global set and reset */
|
||||
fprintf(fp, "reg [0:0] %s;\n", top_tb_reset_port_name);
|
||||
fprintf(fp, "reg [0:0] %s;\n", top_tb_set_port_name);
|
||||
/* Generate stimuli for global ports or connect them to existed signals */
|
||||
dump_verilog_top_testbench_global_ports_stimuli(fp, global_ports_head);
|
||||
|
||||
/* Configuration ports depend on the organization of SRAMs */
|
||||
switch(cur_sram_orgz_info->type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
dump_verilog_generic_port(fp, VERILOG_PORT_WIRE,
|
||||
sram_verilog_model->prefix, sram_verilog_model->cnt - 1, 0);
|
||||
fprintf(fp, "; //---- SRAM outputs \n");
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
/* We put the head of scan-chains here
|
||||
*/
|
||||
dump_verilog_generic_port(fp, VERILOG_PORT_REG,
|
||||
top_netlist_scan_chain_head_prefix, 0, 0);
|
||||
fprintf(fp, "; //---- Scan-chain head \n");
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
/* Get the number of array BLs/WLs, decoder sizes */
|
||||
determine_blwl_decoder_size(cur_sram_orgz_info,
|
||||
&num_array_bl, &num_array_wl, &bl_decoder_size, &wl_decoder_size);
|
||||
|
||||
fprintf(fp, " wire [0:0] %s;\n",
|
||||
top_netlist_bl_enable_port_name);
|
||||
fprintf(fp, " wire [0:0] %s;\n",
|
||||
top_netlist_wl_enable_port_name);
|
||||
/* Wire en_bl, en_wl to prog_clock */
|
||||
fprintf(fp, "assign %s[0:0] = %s[0:0];\n",
|
||||
top_netlist_bl_enable_port_name,
|
||||
top_tb_prog_clock_port_name);
|
||||
fprintf(fp, "assign %s [0:0]= %s[0:0];\n",
|
||||
top_netlist_wl_enable_port_name,
|
||||
top_tb_prog_clock_port_name);
|
||||
dump_verilog_generic_port(fp, VERILOG_PORT_REG,
|
||||
top_netlist_addr_bl_port_name, bl_decoder_size - 1, 0);
|
||||
fprintf(fp, "; //--- Address of bit lines \n");
|
||||
dump_verilog_generic_port(fp, VERILOG_PORT_REG,
|
||||
top_netlist_addr_wl_port_name, wl_decoder_size - 1, 0);
|
||||
fprintf(fp, "; //--- Address of word lines \n");
|
||||
/* data_in is only require by BL decoder of SRAM array
|
||||
* As for RRAM array, the data_in signal will not be used
|
||||
*/
|
||||
if (SPICE_MODEL_DESIGN_CMOS == mem_model->design_tech) {
|
||||
fprintf(fp, " reg [0:0] %s; // --- Data_in signal for BL decoder, only required by SRAM array \n",
|
||||
top_netlist_bl_data_in_port_name);
|
||||
}
|
||||
/* I add all the Bit lines and Word lines here just for testbench usage
|
||||
fprintf(fp, " input wire [%d:0] %s_out; //--- Bit lines \n",
|
||||
sram_verilog_model->cnt - 1, sram_verilog_model->prefix);
|
||||
fprintf(fp, " input wire [%d:0] %s_outb; //--- Word lines \n",
|
||||
sram_verilog_model->cnt - 1, sram_verilog_model->prefix);
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization in Verilog Generator!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Add signals from blif benchmark and short-wire them to FPGA I/O PADs
|
||||
* This brings convenience to checking functionality
|
||||
*/
|
||||
fprintf(fp, "//-----Link Blif Benchmark inputs to FPGA IOPADs -----\n");
|
||||
for (iblock = 0; iblock < num_logical_blocks; iblock++) {
|
||||
/* General INOUT*/
|
||||
if (iopad_verilog_model == logical_block[iblock].mapped_spice_model) {
|
||||
iopad_idx = logical_block[iblock].mapped_spice_model_index;
|
||||
/* Make sure We find the correct logical block !*/
|
||||
assert((VPACK_INPAD == logical_block[iblock].type)
|
||||
||(VPACK_OUTPAD == logical_block[iblock].type));
|
||||
fprintf(fp, "//----- Blif Benchmark inout %s is mapped to FPGA IOPAD %s[%d] -----\n",
|
||||
logical_block[iblock].name, gio_inout_prefix, iopad_idx);
|
||||
fprintf(fp, "wire %s_%s_%d_;\n",
|
||||
logical_block[iblock].name, gio_inout_prefix, iopad_idx);
|
||||
fprintf(fp, "assign %s_%s_%d_ = %s%s[%d];\n",
|
||||
logical_block[iblock].name, gio_inout_prefix, iopad_idx,
|
||||
gio_inout_prefix, iopad_verilog_model->prefix, iopad_idx);
|
||||
// AA: Generate wire and reg to autocheck with benchmark
|
||||
if(VPACK_OUTPAD == logical_block[iblock].type) {
|
||||
fprintf(fp, "wire %s%s;\n",
|
||||
logical_block[iblock].name,
|
||||
autocheck_testbench_reference_output_postfix);
|
||||
fprintf(fp, "reg %s%s;\n",
|
||||
logical_block[iblock].name,
|
||||
autocheck_testbench_verification_output_postfix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate an integer to count the number of error and determine if the simulation succeed or failed
|
||||
fprintf(fp, "\n//----- Error counter \n");
|
||||
fprintf(fp, " integer %s = 0;\n\n", error_counter);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
void dump_verilog_top_auto_testbench_call_benchmark(FILE* fp,
|
||||
char* reference_verilog_top_name){
|
||||
int iblock, iopad_idx;
|
||||
|
||||
fprintf(fp, "// Reference Benchmark instanciation\n");
|
||||
fprintf(fp, " %s ref_U0(\n", reference_verilog_top_name);
|
||||
|
||||
for (iblock = 0; iblock < num_logical_blocks; iblock++) {
|
||||
/* General INOUT*/
|
||||
if (iopad_verilog_model == logical_block[iblock].mapped_spice_model) {
|
||||
iopad_idx = logical_block[iblock].mapped_spice_model_index;
|
||||
/* Make sure We find the correct logical block !*/
|
||||
assert((VPACK_INPAD == logical_block[iblock].type)
|
||||
||(VPACK_OUTPAD == logical_block[iblock].type));
|
||||
if(iblock > 0){
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
if(VPACK_INPAD == logical_block[iblock].type){
|
||||
/* See if this is a clock net */
|
||||
if (TRUE == logical_block[iblock].is_clock) {
|
||||
fprintf(fp, " %s", top_tb_op_clock_port_name);
|
||||
} else{
|
||||
fprintf(fp, " %s_%s_%d_", logical_block[iblock].name, gio_inout_prefix, iopad_idx);
|
||||
}
|
||||
} else if(VPACK_OUTPAD == logical_block[iblock].type){
|
||||
fprintf(fp, " %s%s",
|
||||
logical_block[iblock].name,
|
||||
autocheck_testbench_reference_output_postfix);
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(fp, " );\n");
|
||||
fprintf(fp, "// End Benchmark instanciation\n\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
int get_simulation_time(int num_prog_clock_cycles,
|
||||
float prog_clock_period,
|
||||
int num_op_clock_cycles,
|
||||
float op_clock_period) {
|
||||
int total_time_period = 0;
|
||||
|
||||
/* Take into account the prog_reset and reset cycles */
|
||||
total_time_period = ((num_prog_clock_cycles + 2) * prog_clock_period + (2 * num_op_clock_cycles * op_clock_period)) * 1000000000; // * 1000000000 is to change the unit to ns rather than second
|
||||
|
||||
return total_time_period;
|
||||
}
|
||||
|
||||
static
|
||||
void dump_verilog_timeout_and_vcd(FILE * fp,
|
||||
char* circuit_name,
|
||||
t_spice verilog,
|
||||
t_sram_orgz_info* cur_sram_orgz_info){
|
||||
int simulation_time;
|
||||
|
||||
simulation_time = get_simulation_time(get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info),
|
||||
1./verilog.spice_params.stimulate_params.prog_clock_freq,
|
||||
verilog.spice_params.meas_params.sim_num_clock_cycle,
|
||||
1./verilog.spice_params.stimulate_params.op_clock_freq);
|
||||
|
||||
fprintf(fp, " // Begin Icarus requirement\n");
|
||||
fprintf(fp, "`ifdef %s\n", icarus_simulator_flag);
|
||||
fprintf(fp, " initial begin\n");
|
||||
fprintf(fp, " $dumpfile(\"%s_autochecked.vcd\");\n", circuit_name);
|
||||
fprintf(fp, " $dumpvars(1, %s%s);\n", circuit_name,
|
||||
modelsim_autocheck_testbench_module_postfix);
|
||||
fprintf(fp, " end\n\n");
|
||||
fprintf(fp, " initial begin\n");
|
||||
fprintf(fp, " $timeformat(-9, 2, \"ns\", 20);\n");
|
||||
fprintf(fp, " $display(\"Simulation start\");\n");
|
||||
fprintf(fp, " #%i // Can be changed by the user for his need\n", simulation_time);
|
||||
fprintf(fp, " if(%s == 0) begin\n", error_counter);
|
||||
fprintf(fp, " $display(\"Simulation Succeed\");\n");
|
||||
fprintf(fp, " end else begin\n");
|
||||
fprintf(fp, " $display(\"Simulation Failed with %s error(s)\", %s);\n", "%d", error_counter);
|
||||
fprintf(fp, " end\n");
|
||||
fprintf(fp, " $finish;\n");
|
||||
fprintf(fp, " end\n");
|
||||
fprintf(fp, "`endif\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
void dump_verilog_top_auto_testbench_check(FILE* fp){
|
||||
int iblock, iopad_idx;
|
||||
fprintf(fp, " // Begin checking\n");
|
||||
fprintf(fp, " always@(negedge %s) begin\n", top_tb_op_clock_port_name);
|
||||
for (iblock = 0; iblock < num_logical_blocks; iblock++) {
|
||||
if (iopad_verilog_model == logical_block[iblock].mapped_spice_model) {
|
||||
iopad_idx = logical_block[iblock].mapped_spice_model_index;
|
||||
/* 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){
|
||||
fprintf(fp, " %s%s <= %s%s ^ %s_%s_%d_ ;\n",
|
||||
logical_block[iblock].name,
|
||||
autocheck_testbench_verification_output_postfix,
|
||||
logical_block[iblock].name,
|
||||
autocheck_testbench_reference_output_postfix,
|
||||
logical_block[iblock].name,
|
||||
gio_inout_prefix, iopad_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(fp, " end\n\n");
|
||||
for (iblock = 0; iblock < num_logical_blocks; iblock++) {
|
||||
if (iopad_verilog_model == logical_block[iblock].mapped_spice_model) {
|
||||
iopad_idx = logical_block[iblock].mapped_spice_model_index;
|
||||
/* 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){
|
||||
fprintf(fp, " always@(posedge %s%s) begin\n",
|
||||
logical_block[iblock].name,
|
||||
autocheck_testbench_verification_output_postfix);
|
||||
fprintf(fp, " if(%s%s) begin\n",
|
||||
logical_block[iblock].name,
|
||||
autocheck_testbench_verification_output_postfix);
|
||||
fprintf(fp, " %s = %s + 1;\n", error_counter, error_counter);
|
||||
fprintf(fp, " $display(\"Mismatch on %s%s at time = %s\", $realtime);\n",
|
||||
logical_block[iblock].name,
|
||||
autocheck_testbench_verification_output_postfix, "%t");
|
||||
fprintf(fp, " end\n");
|
||||
fprintf(fp, " end\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void dump_verilog_autocheck_top_testbench(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* circuit_name,
|
||||
const char* top_netlist_name,
|
||||
char* verilog_dir_path,
|
||||
t_syn_verilog_opts fpga_verilog_opts,
|
||||
t_spice verilog) {
|
||||
FILE* fp = NULL;
|
||||
char* title = my_strcat("FPGA Verilog Testbench for Top-level netlist of Design: ", circuit_name);
|
||||
bool is_explicit_mapping = fpga_verilog_opts.dump_explicit_verilog;
|
||||
|
||||
/* Check if the path exists*/
|
||||
fp = fopen(top_netlist_name,"w");
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s,LINE[%d])Failure in create top Verilog testbench %s!",
|
||||
__FILE__, __LINE__, top_netlist_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Writing Autocheck Testbench for FPGA Top-level Verilog netlist for %s...\n",
|
||||
circuit_name);
|
||||
|
||||
/* Print the title */
|
||||
dump_verilog_file_header(fp, title);
|
||||
my_free(title);
|
||||
|
||||
/* Print preprocessing flags */
|
||||
verilog_include_defines_preproc_file(fp, verilog_dir_path);
|
||||
|
||||
/* Start of testbench */
|
||||
dump_verilog_top_auto_testbench_ports(fp, cur_sram_orgz_info, circuit_name, fpga_verilog_opts);
|
||||
|
||||
/* Call defined top-level module */
|
||||
dump_verilog_top_testbench_call_top_module(cur_sram_orgz_info, fp,
|
||||
circuit_name, is_explicit_mapping);
|
||||
|
||||
/* Call defined benchmark */
|
||||
dump_verilog_top_auto_testbench_call_benchmark(fp, circuit_name);
|
||||
|
||||
/* Add stimuli for reset, set, clock and iopad signals */
|
||||
dump_verilog_top_testbench_stimuli(cur_sram_orgz_info, fp, verilog);
|
||||
|
||||
/* Add output autocheck */
|
||||
dump_verilog_top_auto_testbench_check(fp);
|
||||
|
||||
/* Add Icarus requirement */
|
||||
dump_verilog_timeout_and_vcd(fp, circuit_name , verilog, cur_sram_orgz_info);
|
||||
|
||||
/* Testbench ends*/
|
||||
fprintf(fp, "endmodule\n");
|
||||
|
||||
/* Close the file*/
|
||||
fclose(fp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef VERILOG_AUTOCHECK_TOP_TESTBENCH_H
|
||||
#define VERILOG_AUTOCHECK_TOP_TESTBENCH_H
|
||||
|
||||
|
||||
void dump_verilog_autocheck_top_testbench(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* circuit_name,
|
||||
const char* top_netlist_name,
|
||||
char* verilog_dir_path,
|
||||
t_syn_verilog_opts fpga_verilog_opts,
|
||||
t_spice verilog);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,32 +0,0 @@
|
|||
#ifndef VERILOG_COMPACT_NETLIST_H
|
||||
#define VERILOG_COMPACT_NETLIST_H
|
||||
|
||||
|
||||
void dump_compact_verilog_one_physical_block(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* verilog_dir_path,
|
||||
char* subckt_dir_path,
|
||||
t_type_ptr phy_block_type,
|
||||
int border_side,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void print_compact_verilog_logic_blocks(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* verilog_dir,
|
||||
char* subckt_dir,
|
||||
t_arch& arch,
|
||||
const bool& is_explicit_mapping);
|
||||
|
||||
void dump_compact_verilog_top_netlist(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* circuit_name,
|
||||
char* top_netlist_name,
|
||||
char* verilog_dir_path,
|
||||
char* submodule_dir_path,
|
||||
char* lb_dir_path,
|
||||
char* rr_dir_path,
|
||||
int LL_num_rr_nodes,
|
||||
t_rr_node* LL_rr_node,
|
||||
t_ivec*** LL_rr_node_indices,
|
||||
int num_clock,
|
||||
boolean compact_routing_hierarchy,
|
||||
t_spice verilog,
|
||||
bool is_explicit_verilog);
|
||||
#endif
|
|
@ -1,751 +0,0 @@
|
|||
/***********************************/
|
||||
/* Synthesizable Verilog Dumping */
|
||||
/* Xifan TANG, EPFL/LSI */
|
||||
/***********************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Include vpr structs*/
|
||||
#include "util.h"
|
||||
#include "physical_types.h"
|
||||
#include "vpr_types.h"
|
||||
#include "globals.h"
|
||||
#include "rr_graph.h"
|
||||
#include "vpr_utils.h"
|
||||
#include "path_delay.h"
|
||||
#include "stats.h"
|
||||
|
||||
/* Include FPGA-SPICE utils */
|
||||
#include "linkedlist.h"
|
||||
#include "fpga_x2p_utils.h"
|
||||
#include "fpga_x2p_bitstream_utils.h"
|
||||
#include "fpga_x2p_globals.h"
|
||||
|
||||
/* Include verilog utils */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_utils.h"
|
||||
|
||||
#include "verilog_decoder.h"
|
||||
|
||||
/***** Subroutines *****/
|
||||
void dump_verilog_decoder_memory_bank_ports(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
enum e_dump_verilog_port_type dump_port_type) {
|
||||
t_spice_model* mem_model = NULL;
|
||||
int num_array_bl, num_array_wl;
|
||||
int bl_decoder_size, wl_decoder_size;
|
||||
char split_sign;
|
||||
|
||||
split_sign = determine_verilog_generic_port_split_sign(dump_port_type);
|
||||
|
||||
/* Only accept two types of dump_port_type here! */
|
||||
assert((VERILOG_PORT_INPUT == dump_port_type)||(VERILOG_PORT_CONKT == dump_port_type));
|
||||
|
||||
/* Check */
|
||||
assert (cur_sram_orgz_info->type == SPICE_SRAM_MEMORY_BANK);
|
||||
|
||||
/* A valid file handler */
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid File Handler!\n", __FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Depending on the memory technology*/
|
||||
get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
|
||||
assert(NULL != mem_model);
|
||||
|
||||
determine_blwl_decoder_size(cur_sram_orgz_info,
|
||||
&num_array_bl, &num_array_wl, &bl_decoder_size, &wl_decoder_size);
|
||||
|
||||
/* Depend on the memory technology */
|
||||
switch (mem_model->design_tech) {
|
||||
case SPICE_MODEL_DESIGN_CMOS:
|
||||
dump_verilog_generic_port(fp, dump_port_type,
|
||||
top_netlist_bl_enable_port_name, 0, 0);
|
||||
fprintf(fp, "%c //--- BL enable port \n", split_sign);
|
||||
dump_verilog_generic_port(fp, dump_port_type,
|
||||
top_netlist_wl_enable_port_name, 0, 0);
|
||||
fprintf(fp, "%c //--- WL enable port \n", split_sign);
|
||||
dump_verilog_generic_port(fp, dump_port_type,
|
||||
top_netlist_bl_data_in_port_name, 0, 0);
|
||||
fprintf(fp, "%c //--- BL data input port \n", split_sign);
|
||||
break;
|
||||
case SPICE_MODEL_DESIGN_RRAM:
|
||||
dump_verilog_generic_port(fp, dump_port_type,
|
||||
top_netlist_bl_enable_port_name, 0, 0);
|
||||
fprintf(fp, "%c //--- BL enable port \n", split_sign);
|
||||
dump_verilog_generic_port(fp, dump_port_type,
|
||||
top_netlist_wl_enable_port_name, 0, 0);
|
||||
fprintf(fp, "%c //--- WL enable port \n", split_sign);
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization in Verilog Generator!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dump_verilog_generic_port(fp, dump_port_type,
|
||||
top_netlist_addr_bl_port_name, bl_decoder_size - 1, 0);
|
||||
fprintf(fp, "%c //--- Address of bit lines \n", split_sign);
|
||||
dump_verilog_generic_port(fp, dump_port_type,
|
||||
top_netlist_addr_wl_port_name, wl_decoder_size - 1, 0);
|
||||
fprintf(fp, " //--- Address of word lines \n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void dump_verilog_decoder(FILE* fp,
|
||||
t_sram_orgz_info* cur_sram_orgz_info) {
|
||||
int num_array_bl, num_array_wl;
|
||||
int bl_decoder_size, wl_decoder_size;
|
||||
t_spice_model* mem_model = NULL;
|
||||
boolean bl_inverted = FALSE;
|
||||
boolean wl_inverted = FALSE;
|
||||
|
||||
/* Check */
|
||||
assert(SPICE_SRAM_MEMORY_BANK == cur_sram_orgz_info->type);
|
||||
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Get number of BLs,WLs and decoder sizes */
|
||||
determine_blwl_decoder_size(cur_sram_orgz_info,
|
||||
&num_array_bl, &num_array_wl,
|
||||
&bl_decoder_size, &wl_decoder_size);
|
||||
|
||||
/* Different design technology requires different BL decoder logic */
|
||||
get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
|
||||
/* Find if we need an inversion of the BL */
|
||||
check_mem_model_blwl_inverted(mem_model, SPICE_MODEL_PORT_BL, &bl_inverted);
|
||||
check_mem_model_blwl_inverted(mem_model, SPICE_MODEL_PORT_WL, &wl_inverted);
|
||||
|
||||
switch (mem_model->design_tech) {
|
||||
case SPICE_MODEL_DESIGN_CMOS: /* CMOS SRAM*/
|
||||
/* SRAM technology requires its BL decoder has an additional input called data_in
|
||||
* only the selected BL will be set to the value of data_in, other BLs will be in high-resistance state
|
||||
*/
|
||||
/* Start the BL decoder module definition */
|
||||
fprintf(fp, "//----- BL Decoder convert %d bits to binary %d bits -----\n",
|
||||
bl_decoder_size, num_array_bl);
|
||||
fprintf(fp, "module bl_decoder%dto%d (\n",
|
||||
bl_decoder_size, num_array_bl);
|
||||
fprintf(fp, "input wire enable,\n");
|
||||
fprintf(fp, "input wire [%d:0] addr_in,\n",
|
||||
bl_decoder_size - 1);
|
||||
fprintf(fp, "input wire data_in,\n");
|
||||
fprintf(fp, "output reg [0:%d] addr_out\n",
|
||||
num_array_bl - 1);
|
||||
fprintf(fp, ");\n");
|
||||
|
||||
/* Wee need to know the default value of bl port and wl port */
|
||||
|
||||
/* Internal logics */
|
||||
|
||||
fprintf(fp, "always@(addr_out,addr_in,enable, data_in)\n");
|
||||
fprintf(fp, "begin\n");
|
||||
fprintf(fp, "\taddr_out = %d'bz;\n", num_array_bl);
|
||||
fprintf(fp, "\tif (1'b1 == enable) begin\n");
|
||||
fprintf(fp, "\t\taddr_out[addr_in] = data_in;\n");
|
||||
fprintf(fp, "\tend\n");
|
||||
fprintf(fp, "end\n");
|
||||
|
||||
fprintf(fp, "endmodule\n");
|
||||
break;
|
||||
case SPICE_MODEL_DESIGN_RRAM: /* RRAM */
|
||||
/* For RRAM technology, BL decoder should be same as the WL decoder */
|
||||
/* Start the BL decoder module definition */
|
||||
fprintf(fp, "//----- BL Decoder convert %d bits to binary %d bits -----\n",
|
||||
bl_decoder_size, num_array_bl);
|
||||
fprintf(fp, "module bl_decoder%dto%d (\n",
|
||||
bl_decoder_size, num_array_bl);
|
||||
fprintf(fp, "input wire enable,\n");
|
||||
fprintf(fp, "input wire [%d:0] addr_in,\n",
|
||||
bl_decoder_size-1);
|
||||
fprintf(fp, "output reg [0:%d] addr_out\n",
|
||||
num_array_bl-1);
|
||||
fprintf(fp, ");\n");
|
||||
|
||||
/* Internal logics */
|
||||
fprintf(fp, "always@(addr_out,addr_in,enable)\n");
|
||||
fprintf(fp, "begin\n");
|
||||
if (TRUE == bl_inverted) {
|
||||
fprintf(fp, "\taddr_out = %d'b1;\n", num_array_bl);
|
||||
} else {
|
||||
assert (FALSE == bl_inverted);
|
||||
fprintf(fp, "\taddr_out = %d'b0;\n", num_array_bl);
|
||||
}
|
||||
fprintf(fp, "\tif (1'b1 == enable) begin\n");
|
||||
if (TRUE == bl_inverted) {
|
||||
fprintf(fp, "\t\taddr_out[addr_in] = 1'b0;\n");
|
||||
} else {
|
||||
assert (FALSE == bl_inverted);
|
||||
fprintf(fp, "\t\taddr_out[addr_in] = 1'b1;\n");
|
||||
}
|
||||
fprintf(fp, "\tend\n");
|
||||
fprintf(fp, "end\n");
|
||||
|
||||
fprintf(fp, "endmodule\n");
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid design technology [CMOS|RRAM] for memory technology!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* WL decoder logic is the same whatever SRAM or RRAM technology is considered */
|
||||
/* Start the WL module definition */
|
||||
fprintf(fp, "//----- WL Decoder convert %d bits to binary %d bits -----\n",
|
||||
wl_decoder_size, num_array_wl);
|
||||
fprintf(fp, "module wl_decoder%dto%d (\n",
|
||||
wl_decoder_size, num_array_wl);
|
||||
fprintf(fp, "input wire enable,\n");
|
||||
fprintf(fp, "input wire [%d:0] addr_in,\n",
|
||||
wl_decoder_size-1);
|
||||
fprintf(fp, "output reg [0:%d] addr_out\n",
|
||||
num_array_bl-1);
|
||||
fprintf(fp, ");\n");
|
||||
|
||||
/* Internal logics */
|
||||
fprintf(fp, "always@(addr_out,addr_in,enable)\n");
|
||||
fprintf(fp, "begin\n");
|
||||
if (TRUE == wl_inverted) {
|
||||
fprintf(fp, "\taddr_out = %d'b1;\n", num_array_wl);
|
||||
} else {
|
||||
assert (FALSE == wl_inverted);
|
||||
fprintf(fp, "\taddr_out = %d'b0;\n", num_array_wl);
|
||||
}
|
||||
fprintf(fp, "\tif (1'b1 == enable) begin\n");
|
||||
if (TRUE == wl_inverted) {
|
||||
fprintf(fp, "\t\taddr_out[addr_in] = 1'b0;\n");
|
||||
} else {
|
||||
assert (FALSE == wl_inverted);
|
||||
fprintf(fp, "\t\taddr_out[addr_in] = 1'b1;\n");
|
||||
}
|
||||
fprintf(fp, "\tend\n");
|
||||
fprintf(fp, "end\n");
|
||||
|
||||
fprintf(fp, "endmodule\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* For standalone-SRAM configuration organization:
|
||||
* Dump the module of configuration module which connect configuration ports to SRAMs/CCFFs
|
||||
*/
|
||||
static
|
||||
void dump_verilog_standalone_sram_config_module(FILE* fp,
|
||||
t_sram_orgz_info* cur_sram_orgz_info) {
|
||||
int i, num_mem_bits;
|
||||
|
||||
/* Check */
|
||||
assert(SPICE_SRAM_STANDALONE == cur_sram_orgz_info->type);
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler!",__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Get the total memory bits */
|
||||
num_mem_bits = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info);
|
||||
|
||||
/* Dump each SRAM */
|
||||
fprintf(fp, "//------ Configuration Peripheral for Standalone SRAMs -----\n");
|
||||
fprintf(fp, "module %s (\n",
|
||||
verilog_config_peripheral_prefix);
|
||||
/* Dump port map*/
|
||||
fprintf(fp, "input %s_in[%d:%d],\n",
|
||||
sram_verilog_model->prefix,
|
||||
0, num_mem_bits - 1);
|
||||
fprintf(fp, "output %s_out[%d:%d],\n",
|
||||
sram_verilog_model->prefix,
|
||||
0, num_mem_bits - 1);
|
||||
fprintf(fp, "output %s_outb[%d:%d]);\n",
|
||||
sram_verilog_model->prefix,
|
||||
0, num_mem_bits - 1);
|
||||
|
||||
for (i = 0; i < num_mem_bits; i++) {
|
||||
/* Input and 2 outputs */
|
||||
fprintf(fp, "assign %s_out[%d] = %s_in[%d];\n",
|
||||
sram_verilog_model->prefix, i,
|
||||
sram_verilog_model->prefix, i);
|
||||
fprintf(fp, ");\n");
|
||||
}
|
||||
fprintf(fp, "endmodule\n");
|
||||
fprintf(fp, "//------ END Standalone SRAMs -----\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* For scan-chain configuration organization:
|
||||
* Dump the module of configuration module which connect configuration ports to SRAMs/CCFFs
|
||||
*/
|
||||
static
|
||||
void dump_verilog_scan_chain_config_module(FILE* fp,
|
||||
t_sram_orgz_info* cur_sram_orgz_info) {
|
||||
int num_mem_bits;
|
||||
|
||||
/* Check */
|
||||
assert(SPICE_SRAM_SCAN_CHAIN == cur_sram_orgz_info->type);
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid file handler!",__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Get the total memory bits */
|
||||
num_mem_bits = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info);
|
||||
|
||||
/* Dump each Scan-chain FF */
|
||||
fprintf(fp, "//------ Configuration Peripheral for Scan-chain FFs -----\n");
|
||||
fprintf(fp, "module %s (\n",
|
||||
verilog_config_peripheral_prefix);
|
||||
/* Port map definition */
|
||||
/* Scan-chain input*/
|
||||
dump_verilog_generic_port(fp, VERILOG_PORT_INPUT,
|
||||
top_netlist_scan_chain_head_prefix, 0, 0);
|
||||
fprintf(fp, ",\n");
|
||||
/* Scan-chain regular inputs */
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, 0, num_mem_bits - 1, -1, VERILOG_PORT_OUTPUT);
|
||||
fprintf(fp, ",\n");
|
||||
fprintf(fp, "input ");
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, 0, num_mem_bits - 1, 0, VERILOG_PORT_WIRE);
|
||||
fprintf(fp, ");\n");
|
||||
|
||||
/* Connect scan-chain input to the first scan-chain input */
|
||||
fprintf(fp, " ");
|
||||
fprintf(fp, "assign ");
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, 0, 0, -1, VERILOG_PORT_CONKT);
|
||||
fprintf(fp, " = ");
|
||||
dump_verilog_generic_port(fp, VERILOG_PORT_CONKT,
|
||||
top_netlist_scan_chain_head_prefix, 0, 0);
|
||||
fprintf(fp, ";\n");
|
||||
|
||||
/* Verilog Module body */
|
||||
/* 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);
|
||||
fprintf(fp, " = ");
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info, 0, num_mem_bits - 2, 0, VERILOG_PORT_CONKT);
|
||||
fprintf(fp, ";\n");
|
||||
fprintf(fp, "endmodule\n");
|
||||
fprintf(fp, "//------ END Scan-chain FFs -----\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Output a inverter module for inverting a BL/WL line
|
||||
*/
|
||||
static
|
||||
void dump_verilog_membank_one_inv_module(FILE* fp,
|
||||
const t_spice_model* inv_spice_model,
|
||||
const char* instance_tag,
|
||||
const char* in_port_name,
|
||||
const char* out_port_name,
|
||||
int inv_index) {
|
||||
/* A valid file handler */
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid File Handler!\n", __FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
assert(NULL != instance_tag);
|
||||
assert(NULL != in_port_name);
|
||||
assert(NULL != out_port_name);
|
||||
|
||||
/* Find the input port, output port, and sram port*/
|
||||
int num_buf_input_port;
|
||||
int num_buf_output_port;
|
||||
t_spice_model_port** buf_input_port = find_spice_model_ports(inv_spice_model, SPICE_MODEL_PORT_INPUT, &num_buf_input_port, TRUE);
|
||||
t_spice_model_port** buf_output_port = find_spice_model_ports(inv_spice_model, SPICE_MODEL_PORT_OUTPUT, &num_buf_output_port, TRUE);
|
||||
/* Instanciate an inverter module */
|
||||
fprintf(fp, " %s %s_%s_%d (",
|
||||
inv_spice_model->name, inv_spice_model->prefix,
|
||||
instance_tag, inv_index);
|
||||
/* Dump global ports */
|
||||
if (0 < rec_dump_verilog_spice_model_global_ports(fp, inv_spice_model, FALSE, FALSE, inv_spice_model->dump_explicit_port_map, TRUE)) {
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
/* Dump explicit port map if required */
|
||||
if ( TRUE == inv_spice_model->dump_explicit_port_map) {
|
||||
fprintf(fp, ".%s(",
|
||||
buf_input_port[0]->lib_name);
|
||||
}
|
||||
fprintf(fp, "%s[%d]",
|
||||
in_port_name, inv_index);
|
||||
if ( TRUE == inv_spice_model->dump_explicit_port_map) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
fprintf(fp, ", ");
|
||||
if ( TRUE == inv_spice_model->dump_explicit_port_map) {
|
||||
fprintf(fp, ".%s(",
|
||||
buf_output_port[0]->lib_name);
|
||||
}
|
||||
fprintf(fp, "%s[%d]",
|
||||
out_port_name, inv_index);
|
||||
if ( TRUE == inv_spice_model->dump_explicit_port_map) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
fprintf(fp, ");\n");
|
||||
|
||||
/* Free */
|
||||
my_free(buf_input_port);
|
||||
my_free(buf_output_port);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* For Memory-bank configuration organization:
|
||||
* Dump the module of configuration module which connect configuration ports to SRAMs/CCFFs
|
||||
*/
|
||||
static
|
||||
void dump_verilog_membank_config_module(FILE* fp,
|
||||
t_sram_orgz_info* cur_sram_orgz_info) {
|
||||
t_spice_model* mem_model = NULL;
|
||||
int iinv, icol, irow;
|
||||
int num_bl, num_wl;
|
||||
int num_array_bl, num_array_wl;
|
||||
int num_reserved_bl, num_reserved_wl;
|
||||
int cur_bl_lsb, cur_wl_lsb;
|
||||
int cur_bl_msb, cur_wl_msb;
|
||||
int bl_decoder_size, wl_decoder_size;
|
||||
int num_blb_ports, num_wlb_ports;
|
||||
t_spice_model_port** blb_port = NULL;
|
||||
t_spice_model_port** wlb_port = NULL;
|
||||
t_spice_model* blb_inv_spice_model = NULL;
|
||||
t_spice_model* wlb_inv_spice_model = NULL;
|
||||
|
||||
/* Check */
|
||||
assert(SPICE_SRAM_MEMORY_BANK == cur_sram_orgz_info->type);
|
||||
assert(NULL != cur_sram_orgz_info->mem_bank_info);
|
||||
|
||||
/* A valid file handler */
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid File Handler!\n", __FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Depending on the memory technology*/
|
||||
get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
|
||||
assert(NULL != mem_model);
|
||||
|
||||
/* Get the total number of BLs and WLs */
|
||||
get_sram_orgz_info_num_blwl(cur_sram_orgz_info, &num_bl, &num_wl);
|
||||
/* Get the reserved BLs and WLs */
|
||||
get_sram_orgz_info_reserved_blwl(cur_sram_orgz_info, &num_reserved_bl, &num_reserved_wl);
|
||||
|
||||
determine_blwl_decoder_size(cur_sram_orgz_info,
|
||||
&num_array_bl, &num_array_wl, &bl_decoder_size, &wl_decoder_size);
|
||||
|
||||
/* Get BLB and WLB ports */
|
||||
find_blb_wlb_ports_spice_model(mem_model, &num_blb_ports, &blb_port,
|
||||
&num_wlb_ports, &wlb_port);
|
||||
/* Get inverter spice_model */
|
||||
|
||||
/* Dump each SRAM */
|
||||
fprintf(fp, "//------ Configuration Peripheral for Memory-bank -----\n");
|
||||
fprintf(fp, "module %s (\n",
|
||||
verilog_config_peripheral_prefix);
|
||||
/* Port map */
|
||||
/* Ports for memory decoders */
|
||||
dump_verilog_decoder_memory_bank_ports(cur_sram_orgz_info, fp, VERILOG_PORT_INPUT);
|
||||
fprintf(fp, ",\n");
|
||||
/* Ports for all the SRAM cells */
|
||||
switch (mem_model->design_tech) {
|
||||
case SPICE_MODEL_DESIGN_CMOS:
|
||||
assert( 0 == num_reserved_bl );
|
||||
assert( 0 == num_reserved_wl );
|
||||
|
||||
/* Declare normal BL / WL inputs */
|
||||
fprintf(fp, " output wire [%d:%d] %s%s",
|
||||
0, num_bl - 1, mem_model->prefix, top_netlist_normal_bl_port_postfix);
|
||||
fprintf(fp, ", //---- Normal Bit lines \n");
|
||||
|
||||
fprintf(fp, " output wire [%d:%d] %s%s",
|
||||
0, num_wl - 1, mem_model->prefix, top_netlist_normal_wl_port_postfix);
|
||||
/* Declare inverted wires if needed */
|
||||
if (1 == num_blb_ports) {
|
||||
fprintf(fp, ", //---- Normal Word lines \n");
|
||||
} else {
|
||||
fprintf(fp, " //---- Normal Word lines\n");
|
||||
}
|
||||
if (1 == num_blb_ports) {
|
||||
fprintf(fp, " output wire [%d:%d] %s%s",
|
||||
0, num_bl - 1, mem_model->prefix, top_netlist_normal_blb_port_postfix);
|
||||
}
|
||||
if (1 == num_wlb_ports) {
|
||||
fprintf(fp, ", //---- Inverted Normal Bit lines \n");
|
||||
} else {
|
||||
fprintf(fp, " //---- Inverted Normal Bit lines \n");
|
||||
}
|
||||
if (1 == num_wlb_ports) {
|
||||
fprintf(fp, " output wire [%d:%d] %s%s //---- Inverted Normal Word lines \n",
|
||||
0, num_wl - 1, mem_model->prefix, top_netlist_normal_wlb_port_postfix);
|
||||
}
|
||||
fprintf(fp, ");\n");
|
||||
break;
|
||||
case SPICE_MODEL_DESIGN_RRAM:
|
||||
/* Check: there should be reserved BLs and WLs */
|
||||
assert( 0 < num_reserved_bl );
|
||||
assert( 0 < num_reserved_wl );
|
||||
/* Declare reserved and normal conf_bits ports */
|
||||
fprintf(fp, " input wire [0:%d] %s%s, //---- Reserved Bit lines \n",
|
||||
num_reserved_bl - 1, mem_model->prefix, top_netlist_reserved_bl_port_postfix);
|
||||
fprintf(fp, " input wire [0:%d] %s%s, //---- Reserved Word lines \n",
|
||||
num_reserved_wl - 1, mem_model->prefix, top_netlist_reserved_wl_port_postfix);
|
||||
fprintf(fp, " input wire [%d:%d] %s%s, //---- Normal Bit lines \n",
|
||||
num_reserved_bl, num_array_bl - 1, mem_model->prefix, top_netlist_normal_bl_port_postfix);
|
||||
fprintf(fp, " input wire [%d:%d] %s%s); //---- Normal Word lines \n",
|
||||
num_reserved_wl, num_array_wl - 1, mem_model->prefix, top_netlist_normal_wl_port_postfix);
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization in Verilog Generator!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Important!!!:
|
||||
* BL/WL should always start from LSB to MSB!
|
||||
* In order to follow this convention in primitive nodes.
|
||||
*/
|
||||
fprintf(fp, "\n");
|
||||
/* No. of BLs and WLs in the array */
|
||||
dump_verilog_generic_port(fp, VERILOG_PORT_WIRE,
|
||||
top_netlist_array_bl_port_name, 0, num_array_bl - 1);
|
||||
fprintf(fp, "; //--- Array Bit lines bus \n");
|
||||
dump_verilog_generic_port(fp, VERILOG_PORT_WIRE,
|
||||
top_netlist_array_wl_port_name, 0, num_array_wl - 1);
|
||||
fprintf(fp, "; //--- Array Bit lines bus \n");
|
||||
if (1 == num_blb_ports) {
|
||||
dump_verilog_generic_port(fp, VERILOG_PORT_WIRE,
|
||||
top_netlist_array_blb_port_name, 0, num_array_bl - 1);
|
||||
fprintf(fp, "; //--- Inverted Array Bit lines bus \n");
|
||||
}
|
||||
if (1 == num_wlb_ports) {
|
||||
dump_verilog_generic_port(fp, VERILOG_PORT_WIRE,
|
||||
top_netlist_array_wlb_port_name, 0, num_array_wl - 1);
|
||||
fprintf(fp, "; //--- Inverted Array Word lines bus \n");
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
|
||||
switch (mem_model->design_tech) {
|
||||
case SPICE_MODEL_DESIGN_CMOS:
|
||||
assert( 0 == num_reserved_bl );
|
||||
assert( 0 == num_reserved_wl );
|
||||
/* SRAMs are place in an array
|
||||
* BLs of SRAMs in the same column are connected to a common BL
|
||||
* BLs of SRAMs in the same row are connected to a common WL
|
||||
*/
|
||||
/* Declare inverted wires if needed */
|
||||
if (1 == num_blb_ports) {
|
||||
/* get inv_spice_model */
|
||||
blb_inv_spice_model = blb_port[0]->inv_spice_model;
|
||||
/* Make an inversion of the BL */
|
||||
for (iinv = 0; iinv < num_array_bl; iinv++) {
|
||||
dump_verilog_membank_one_inv_module(fp, blb_inv_spice_model, "blb",
|
||||
top_netlist_array_bl_port_name,
|
||||
top_netlist_array_blb_port_name,
|
||||
iinv);
|
||||
}
|
||||
}
|
||||
if (1 == num_wlb_ports) {
|
||||
/* get inv_spice_model */
|
||||
wlb_inv_spice_model = wlb_port[0]->inv_spice_model;
|
||||
/* Make an inversion of the WL */
|
||||
for (iinv = 0; iinv < num_array_wl; iinv++) {
|
||||
dump_verilog_membank_one_inv_module(fp, wlb_inv_spice_model, "wlb",
|
||||
top_netlist_array_wl_port_name,
|
||||
top_netlist_array_wlb_port_name,
|
||||
iinv);
|
||||
}
|
||||
}
|
||||
|
||||
/* Connections for columns */
|
||||
for (icol = 0; icol < num_array_bl; icol++) {
|
||||
cur_bl_lsb = icol * num_array_bl;
|
||||
cur_bl_msb = (icol + 1) * num_array_bl - 1;
|
||||
/* Check if the msb exceeds the upbound of num_bl */
|
||||
if (cur_bl_msb > num_bl - 1) {
|
||||
cur_bl_msb = num_bl - 1;
|
||||
}
|
||||
/* connect to the BLs of all the SRAMs in the column */
|
||||
fprintf(fp, " assign %s%s[%d:%d] = %s[%d:%d];\n",
|
||||
mem_model->prefix, top_netlist_normal_bl_port_postfix, cur_bl_lsb, cur_bl_msb,
|
||||
top_netlist_array_bl_port_name, 0, cur_bl_msb - cur_bl_lsb);
|
||||
if (1 == num_blb_ports) {
|
||||
fprintf(fp, " assign %s%s[%d:%d] = %s[%d:%d];\n",
|
||||
mem_model->prefix, top_netlist_normal_blb_port_postfix, cur_bl_lsb, cur_bl_msb,
|
||||
top_netlist_array_blb_port_name, 0, cur_bl_msb - cur_bl_lsb);
|
||||
}
|
||||
/* Finish if MSB meets the upbound */
|
||||
if (cur_bl_msb == num_bl - 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Connections for rows */
|
||||
for (irow = 0; irow < num_array_wl; irow++) {
|
||||
cur_wl_lsb = irow * num_array_wl;
|
||||
cur_wl_msb = (irow + 1) * num_array_wl - 1;
|
||||
/* Check if the msb exceeds the upbound of num_bl */
|
||||
if (cur_wl_msb > num_wl - 1) {
|
||||
cur_wl_msb = num_wl - 1;
|
||||
}
|
||||
/* connect to the BLs of all the SRAMs in the column */
|
||||
for (icol = cur_wl_lsb; icol < cur_wl_msb + 1; icol++) {
|
||||
fprintf(fp, " assign %s%s[%d] = %s[%d];\n",
|
||||
mem_model->prefix, top_netlist_normal_wl_port_postfix, icol,
|
||||
top_netlist_array_wl_port_name, irow);
|
||||
if (1 == num_wlb_ports) {
|
||||
fprintf(fp, " assign %s%s[%d] = %s[%d];\n",
|
||||
mem_model->prefix, top_netlist_normal_wlb_port_postfix, icol,
|
||||
top_netlist_array_wlb_port_name, irow);
|
||||
}
|
||||
}
|
||||
/* Finish if MSB meets the upbound */
|
||||
if (cur_wl_msb == num_wl - 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPICE_MODEL_DESIGN_RRAM:
|
||||
/* Check: there should be reserved BLs and WLs */
|
||||
assert( 0 < num_reserved_bl );
|
||||
assert( 0 < num_reserved_wl );
|
||||
/* Declare reserved and normal conf_bits ports */
|
||||
fprintf(fp, " wire [0:%d] %s%s; //---- Reserved Bit lines \n",
|
||||
num_reserved_bl - 1, mem_model->prefix, top_netlist_reserved_bl_port_postfix);
|
||||
fprintf(fp, " wire [0:%d] %s%s; //---- Reserved Word lines \n",
|
||||
num_reserved_wl - 1, mem_model->prefix, top_netlist_reserved_wl_port_postfix);
|
||||
fprintf(fp, " wire [%d:%d] %s%s; //---- Normal Bit lines \n",
|
||||
num_reserved_bl, num_array_bl - 1, mem_model->prefix, top_netlist_normal_bl_port_postfix);
|
||||
fprintf(fp, " wire [%d:%d] %s%s; //---- Normal Word lines \n",
|
||||
num_reserved_wl, num_array_wl - 1, mem_model->prefix, top_netlist_normal_wl_port_postfix);
|
||||
/* Connect reserved conf_bits and normal conf_bits to the bus */
|
||||
fprintf(fp, " assign %s%s[0:%d] = %s[0:%d];\n",
|
||||
mem_model->prefix, top_netlist_reserved_bl_port_postfix, num_reserved_bl - 1,
|
||||
top_netlist_array_bl_port_name, num_reserved_bl - 1);
|
||||
fprintf(fp, " assign %s%s[0:%d] = %s[0:%d];\n",
|
||||
mem_model->prefix, top_netlist_reserved_wl_port_postfix, num_reserved_wl - 1,
|
||||
top_netlist_array_wl_port_name, num_reserved_wl - 1);
|
||||
fprintf(fp, " assign %s%s[%d:%d] = %s[%d:%d];\n",
|
||||
mem_model->prefix, top_netlist_normal_bl_port_postfix, num_reserved_bl, num_array_bl - 1,
|
||||
top_netlist_array_bl_port_name, num_reserved_bl, num_array_bl - 1);
|
||||
fprintf(fp, " assign %s%s[%d:%d] = %s[%d:%d];\n",
|
||||
mem_model->prefix, top_netlist_normal_wl_port_postfix, num_reserved_wl, num_array_wl - 1,
|
||||
top_netlist_array_wl_port_name, num_reserved_wl, num_array_wl - 1);
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization in Verilog Generator!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Comment lines */
|
||||
fprintf(fp, "//----- BEGIN call decoders for memory bank controller -----\n");
|
||||
|
||||
/* Dump Decoders for Bit lines and Word lines */
|
||||
/* Two huge decoders
|
||||
* TODO: divide to a number of small decoders ?
|
||||
*/
|
||||
/* Bit lines decoder */
|
||||
fprintf(fp, " ");
|
||||
fprintf(fp, "bl_decoder%dto%d mem_bank_bl_decoder (",
|
||||
bl_decoder_size, num_array_bl);
|
||||
/* Prefix of BL & WL is fixed, in order to simplify grouping nets */
|
||||
fprintf(fp, "%s, %s[%d:0], ",
|
||||
top_netlist_bl_enable_port_name,
|
||||
top_netlist_addr_bl_port_name, bl_decoder_size - 1);
|
||||
/* Port map depends on the memory technology */
|
||||
switch (mem_model->design_tech) {
|
||||
case SPICE_MODEL_DESIGN_CMOS:
|
||||
/* Data input port of BL decoder, only required by SRAM array */
|
||||
fprintf(fp, "%s, ",
|
||||
top_netlist_bl_data_in_port_name);
|
||||
break;
|
||||
case SPICE_MODEL_DESIGN_RRAM:
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid type of SRAM organization in Verilog Generator!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(fp, "%s[0:%d]",
|
||||
top_netlist_array_bl_port_name, num_array_bl - 1);
|
||||
fprintf(fp, ");\n");
|
||||
|
||||
/* Word lines decoder is the same for both technology */
|
||||
fprintf(fp, " ");
|
||||
fprintf(fp, "wl_decoder%dto%d mem_bank_wl_decoder (",
|
||||
wl_decoder_size, num_array_wl);
|
||||
fprintf(fp, "%s, %s[%d:0], ",
|
||||
top_netlist_wl_enable_port_name,
|
||||
top_netlist_addr_wl_port_name, wl_decoder_size - 1);
|
||||
fprintf(fp, "%s[0:%d]",
|
||||
top_netlist_array_wl_port_name, num_array_wl - 1);
|
||||
fprintf(fp, ");\n");
|
||||
fprintf(fp, "//----- END call decoders for memory bank controller -----\n\n");
|
||||
|
||||
/* Comment lines */
|
||||
fprintf(fp, "endmodule\n");
|
||||
fprintf(fp, "//----- END configuration peripheral for memory-bank -----\n\n");
|
||||
|
||||
}
|
||||
|
||||
/* Top-level function */
|
||||
void dump_verilog_config_peripherals(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* verilog_dir_path,
|
||||
char* submodule_dir_path) {
|
||||
FILE* fp = NULL;
|
||||
|
||||
char* verilog_name = my_strcat(submodule_dir_path, config_peripheral_verilog_file_name);
|
||||
|
||||
/* Open file and file handler */
|
||||
fp = fopen(verilog_name, "w");
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create decoder SPICE netlist %s",
|
||||
__FILE__, __LINE__, verilog_name);
|
||||
exit(1);
|
||||
}
|
||||
/* Generate file header*/
|
||||
vpr_printf(TIO_MESSAGE_INFO, "Writing configuration peripheral verilog netlist...\n");
|
||||
|
||||
/* Generate the descriptions*/
|
||||
dump_verilog_file_header(fp, " Verilog Configuration Peripheral");
|
||||
|
||||
verilog_include_defines_preproc_file(fp, verilog_dir_path);
|
||||
|
||||
switch(cur_sram_orgz_info->type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
dump_verilog_scan_chain_config_module(fp, cur_sram_orgz_info);
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
/* Dump verilog decoder */
|
||||
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*/
|
||||
fclose(fp);
|
||||
|
||||
/* Add fname to the linked list */
|
||||
submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef VERILOG_DECODER_H
|
||||
#define VERILOG_DECODER_H
|
||||
|
||||
void dump_verilog_decoder_memory_bank_ports(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
enum e_dump_verilog_port_type dump_port_type);
|
||||
|
||||
void dump_verilog_config_peripherals(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* verilog_dir_path,
|
||||
char* submodule_dir);
|
||||
|
||||
#endif
|
|
@ -162,6 +162,7 @@ void print_verilog_mux_local_decoder_module(std::fstream& fp,
|
|||
* See more details in the function print_verilog_mux_local_decoder() for more details
|
||||
***************************************************************************************/
|
||||
void print_verilog_submodule_mux_local_decoders(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::string& verilog_dir,
|
||||
|
@ -222,8 +223,9 @@ void print_verilog_submodule_mux_local_decoders(ModuleManager& module_manager,
|
|||
/* Close the file stream */
|
||||
fp.close();
|
||||
|
||||
/* Add fname to the linked list when debugging is finished */
|
||||
submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_fname.c_str());
|
||||
|
||||
/* Add fname to the netlist name list */
|
||||
netlist_names.push_back(verilog_fname);
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
|
|
|
@ -9,13 +9,16 @@
|
|||
/* Include other header files which are dependency on the function declared below */
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "vpr_types.h"
|
||||
#include "circuit_library.h"
|
||||
#include "mux_graph.h"
|
||||
#include "mux_library.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
void print_verilog_submodule_mux_local_decoders(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::string& verilog_dir,
|
||||
|
|
|
@ -525,6 +525,7 @@ void print_verilog_constant_generator_module(const ModuleManager& module_manager
|
|||
* etc.
|
||||
***********************************************/
|
||||
void print_verilog_submodule_essentials(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& submodule_dir,
|
||||
const CircuitLibrary& circuit_lib) {
|
||||
|
@ -575,8 +576,6 @@ void print_verilog_submodule_essentials(ModuleManager& module_manager,
|
|||
/* Close file handler*/
|
||||
fp.close();
|
||||
|
||||
/* Add fname to the linked list */
|
||||
submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_fname.c_str());
|
||||
|
||||
return;
|
||||
/* Add fname to the netlist name list */
|
||||
netlist_names.push_back(verilog_fname);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "circuit_library.h"
|
||||
|
||||
void print_verilog_submodule_essentials(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& submodule_dir,
|
||||
const CircuitLibrary& circuit_lib);
|
||||
|
|
|
@ -1,315 +0,0 @@
|
|||
/***********************************/
|
||||
/* SPICE Modeling for VPR */
|
||||
/* Xifan TANG, EPFL/LSI */
|
||||
/***********************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#define MINI_CASE_SENSITIVE
|
||||
#include "ini.h"
|
||||
|
||||
/* Include vpr structs*/
|
||||
#include "util.h"
|
||||
#include "physical_types.h"
|
||||
#include "vpr_types.h"
|
||||
#include "globals.h"
|
||||
#include "rr_graph_util.h"
|
||||
#include "rr_graph.h"
|
||||
#include "rr_graph2.h"
|
||||
#include "route_common.h"
|
||||
#include "vpr_utils.h"
|
||||
|
||||
/* Include SPICE support headers*/
|
||||
#include "linkedlist.h"
|
||||
#include "fpga_x2p_types.h"
|
||||
#include "fpga_x2p_utils.h"
|
||||
#include "fpga_x2p_backannotate_utils.h"
|
||||
#include "fpga_x2p_mux_utils.h"
|
||||
#include "fpga_x2p_pbtypes_utils.h"
|
||||
#include "fpga_x2p_bitstream_utils.h"
|
||||
#include "fpga_x2p_rr_graph_utils.h"
|
||||
#include "fpga_x2p_globals.h"
|
||||
|
||||
/* Include Verilog support headers*/
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_utils.h"
|
||||
#include "verilog_routing.h"
|
||||
#include "verilog_tcl_utils.h"
|
||||
|
||||
mINI::INIStructure ini;
|
||||
|
||||
static void searching_used_latch(FILE *fp, t_pb * pb, int pb_index, char* chomped_circuit_name, char* inst_name){
|
||||
int i, j;
|
||||
char WriteBuffer[200];
|
||||
char INI_lbl[100];
|
||||
// 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];
|
||||
|
||||
// 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) );
|
||||
sprintf(WriteBuffer, "%s/%sdff_0 ",
|
||||
inst_name, gen_verilog_one_pb_graph_node_full_name_in_hierarchy(node));
|
||||
|
||||
sprintf(INI_lbl, "%s_reg", pb->name);
|
||||
ini["REGISTER_MATCH"][INI_lbl] = WriteBuffer;
|
||||
}
|
||||
//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;
|
||||
|
||||
x_pos = block[h].x;
|
||||
y_pos = block[h].y;
|
||||
|
||||
pb = (t_pb*) block[h].pb;
|
||||
|
||||
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), "_"));
|
||||
|
||||
|
||||
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) {
|
||||
int i;
|
||||
|
||||
/* A valid file handler*/
|
||||
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) {
|
||||
assert(NULL != spice.include_netlists[i].path);
|
||||
fprintf(fp, "%s ", spice.include_netlists[i].path);
|
||||
spice.include_netlists[i].included = 1;
|
||||
} 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, i, FileCounter=0;
|
||||
char* formality_script_file_name = NULL;
|
||||
char* benchmark_path = NULL;
|
||||
char* original_output_name = NULL;
|
||||
char WriteBuffer[4096];
|
||||
char INI_lbl[4096];
|
||||
/* int output_length; */
|
||||
/* int pos; */
|
||||
FILE* fp = NULL;
|
||||
|
||||
if(TRUE == fpga_verilog_opts.print_autocheck_top_testbench)
|
||||
benchmark_path = fpga_verilog_opts.reference_verilog_benchmark_file;
|
||||
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);
|
||||
}
|
||||
|
||||
/* Load Verilog benchmark as reference */
|
||||
fprintf(fp, "read_verilog -container r -libname WORK -05 { %s }\n", benchmark_path);
|
||||
ini["BENCHMARK_INFO"]["benchmark_netlist "] = benchmark_path;
|
||||
|
||||
/* Set reference top */
|
||||
fprintf(fp, "set_top r:/WORK/%s\n", chomped_circuit_name);
|
||||
ini["BENCHMARK_INFO"]["src_top_module "] = 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);
|
||||
sprintf(WriteBuffer, "%s%s%s", src_dir_formatted, chomped_circuit_name,
|
||||
verilog_top_postfix);
|
||||
sprintf(INI_lbl, "impl_netlist_%02d",FileCounter++);
|
||||
ini["FPGA_INFO"][INI_lbl] = WriteBuffer;
|
||||
|
||||
fprintf(fp, "%s%s%s ", src_dir_formatted,
|
||||
chomped_circuit_name,
|
||||
formal_verification_verilog_file_postfix);
|
||||
sprintf(WriteBuffer, "%s%s%s\n", src_dir_formatted,
|
||||
chomped_circuit_name, formal_verification_verilog_file_postfix);
|
||||
sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++);
|
||||
ini["FPGA_INFO"][INI_lbl] = WriteBuffer;
|
||||
|
||||
init_include_user_defined_verilog_netlists(spice);
|
||||
// formality_include_user_defined_verilog_netlists(fp, spice);
|
||||
|
||||
/* Include user-defined sub-circuit netlist */
|
||||
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);
|
||||
sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++);
|
||||
ini["FPGA_INFO"][INI_lbl] = spice.include_netlists[i].path;
|
||||
spice.include_netlists[i].included = 1;
|
||||
} else {
|
||||
assert(1 == spice.include_netlists[i].included);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fp, "%s%s%s ", src_dir_formatted,
|
||||
default_rr_dir_name,
|
||||
routing_verilog_file_name);
|
||||
sprintf(WriteBuffer, "%s%s%s\n", src_dir_formatted,
|
||||
default_rr_dir_name,
|
||||
routing_verilog_file_name);
|
||||
sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++);
|
||||
ini["FPGA_INFO"][INI_lbl] = WriteBuffer;
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
fprintf(fp, "%s%s%s ", src_dir_formatted,
|
||||
default_lb_dir_name,
|
||||
logic_block_verilog_file_name);
|
||||
sprintf(WriteBuffer, "%s%s%s\n", src_dir_formatted,
|
||||
default_lb_dir_name,
|
||||
logic_block_verilog_file_name);
|
||||
sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++);
|
||||
ini["FPGA_INFO"][INI_lbl] = WriteBuffer;
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
fprintf(fp, "%s%s%s ", src_dir_formatted,
|
||||
default_submodule_dir_name,
|
||||
submodule_verilog_file_name);
|
||||
sprintf(WriteBuffer, "%s%s%s\n", src_dir_formatted,
|
||||
default_submodule_dir_name,
|
||||
submodule_verilog_file_name);
|
||||
sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++);
|
||||
ini["FPGA_INFO"][INI_lbl] = WriteBuffer;
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
/* Set implementation top */
|
||||
fprintf(fp, "set_top i:/WORK/%s\n", my_strcat(chomped_circuit_name,
|
||||
formal_verification_top_postfix));
|
||||
sprintf(WriteBuffer, "%s", my_strcat(chomped_circuit_name,
|
||||
formal_verification_top_postfix));
|
||||
ini["FPGA_INFO"]["impl_top_module"] = WriteBuffer;
|
||||
|
||||
/* Run matching */
|
||||
fprintf(fp, "match\n");
|
||||
/* Add manual matching for the outputs */
|
||||
for (iblock = 0; iblock < num_logical_blocks; iblock++) {
|
||||
original_output_name = NULL;
|
||||
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){
|
||||
/* 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",
|
||||
chomped_circuit_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));
|
||||
|
||||
sprintf(WriteBuffer, "%s/%s[0]",
|
||||
my_strcat(chomped_circuit_name, formal_verification_top_postfix),
|
||||
my_strcat(logical_block[iblock].name, formal_verification_top_module_port_postfix));
|
||||
|
||||
sprintf(INI_lbl, "%s", original_output_name);
|
||||
ini["PORT_MATCHING"][INI_lbl] = WriteBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
match_registers(fp, chomped_circuit_name);
|
||||
/* Run verification */
|
||||
fprintf(fp, "verify\n");
|
||||
/* Script END */
|
||||
fclose(fp);
|
||||
|
||||
mINI::INIFile file(my_strcat(formality_script_file_name,".ini"));
|
||||
file.generate(ini, true);
|
||||
return;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
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);
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
/* Header files for Verilog generator */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_utils.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
#include "verilog_module_writer.h"
|
||||
#include "verilog_grid.h"
|
||||
|
@ -183,6 +182,7 @@ void print_verilog_physical_blocks_rec(std::fstream& fp,
|
|||
*****************************************************************************/
|
||||
static
|
||||
void print_verilog_grid(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& subckt_dir,
|
||||
t_type_ptr phy_block_type,
|
||||
|
@ -261,10 +261,8 @@ void print_verilog_grid(ModuleManager& module_manager,
|
|||
/* Close file handler */
|
||||
fp.close();
|
||||
|
||||
/* Add fname to the linked list */
|
||||
/* TODO: add it when it is ready
|
||||
grid_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(grid_verilog_subckt_file_path_head, verilog_fname.c_str());
|
||||
*/
|
||||
/* Add fname to the netlist name list */
|
||||
netlist_names.push_back(verilog_fname);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -277,6 +275,9 @@ void print_verilog_grids(ModuleManager& module_manager,
|
|||
const std::string& verilog_dir,
|
||||
const std::string& subckt_dir,
|
||||
const bool& use_explicit_mapping) {
|
||||
/* Create a vector to contain all the Verilog netlist names that have been generated in this function */
|
||||
std::vector<std::string> netlist_names;
|
||||
|
||||
/* Enumerate the types, dump one Verilog module for each */
|
||||
for (int itype = 0; itype < num_types; itype++) {
|
||||
if (EMPTY_TYPE == &type_descriptors[itype]) {
|
||||
|
@ -286,7 +287,7 @@ void print_verilog_grids(ModuleManager& module_manager,
|
|||
/* Special for I/O block, generate one module for each border side */
|
||||
for (int iside = 0; iside < NUM_SIDES; iside++) {
|
||||
Side side_manager(iside);
|
||||
print_verilog_grid(module_manager,
|
||||
print_verilog_grid(module_manager, netlist_names,
|
||||
verilog_dir, subckt_dir,
|
||||
&type_descriptors[itype],
|
||||
side_manager.get_side(),
|
||||
|
@ -295,7 +296,7 @@ void print_verilog_grids(ModuleManager& module_manager,
|
|||
continue;
|
||||
} else if (FILL_TYPE == &type_descriptors[itype]) {
|
||||
/* For CLB */
|
||||
print_verilog_grid(module_manager,
|
||||
print_verilog_grid(module_manager, netlist_names,
|
||||
verilog_dir, subckt_dir,
|
||||
&type_descriptors[itype],
|
||||
NUM_SIDES,
|
||||
|
@ -303,7 +304,7 @@ void print_verilog_grids(ModuleManager& module_manager,
|
|||
continue;
|
||||
} else {
|
||||
/* For heterogenenous blocks */
|
||||
print_verilog_grid(module_manager,
|
||||
print_verilog_grid(module_manager, netlist_names,
|
||||
verilog_dir, subckt_dir,
|
||||
&type_descriptors[itype],
|
||||
NUM_SIDES,
|
||||
|
@ -314,10 +315,8 @@ void print_verilog_grids(ModuleManager& module_manager,
|
|||
/* Output a header file for all the logic blocks */
|
||||
vpr_printf(TIO_MESSAGE_INFO, "Generating header file for grid Verilog modules...\n");
|
||||
std::string grid_verilog_fname(logic_block_verilog_file_name);
|
||||
/* TODO: remove .bak when it is ready */
|
||||
//grid_verilog_fname += ".bak";
|
||||
dump_verilog_subckt_header_file(grid_verilog_subckt_file_path_head,
|
||||
subckt_dir.c_str(),
|
||||
grid_verilog_fname.c_str());
|
||||
print_verilog_netlist_include_header_file(netlist_names,
|
||||
subckt_dir.c_str(),
|
||||
grid_verilog_fname.c_str());
|
||||
}
|
||||
|
||||
|
|
|
@ -29,13 +29,12 @@
|
|||
* in the circuit library
|
||||
********************************************************************/
|
||||
void print_verilog_submodule_luts(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& submodule_dir,
|
||||
const bool& use_explicit_port_map) {
|
||||
/* TODO: remove .bak when this part is completed and tested */
|
||||
std::string verilog_fname = submodule_dir + luts_verilog_file_name;
|
||||
//verilog_fname +=".bak";
|
||||
|
||||
std::fstream fp;
|
||||
|
||||
|
@ -70,11 +69,7 @@ void print_verilog_submodule_luts(ModuleManager& module_manager,
|
|||
/* Close the file handler */
|
||||
fp.close();
|
||||
|
||||
/* Add fname to the linked list */
|
||||
/* Add it when the Verilog generation is refactored
|
||||
submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_fname.c_str());
|
||||
*/
|
||||
|
||||
return;
|
||||
/* Add fname to the netlist name list */
|
||||
netlist_names.push_back(verilog_fname);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "module_manager.h"
|
||||
|
||||
void print_verilog_submodule_luts(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& submodule_dir,
|
||||
|
|
|
@ -97,6 +97,7 @@ void print_verilog_mux_memory_module(ModuleManager& module_manager,
|
|||
* memory-bank organization for the memories.
|
||||
********************************************************************/
|
||||
void print_verilog_submodule_memories(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::string& verilog_dir,
|
||||
|
@ -104,7 +105,6 @@ void print_verilog_submodule_memories(ModuleManager& module_manager,
|
|||
const bool& use_explicit_port_map) {
|
||||
/* Plug in with the mux subckt */
|
||||
std::string verilog_fname(submodule_dir + memories_verilog_file_name);
|
||||
//verilog_fname += ".bak";
|
||||
|
||||
/* Create the file stream */
|
||||
std::fstream fp;
|
||||
|
@ -187,8 +187,7 @@ void print_verilog_submodule_memories(ModuleManager& module_manager,
|
|||
/* Close the file stream */
|
||||
fp.close();
|
||||
|
||||
/* Add fname to the linked list
|
||||
submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_fname.c_str());
|
||||
*/
|
||||
/* Add fname to the netlist name list */
|
||||
netlist_names.push_back(verilog_fname);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "module_manager.h"
|
||||
|
||||
void print_verilog_submodule_memories(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::string& verilog_dir,
|
||||
|
|
|
@ -1,570 +0,0 @@
|
|||
/***********************************/
|
||||
/* Synthesizable Verilog Dumping */
|
||||
/* Xifan TANG, EPFL/LSI */
|
||||
/***********************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Include vpr structs*/
|
||||
#include "util.h"
|
||||
#include "physical_types.h"
|
||||
#include "vpr_types.h"
|
||||
#include "globals.h"
|
||||
#include "rr_graph.h"
|
||||
#include "vpr_utils.h"
|
||||
#include "path_delay.h"
|
||||
#include "stats.h"
|
||||
|
||||
/* Include FPGA-SPICE utils */
|
||||
#include "linkedlist.h"
|
||||
#include "fpga_x2p_utils.h"
|
||||
#include "fpga_x2p_globals.h"
|
||||
|
||||
/* Include verilog utils */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_utils.h"
|
||||
|
||||
/***** Subroutines *****/
|
||||
/* Return the float number of the time unit required by Modelsim */
|
||||
float convert_modelsim_time_unit_to_float(char* modelsim_time_unit) {
|
||||
/* switch cases is made for s, ms, us, ns, ps and fs*/
|
||||
if (0 == strcmp("s", modelsim_time_unit)) {
|
||||
return 1;
|
||||
} else if (0 == strcmp("ms", modelsim_time_unit)) {
|
||||
return 1e-3;
|
||||
} else if (0 == strcmp("us", modelsim_time_unit)) {
|
||||
return 1e-6;
|
||||
} else if (0 == strcmp("ns", modelsim_time_unit)) {
|
||||
return 1e-9;
|
||||
} else if (0 == strcmp("ps", modelsim_time_unit)) {
|
||||
return 1e-12;
|
||||
} else if (0 == strcmp("fs", modelsim_time_unit)) {
|
||||
return 1e-15;
|
||||
} else {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid time unit(=%s) for modelsim!\n",
|
||||
__FILE__, __LINE__, modelsim_time_unit);
|
||||
exit(1);
|
||||
return 0.;
|
||||
}
|
||||
return 0.;
|
||||
}
|
||||
|
||||
static
|
||||
void modelsim_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", __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) {
|
||||
assert(NULL != spice.include_netlists[i].path);
|
||||
fprintf(fp, " %s \\\n", spice.include_netlists[i].path);
|
||||
spice.include_netlists[i].included = 1;
|
||||
} else {
|
||||
assert(1 == spice.include_netlists[i].included);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Estimate the simulation time period to be assigned in Modelsim:
|
||||
* Total simulation time = number of programming clock cycles * programming clock period
|
||||
* + number of operating clock cycles * operating clock period
|
||||
*/
|
||||
static
|
||||
float get_verilog_modelsim_simulation_time_period(float time_unit,
|
||||
int num_prog_clock_cycles,
|
||||
float prog_clock_period,
|
||||
int num_op_clock_cycles,
|
||||
float op_clock_period) {
|
||||
float total_time_period = 0.;
|
||||
|
||||
/* Take into account the prog_reset and reset cycles */
|
||||
total_time_period = (num_prog_clock_cycles + 2) * prog_clock_period + num_op_clock_cycles * op_clock_period;
|
||||
total_time_period = total_time_period / time_unit;
|
||||
|
||||
return total_time_period;
|
||||
}
|
||||
|
||||
static
|
||||
void dump_verilog_modelsim_proc_script(char* modelsim_proc_filename,
|
||||
char* modelsim_ini_path,
|
||||
char* circuit_name) {
|
||||
FILE* fp = NULL;
|
||||
char* circuit_top_tb_name = NULL;
|
||||
|
||||
circuit_top_tb_name = my_strcat(circuit_name, modelsim_testbench_module_postfix);
|
||||
|
||||
/* Create Modelsim proc file */
|
||||
/* Open file and file handler */
|
||||
fp = fopen(modelsim_proc_filename, "w");
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create Modelsim simulation deck auto-generation scripts: %s",
|
||||
__FILE__, __LINE__, modelsim_proc_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(fp, "proc create_project {projectname project_path} {\n");
|
||||
fprintf(fp, " #Switch to the modelsim folder to create the project\n");
|
||||
fprintf(fp, " set libname $projectname\n");
|
||||
fprintf(fp, " set initfile %s\n", modelsim_ini_path);
|
||||
fprintf(fp, " project new $project_path/$projectname $projectname $libname $initfile 0\n");
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
fprintf(fp, " \n");
|
||||
|
||||
fprintf(fp, "proc create_project_with_close {projectname modelsim_path} {\n");
|
||||
fprintf(fp, " #Get the current project name\n");
|
||||
fprintf(fp, " set project_env [project env]\n");
|
||||
fprintf(fp, " if {$project_env eq \"\"} {\n");
|
||||
fprintf(fp, " #If string empty (no project)\n");
|
||||
fprintf(fp, " create_project $projectname $modelsim_path\n");
|
||||
fprintf(fp, " } else {\n");
|
||||
fprintf(fp, " #If string not empty (a project is loaded so clsoe it first)\n");
|
||||
fprintf(fp, " project close\n");
|
||||
fprintf(fp, " create_project $projectname $modelsim_path\n");
|
||||
fprintf(fp, " }\n");
|
||||
fprintf(fp, " }\n");
|
||||
|
||||
fprintf(fp, " \n");
|
||||
|
||||
fprintf(fp, "proc add_files_project {verilog_files} {\n");
|
||||
fprintf(fp, " #Get the length of the list\n");
|
||||
fprintf(fp, " set listlength [llength $verilog_files]\n");
|
||||
fprintf(fp, " #Add the verilog files one by one\n");
|
||||
fprintf(fp, " for {set x 0} {$x<$listlength} {incr x} {\n");
|
||||
fprintf(fp, " project addfile [lindex $verilog_files $x]\n");
|
||||
fprintf(fp, " }\n");
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
fprintf(fp, " \n");
|
||||
|
||||
fprintf(fp, "proc add_waves {} {\n");
|
||||
fprintf(fp, " add wave -position insertpoint sim:/%s/*\n", circuit_top_tb_name);
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
|
||||
fprintf(fp, "proc runsim {simtime unit} {\n");
|
||||
fprintf(fp, " run $simtime $unit\n");
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
|
||||
fprintf(fp, "#Top procedure to create enw project\n");
|
||||
fprintf(fp, "proc top_create_new_project {projectname verilog_files modelsim_path simtime unit} {\n");
|
||||
fprintf(fp, " #Create the project\n");
|
||||
fprintf(fp, " create_project_with_close $projectname $modelsim_path\n");
|
||||
fprintf(fp, " #Add the verilog files\n");
|
||||
fprintf(fp, " add_files_project $verilog_files\n");
|
||||
fprintf(fp, " #Compile all the files\n");
|
||||
fprintf(fp, " project compileall\n");
|
||||
fprintf(fp, " #Start the simulation\n");
|
||||
fprintf(fp, " vsim $projectname.%s -voptargs=+acc\n", circuit_top_tb_name);
|
||||
fprintf(fp, " #Add the waves \n");
|
||||
fprintf(fp, " add_waves\n");
|
||||
fprintf(fp, " #run the simulation\n");
|
||||
fprintf(fp, " runsim $simtime $unit\n");
|
||||
fprintf(fp, " #Fit the window view\n");
|
||||
fprintf(fp, " wave zoom full\n");
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
fprintf(fp, "#Top proc to recompile files and re run the simulation\n");
|
||||
fprintf(fp, "proc top_rerun_sim {simtime unit} {\n");
|
||||
fprintf(fp, " #Compile updated verilog files\n");
|
||||
fprintf(fp, " project compileoutofdate\n");
|
||||
fprintf(fp, " #restart the simulation\n");
|
||||
fprintf(fp, " restart -force\n");
|
||||
fprintf(fp, " #run the simulation\n");
|
||||
fprintf(fp, " runsim $simtime $unit\n");
|
||||
fprintf(fp, " #Fit the window view\n");
|
||||
fprintf(fp, " wave zoom full\n");
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
/* Close File handler */
|
||||
fclose(fp);
|
||||
|
||||
/* Free */
|
||||
my_free(circuit_top_tb_name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
void dump_verilog_modelsim_proc_auto_script(char* modelsim_proc_filename,
|
||||
char* modelsim_ini_path,
|
||||
char* circuit_name,
|
||||
boolean include_timing,
|
||||
boolean init_sim,
|
||||
char* modelsim_project_name) {
|
||||
FILE* fp = NULL;
|
||||
char* circuit_top_tb_name = NULL;
|
||||
|
||||
circuit_top_tb_name = my_strcat(circuit_name, my_strcat(autocheck_testbench_postfix, modelsim_testbench_module_postfix));
|
||||
|
||||
/* Create Modelsim proc file */
|
||||
/* Open file and file handler */
|
||||
fp = fopen(modelsim_proc_filename, "w");
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create Modelsim simulation deck auto-generation scripts: %s",
|
||||
__FILE__, __LINE__, modelsim_proc_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(fp, "proc create_project {projectname project_path} {\n");
|
||||
fprintf(fp, " #Switch to the modelsim folder to create the project\n");
|
||||
fprintf(fp, " set libname $projectname\n");
|
||||
fprintf(fp, " set initfile %s\n", modelsim_ini_path);
|
||||
fprintf(fp, " project new $project_path/$projectname $projectname $libname $initfile 0\n");
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
fprintf(fp, " \n");
|
||||
|
||||
fprintf(fp, "proc create_project_with_close {projectname modelsim_path} {\n");
|
||||
fprintf(fp, " #Get the current project name\n");
|
||||
fprintf(fp, " set project_env [project env]\n");
|
||||
fprintf(fp, " if {$project_env eq \"\"} {\n");
|
||||
fprintf(fp, " #If string empty (no project)\n");
|
||||
fprintf(fp, " create_project $projectname $modelsim_path\n");
|
||||
fprintf(fp, " } else {\n");
|
||||
fprintf(fp, " #If string not empty (a project is loaded so clsoe it first)\n");
|
||||
fprintf(fp, " project close\n");
|
||||
fprintf(fp, " create_project $projectname $modelsim_path\n");
|
||||
fprintf(fp, " }\n");
|
||||
fprintf(fp, " }\n");
|
||||
|
||||
fprintf(fp, " \n");
|
||||
|
||||
fprintf(fp, "proc add_files_project {verilog_files} {\n");
|
||||
fprintf(fp, " #Get the length of the list\n");
|
||||
fprintf(fp, " set listlength [llength $verilog_files]\n");
|
||||
fprintf(fp, " #Add the verilog files one by one\n");
|
||||
fprintf(fp, " for {set x 0} {$x<$listlength} {incr x} {\n");
|
||||
fprintf(fp, " project addfile [lindex $verilog_files $x]\n");
|
||||
fprintf(fp, " }\n");
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
fprintf(fp, " \n");
|
||||
|
||||
fprintf(fp, "proc add_waves {} {\n");
|
||||
fprintf(fp, " add wave -position insertpoint sim:/%s/*\n", circuit_top_tb_name);
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
|
||||
fprintf(fp, "proc runsim {simtime unit} {\n");
|
||||
fprintf(fp, " run $simtime $unit\n");
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
|
||||
fprintf(fp, "#Top procedure to create enw project\n");
|
||||
fprintf(fp, "proc top_create_new_project {projectname verilog_files modelsim_path simtime unit} {\n");
|
||||
fprintf(fp, " #Create the project\n");
|
||||
fprintf(fp, " create_project_with_close $projectname $modelsim_path\n");
|
||||
fprintf(fp, " #Add the verilog files\n");
|
||||
fprintf(fp, " add_files_project $verilog_files\n");
|
||||
fprintf(fp, " #Compile all the files\n");
|
||||
// fprintf(fp, " project compileall\n"); // removed to allow compilation with define
|
||||
// Begin of compilation with Define
|
||||
fprintf(fp, " set myFiles [project filenames]\n");
|
||||
fprintf(fp, " foreach x $myFiles {\n");
|
||||
fprintf(fp, " vlog ");
|
||||
if(TRUE == include_timing){
|
||||
fprintf(fp, "+define+%s ", verilog_timing_preproc_flag);
|
||||
}
|
||||
if(TRUE == init_sim){
|
||||
fprintf(fp, "+define+%s ", verilog_signal_init_preproc_flag);
|
||||
}
|
||||
fprintf(fp, "$x\n }\n");
|
||||
// End of compilation with Define
|
||||
fprintf(fp, " #Start the simulation\n");
|
||||
fprintf(fp, " vsim $projectname.%s -voptargs=+acc\n", circuit_top_tb_name);
|
||||
fprintf(fp, " #Add the waves \n");
|
||||
fprintf(fp, " add_waves\n");
|
||||
fprintf(fp, " #run the simulation\n");
|
||||
fprintf(fp, " runsim $simtime $unit\n");
|
||||
fprintf(fp, " #Fit the window view\n");
|
||||
fprintf(fp, " wave zoom full\n");
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
fprintf(fp, "#Top proc to recompile files and re run the simulation\n");
|
||||
fprintf(fp, "proc top_rerun_sim {simtime unit} {\n");
|
||||
// Save format
|
||||
fprintf(fp, " #Save actual format\n");
|
||||
fprintf(fp, " set myLoc [pwd]\n");
|
||||
fprintf(fp, " write format wave -window .main_pane.wave.interior.cs.body.pw.wf $myLoc/relaunch.do\n");
|
||||
// Quit simulation
|
||||
fprintf(fp, " quit -sim\n");
|
||||
// Recompile file
|
||||
fprintf(fp, " #Compile updated verilog files\n");
|
||||
fprintf(fp, " set myFiles [project filenames]\n");
|
||||
fprintf(fp, " foreach x $myFiles {\n");
|
||||
fprintf(fp, " vlog ");
|
||||
if(TRUE == include_timing){
|
||||
fprintf(fp, "+define+%s ", verilog_timing_preproc_flag);
|
||||
}
|
||||
if(TRUE == init_sim){
|
||||
fprintf(fp, "+define+%s ", verilog_signal_init_preproc_flag);
|
||||
}
|
||||
fprintf(fp, "$x\n }\n");
|
||||
// Restart the Simulation
|
||||
fprintf(fp, " set projectname %s\n", modelsim_project_name);
|
||||
fprintf(fp, " vsim $projectname.%s -voptargs=+acc -do relaunch.do\n", circuit_top_tb_name);
|
||||
// Relaunch the Simulation
|
||||
fprintf(fp, " #run the simulation\n");
|
||||
fprintf(fp, " run $simtime $unit\n");
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
/* Close File handler */
|
||||
fclose(fp);
|
||||
|
||||
/* Free */
|
||||
my_free(circuit_top_tb_name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void dump_verilog_modelsim_top_script(char* modelsim_top_script_filename,
|
||||
char* modelsim_proc_script_filename,
|
||||
char* modelsim_project_path,
|
||||
char* circuit_name,
|
||||
char* modelsim_project_name,
|
||||
float sim_time,
|
||||
char* sim_time_unit,
|
||||
t_spice spice,
|
||||
char* src_dir_path) {
|
||||
FILE* fp = NULL;
|
||||
|
||||
/* Create Modelsim proc file */
|
||||
/* Open file and file handler */
|
||||
fp = fopen(modelsim_top_script_filename, "w");
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create Modelsim simulation deck auto-generation scripts: %s",
|
||||
__FILE__, __LINE__, modelsim_top_script_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(fp, "set projectname %s\n", modelsim_project_name);
|
||||
fprintf(fp, "set benchmark %s\n", circuit_name);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "#in ms\n");
|
||||
fprintf(fp, "set simtime %.10g\n", sim_time);
|
||||
fprintf(fp, "set unit %s\n",
|
||||
sim_time_unit);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "#Path were both tcl script are located\n");
|
||||
fprintf(fp, "set project_path \"%s%s\"\n", modelsim_project_path, default_modelsim_dir_name);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "#Path were the verilog files are located\n");
|
||||
fprintf(fp, "set script_path \"%s\"\n", modelsim_project_path);
|
||||
fprintf(fp, "set verilog_path \"%s\"\n", src_dir_path);
|
||||
fprintf(fp, "set verilog_files [list \\\n");
|
||||
/* TODO: include verilog files */
|
||||
fprintf(fp, " ${verilog_path}${benchmark}%s \\\n",
|
||||
verilog_top_postfix);
|
||||
fprintf(fp, " ${verilog_path}${benchmark}%s \\\n",
|
||||
top_testbench_verilog_file_postfix);
|
||||
/* User-defined verilog netlists */
|
||||
init_include_user_defined_verilog_netlists(spice);
|
||||
modelsim_include_user_defined_verilog_netlists(fp, spice);
|
||||
|
||||
fprintf(fp, " ${verilog_path}%s%s \\\n",
|
||||
default_lb_dir_name, logic_block_verilog_file_name);
|
||||
fprintf(fp, " ${verilog_path}%s%s \\\n",
|
||||
default_rr_dir_name, routing_verilog_file_name);
|
||||
fprintf(fp, " ${verilog_path}%s%s ] \n",
|
||||
default_submodule_dir_name, submodule_verilog_file_name);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "#Source the tcl script\n");
|
||||
fprintf(fp, "source ${script_path}%s\n", modelsim_proc_script_filename);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "#Execute the top level procedure\n");
|
||||
fprintf(fp, "top_create_new_project $projectname $verilog_files $project_path $simtime $unit\n");
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "#Relaunch simulation\n");
|
||||
|
||||
/* Close File handler */
|
||||
fclose(fp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
void dump_verilog_modelsim_top_auto_script(char* modelsim_top_auto_script_filename,
|
||||
char* modelsim_proc_auto_script_filename,
|
||||
char* modelsim_project_path,
|
||||
char* circuit_name,
|
||||
char* modelsim_project_name,
|
||||
float sim_time,
|
||||
char* sim_time_unit,
|
||||
t_spice spice,
|
||||
char* src_dir_path) {
|
||||
FILE* fp = NULL;
|
||||
|
||||
/* Create Modelsim proc file */
|
||||
/* Open file and file handler */
|
||||
fp = fopen(modelsim_top_auto_script_filename, "w");
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create Modelsim simulation deck auto-generation scripts: %s",
|
||||
__FILE__, __LINE__, modelsim_top_auto_script_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(fp, "set projectname %s\n", modelsim_project_name);
|
||||
fprintf(fp, "set benchmark %s\n", circuit_name);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "#in ms\n");
|
||||
fprintf(fp, "set simtime %.4g\n", sim_time);
|
||||
fprintf(fp, "set unit %s\n",
|
||||
sim_time_unit);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "#Path were both tcl script are located\n");
|
||||
fprintf(fp, "set project_path \"%s%s\"\n", modelsim_project_path, default_modelsim_dir_name);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "#Path were the verilog files are located\n");
|
||||
fprintf(fp, "set script_path \"%s\"\n", modelsim_project_path);
|
||||
fprintf(fp, "set verilog_path \"%s\"\n", src_dir_path);
|
||||
fprintf(fp, "set verilog_files [list \\\n");
|
||||
/* TODO: include verilog files */
|
||||
fprintf(fp, " ${verilog_path}${benchmark}%s \\\n",
|
||||
verilog_top_postfix);
|
||||
fprintf(fp, " ${verilog_path}${benchmark}%s%s \\\n",
|
||||
autocheck_testbench_postfix, top_testbench_verilog_file_postfix);
|
||||
|
||||
/* User-defined verilog netlists */
|
||||
init_include_user_defined_verilog_netlists(spice);
|
||||
modelsim_include_user_defined_verilog_netlists(fp, spice);
|
||||
|
||||
fprintf(fp, " ${verilog_path}%s%s \\\n",
|
||||
default_lb_dir_name, logic_block_verilog_file_name);
|
||||
fprintf(fp, " ${verilog_path}%s%s \\\n",
|
||||
default_rr_dir_name, routing_verilog_file_name);
|
||||
fprintf(fp, " ${verilog_path}%s%s ] \n",
|
||||
default_submodule_dir_name, submodule_verilog_file_name);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "#Source the tcl script\n");
|
||||
fprintf(fp, "source ${script_path}%s\n", modelsim_proc_auto_script_filename);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "#Execute the top level procedure\n");
|
||||
fprintf(fp, "top_create_new_project $projectname $verilog_files $project_path $simtime $unit\n");
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "#Relaunch simulation\n");
|
||||
|
||||
/* Close File handler */
|
||||
fclose(fp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/***** Top-level function *****/
|
||||
void dump_verilog_modelsim_autodeck(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
t_syn_verilog_opts fpga_verilog_opts,
|
||||
t_spice spice,
|
||||
int num_operating_clock_cycles,
|
||||
char* verilog_dir_formatted,
|
||||
char* chomped_circuit_name,
|
||||
char* src_dir_path) {
|
||||
char* modelsim_project_name = NULL;
|
||||
char* modelsim_proc_script_filename = NULL;
|
||||
char* modelsim_top_script_filename = NULL;
|
||||
char* modelsim_proc_auto_script_filename = NULL;
|
||||
char* modelsim_top_auto_script_filename = NULL;
|
||||
float simulation_time_period = 0.;
|
||||
|
||||
/* Determine the project name for Modelsim */
|
||||
modelsim_project_name = my_strcat(chomped_circuit_name, modelsim_project_name_postfix);
|
||||
modelsim_top_script_filename = my_strcat(verilog_dir_formatted, my_strcat(chomped_circuit_name, modelsim_top_script_name_postfix));
|
||||
modelsim_proc_script_filename = my_strcat(verilog_dir_formatted, my_strcat(chomped_circuit_name, modelsim_proc_script_name_postfix));
|
||||
|
||||
modelsim_top_auto_script_filename = my_strcat(verilog_dir_formatted, my_strcat(chomped_circuit_name, my_strcat(autocheck_testbench_postfix, modelsim_top_script_name_postfix)));
|
||||
modelsim_proc_auto_script_filename = my_strcat(verilog_dir_formatted, my_strcat(chomped_circuit_name, my_strcat(autocheck_testbench_postfix, modelsim_proc_script_name_postfix)));
|
||||
|
||||
/* Generate files */
|
||||
vpr_printf(TIO_MESSAGE_INFO, "Writing Modelsim simulation deck auto-generation scripts...\n");
|
||||
|
||||
/* Check */
|
||||
/* Modelsim ini path must be valid!*/
|
||||
if (NULL == fpga_verilog_opts.modelsim_ini_path) {
|
||||
vpr_printf(TIO_MESSAGE_INFO, "(FILE:%s, [LINE%d])Invalid Modelsim ini path!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Dump the Modelsim process function file */
|
||||
if (fpga_verilog_opts.print_top_testbench){
|
||||
dump_verilog_modelsim_proc_script(modelsim_proc_script_filename,
|
||||
fpga_verilog_opts.modelsim_ini_path, chomped_circuit_name);
|
||||
}
|
||||
|
||||
if (fpga_verilog_opts.print_autocheck_top_testbench){
|
||||
dump_verilog_modelsim_proc_auto_script(modelsim_proc_auto_script_filename,
|
||||
fpga_verilog_opts.modelsim_ini_path, chomped_circuit_name,
|
||||
fpga_verilog_opts.include_timing, fpga_verilog_opts.include_signal_init,
|
||||
modelsim_project_name);
|
||||
}
|
||||
|
||||
|
||||
/* Compute simulation time period */
|
||||
simulation_time_period = get_verilog_modelsim_simulation_time_period(convert_modelsim_time_unit_to_float(modelsim_simulation_time_unit),
|
||||
get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info),
|
||||
1./spice.spice_params.stimulate_params.prog_clock_freq,
|
||||
num_operating_clock_cycles,
|
||||
1./spice.spice_params.stimulate_params.op_clock_freq);
|
||||
|
||||
/* Dump the Modelsim top-level script file */
|
||||
if (fpga_verilog_opts.print_top_testbench){
|
||||
dump_verilog_modelsim_top_script(modelsim_top_script_filename,
|
||||
my_strcat(chomped_circuit_name, modelsim_proc_script_name_postfix),
|
||||
verilog_dir_formatted,
|
||||
chomped_circuit_name, modelsim_project_name,
|
||||
simulation_time_period, modelsim_simulation_time_unit,
|
||||
spice,
|
||||
src_dir_path);
|
||||
}
|
||||
|
||||
if (fpga_verilog_opts.print_autocheck_top_testbench){
|
||||
dump_verilog_modelsim_top_auto_script(modelsim_top_auto_script_filename,
|
||||
my_strcat(chomped_circuit_name, my_strcat(autocheck_testbench_postfix, modelsim_proc_script_name_postfix)),
|
||||
verilog_dir_formatted,
|
||||
chomped_circuit_name, modelsim_project_name,
|
||||
simulation_time_period, modelsim_simulation_time_unit,
|
||||
spice,
|
||||
src_dir_path);
|
||||
}
|
||||
|
||||
/* Free */
|
||||
my_free(modelsim_project_name);
|
||||
my_free(modelsim_proc_script_filename);
|
||||
my_free(modelsim_top_script_filename);
|
||||
my_free(modelsim_proc_auto_script_filename);
|
||||
my_free(modelsim_top_auto_script_filename);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
void dump_verilog_modelsim_autodeck(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
t_syn_verilog_opts fpga_verilog_opts,
|
||||
t_spice spice,
|
||||
int num_operating_clock_cycles,
|
||||
char* verilog_dir_formatted,
|
||||
char* chomped_circuit_name,
|
||||
char* src_dir_path);
|
|
@ -1218,6 +1218,7 @@ void generate_verilog_mux_module(ModuleManager& module_manager,
|
|||
* multiplexers in the FPGA device
|
||||
**********************************************/
|
||||
void print_verilog_submodule_muxes(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
|
@ -1279,9 +1280,7 @@ void print_verilog_submodule_muxes(ModuleManager& module_manager,
|
|||
try_update_sram_orgz_info_reserved_blwl(cur_sram_orgz_info,
|
||||
mux_lib.max_mux_size(), mux_lib.max_mux_size());
|
||||
|
||||
/* TODO: Add fname to the linked list when debugging is finished */
|
||||
/*
|
||||
submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_fname.c_str());
|
||||
*/
|
||||
/* Add fname to the netlist name list */
|
||||
netlist_names.push_back(verilog_fname);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
/* Include other header files which are dependency on the function declared below */
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "circuit_library.h"
|
||||
#include "mux_graph.h"
|
||||
|
@ -14,6 +15,7 @@
|
|||
#include "module_manager.h"
|
||||
|
||||
void print_verilog_submodule_muxes(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,164 +0,0 @@
|
|||
|
||||
void match_pb_types_verilog_model_rec(t_pb_type* cur_pb_type,
|
||||
int num_verilog_model,
|
||||
t_spice_model* verilog_models);
|
||||
|
||||
int verilog_find_path_id_between_pb_rr_nodes(t_rr_node* local_rr_graph,
|
||||
int src_node,
|
||||
int des_node);
|
||||
|
||||
enum e_interconnect verilog_find_pb_graph_pin_in_edges_interc_type(t_pb_graph_pin pb_graph_pin);
|
||||
|
||||
t_spice_model* find_pb_graph_pin_in_edges_interc_verilog_model(t_pb_graph_pin pb_graph_pin);
|
||||
|
||||
void stats_mux_verilog_model_pb_type_rec(t_llist** muxes_head,
|
||||
t_pb_type* cur_pb_type);
|
||||
|
||||
void stats_mux_verilog_model_pb_node_rec(t_llist** muxes_head,
|
||||
t_pb_graph_node* cur_pb_node);
|
||||
|
||||
|
||||
void dump_verilog_pb_type_bus_ports(FILE* fp,
|
||||
char* port_prefix,
|
||||
int use_global_clock,
|
||||
t_pb_type* cur_pb_type,
|
||||
boolean dump_port_type,
|
||||
boolean dump_last_comma,
|
||||
boolean dump_explicit_port_map);
|
||||
|
||||
void dump_verilog_pb_type_ports(FILE* fp,
|
||||
char* port_prefix,
|
||||
int use_global_clock,
|
||||
t_pb_type* cur_pb_type,
|
||||
boolean dump_port_type,
|
||||
boolean dump_last_comma,
|
||||
boolean require_explicit_port_map,
|
||||
bool is_full_name);
|
||||
|
||||
void dump_verilog_dangling_des_pb_graph_pin_interc(FILE* fp,
|
||||
t_pb_graph_pin* des_pb_graph_pin,
|
||||
t_mode* cur_mode,
|
||||
enum e_spice_pin2pin_interc_type pin2pin_interc_type,
|
||||
char* parent_pin_prefix);
|
||||
|
||||
void generate_verilog_src_des_pb_graph_pin_prefix(t_pb_graph_pin* src_pb_graph_pin,
|
||||
t_pb_graph_pin* des_pb_graph_pin,
|
||||
enum e_spice_pin2pin_interc_type pin2pin_interc_type,
|
||||
t_interconnect* pin2pin_interc,
|
||||
char* parent_pin_prefix,
|
||||
char** src_pin_prefix,
|
||||
char** des_pin_prefix);
|
||||
|
||||
void verilog_find_interc_fan_in_des_pb_graph_pin(t_pb_graph_pin* des_pb_graph_pin,
|
||||
t_mode* cur_mode,
|
||||
t_interconnect** cur_interc,
|
||||
int* fan_in);
|
||||
|
||||
void dump_verilog_pb_graph_pin_interc(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
char* parent_pin_prefix,
|
||||
enum e_spice_pin2pin_interc_type pin2pin_interc_type,
|
||||
t_pb_graph_pin* des_pb_graph_pin,
|
||||
t_mode* cur_mode,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void dump_verilog_pb_graph_interc(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
char* pin_prefix,
|
||||
t_pb_graph_node* cur_pb_graph_node,
|
||||
int select_mode_index,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void dump_verilog_pb_graph_primitive_node(FILE* fp,
|
||||
char* subckt_prefix,
|
||||
t_pb_graph_node* cur_pb_graph_node,
|
||||
int pb_type_index);
|
||||
|
||||
void dump_verilog_pb_primitive_verilog_model(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
char* subckt_prefix,
|
||||
t_pb* prim_pb,
|
||||
t_pb_graph_node* prim_pb_graph_node,
|
||||
int pb_index,
|
||||
t_spice_model* verilog_model,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void dump_verilog_phy_pb_graph_node_rec(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
char* subckt_prefix,
|
||||
t_pb_graph_node* cur_pb_graph_node,
|
||||
int pb_type_index,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void dump_verilog_block(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
char* subckt_name,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
t_type_ptr type_descriptor,
|
||||
t_block* mapped_block);
|
||||
|
||||
void dump_verilog_physical_block(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
char* subckt_name,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
t_type_ptr type_descriptor,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void dump_verilog_grid_pins(FILE* fp,
|
||||
int x, int y,
|
||||
boolean top_level,
|
||||
boolean dump_port_type,
|
||||
boolean dump_last_comma,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void dump_verilog_io_grid_pins(FILE* fp,
|
||||
int x, int y,
|
||||
boolean top_level,
|
||||
int border_side,
|
||||
boolean dump_port_type,
|
||||
boolean dump_last_comma,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
char* get_grid_block_subckt_name(int x,
|
||||
int y,
|
||||
int z,
|
||||
char* subckt_prefix,
|
||||
t_block* mapped_block);
|
||||
|
||||
void dump_verilog_grid_block_subckt_pins(FILE* fp,
|
||||
int z,
|
||||
t_type_ptr type_descriptor,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void dump_verilog_io_grid_block_subckt_pins(FILE* fp,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
t_type_ptr type_descriptor);
|
||||
|
||||
void dump_verilog_grid_blocks(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
int ix, int iy);
|
||||
|
||||
void dump_verilog_physical_grid_blocks(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
int ix, int iy,
|
||||
t_arch* arch,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void dump_verilog_idle_block(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
char* subckt_name,
|
||||
int x, int y, int z,
|
||||
t_type_ptr type_descriptor);
|
||||
|
||||
void dump_verilog_logic_blocks(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* subckt_dir, t_arch* arch,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void rec_copy_name_mux_in_node(t_pb_graph_node* master_node,
|
||||
t_pb_graph_node* target_node);
|
|
@ -1,779 +0,0 @@
|
|||
/***********************************/
|
||||
/* SPICE Modeling for VPR */
|
||||
/* Xifan TANG, EPFL/LSI */
|
||||
/***********************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Include vpr structs*/
|
||||
#include "util.h"
|
||||
#include "physical_types.h"
|
||||
#include "vpr_types.h"
|
||||
#include "globals.h"
|
||||
#include "rr_graph.h"
|
||||
#include "rr_graph_swseg.h"
|
||||
#include "route_common.h"
|
||||
#include "vpr_utils.h"
|
||||
|
||||
/* Include spice support headers*/
|
||||
#include "linkedlist.h"
|
||||
#include "fpga_x2p_types.h"
|
||||
#include "fpga_x2p_utils.h"
|
||||
#include "fpga_x2p_pbtypes_utils.h"
|
||||
#include "fpga_x2p_bitstream_utils.h"
|
||||
#include "fpga_x2p_globals.h"
|
||||
|
||||
/* Include verilog support headers*/
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_utils.h"
|
||||
#include "verilog_pbtypes.h"
|
||||
#include "verilog_primitives.h"
|
||||
|
||||
/* Subroutines */
|
||||
/* Dump a hard logic primitive node
|
||||
* This primitive can be a FF or a hard_logic, or an iopad */
|
||||
void dump_verilog_pb_generic_primitive(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
char* subckt_prefix,
|
||||
t_pb_graph_node* prim_pb_graph_node,
|
||||
int index,
|
||||
t_spice_model* verilog_model,
|
||||
bool is_explicit_mapping) {
|
||||
int num_pad_port = 0; /* INOUT port */
|
||||
t_spice_model_port** pad_ports = NULL;
|
||||
int num_input_port = 0;
|
||||
t_spice_model_port** input_ports = NULL;
|
||||
int num_output_port = 0;
|
||||
t_spice_model_port** output_ports = NULL;
|
||||
int num_clock_port = 0;
|
||||
t_spice_model_port** clock_ports = NULL;
|
||||
int num_sram_port = 0;
|
||||
t_spice_model_port** sram_ports = NULL;
|
||||
|
||||
int num_sram = 0;
|
||||
/* int* sram_bits = NULL; */
|
||||
|
||||
char* formatted_subckt_prefix = format_verilog_node_prefix(subckt_prefix); /* Complete a "_" at the end if needed*/
|
||||
t_pb_type* prim_pb_type = NULL;
|
||||
char* port_prefix = NULL;
|
||||
|
||||
/* For each SRAM, we could have multiple BLs/WLs */
|
||||
int num_bl_ports = 0;
|
||||
t_spice_model_port** bl_port = NULL;
|
||||
int num_wl_ports = 0;
|
||||
t_spice_model_port** wl_port = NULL;
|
||||
|
||||
int cur_num_sram = 0;
|
||||
int num_conf_bits = 0;
|
||||
int num_reserved_conf_bits = 0;
|
||||
t_spice_model* mem_model = NULL;
|
||||
int cur_bl, cur_wl;
|
||||
|
||||
char* mem_subckt_name = NULL;
|
||||
|
||||
/* Ensure a valid file handler*/
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Ensure a valid pb_graph_node */
|
||||
if (NULL == prim_pb_graph_node) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid prim_pb_graph_node!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Find ports*/
|
||||
pad_ports = find_spice_model_ports(verilog_model, SPICE_MODEL_PORT_INOUT, &num_pad_port, TRUE);
|
||||
input_ports = find_spice_model_ports(verilog_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE);
|
||||
output_ports = find_spice_model_ports(verilog_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE);
|
||||
clock_ports = find_spice_model_ports(verilog_model, SPICE_MODEL_PORT_CLOCK, &num_clock_port, TRUE);
|
||||
sram_ports = find_spice_model_ports(verilog_model, SPICE_MODEL_PORT_SRAM, &num_sram_port, TRUE);
|
||||
|
||||
/* Asserts */
|
||||
assert((SPICE_MODEL_IOPAD == verilog_model->type) /* Support IO PAD which matches the physical design */
|
||||
|| (SPICE_MODEL_FF == verilog_model->type) /* Support IO PAD which matches the physical design */
|
||||
|| (SPICE_MODEL_HARDLOGIC == verilog_model->type)); /* Support IO PAD which matches the physical design */
|
||||
|
||||
/* Initialize */
|
||||
get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
|
||||
|
||||
prim_pb_type = prim_pb_graph_node->pb_type;
|
||||
|
||||
/* Generate Subckt for pb_type*/
|
||||
/* Simplify the port prefix, make SPICE netlist readable */
|
||||
port_prefix = (char*)my_malloc(sizeof(char)*
|
||||
(strlen(prim_pb_type->name) + 1));
|
||||
sprintf(port_prefix, "%s", prim_pb_type->name);
|
||||
|
||||
/* Print Comment lines depends on the type of this SPICE model */
|
||||
fprintf(fp, "//----- %s Verilog module: %s%s -----\n",
|
||||
generate_string_spice_model_type(verilog_model->type),
|
||||
formatted_subckt_prefix, port_prefix);
|
||||
/* Definition line */
|
||||
fprintf(fp, "module %s%s (", formatted_subckt_prefix, port_prefix);
|
||||
fprintf(fp, "\n");
|
||||
/* Only dump the global ports belonging to a spice_model
|
||||
*/
|
||||
if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, TRUE, TRUE, my_bool_to_boolean(is_explicit_mapping), TRUE)) {
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
|
||||
/* TODO: assert this is physical mode */
|
||||
num_sram = count_num_sram_bits_one_spice_model(verilog_model, -1);
|
||||
/* Get current counter of mem_bits, bl and wl */
|
||||
cur_num_sram = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info);
|
||||
get_sram_orgz_info_num_blwl(cur_sram_orgz_info, &cur_bl, &cur_wl);
|
||||
|
||||
/* print ports --> input ports */
|
||||
dump_verilog_pb_type_ports(fp, port_prefix, 0, prim_pb_type, TRUE, FALSE, FALSE, true);
|
||||
/* IOPADs requires a specical port to output */
|
||||
if (SPICE_MODEL_IOPAD == verilog_model->type) {
|
||||
fprintf(fp, ",\n");
|
||||
/* Print output port */
|
||||
fprintf(fp, "inout [%d:%d] %s%s\n",
|
||||
verilog_model->cnt, verilog_model->cnt,
|
||||
gio_inout_prefix, verilog_model->prefix);
|
||||
}
|
||||
|
||||
/* Print SRAM ports */
|
||||
/* connect to reserved BL/WLs ? */
|
||||
num_reserved_conf_bits = count_num_reserved_conf_bits_one_spice_model(verilog_model, cur_sram_orgz_info->type, 0);
|
||||
/* Get the number of configuration bits required by this MUX */
|
||||
num_conf_bits = count_num_conf_bits_one_spice_model(verilog_model, cur_sram_orgz_info->type, 0);
|
||||
/* Reserved sram ports */
|
||||
if (0 < num_reserved_conf_bits) {
|
||||
fprintf(fp, ",\n");
|
||||
dump_verilog_reserved_sram_ports(fp, cur_sram_orgz_info,
|
||||
0, num_reserved_conf_bits - 1,
|
||||
VERILOG_PORT_INPUT);
|
||||
}
|
||||
/* Normal sram ports */
|
||||
if (0 < num_conf_bits) {
|
||||
fprintf(fp, ",\n");
|
||||
dump_verilog_sram_ports(fp, cur_sram_orgz_info,
|
||||
cur_num_sram, cur_num_sram + num_sram - 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,
|
||||
cur_num_sram + num_conf_bits - 1,
|
||||
VERILOG_PORT_INPUT, false);
|
||||
fprintf(fp, "\n");
|
||||
fprintf(fp, "`endif\n");
|
||||
}
|
||||
|
||||
/* Local vdd and gnd*/
|
||||
fprintf(fp, ");\n");
|
||||
|
||||
if (0 < num_sram_port) {
|
||||
dump_verilog_sram_config_bus_internal_wires(fp, cur_sram_orgz_info,
|
||||
cur_num_sram, cur_num_sram + num_sram - 1);
|
||||
}
|
||||
if (0 < num_sram_port) {
|
||||
switch (cur_sram_orgz_info->type) {
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
/* Local wires */
|
||||
/* Find the number of BLs/WLs of each SRAM */
|
||||
/* Detect the SRAM SPICE model linked to this SRAM port */
|
||||
assert(NULL != sram_ports[0]->spice_model);
|
||||
assert(SPICE_MODEL_SRAM == sram_ports[0]->spice_model->type);
|
||||
find_bl_wl_ports_spice_model(sram_ports[0]->spice_model,
|
||||
&num_bl_ports, &bl_port, &num_wl_ports, &wl_port);
|
||||
assert(1 == num_bl_ports);
|
||||
assert(1 == num_wl_ports);
|
||||
break;
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid SRAM organization type!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
/* Definition ends*/
|
||||
|
||||
/* Dump the configuration port bus */
|
||||
if ((0 < num_reserved_conf_bits)
|
||||
|| (0 < num_conf_bits)) {
|
||||
dump_verilog_mem_config_bus(fp, mem_model, cur_sram_orgz_info,
|
||||
cur_num_sram, num_reserved_conf_bits, num_conf_bits);
|
||||
/* Dump ports only visible during formal verification*/
|
||||
fprintf(fp, "`ifdef %s\n", verilog_formal_verification_preproc_flag);
|
||||
dump_verilog_formal_verification_sram_ports_wiring(fp, cur_sram_orgz_info,
|
||||
cur_num_sram,
|
||||
cur_num_sram + num_conf_bits - 1);
|
||||
fprintf(fp, "`endif\n");
|
||||
}
|
||||
|
||||
/* Explicit port map support: turn it on when there is need for the full netlist or just standard cell */
|
||||
boolean subckt_require_explicit_port_map = FALSE;
|
||||
if ( (TRUE == verilog_model->dump_explicit_port_map) || (true == is_explicit_mapping) ) {
|
||||
subckt_require_explicit_port_map = TRUE;
|
||||
}
|
||||
|
||||
/* Call the subckt*/
|
||||
if (0 == strcmp(verilog_model->name,port_prefix)) {
|
||||
fprintf(fp, "%s %s_logic_%d_ (", verilog_model->name, verilog_model->prefix, verilog_model->cnt);
|
||||
} else {
|
||||
fprintf(fp, "%s %s_%d_ (", verilog_model->name, verilog_model->prefix, verilog_model->cnt);
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
/* Only dump the global ports belonging to a spice_model
|
||||
* Disable recursive here !
|
||||
*/
|
||||
/*if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, FALSE, FALSE, my_bool_to_boolean(is_explicit_mapping))) {*/
|
||||
if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, FALSE, FALSE, subckt_require_explicit_port_map, TRUE)) {
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
|
||||
/* assert */
|
||||
num_sram = count_num_sram_bits_one_spice_model(verilog_model, -1);
|
||||
/* print ports --> input ports */
|
||||
dump_verilog_pb_type_bus_ports(fp, port_prefix, 1, prim_pb_type, FALSE, FALSE,
|
||||
subckt_require_explicit_port_map);
|
||||
/* my_bool_to_boolean(is_explicit_mapping));*/
|
||||
/* IOPADs requires a specical port to output */
|
||||
if (SPICE_MODEL_IOPAD == verilog_model->type) {
|
||||
fprintf(fp, ",\n");
|
||||
assert(1 == num_pad_port);
|
||||
assert(NULL != pad_ports[0]);
|
||||
/* Add explicit port mapping if required */
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
/*if (true == is_explicit_mapping) {*/
|
||||
fprintf(fp, ".%s (",
|
||||
pad_ports[0]->lib_name);
|
||||
}
|
||||
/* Print inout port */
|
||||
fprintf(fp, "%s%s[%d]", gio_inout_prefix,
|
||||
verilog_model->prefix, verilog_model->cnt);
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
/*if (true == is_explicit_mapping) {*/
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
fprintf(fp, ", ");
|
||||
}
|
||||
/* Print SRAM ports */
|
||||
/* Connect srams: TODO: to find the SRAM model used by this Verilog model */
|
||||
if (0 < num_sram) {
|
||||
switch (cur_sram_orgz_info->type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
/* Add explicit port mapping if required */
|
||||
if ( (0 < num_sram)
|
||||
&& (TRUE == subckt_require_explicit_port_map)) {
|
||||
assert( 1 == num_sram_port);
|
||||
assert( NULL != sram_ports[0]);
|
||||
fprintf(fp, ".%s (",
|
||||
sram_ports[0]->lib_name);
|
||||
}
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
|
||||
cur_num_sram, cur_num_sram + num_sram - 1,
|
||||
0, VERILOG_PORT_CONKT);
|
||||
if ( (0 < num_sram)
|
||||
&& (true == subckt_require_explicit_port_map)) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
|
||||
/* Check if we have an inverterd prefix */
|
||||
if (NULL == sram_ports[0]->inv_prefix) {
|
||||
break;
|
||||
}
|
||||
fprintf(fp, ", ");
|
||||
/* Add explicit port mapping if required */
|
||||
if ( (0 < num_sram)
|
||||
&& (TRUE == subckt_require_explicit_port_map)) {
|
||||
assert( 1 == num_sram_port);
|
||||
assert( NULL != sram_ports[0]);
|
||||
fprintf(fp, ".%s (",
|
||||
sram_ports[0]->inv_prefix);
|
||||
}
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
|
||||
cur_num_sram, cur_num_sram + num_sram - 1,
|
||||
1, VERILOG_PORT_CONKT);
|
||||
if ( (0 < num_sram)
|
||||
&& (TRUE == subckt_require_explicit_port_map)) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
/* Add explicit port mapping if required */
|
||||
if ( (0 < num_sram)
|
||||
&& (TRUE == subckt_require_explicit_port_map)) {
|
||||
assert( 1 == num_sram_port);
|
||||
assert( NULL != sram_ports[0]);
|
||||
fprintf(fp, ".%s (",
|
||||
sram_ports[0]->lib_name);
|
||||
}
|
||||
dump_verilog_sram_one_outport(fp, cur_sram_orgz_info,
|
||||
cur_num_sram, cur_num_sram + num_sram - 1,
|
||||
0, VERILOG_PORT_CONKT);
|
||||
if ( (0 < num_sram)
|
||||
&& (TRUE == subckt_require_explicit_port_map)) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
/* Check if we have an inverterd prefix */
|
||||
if (NULL == sram_ports[0]->inv_prefix) {
|
||||
break;
|
||||
}
|
||||
fprintf(fp, ", ");
|
||||
/* Add explicit port mapping if required */
|
||||
if ( (0 < num_sram)
|
||||
&& (TRUE == subckt_require_explicit_port_map)) {
|
||||
assert( 1 == num_sram_port);
|
||||
assert( NULL != sram_ports[0]);
|
||||
fprintf(fp, ".%s (",
|
||||
sram_ports[0]->inv_prefix);
|
||||
}
|
||||
dump_verilog_sram_one_outport(fp, cur_sram_orgz_info,
|
||||
cur_num_sram, cur_num_sram + num_sram - 1,
|
||||
1, VERILOG_PORT_CONKT);
|
||||
if ( (0 < num_sram)
|
||||
&& (TRUE == subckt_require_explicit_port_map)) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid SRAM organization type!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Local vdd and gnd, verilog_model name,
|
||||
* TODO: Global vdd for i/o pad to split?
|
||||
*/
|
||||
fprintf(fp, ");\n");
|
||||
|
||||
/* Call SRAM subckt */
|
||||
/* what is the SRAM bit of a mode? */
|
||||
/* If logical block is not NULL, we need to decode the sram bit */
|
||||
/* SRAM bits are decoded in bitstream generator! NOT here
|
||||
if (NULL != mapped_logical_block) {
|
||||
assert(NULL != mapped_logical_block->pb->pb_graph_node->pb_type->mode_bits);
|
||||
sram_bits = decode_mode_bits(mapped_logical_block->pb->pb_graph_node->pb_type->mode_bits, &expected_num_sram);
|
||||
assert(expected_num_sram == num_sram);
|
||||
} else {
|
||||
sram_bits = (int*)my_calloc(num_sram, sizeof(int));
|
||||
for (i = 0; i < num_sram; i++) {
|
||||
sram_bits[i] = sram_ports[0]->default_val;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/* Call the memory module defined for this SRAM-based MUX! */
|
||||
if (0 < num_sram_port) {
|
||||
mem_subckt_name = generate_verilog_mem_subckt_name(verilog_model, mem_model, verilog_mem_posfix);
|
||||
fprintf(fp, "%s %s_%d_ ( ",
|
||||
mem_subckt_name, mem_subckt_name, verilog_model->cnt);
|
||||
dump_verilog_mem_sram_submodule(fp, cur_sram_orgz_info, verilog_model, -1,
|
||||
mem_model, cur_num_sram, cur_num_sram + num_sram - 1, my_bool_to_boolean(is_explicit_mapping));
|
||||
fprintf(fp, ");\n");
|
||||
/* update the number of memory bits */
|
||||
update_sram_orgz_info_num_mem_bit(cur_sram_orgz_info, cur_num_sram + num_sram);
|
||||
}
|
||||
|
||||
/* End */
|
||||
fprintf(fp, "endmodule\n");
|
||||
/* Comment lines */
|
||||
fprintf(fp, "//----- END %s Verilog module: %s%s -----\n\n",
|
||||
generate_string_spice_model_type(verilog_model->type),
|
||||
formatted_subckt_prefix, port_prefix);
|
||||
|
||||
/* Update the verilog_model counter */
|
||||
verilog_model->cnt++;
|
||||
|
||||
/*Free*/
|
||||
free(formatted_subckt_prefix);
|
||||
free(port_prefix);
|
||||
my_free(input_ports);
|
||||
my_free(output_ports);
|
||||
my_free(pad_ports);
|
||||
my_free(clock_ports);
|
||||
my_free(sram_ports);
|
||||
/* my_free(sram_bits); */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void dump_verilog_pb_primitive_lut(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
char* subckt_prefix,
|
||||
t_pb_graph_node* prim_pb_graph_node,
|
||||
int index,
|
||||
t_spice_model* verilog_model,
|
||||
bool is_explicit_mapping) {
|
||||
int i;
|
||||
int lut_size = 0;
|
||||
int num_input_port = 0;
|
||||
t_spice_model_port** input_ports = NULL;
|
||||
int num_output_port = 0;
|
||||
t_spice_model_port** output_ports = NULL;
|
||||
int num_sram_port = 0;
|
||||
t_spice_model_port** sram_ports = NULL;
|
||||
|
||||
int num_lut_sram = 0;
|
||||
int num_mode_sram = 0;
|
||||
t_spice_model_port* lut_sram_port = NULL;
|
||||
|
||||
char* formatted_subckt_prefix = format_verilog_node_prefix(subckt_prefix); /* Complete a "_" at the end if needed*/
|
||||
t_pb_type* cur_pb_type = NULL;
|
||||
char* port_prefix = NULL;
|
||||
int cur_num_sram = 0;
|
||||
int num_sram = 0;
|
||||
/* For each SRAM, we could have multiple BLs/WLs */
|
||||
int num_bl_ports = 0;
|
||||
t_spice_model_port** bl_port = NULL;
|
||||
int num_wl_ports = 0;
|
||||
t_spice_model_port** wl_port = NULL;
|
||||
int num_bl_per_sram = 0;
|
||||
int num_wl_per_sram = 0;
|
||||
int num_conf_bits = 0;
|
||||
int num_reserved_conf_bits = 0;
|
||||
int cur_bl, cur_wl;
|
||||
t_spice_model* mem_model = NULL;
|
||||
char* mem_subckt_name = NULL;
|
||||
|
||||
/* Ensure a valid file handler*/
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Ensure a valid pb_graph_node */
|
||||
if (NULL == prim_pb_graph_node) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid prim_pb_graph_node!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
/* Asserts */
|
||||
assert(SPICE_MODEL_LUT == verilog_model->type);
|
||||
|
||||
/* Determine size of LUT*/
|
||||
input_ports = find_spice_model_ports(verilog_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE);
|
||||
output_ports = find_spice_model_ports(verilog_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE);
|
||||
assert(1 == num_input_port);
|
||||
lut_size = input_ports[0]->size;
|
||||
/* Find SRAM ports for truth tables and mode bits */
|
||||
sram_ports = find_spice_model_ports(verilog_model, SPICE_MODEL_PORT_SRAM, &num_sram_port, TRUE);
|
||||
assert((1 == num_sram_port) || (2 == num_sram_port));
|
||||
for (i = 0; i < num_sram_port; i++) {
|
||||
if (FALSE == sram_ports[i]->mode_select) {
|
||||
lut_sram_port = sram_ports[i];
|
||||
num_lut_sram = sram_ports[i]->size;
|
||||
assert (num_lut_sram == (int)pow(2.,(double)(lut_size)));
|
||||
} else {
|
||||
assert (TRUE == sram_ports[i]->mode_select);
|
||||
num_mode_sram = sram_ports[i]->size;
|
||||
}
|
||||
}
|
||||
/* Must have a lut_sram_port, while mode_bit_port is optional */
|
||||
assert (NULL != lut_sram_port);
|
||||
|
||||
/* Count the number of configuration bits */
|
||||
num_sram = count_num_sram_bits_one_spice_model(verilog_model, -1);
|
||||
/* Get memory model */
|
||||
get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
|
||||
|
||||
/* Find the number of BLs/WLs of each SRAM */
|
||||
switch (cur_sram_orgz_info->type) {
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
/* Detect the SRAM SPICE model linked to this SRAM port */
|
||||
assert(NULL != sram_ports[0]->spice_model);
|
||||
assert(SPICE_MODEL_SRAM == sram_ports[0]->spice_model->type);
|
||||
find_bl_wl_ports_spice_model(sram_ports[0]->spice_model,
|
||||
&num_bl_ports, &bl_port, &num_wl_ports, &wl_port);
|
||||
assert(1 == num_bl_ports);
|
||||
assert(1 == num_wl_ports);
|
||||
num_bl_per_sram = bl_port[0]->size;
|
||||
num_wl_per_sram = wl_port[0]->size;
|
||||
/* Asserts */
|
||||
assert(num_bl_per_sram == num_wl_per_sram);
|
||||
break;
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid SRAM organization type!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Disable Generate sram bits*/
|
||||
/* SRAM bits are decoded in bitstream generator! NOT here
|
||||
sram_bits = generate_lut_sram_bits(truth_table_length, truth_table,
|
||||
lut_size, sram_ports[0]->default_val);
|
||||
*/
|
||||
|
||||
/* Print the subckts*/
|
||||
cur_pb_type = prim_pb_graph_node->pb_type;
|
||||
|
||||
/* Comment lines */
|
||||
fprintf(fp, "//----- LUT Verilog module: %s%s_%d_ -----\n",
|
||||
formatted_subckt_prefix, cur_pb_type->name, index);
|
||||
|
||||
/* Simplify the prefix, make the SPICE netlist readable*/
|
||||
port_prefix = (char*)my_malloc(sizeof(char)*
|
||||
(strlen(cur_pb_type->name) + 1));
|
||||
sprintf(port_prefix, "%s", cur_pb_type->name);
|
||||
|
||||
/* Subckt definition*/
|
||||
fprintf(fp, "module %s%s (",
|
||||
formatted_subckt_prefix, cur_pb_type->name);
|
||||
fprintf(fp, "\n");
|
||||
/* Only dump the global ports belonging to a spice_model */
|
||||
if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, TRUE, TRUE, my_bool_to_boolean(is_explicit_mapping), TRUE)) {
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
/* Print inputs, outputs, inouts, clocks, NO SRAMs*/
|
||||
dump_verilog_pb_type_ports(fp, port_prefix, 0, cur_pb_type, TRUE, TRUE, FALSE, false);
|
||||
/* Print SRAM ports */
|
||||
cur_num_sram = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info);
|
||||
get_sram_orgz_info_num_blwl(cur_sram_orgz_info, &cur_bl, &cur_wl);
|
||||
/* connect to reserved BL/WLs ? */
|
||||
num_reserved_conf_bits = count_num_reserved_conf_bits_one_spice_model(verilog_model, cur_sram_orgz_info->type, 0);
|
||||
/* Get the number of configuration bits required by this MUX */
|
||||
num_conf_bits = count_num_conf_bits_one_spice_model(verilog_model, cur_sram_orgz_info->type, 0);
|
||||
/* Reserved sram ports */
|
||||
if ( 0 < num_reserved_conf_bits) {
|
||||
dump_verilog_reserved_sram_ports(fp, cur_sram_orgz_info,
|
||||
0, num_reserved_conf_bits - 1,
|
||||
VERILOG_PORT_INPUT);
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
/* Normal sram ports */
|
||||
if (0 < num_conf_bits) {
|
||||
dump_verilog_sram_ports(fp, cur_sram_orgz_info,
|
||||
cur_num_sram, cur_num_sram + num_conf_bits - 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,
|
||||
cur_num_sram + num_conf_bits - 1,
|
||||
VERILOG_PORT_INPUT, false);
|
||||
fprintf(fp, "\n");
|
||||
fprintf(fp, "`endif\n");
|
||||
}
|
||||
|
||||
/* Local Vdd and gnd*/
|
||||
fprintf(fp, ");\n");
|
||||
/* Definition ends*/
|
||||
|
||||
/* Specify SRAM output are wires */
|
||||
cur_num_sram = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info);
|
||||
dump_verilog_sram_config_bus_internal_wires(fp, cur_sram_orgz_info, cur_num_sram, cur_num_sram + num_sram - 1);
|
||||
|
||||
/* Dump ports only visible during formal verification*/
|
||||
if ((0 < num_reserved_conf_bits)
|
||||
|| (0 < num_conf_bits)) {
|
||||
dump_verilog_mem_config_bus(fp, mem_model, cur_sram_orgz_info,
|
||||
cur_num_sram, num_reserved_conf_bits, num_conf_bits);
|
||||
|
||||
fprintf(fp, "`ifdef %s\n", verilog_formal_verification_preproc_flag);
|
||||
dump_verilog_formal_verification_sram_ports_wiring(fp, cur_sram_orgz_info,
|
||||
cur_num_sram,
|
||||
cur_num_sram + num_sram - 1);
|
||||
fprintf(fp, "`endif\n");
|
||||
}
|
||||
|
||||
/*
|
||||
fprintf(fp, "wire [%d:%d] %s_out;\n",
|
||||
cur_num_sram, cur_num_sram + num_sram - 1, mem_model->prefix);
|
||||
fprintf(fp, "wire [%d:%d] %s_outb;\n",
|
||||
cur_num_sram, cur_num_sram + num_sram - 1, mem_model->prefix);
|
||||
*/
|
||||
|
||||
num_sram = count_num_sram_bits_one_spice_model(verilog_model, -1);
|
||||
cur_num_sram = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info);
|
||||
|
||||
/* Explicit port map support: turn it on when there is need for the full netlist or just standard cell */
|
||||
boolean subckt_require_explicit_port_map = FALSE;
|
||||
if ( (TRUE == verilog_model->dump_explicit_port_map) || (true == is_explicit_mapping) ) {
|
||||
subckt_require_explicit_port_map = TRUE;
|
||||
}
|
||||
/* Call LUT subckt*/
|
||||
if (0 == strcmp(verilog_model->name,port_prefix)) {
|
||||
fprintf(fp, "%s %s_logic_%d_ (", verilog_model->name, verilog_model->prefix, verilog_model->cnt);
|
||||
} else {
|
||||
fprintf(fp, "%s %s_%d_ (", verilog_model->name, verilog_model->prefix, verilog_model->cnt);
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
/* if we have to add global ports when dumping submodules of LUTs
|
||||
* otherwise, the port map here does not match that of submodules
|
||||
* Only dump the global ports belonging to a spice_model
|
||||
* DISABLE recursive here !
|
||||
*/
|
||||
if (0 < rec_dump_verilog_spice_model_global_ports(fp, verilog_model, FALSE, FALSE, subckt_require_explicit_port_map, TRUE)) {
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
/* Connect inputs*/
|
||||
/* Connect outputs*/
|
||||
fprintf(fp, "//----- Input and output ports -----\n");
|
||||
dump_verilog_pb_type_bus_ports(fp, port_prefix, 1, cur_pb_type, FALSE, TRUE, subckt_require_explicit_port_map);
|
||||
fprintf(fp, "\n//----- SRAM ports -----\n");
|
||||
|
||||
/* check */
|
||||
assert (num_sram == num_lut_sram + num_mode_sram);
|
||||
/* Connect srams: TODO: to find the SRAM model used by this Verilog model */
|
||||
cur_num_sram = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info);
|
||||
/* TODO: switch depending on the type of configuration circuit */
|
||||
switch (cur_sram_orgz_info->type) {
|
||||
case SPICE_SRAM_STANDALONE:
|
||||
break;
|
||||
case SPICE_SRAM_SCAN_CHAIN:
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ".sram_out( ");
|
||||
}
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
|
||||
cur_num_sram, cur_num_sram + num_lut_sram - 1,
|
||||
0, VERILOG_PORT_CONKT);
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
fprintf(fp, ", ");
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ".sram_outb( ");
|
||||
}
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
|
||||
cur_num_sram, cur_num_sram + num_lut_sram - 1,
|
||||
1, VERILOG_PORT_CONKT);
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
if (0 < num_mode_sram) {
|
||||
fprintf(fp, ", ");
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ".mode_out( ");
|
||||
}
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
|
||||
cur_num_sram + num_lut_sram, cur_num_sram + num_lut_sram + num_mode_sram - 1,
|
||||
0, VERILOG_PORT_CONKT);
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
fprintf(fp, ", ");
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ".mode_outb( ");
|
||||
}
|
||||
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
|
||||
cur_num_sram + num_lut_sram, cur_num_sram + num_lut_sram + num_mode_sram - 1,
|
||||
1, VERILOG_PORT_CONKT);
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPICE_SRAM_MEMORY_BANK:
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ".sram_out( ");
|
||||
}
|
||||
dump_verilog_sram_one_outport(fp, cur_sram_orgz_info,
|
||||
cur_num_sram, cur_num_sram + num_lut_sram - 1,
|
||||
0, VERILOG_PORT_CONKT);
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
fprintf(fp, ", ");
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ".sram_outb( ");
|
||||
}
|
||||
dump_verilog_sram_one_outport(fp, cur_sram_orgz_info,
|
||||
cur_num_sram, cur_num_sram + num_lut_sram - 1,
|
||||
1, VERILOG_PORT_CONKT);
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
if (0 < num_mode_sram) {
|
||||
fprintf(fp, ", ");
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ".mode_out( ");
|
||||
}
|
||||
dump_verilog_sram_one_outport(fp, cur_sram_orgz_info,
|
||||
cur_num_sram + num_lut_sram, cur_num_sram + num_lut_sram + num_mode_sram - 1,
|
||||
0, VERILOG_PORT_CONKT);
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
fprintf(fp, ", ");
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ".mode_outb( ");
|
||||
}
|
||||
dump_verilog_sram_one_outport(fp, cur_sram_orgz_info,
|
||||
cur_num_sram + num_lut_sram, cur_num_sram + num_lut_sram + num_mode_sram - 1,
|
||||
1, VERILOG_PORT_CONKT);
|
||||
}
|
||||
if (TRUE == subckt_require_explicit_port_map) {
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid SRAM organization type!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
/* vdd should be connected to special global wire gvdd_lut and gnd,
|
||||
* Every LUT has a special VDD for statistics
|
||||
*/
|
||||
fprintf(fp, ");\n");
|
||||
|
||||
/* Call SRAM subckts only
|
||||
* when Configuration organization style is memory bank */
|
||||
/* No. of SRAMs is different from the number of configuration lines.
|
||||
* Especially when SRAMs/RRAMs are configured with BL/WLs
|
||||
*/
|
||||
num_sram = count_num_sram_bits_one_spice_model(verilog_model, -1);
|
||||
cur_num_sram = get_sram_orgz_info_num_mem_bit(cur_sram_orgz_info);
|
||||
|
||||
/* Call the memory module defined for this SRAM-based MUX! */
|
||||
mem_subckt_name = generate_verilog_mem_subckt_name(verilog_model, mem_model, verilog_mem_posfix);
|
||||
fprintf(fp, "%s %s_%d_ ( ",
|
||||
mem_subckt_name, mem_subckt_name, verilog_model->cnt);
|
||||
dump_verilog_mem_sram_submodule(fp, cur_sram_orgz_info, verilog_model, -1,
|
||||
mem_model, cur_num_sram, cur_num_sram + num_sram - 1, is_explicit_mapping);
|
||||
fprintf(fp, ");\n");
|
||||
/* update the number of memory bits */
|
||||
update_sram_orgz_info_num_mem_bit(cur_sram_orgz_info, cur_num_sram + num_sram);
|
||||
|
||||
/* End of subckt*/
|
||||
fprintf(fp, "endmodule\n");
|
||||
|
||||
/* Comment lines */
|
||||
fprintf(fp, "//----- END LUT Verilog module: %s%s_%d_ -----\n\n",
|
||||
formatted_subckt_prefix, cur_pb_type->name, index);
|
||||
|
||||
/* Update counter */
|
||||
verilog_model->cnt++;
|
||||
|
||||
/*Free*/
|
||||
my_free(formatted_subckt_prefix);
|
||||
my_free(input_ports);
|
||||
my_free(output_ports);
|
||||
my_free(sram_ports);
|
||||
my_free(mem_subckt_name);
|
||||
/* my_free(sram_bits); */
|
||||
my_free(port_prefix);
|
||||
|
||||
return;
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
|
||||
|
||||
void dump_verilog_pb_generic_primitive(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
char* subckt_prefix,
|
||||
t_pb_graph_node* prim_pb_graph_node,
|
||||
int index,
|
||||
t_spice_model* spice_model,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void dump_verilog_pb_primitive_lut(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
char* subckt_prefix,
|
||||
t_pb_graph_node* prim_pb_graph_node,
|
||||
int index,
|
||||
t_spice_model* spice_model,
|
||||
bool is_explicit_mapping);
|
File diff suppressed because it is too large
Load Diff
|
@ -1,10 +0,0 @@
|
|||
|
||||
void verilog_generate_report_timing(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* sdc_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_syn_verilog_opts fpga_verilog_opts,
|
||||
boolean compact_routing_hierarchy);
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,355 @@
|
|||
/*********************************************************************
|
||||
* This file includes functions that are used for
|
||||
* Verilog generation of FPGA routing architecture (global routing)
|
||||
*********************************************************************/
|
||||
#include <time.h>
|
||||
#include "vtr_assert.h"
|
||||
|
||||
/* Include FPGA-X2P header files*/
|
||||
#include "fpga_x2p_naming.h"
|
||||
#include "fpga_x2p_utils.h"
|
||||
|
||||
/* Include FPGA-Verilog header files*/
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
#include "verilog_module_writer.h"
|
||||
#include "verilog_routing.h"
|
||||
|
||||
/********************************************************************
|
||||
* Print the sub-circuit of a connection Box (Type: [CHANX|CHANY])
|
||||
* Actually it is very similiar to switch box but
|
||||
* the difference is connection boxes connect Grid INPUT Pins to channels
|
||||
* NOTE: direct connection between CLBs should NOT be included inside this
|
||||
* module! They should be added in the top-level module as their connection
|
||||
* is not limited to adjacent CLBs!!!
|
||||
*
|
||||
* Location of a X- and Y-direction Connection Block in FPGA fabric
|
||||
* +------------+ +-------------+
|
||||
* | |------>| |
|
||||
* | CLB |<------| Y-direction |
|
||||
* | | ... | Connection |
|
||||
* | |------>| Block |
|
||||
* +------------+ +-------------+
|
||||
* | ^ ... | | ^ ... |
|
||||
* v | v v | v
|
||||
* +-------------------+ +-------------+
|
||||
* --->| |--->| |
|
||||
* <---| X-direction |<---| Switch |
|
||||
* ...| Connection block |... | Block |
|
||||
* --->| |--->| |
|
||||
* +-------------------+ +-------------+
|
||||
*
|
||||
* Internal structure:
|
||||
* This is an example of a X-direction connection block
|
||||
* Note that middle output ports are shorted wire from inputs of routing tracks,
|
||||
* which are also the inputs of routing multiplexer of the connection block
|
||||
*
|
||||
* CLB Input Pins
|
||||
* (IPINs)
|
||||
* ^ ^ ^
|
||||
* | | ... |
|
||||
* +--------------------------+
|
||||
* | ^ ^ ^ |
|
||||
* | | | ... | |
|
||||
* | +--------------------+ |
|
||||
* | | routing | |
|
||||
* | | multiplexers | |
|
||||
* | +--------------------+ |
|
||||
* | middle outputs |
|
||||
* | of routing channel |
|
||||
* | ^ ^ ^ ^ ^ ^ ^ ^ |
|
||||
* | | | | | ... | | | | |
|
||||
* in[0] -->|------------------------->|---> out[0]
|
||||
* out[1] <--|<-------------------------|<--- in[1]
|
||||
* | ... |
|
||||
* in[W-2] -->|------------------------->|---> out[W-2]
|
||||
* out[W-1] <--|<-------------------------|<--- in[W-1]
|
||||
* +--------------------------+
|
||||
*
|
||||
* W: routing channel width
|
||||
*
|
||||
********************************************************************/
|
||||
static
|
||||
void print_verilog_routing_connection_box_unique_module(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& subckt_dir,
|
||||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
const bool& use_explicit_port_map) {
|
||||
/* Create the netlist */
|
||||
vtr::Point<size_t> gsb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||
std::string verilog_fname(subckt_dir + generate_connection_block_netlist_name(cb_type, 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 Connection Blocks[" + std::to_string(rr_gsb.get_cb_x(cb_type)) + "]["+ std::to_string(rr_gsb.get_cb_y(cb_type)) + "]"));
|
||||
|
||||
/* 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 cb_module = module_manager.find_module(generate_connection_block_module_name(cb_type, gsb_coordinate));
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(cb_module));
|
||||
|
||||
/* Write the verilog module */
|
||||
write_verilog_module_to_file(fp, module_manager, cb_module, use_explicit_port_map);
|
||||
|
||||
/* Add an empty line as a splitter */
|
||||
fp << std::endl;
|
||||
|
||||
/* Close file handler */
|
||||
fp.close();
|
||||
|
||||
/* Add fname to the netlist name list */
|
||||
netlist_names.push_back(verilog_fname);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* 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:
|
||||
*
|
||||
* -------------- --------------
|
||||
* | | | |
|
||||
* | 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] |
|
||||
* | | | |
|
||||
* -------------- --------------
|
||||
*
|
||||
* 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 print_verilog_routing_switch_box_unique_module(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& subckt_dir,
|
||||
const RRGSB& rr_gsb,
|
||||
const bool& use_explicit_port_map) {
|
||||
/* Create the netlist */
|
||||
vtr::Point<size_t> 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 */
|
||||
print_verilog_include_defines_preproc_file(fp, verilog_dir);
|
||||
|
||||
/* Create a Verilog Module based on the circuit model, and add to module manager */
|
||||
ModuleId sb_module = module_manager.find_module(generate_switch_block_module_name(gsb_coordinate));
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(sb_module));
|
||||
|
||||
/* Write the verilog module */
|
||||
write_verilog_module_to_file(fp, module_manager, sb_module, use_explicit_port_map);
|
||||
|
||||
/* Close file handler */
|
||||
fp.close();
|
||||
|
||||
/* Add fname to the netlist name list */
|
||||
netlist_names.push_back(verilog_fname);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Iterate over all the connection blocks in a device
|
||||
* and build a module for each of them
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_flatten_connection_block_modules(ModuleManager& module_manager,
|
||||
std::vector<std::string>& netlist_names,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& subckt_dir,
|
||||
const t_rr_type& cb_type,
|
||||
const bool& use_explicit_port_map) {
|
||||
/* Build unique X-direction connection block modules */
|
||||
DeviceCoordinator cb_range = L_device_rr_gsb.get_gsb_range();
|
||||
|
||||
for (size_t ix = 0; ix < cb_range.get_x(); ++ix) {
|
||||
for (size_t iy = 0; iy < cb_range.get_y(); ++iy) {
|
||||
/* Check if the connection block exists in the device!
|
||||
* Some of them do NOT exist due to heterogeneous blocks (height > 1)
|
||||
* We will skip those modules
|
||||
*/
|
||||
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
|
||||
if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)))
|
||||
|| (true != rr_gsb.is_cb_exist(cb_type))) {
|
||||
continue;
|
||||
}
|
||||
print_verilog_routing_connection_box_unique_module(module_manager, netlist_names,
|
||||
verilog_dir,
|
||||
subckt_dir,
|
||||
rr_gsb, cb_type,
|
||||
use_explicit_port_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A top-level function of this file
|
||||
* Print all the modules for global routing architecture of a FPGA fabric
|
||||
* in Verilog format in a flatten way:
|
||||
* Each connection block and switch block will be generated as a unique module
|
||||
* Covering:
|
||||
* 1. Connection blocks
|
||||
* 2. Switch blocks
|
||||
*******************************************************************/
|
||||
void print_verilog_flatten_routing_modules(ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const t_det_routing_arch& routing_arch,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& subckt_dir,
|
||||
const bool& use_explicit_port_map) {
|
||||
/* We only support uni-directional routing architecture now */
|
||||
VTR_ASSERT (UNI_DIRECTIONAL == routing_arch.directionality);
|
||||
|
||||
/* Create a vector to contain all the Verilog netlist names that have been generated in this function */
|
||||
std::vector<std::string> netlist_names;
|
||||
|
||||
/* TODO: deprecate DeviceCoordinator, use vtr::Point<size_t> only! */
|
||||
DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range();
|
||||
|
||||
/* Build unique switch block modules */
|
||||
for (size_t ix = 0; ix < sb_range.get_x(); ++ix) {
|
||||
for (size_t iy = 0; iy < sb_range.get_y(); ++iy) {
|
||||
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
|
||||
print_verilog_routing_switch_box_unique_module(module_manager, netlist_names,
|
||||
verilog_dir,
|
||||
subckt_dir,
|
||||
rr_gsb,
|
||||
use_explicit_port_map);
|
||||
}
|
||||
}
|
||||
|
||||
print_verilog_flatten_connection_block_modules(module_manager, netlist_names, L_device_rr_gsb, verilog_dir, subckt_dir, CHANX, use_explicit_port_map);
|
||||
|
||||
print_verilog_flatten_connection_block_modules(module_manager, netlist_names, L_device_rr_gsb, verilog_dir, subckt_dir, CHANY, use_explicit_port_map);
|
||||
|
||||
vpr_printf(TIO_MESSAGE_INFO,"Generating header file for routing submodules...\n");
|
||||
print_verilog_netlist_include_header_file(netlist_names,
|
||||
subckt_dir.c_str(),
|
||||
routing_verilog_file_name);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* A top-level function of this file
|
||||
* Print all the unique modules for global routing architecture of a FPGA fabric
|
||||
* in Verilog format, including:
|
||||
* 1. Connection blocks
|
||||
* 2. Switch blocks
|
||||
*
|
||||
* Note: this function SHOULD be called only when
|
||||
* the option compact_routing_hierarchy is turned on!!!
|
||||
*******************************************************************/
|
||||
void print_verilog_unique_routing_modules(ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const t_det_routing_arch& routing_arch,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& subckt_dir,
|
||||
const bool& use_explicit_port_map) {
|
||||
/* We only support uni-directional routing architecture now */
|
||||
VTR_ASSERT (UNI_DIRECTIONAL == routing_arch.directionality);
|
||||
|
||||
/* Create a vector to contain all the Verilog netlist names that have been generated in this function */
|
||||
std::vector<std::string> netlist_names;
|
||||
|
||||
/* Build unique switch block modules */
|
||||
for (size_t isb = 0; isb < L_device_rr_gsb.get_num_sb_unique_module(); ++isb) {
|
||||
const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(isb);
|
||||
print_verilog_routing_switch_box_unique_module(module_manager, netlist_names,
|
||||
verilog_dir,
|
||||
subckt_dir,
|
||||
unique_mirror,
|
||||
use_explicit_port_map);
|
||||
}
|
||||
|
||||
/* Build unique X-direction connection block modules */
|
||||
for (size_t icb = 0; icb < L_device_rr_gsb.get_num_cb_unique_module(CHANX); ++icb) {
|
||||
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(CHANX, icb);
|
||||
|
||||
print_verilog_routing_connection_box_unique_module(module_manager, netlist_names,
|
||||
verilog_dir,
|
||||
subckt_dir,
|
||||
unique_mirror, CHANX,
|
||||
use_explicit_port_map);
|
||||
}
|
||||
|
||||
/* Build unique X-direction connection block modules */
|
||||
for (size_t icb = 0; icb < L_device_rr_gsb.get_num_cb_unique_module(CHANY); ++icb) {
|
||||
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(CHANY, icb);
|
||||
|
||||
print_verilog_routing_connection_box_unique_module(module_manager, netlist_names,
|
||||
verilog_dir,
|
||||
subckt_dir,
|
||||
unique_mirror, CHANY,
|
||||
use_explicit_port_map);
|
||||
}
|
||||
|
||||
vpr_printf(TIO_MESSAGE_INFO,"Generating header file for routing submodules...\n");
|
||||
print_verilog_netlist_include_header_file(netlist_names,
|
||||
subckt_dir.c_str(),
|
||||
routing_verilog_file_name);
|
||||
}
|
|
@ -9,150 +9,6 @@
|
|||
#include "module_manager.h"
|
||||
#include "rr_blocks.h"
|
||||
|
||||
void dump_verilog_routing_chan_subckt(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* verilog_dir,
|
||||
char* subckt_dir,
|
||||
int x, int y,
|
||||
t_rr_type chan_type,
|
||||
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, t_segment_inf* segments,
|
||||
t_syn_verilog_opts fpga_verilog_opts);
|
||||
|
||||
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);
|
||||
|
||||
void dump_verilog_grid_side_pins(FILE* fp,
|
||||
t_rr_type pin_type, int x, int y, int side,
|
||||
boolean dump_port_type);
|
||||
|
||||
void dump_verilog_switch_box_chan_port(FILE* fp,
|
||||
t_sb* cur_sb_info,
|
||||
int chan_side,
|
||||
t_rr_node* cur_rr_node,
|
||||
enum PORTS cur_rr_node_direction);
|
||||
|
||||
void dump_verilog_switch_box_short_interc(FILE* fp,
|
||||
t_sb* cur_sb_info,
|
||||
int chan_side,
|
||||
t_rr_node* cur_rr_node,
|
||||
int actual_fan_in,
|
||||
t_rr_node* drive_rr_node,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void dump_verilog_switch_box_mux(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
t_sb* cur_sb_info,
|
||||
int chan_side,
|
||||
t_rr_node* cur_rr_node,
|
||||
int mux_size,
|
||||
t_rr_node** drive_rr_nodes,
|
||||
int switch_index,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
int count_verilog_switch_box_interc_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
t_sb cur_sb_info, int chan_side,
|
||||
t_rr_node* cur_rr_node);
|
||||
|
||||
int count_verilog_switch_box_interc_reserved_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
t_sb cur_sb_info, int chan_side,
|
||||
t_rr_node* cur_rr_node);
|
||||
|
||||
void dump_verilog_switch_box_interc(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
t_sb* cur_sb_info,
|
||||
int chan_side,
|
||||
t_rr_node* cur_rr_node,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
int count_verilog_switch_box_reserved_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
t_sb cur_sb_info);
|
||||
|
||||
int count_verilog_switch_box_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
t_sb cur_sb_info);
|
||||
|
||||
void dump_verilog_routing_switch_box_subckt(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* verilog_dir, char* subckt_dir,
|
||||
t_sb* cur_sb_info,
|
||||
int LL_num_rr_nodes, t_rr_node* LL_rr_node,
|
||||
t_ivec*** LL_rr_node_indices,
|
||||
t_syn_verilog_opts fpga_verilog_opts,
|
||||
boolean compact_routing_hierarchy,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
|
||||
void dump_verilog_connection_box_short_interc(FILE* fp,
|
||||
t_cb* cur_cb_info,
|
||||
t_rr_node* src_rr_node,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void dump_verilog_connection_box_mux(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
t_cb* cur_cb_info,
|
||||
t_rr_node* src_rr_node,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void dump_verilog_connection_box_interc(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
t_cb* cur_cb_info,
|
||||
t_rr_node* src_rr_node,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
|
||||
int count_verilog_connection_box_interc_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
t_rr_node* cur_rr_node);
|
||||
|
||||
int count_verilog_connection_box_one_side_reserved_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
const RRGSB& rr_gsb, enum e_side cb_side);
|
||||
|
||||
int count_verilog_connection_box_interc_reserved_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
t_rr_node* cur_rr_node);
|
||||
|
||||
int count_verilog_connection_box_one_side_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
const RRGSB& rr_gsb, enum e_side cb_side);
|
||||
|
||||
int count_verilog_connection_box_one_side_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
int num_ipin_rr_nodes,
|
||||
t_rr_node** ipin_rr_node);
|
||||
|
||||
int count_verilog_connection_box_reserved_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
const RRGSB& rr_gsb, t_rr_type cb_type);
|
||||
|
||||
int count_verilog_connection_box_one_side_reserved_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
int num_ipin_rr_nodes,
|
||||
t_rr_node** ipin_rr_node);
|
||||
|
||||
int count_verilog_connection_box_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
const RRGSB& rr_gsb, t_rr_type cb_type);
|
||||
|
||||
int count_verilog_connection_box_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
t_cb* cur_cb_info);
|
||||
|
||||
int count_verilog_connection_box_reserved_conf_bits(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
t_cb* cur_cb_info);
|
||||
|
||||
void dump_verilog_routing_connection_box_subckt(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* verilog_dir, char* subckt_dir,
|
||||
t_cb* cur_cb_info,
|
||||
boolean compact_routing_hierarchy,
|
||||
bool is_explicit_mapping);
|
||||
|
||||
void print_verilog_routing_resources(ModuleManager& module_manager,
|
||||
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);
|
||||
|
||||
void print_verilog_flatten_routing_modules(ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const t_det_routing_arch& routing_arch,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,50 +0,0 @@
|
|||
#ifndef VERILOG_SDC_H
|
||||
#define VERILOG_SDC_H
|
||||
|
||||
void verilog_generate_sdc_pnr(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* sdc_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,
|
||||
int LL_nx, int LL_ny, DeviceRRGSB& LL_device_rr_gsb,
|
||||
boolean compact_routing_hierarchy);
|
||||
|
||||
void verilog_generate_sdc_analysis(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* sdc_dir,
|
||||
t_arch arch,
|
||||
int LL_num_rr_nodes, t_rr_node* LL_rr_node,
|
||||
t_ivec*** LL_rr_node_indices,
|
||||
int LL_nx, int LL_ny, t_grid_tile** LL_grid,
|
||||
t_block* LL_block, DeviceRRGSB& LL_device_rr_gsb,
|
||||
boolean compact_routing_hierarchy);
|
||||
|
||||
void dump_sdc_one_clb_muxes(FILE* fp,
|
||||
char* grid_instance_name,
|
||||
t_rr_graph* rr_graph,
|
||||
t_pb_graph_node* pb_graph_head);
|
||||
|
||||
|
||||
void dump_sdc_rec_one_pb_muxes(FILE* fp,
|
||||
char* grid_instance_name,
|
||||
t_rr_graph* rr_graph,
|
||||
t_pb_graph_node* cur_pb_graph_node);
|
||||
|
||||
void dump_sdc_pb_graph_node_muxes(FILE* fp,
|
||||
char* grid_instance_name,
|
||||
t_rr_graph* rr_graph,
|
||||
t_pb_graph_node* cur_pb_graph_node);
|
||||
|
||||
void dump_sdc_pb_graph_pin_muxes(FILE* fp,
|
||||
char* grid_instance_name,
|
||||
t_rr_graph* rr_graph,
|
||||
t_pb_graph_pin pb_graph_pin);
|
||||
|
||||
/*void verilog_generate_wire_report_timing_blockage_direction(FILE* fp,
|
||||
char* direction,
|
||||
int LL_nx, int LL_ny);
|
||||
|
||||
void verilog_generate_sdc_wire_report_timing_blockage(t_sdc_opts sdc_opts,
|
||||
int LL_nx, int LL_ny);*/
|
||||
#endif
|
|
@ -1,553 +0,0 @@
|
|||
/***********************************/
|
||||
/* SDC Generation dumping */
|
||||
/* Xifan TANG, EPFL/LSI */
|
||||
/* Baudouin Chauviere LNIS */
|
||||
/***********************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Include vpr structs*/
|
||||
#include "util.h"
|
||||
#include "physical_types.h"
|
||||
#include "vpr_types.h"
|
||||
#include "globals.h"
|
||||
#include "rr_graph.h"
|
||||
#include "vpr_utils.h"
|
||||
#include "path_delay.h"
|
||||
#include "stats.h"
|
||||
#include "route_common.h"
|
||||
|
||||
/* Include FPGA-SPICE utils */
|
||||
#include "read_xml_spice_util.h"
|
||||
#include "linkedlist.h"
|
||||
#include "fpga_x2p_types.h"
|
||||
#include "fpga_x2p_utils.h"
|
||||
#include "fpga_x2p_pbtypes_utils.h"
|
||||
#include "fpga_x2p_backannotate_utils.h"
|
||||
#include "fpga_x2p_globals.h"
|
||||
#include "fpga_bitstream.h"
|
||||
|
||||
/* Include SynVerilog headers */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_utils.h"
|
||||
#include "verilog_submodules.h"
|
||||
#include "verilog_pbtypes.h"
|
||||
#include "verilog_routing.h"
|
||||
#include "verilog_compact_netlist.h"
|
||||
#include "verilog_top_testbench.h"
|
||||
#include "verilog_autocheck_top_testbench.h"
|
||||
#include "verilog_verification_top_netlist.h"
|
||||
#include "verilog_modelsim_autodeck.h"
|
||||
#include "verilog_report_timing.h"
|
||||
#include "verilog_sdc.h"
|
||||
#include "verilog_formality_autodeck.h"
|
||||
#include "verilog_sdc_pb_types.h"
|
||||
|
||||
|
||||
void sdc_dump_annotation(char* from_path, // includes the cell
|
||||
char* to_path,
|
||||
FILE* fp,
|
||||
t_pb_graph_edge* cur_edge){
|
||||
|
||||
float min_value = 0;
|
||||
float max_value = 0;
|
||||
|
||||
// Find in the annotations the min and max
|
||||
if (0 != cur_edge->delay_min) {
|
||||
min_value = cur_edge->delay_min;
|
||||
min_value = min_value*pow(10,9);
|
||||
fprintf (fp, "set_min_delay -combinational_from_to -from %s -to %s ", from_path, to_path);
|
||||
fprintf (fp,"%f\n", min_value);
|
||||
}
|
||||
if (0 != cur_edge->delay_max) {
|
||||
max_value = cur_edge->delay_max;
|
||||
max_value = max_value*pow(10,9);
|
||||
fprintf (fp, "set_max_delay -combinational_from_to -from %s -to %s ", from_path, to_path);
|
||||
fprintf (fp,"%f\n", max_value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void dump_sdc_pb_graph_pin_interc(FILE* fp,
|
||||
t_pb_graph_pin* des_pb_graph_pin,
|
||||
t_mode* cur_mode,
|
||||
char* instance_name) {
|
||||
int iedge;
|
||||
int fan_in = 0;
|
||||
t_interconnect* cur_interc = NULL;
|
||||
enum e_interconnect verilog_interc_type = DIRECT_INTERC;
|
||||
|
||||
t_pb_graph_pin* src_pb_graph_pin = NULL;
|
||||
t_pb_graph_node* src_pb_graph_node = NULL;
|
||||
|
||||
t_pb_graph_node* des_pb_graph_node = NULL;
|
||||
|
||||
char* from_path = NULL;
|
||||
char* to_path = NULL;
|
||||
|
||||
char* set_disable_path;
|
||||
t_pb_graph_pin* cur_pin_disable;
|
||||
char* input_buffer_path;
|
||||
char* input_buffer_name;
|
||||
char* input_buffer_in;
|
||||
char* input_buffer_out;
|
||||
/* Check the file handler*/
|
||||
if (NULL == fp) {
|
||||
vpr_printf (TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid file handler.\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* 1. identify pin interconnection type,
|
||||
* 2. Identify the number of fan-in (Consider interconnection edges of only selected mode)
|
||||
* 3. Select and print the SPICE netlist
|
||||
*/
|
||||
fan_in = 0;
|
||||
cur_interc = NULL;
|
||||
find_interc_fan_in_des_pb_graph_pin (des_pb_graph_pin, cur_mode, &cur_interc, &fan_in);
|
||||
if ((NULL == cur_interc) || (0 == fan_in)) {
|
||||
/* No interconnection matched */
|
||||
/* Connect this pin to GND for better convergence */
|
||||
/* TODO: find the correct pin name!!!*/
|
||||
/*
|
||||
dump_verilog_dangling_des_pb_graph_pin_interc(fp, des_pb_graph_pin, cur_mode, pin2pin_interc_type,
|
||||
formatted_parent_pin_prefix);
|
||||
*/
|
||||
return;
|
||||
}
|
||||
/* Initialize the interconnection type that will be implemented in SPICE netlist*/
|
||||
verilog_interc_type = determine_actual_pb_interc_type (cur_interc, fan_in);
|
||||
/* This time, (2nd round), we print the subckt, according to interc type*/
|
||||
switch (verilog_interc_type) {
|
||||
case DIRECT_INTERC:
|
||||
/* Check :
|
||||
* 1. Direct interc has only one fan-in!
|
||||
*/
|
||||
assert (1 == fan_in);
|
||||
//assert(1 == des_pb_graph_pin->num_input_edges);
|
||||
/* For more than one mode defined, the direct interc has more than one input_edge ,
|
||||
* We need to find which edge is connected the pin we want
|
||||
*/
|
||||
for (iedge = 0; iedge < des_pb_graph_pin->num_input_edges; iedge++) {
|
||||
if (cur_interc == des_pb_graph_pin->input_edges[iedge]->interconnect) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert (iedge < des_pb_graph_pin->num_input_edges);
|
||||
/* 2. spice_model is a wire */
|
||||
assert (NULL != cur_interc->spice_model);
|
||||
assert (SPICE_MODEL_WIRE == cur_interc->spice_model->type);
|
||||
assert (NULL != cur_interc->spice_model->wire_param);
|
||||
/* Initialize*/
|
||||
/* Source pin, node, pb_type*/
|
||||
src_pb_graph_pin = des_pb_graph_pin->input_edges[iedge]->input_pins[0];
|
||||
src_pb_graph_node = src_pb_graph_pin->parent_node;
|
||||
/* Des pin, node, pb_type */
|
||||
des_pb_graph_node = des_pb_graph_pin->parent_node;
|
||||
|
||||
/* if clock, clock tree synthesis will take care of the timings */
|
||||
if (TRUE == src_pb_graph_pin->port->is_clock ||
|
||||
TRUE == des_pb_graph_pin->port->is_clock) {
|
||||
return;
|
||||
}
|
||||
// Generation of the paths for the dumping of the annotations
|
||||
from_path = (char *) my_malloc(sizeof(char)*(strlen(instance_name) + 1 + strlen(gen_verilog_one_pb_graph_pin_full_name_in_hierarchy (src_pb_graph_pin)) + 1));
|
||||
sprintf (from_path, "%s/%s", instance_name, gen_verilog_one_pb_graph_pin_full_name_in_hierarchy (src_pb_graph_pin));
|
||||
to_path = (char *) my_malloc(sizeof(char)*(strlen(instance_name) + 1 + strlen(gen_verilog_one_pb_graph_pin_full_name_in_hierarchy (des_pb_graph_pin)) + 1));
|
||||
sprintf (to_path, "%s/%s", instance_name, gen_verilog_one_pb_graph_pin_full_name_in_hierarchy (des_pb_graph_pin));
|
||||
|
||||
// Dumping of the annotations
|
||||
sdc_dump_annotation (from_path, to_path, fp, des_pb_graph_pin->input_edges[iedge]);
|
||||
break;
|
||||
case COMPLETE_INTERC:
|
||||
case MUX_INTERC:
|
||||
/* Check :
|
||||
* MUX should have at least 2 fan_in
|
||||
*/
|
||||
assert ((2 == fan_in) || (2 < fan_in));
|
||||
/* 2. spice_model is a wire */
|
||||
assert (NULL != cur_interc->spice_model);
|
||||
assert (SPICE_MODEL_MUX == cur_interc->spice_model->type);
|
||||
for (iedge = 0; iedge < des_pb_graph_pin->num_input_edges; iedge++) {
|
||||
if (cur_mode != des_pb_graph_pin->input_edges[iedge]->interconnect->parent_mode) {
|
||||
continue;
|
||||
}
|
||||
check_pb_graph_edge(*(des_pb_graph_pin->input_edges[iedge]));
|
||||
/* Initialize*/
|
||||
/* Source pin, node, pb_type*/
|
||||
src_pb_graph_pin = des_pb_graph_pin->input_edges[iedge]->input_pins[0];
|
||||
src_pb_graph_node = src_pb_graph_pin->parent_node;
|
||||
/* Des pin, node, pb_type */
|
||||
des_pb_graph_node = des_pb_graph_pin->parent_node;
|
||||
// Generation of the paths for the dumping of the annotations
|
||||
from_path = (char *) my_malloc(sizeof(char)*(strlen(instance_name) + 1 + strlen(gen_verilog_one_pb_graph_pin_full_name_in_hierarchy (src_pb_graph_pin)) + 1));
|
||||
sprintf (from_path, "%s/%s", instance_name, gen_verilog_one_pb_graph_pin_full_name_in_hierarchy (src_pb_graph_pin));
|
||||
to_path = (char *) my_malloc(sizeof(char)*(strlen(instance_name) + 1 + strlen(gen_verilog_one_pb_graph_pin_full_name_in_hierarchy (des_pb_graph_pin)) + 1));
|
||||
sprintf (to_path, "%s/%s", instance_name, gen_verilog_one_pb_graph_pin_full_name_in_hierarchy (des_pb_graph_pin));
|
||||
|
||||
/* If the pin is disabled, the dumping is different. We need to use the
|
||||
* input and output of the inverter of the mux */
|
||||
if (TRUE == des_pb_graph_pin->input_edges[iedge]->is_disabled) {
|
||||
/* We need to find the highest node between src and des */
|
||||
if (src_pb_graph_node->parent_pb_graph_node == des_pb_graph_node->parent_pb_graph_node) {
|
||||
cur_pin_disable = src_pb_graph_pin->parent_node->parent_pb_graph_node->input_pins[0];
|
||||
}
|
||||
else if (src_pb_graph_node->parent_pb_graph_node == des_pb_graph_node) {
|
||||
cur_pin_disable = des_pb_graph_pin;
|
||||
}
|
||||
else {
|
||||
cur_pin_disable = src_pb_graph_pin;
|
||||
}
|
||||
if (cur_interc->spice_model->input_buffer == NULL) {
|
||||
vpr_printf (TIO_MESSAGE_ERROR,
|
||||
"The loop_breaker annotation can only be applied when there is an input buffer");
|
||||
}
|
||||
if (0 == strcmp("",gen_verilog_one_pb_graph_pin_full_name_in_hierarchy_parent_node(cur_pin_disable))) {
|
||||
input_buffer_path = (char *) my_malloc(sizeof(char)*(strlen(instance_name) + 1 +
|
||||
strlen (cur_interc->spice_model->name) + 5 + strlen(my_itoa(cur_interc->fan_in)) + 1 +
|
||||
strlen (my_itoa(des_pb_graph_pin->input_edges[iedge]->nb_mux)) + 1 + 1));
|
||||
|
||||
sprintf (input_buffer_path, "%s/%s_size%d_%d_",instance_name,
|
||||
cur_interc->spice_model->name, cur_interc->fan_in,
|
||||
des_pb_graph_pin->input_edges[iedge]->nb_mux);
|
||||
}
|
||||
else {
|
||||
input_buffer_path = (char *) my_malloc(sizeof(char)*(strlen(instance_name) + 1 +
|
||||
strlen (gen_verilog_one_pb_graph_pin_full_name_in_hierarchy_parent_node(cur_pin_disable)) +
|
||||
strlen (cur_interc->spice_model->name) + 5 + strlen(my_itoa(cur_interc->fan_in)) + 1 +
|
||||
strlen (my_itoa(des_pb_graph_pin->input_edges[iedge]->nb_mux)) + 1 + 1));
|
||||
|
||||
sprintf (input_buffer_path, "%s/%s%s_size%d_%d_",instance_name,
|
||||
gen_verilog_one_pb_graph_pin_full_name_in_hierarchy_parent_node(cur_pin_disable),
|
||||
cur_interc->spice_model->name, cur_interc->fan_in ,
|
||||
des_pb_graph_pin->input_edges[iedge]->nb_mux);
|
||||
}
|
||||
input_buffer_name = cur_interc ->spice_model->input_buffer->spice_model_name;
|
||||
/* BChauviere: might need to find the right port if something other than an inverter is used */
|
||||
input_buffer_in = cur_interc ->spice_model->input_buffer->spice_model->ports[0].lib_name;
|
||||
input_buffer_out = cur_interc ->spice_model->input_buffer->spice_model->ports[1].lib_name;
|
||||
set_disable_path = (char*) my_malloc(sizeof(char)*(
|
||||
strlen(input_buffer_path) + 1 +
|
||||
strlen(input_buffer_name) + 1 +
|
||||
strlen(my_itoa(des_pb_graph_pin->input_edges[iedge]->nb_pin))
|
||||
+ 1 + 1) );
|
||||
sprintf(set_disable_path, "%s/%s_%d_", input_buffer_path, input_buffer_name,
|
||||
des_pb_graph_pin->input_edges[iedge]->nb_pin);
|
||||
|
||||
if (NULL != des_pb_graph_pin->input_edges[iedge]->loop_breaker_delay_before_min) {
|
||||
fprintf (fp, "set_min_delay -from %s -to %s/%s %f \n", from_path, set_disable_path, input_buffer_in,
|
||||
pow(10,9)*atof(des_pb_graph_pin->input_edges[iedge]->loop_breaker_delay_before_min));
|
||||
}
|
||||
if (NULL != des_pb_graph_pin->input_edges[iedge]->loop_breaker_delay_before_max) {
|
||||
fprintf (fp, "set_max_delay -from %s -to %s/%s %f \n", from_path, set_disable_path, input_buffer_in,
|
||||
pow(10,9)*atof(des_pb_graph_pin->input_edges[iedge]->loop_breaker_delay_before_max));
|
||||
}
|
||||
fprintf (fp, "set_disable_timing -from %s -to %s %s \n", input_buffer_in, input_buffer_out, set_disable_path);
|
||||
if (NULL != des_pb_graph_pin->input_edges[iedge]->loop_breaker_delay_after_min) {
|
||||
fprintf (fp, "set_min_delay -from %s/%s -to %s %f \n", set_disable_path, input_buffer_out,
|
||||
to_path,
|
||||
pow(10,9)*atof(des_pb_graph_pin->input_edges[iedge]->loop_breaker_delay_after_min));
|
||||
}
|
||||
if (NULL != des_pb_graph_pin->input_edges[iedge]->loop_breaker_delay_after_max) {
|
||||
fprintf (fp, "set_max_delay -from %s/%s -to %s %f \n", set_disable_path, input_buffer_out,
|
||||
to_path,
|
||||
pow(10,9)*atof(des_pb_graph_pin->input_edges[iedge]->loop_breaker_delay_after_max));
|
||||
}
|
||||
my_free(input_buffer_path);
|
||||
my_free(set_disable_path);
|
||||
}
|
||||
else {
|
||||
// Dumping of the annotations
|
||||
sdc_dump_annotation (from_path, to_path, fp, des_pb_graph_pin->input_edges[iedge]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
vpr_printf (TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid interconnection type for %s (Arch[LINE%d])!\n",
|
||||
__FILE__, __LINE__, cur_interc->name, cur_interc->line_num);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Print the SPICE interconnections of a port defined in pb_graph */
|
||||
void dump_sdc_pb_graph_port_interc(FILE* fp,
|
||||
t_pb_graph_node* cur_pb_graph_node,
|
||||
enum e_spice_pb_port_type pb_port_type,
|
||||
t_mode* cur_mode,
|
||||
char* instance_name) {
|
||||
int iport, ipin;
|
||||
|
||||
/* Check the file handler*/
|
||||
if (NULL == fp) {
|
||||
vpr_printf (TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid file handler.\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
switch (pb_port_type) {
|
||||
case SPICE_PB_PORT_INPUT:
|
||||
for (iport = 0; iport < cur_pb_graph_node->num_input_ports; iport++) {
|
||||
for (ipin = 0; ipin < cur_pb_graph_node->num_input_pins[iport]; ipin++) {
|
||||
/* If this is a idle block, we set 0 to the selected edge*/
|
||||
/* Get the selected edge of current pin*/
|
||||
dump_sdc_pb_graph_pin_interc (fp,
|
||||
&(cur_pb_graph_node->input_pins[iport][ipin]),
|
||||
cur_mode,
|
||||
instance_name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPICE_PB_PORT_OUTPUT:
|
||||
for (iport = 0; iport < cur_pb_graph_node->num_output_ports; iport++) {
|
||||
for (ipin = 0; ipin < cur_pb_graph_node->num_output_pins[iport]; ipin++) {
|
||||
dump_sdc_pb_graph_pin_interc(fp,
|
||||
&(cur_pb_graph_node->output_pins[iport][ipin]),
|
||||
cur_mode,
|
||||
instance_name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPICE_PB_PORT_CLOCK:
|
||||
for (iport = 0; iport < cur_pb_graph_node->num_clock_ports; iport++) {
|
||||
for (ipin = 0; ipin < cur_pb_graph_node->num_clock_pins[iport]; ipin++) {
|
||||
dump_sdc_pb_graph_pin_interc(fp,
|
||||
&(cur_pb_graph_node->clock_pins[iport][ipin]),
|
||||
cur_mode,
|
||||
instance_name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vpr_printf (TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid pb port type!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void sdc_dump_cur_node_constraints(FILE* fp,
|
||||
t_pb_graph_node* cur_pb_graph_node,
|
||||
int select_mode_index,
|
||||
char* instance_name) {
|
||||
int ipb, jpb;
|
||||
t_mode* cur_mode = NULL;
|
||||
t_pb_type* cur_pb_type = cur_pb_graph_node->pb_type;
|
||||
t_pb_graph_node* child_pb_graph_node = NULL;
|
||||
|
||||
|
||||
/* Check the file handler*/
|
||||
if (NULL == fp) {
|
||||
vpr_printf (TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
/* Check cur_pb_type*/
|
||||
if (NULL == cur_pb_type) {
|
||||
vpr_printf (TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid cur_pb_type.\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Assign current mode */
|
||||
cur_mode = &(cur_pb_graph_node->pb_type->modes[select_mode_index]);
|
||||
|
||||
/* We check output_pins of cur_pb_graph_node and its the input_edges
|
||||
* Built the interconnections between outputs of cur_pb_graph_node and outputs of child_pb_graph_node
|
||||
* child_pb_graph_node.output_pins -----------------> cur_pb_graph_node.outpins
|
||||
* /|\
|
||||
* |
|
||||
* input_pins, edges, output_pins
|
||||
*/
|
||||
dump_sdc_pb_graph_port_interc(fp,
|
||||
cur_pb_graph_node,
|
||||
SPICE_PB_PORT_OUTPUT,
|
||||
cur_mode,
|
||||
instance_name);
|
||||
|
||||
/* We check input_pins of child_pb_graph_node and its the input_edges
|
||||
* Built the interconnections between inputs of cur_pb_graph_node and inputs of child_pb_graph_node
|
||||
* cur_pb_graph_node.input_pins -----------------> child_pb_graph_node.input_pins
|
||||
* /|\
|
||||
* |
|
||||
* input_pins, edges, output_pins
|
||||
*/
|
||||
for (ipb = 0; ipb < cur_pb_type->modes[select_mode_index].num_pb_type_children; ipb++) {
|
||||
for (jpb = 0; jpb < cur_pb_type->modes[select_mode_index].pb_type_children[ipb].num_pb; jpb++) {
|
||||
child_pb_graph_node = &(cur_pb_graph_node->child_pb_graph_nodes[select_mode_index][ipb][jpb]);
|
||||
/* For each child_pb_graph_node input pins*/
|
||||
dump_sdc_pb_graph_port_interc(fp,
|
||||
child_pb_graph_node,
|
||||
SPICE_PB_PORT_INPUT,
|
||||
cur_mode,
|
||||
instance_name);
|
||||
/* TODO: for clock pins, we should do the same work */
|
||||
dump_sdc_pb_graph_port_interc(fp,
|
||||
child_pb_graph_node,
|
||||
SPICE_PB_PORT_CLOCK,
|
||||
cur_mode,
|
||||
instance_name);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void sdc_rec_dump_child_pb_graph_node(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
t_pb_graph_node* cur_pb_graph_node,
|
||||
char* instance_name) {
|
||||
|
||||
int mode_index, ipb, jpb;
|
||||
t_pb_type* cur_pb_type = NULL;
|
||||
|
||||
/* Check the file handler */
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n",__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
/* Check current node */
|
||||
if (NULL == cur_pb_graph_node) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid cur_pb_graph_node.\n",__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
cur_pb_type = cur_pb_graph_node->pb_type;
|
||||
|
||||
/* First we only go through the graph through the physical nodes. The other modes don't have sdc constraints. We then check all the children nodes and repeat the operation until arriving to the leaf nodes.
|
||||
* Once at the leaf, all the edges are dumped with a default set_min/max_delay of 0 if non is user-defined.
|
||||
* Contrary to the verilog, because the interconnections can get tricky through shift registers, carry-chains and all, we do not use wild cards or instantiation to be sure to completely constrain our design.
|
||||
*/
|
||||
/* Recursively finish all the child pb types */
|
||||
if (FALSE == is_primitive_pb_type(cur_pb_type)) {
|
||||
/* Find the mode that defines the physical mode*/
|
||||
mode_index = find_pb_type_physical_mode_index((*cur_pb_type));
|
||||
for(ipb = 0; ipb < cur_pb_type->modes[mode_index].num_pb_type_children; ipb++) {
|
||||
for(jpb = 0; jpb < cur_pb_type->modes[mode_index].pb_type_children[ipb].num_pb; jpb++){
|
||||
/* Contrary to the verilog, we do not need to keep the prefix
|
||||
* We go done to every child node to dump the constraints now*/
|
||||
sdc_rec_dump_child_pb_graph_node(cur_sram_orgz_info, fp, &(cur_pb_graph_node->child_pb_graph_nodes[mode_index][ipb][jpb]), instance_name);
|
||||
}
|
||||
}
|
||||
sdc_dump_cur_node_constraints(fp, cur_pb_graph_node, mode_index, instance_name); // graph_head only has one pb_type
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void sdc_dump_all_pb_graph_nodes(FILE* fp,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
int type_descriptors_mode,
|
||||
char* instance_name){
|
||||
|
||||
t_spice_model* mem_model = NULL;
|
||||
int iport, ipin;
|
||||
char* port_name = NULL;
|
||||
|
||||
int num_output_ports = 0;
|
||||
t_spice_model_port** output_ports = NULL;
|
||||
|
||||
// Break all the programming cells
|
||||
get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
|
||||
assert (NULL != mem_model);
|
||||
|
||||
/* Check */
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s,LINE[%d])Invalid file handler!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
get_sram_orgz_info_mem_model(cur_sram_orgz_info, &mem_model);
|
||||
assert (NULL != mem_model);
|
||||
|
||||
/* Find the output ports of mem_model */
|
||||
output_ports = find_spice_model_ports(mem_model, SPICE_MODEL_PORT_OUTPUT, &num_output_ports, TRUE);
|
||||
|
||||
for (iport = 0; iport < num_output_ports; iport++) {
|
||||
for (ipin = 0; ipin < output_ports[iport]->size; ipin++) {
|
||||
if (TRUE == mem_model->dump_explicit_port_map) {
|
||||
port_name = output_ports[iport]->lib_name;
|
||||
} else {
|
||||
port_name = output_ports[iport]->prefix;
|
||||
}
|
||||
/* Disable the timing for all the memory cells */
|
||||
fprintf(fp,
|
||||
"set_disable_timing [get_pins -filter \"name == %s",
|
||||
port_name);
|
||||
if (1 < output_ports[iport]->size) {
|
||||
fprintf(fp, "[%d]", ipin);
|
||||
}
|
||||
fprintf(fp, "\" ");
|
||||
fprintf(fp,
|
||||
"-of [get_cells -hier -filter \"ref_lib_cell_name == %s\"]]\n",
|
||||
mem_model->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free */
|
||||
|
||||
// Give head of the pb_graph to the recursive function
|
||||
sdc_rec_dump_child_pb_graph_node (cur_sram_orgz_info, fp, type_descriptors[type_descriptors_mode].pb_graph_head, instance_name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void dump_sdc_physical_blocks(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* sdc_path,
|
||||
int type_descriptor_mode,
|
||||
char* instance_name) {
|
||||
|
||||
FILE* fp;
|
||||
|
||||
/* Check if the path exists*/
|
||||
fp = fopen (sdc_path,"w");
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in creating SDC for constraining Primitive Blocks %s!",__FILE__, __LINE__, sdc_path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
vpr_printf (TIO_MESSAGE_INFO, "Generating SDC for constraining Primitive Blocks in P&R flow: (%s)...\n",
|
||||
sdc_path);
|
||||
|
||||
|
||||
// Launch a recursive function to visit all the nodes of the correct mode
|
||||
sdc_dump_all_pb_graph_nodes(fp, cur_sram_orgz_info, type_descriptor_mode, instance_name);
|
||||
|
||||
|
||||
/* close file */
|
||||
fclose(fp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void verilog_generate_sdc_constrain_pb_types(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* sdc_dir) {
|
||||
|
||||
int itype;
|
||||
char* sdc_path;
|
||||
char* instance_name;
|
||||
|
||||
sdc_path = my_strcat (sdc_dir, sdc_constrain_pb_type_file_name); // Global var
|
||||
|
||||
for (itype = 0; itype < num_types; itype++){
|
||||
if (FILL_TYPE == &type_descriptors[itype]){
|
||||
instance_name = gen_verilog_one_phy_block_instance_name(&type_descriptors[itype],0); /* it is 0 because the CLBs only have 1 block.*/
|
||||
dump_sdc_physical_blocks(cur_sram_orgz_info, sdc_path, itype, instance_name);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
|
||||
void sdc_dump_annotation(char* from_path, // includes the cell
|
||||
char* to_path,
|
||||
FILE* fp,
|
||||
t_pb_graph_edge* cur_edge);
|
||||
|
||||
void dump_sdc_pb_graph_pin_interc(FILE* fp,
|
||||
t_pb_graph_pin* des_pb_graph_pin,
|
||||
t_mode* cur_mode,
|
||||
char* instance_name);
|
||||
|
||||
void dump_sdc_pb_graph_port_interc(FILE* fp,
|
||||
t_pb_graph_node* cur_pb_graph_node,
|
||||
enum e_spice_pb_port_type pb_port_type,
|
||||
t_mode* cur_mode,
|
||||
char* instance_name);
|
||||
|
||||
void sdc_dump_cur_node_constraints(FILE* fp,
|
||||
t_pb_graph_node* cur_pb_graph_node,
|
||||
int select_mode_index,
|
||||
char* instance_name);
|
||||
|
||||
void sdc_rec_dump_child_pb_graph_node(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
FILE* fp,
|
||||
t_pb_graph_node* cur_pb_graph_node,
|
||||
char* instance_name);
|
||||
|
||||
void sdc_dump_all_pb_graph_nodes(FILE* fp,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
int type_descriptor_mode,
|
||||
char* instance_name);
|
||||
|
||||
void dump_sdc_physical_blocks(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* sdc_path,
|
||||
int type_descriptor_mode,
|
||||
char* instance_name);
|
||||
|
||||
void verilog_generate_sdc_constrain_pb_types(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* sdc_dir);
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
/* FPGA-X2P context header files */
|
||||
#include "fpga_x2p_utils.h"
|
||||
#include "module_manager_utils.h"
|
||||
|
||||
/* FPGA-Verilog context header files */
|
||||
#include "verilog_global.h"
|
||||
|
@ -119,3 +120,117 @@ void print_verilog_submodule_signal_init(std::fstream& fp,
|
|||
fp << "`endif" << std::endl;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Register all the user-defined modules in the module manager
|
||||
* Walk through the circuit library and add user-defined circuit models
|
||||
* to the module_manager
|
||||
********************************************************************/
|
||||
void add_user_defined_verilog_modules(ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib) {
|
||||
/* Iterate over Verilog modules */
|
||||
for (const auto& model : circuit_lib.models()) {
|
||||
/* We only care about user-defined models */
|
||||
if (true == circuit_lib.model_verilog_netlist(model).empty()) {
|
||||
continue;
|
||||
}
|
||||
/* Skip Routing channel wire models because they need a different name. Do it later */
|
||||
if (SPICE_MODEL_CHAN_WIRE == circuit_lib.model_type(model)) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here, the model requires a user-defined Verilog netlist,
|
||||
* Try to find it in the module manager
|
||||
* If not found, register it in the module_manager
|
||||
*/
|
||||
ModuleId module_id = module_manager.find_module(circuit_lib.model_name(model));
|
||||
if (ModuleId::INVALID() == module_id) {
|
||||
add_circuit_model_to_module_manager(module_manager, circuit_lib, model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Print a template for a user-defined circuit model
|
||||
* The template will include just the port declaration of the Verilog module
|
||||
* The template aims to help user to write Verilog codes with a guaranteed
|
||||
* module definition, which can be correctly instanciated (with correct
|
||||
* port mapping) in the FPGA fabric
|
||||
********************************************************************/
|
||||
static
|
||||
void print_one_verilog_template_module(const ModuleManager& module_manager,
|
||||
std::fstream& fp,
|
||||
const std::string& module_name) {
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
print_verilog_comment(fp, std::string("----- Template Verilog module for " + module_name + " -----"));
|
||||
|
||||
/* Find the module in module manager, which should be already registered */
|
||||
/* TODO: routing channel wire model may have a different name! */
|
||||
ModuleId template_module = module_manager.find_module(module_name);
|
||||
VTR_ASSERT(ModuleId::INVALID() != template_module);
|
||||
|
||||
/* dump module definition + ports */
|
||||
print_verilog_module_declaration(fp, module_manager, template_module);
|
||||
/* Finish dumping ports */
|
||||
|
||||
print_verilog_comment(fp, std::string("----- Internal logic should start here -----"));
|
||||
|
||||
/* Add some empty lines as placeholders for the internal logic*/
|
||||
fp << std::endl << std::endl;
|
||||
|
||||
print_verilog_comment(fp, std::string("----- Internal logic should end here -----"));
|
||||
|
||||
/* Put an end to the Verilog module */
|
||||
print_verilog_module_end(fp, module_name);
|
||||
|
||||
/* Add an empty line as a splitter */
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Print a template of all the submodules that are user-defined
|
||||
* The template will include just the port declaration of the submodule
|
||||
* The template aims to help user to write Verilog codes with a guaranteed
|
||||
* module definition, which can be correctly instanciated (with correct
|
||||
* port mapping) in the FPGA fabric
|
||||
********************************************************************/
|
||||
void print_verilog_submodule_templates(const ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& submodule_dir) {
|
||||
std::string verilog_fname(submodule_dir + user_defined_template_verilog_file_name);
|
||||
|
||||
/* 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 template for user-defined Verilog modules (%s)...\n",
|
||||
verilog_fname.c_str());
|
||||
|
||||
print_verilog_file_header(fp, "Template for user-defined Verilog modules");
|
||||
|
||||
print_verilog_include_defines_preproc_file(fp, verilog_dir);
|
||||
|
||||
/* Output essential models*/
|
||||
for (const auto& model : circuit_lib.models()) {
|
||||
/* Focus on user-defined modules, which must have a Verilog netlist defined */
|
||||
if (circuit_lib.model_verilog_netlist(model).empty()) {
|
||||
continue;
|
||||
}
|
||||
/* Skip Routing channel wire models because they need a different name. Do it later */
|
||||
if (SPICE_MODEL_CHAN_WIRE == circuit_lib.model_type(model)) {
|
||||
continue;
|
||||
}
|
||||
/* Print a Verilog template for the circuit model */
|
||||
print_one_verilog_template_module(module_manager, fp, circuit_lib.model_name(model));
|
||||
}
|
||||
|
||||
/* close file stream */
|
||||
fp.close();
|
||||
|
||||
/* No need to add the template to the subckt include files! */
|
||||
}
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
#define VERILOG_SUBMODULE_UTILS_H
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include "module_manager.h"
|
||||
#include "circuit_library.h"
|
||||
|
||||
void print_verilog_submodule_timing(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
|
@ -18,4 +21,12 @@ void print_verilog_submodule_signal_init(std::fstream& fp,
|
|||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
void add_user_defined_verilog_modules(ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib);
|
||||
|
||||
void print_verilog_submodule_templates(const ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& submodule_dir);
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,102 @@
|
|||
/*********************************************************************
|
||||
* This file includes top-level function to generate Verilog primitive modules
|
||||
* and print them to files
|
||||
********************************************************************/
|
||||
/* Standard header files */
|
||||
|
||||
/* External library header files */
|
||||
#include "util.h"
|
||||
|
||||
/* FPGA-Verilog header files */
|
||||
#include "verilog_submodule_utils.h"
|
||||
#include "verilog_essential_gates.h"
|
||||
#include "verilog_decoders.h"
|
||||
#include "verilog_mux.h"
|
||||
#include "verilog_lut.h"
|
||||
#include "verilog_wire.h"
|
||||
#include "verilog_memory.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
|
||||
/* Header file for this source file */
|
||||
#include "verilog_submodules.h"
|
||||
|
||||
/*********************************************************************
|
||||
* Top-level function to generate primitive modules:
|
||||
* 1. Logic gates: AND/OR, inverter, buffer and transmission-gate/pass-transistor
|
||||
* 2. Routing multiplexers
|
||||
* 3. Local encoders for routing multiplexers
|
||||
* 4. Wires
|
||||
* 5. Configuration memory blocks
|
||||
* 6. Verilog template
|
||||
********************************************************************/
|
||||
void print_verilog_submodules(ModuleManager& module_manager,
|
||||
const MuxLibrary& mux_lib,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
const char* verilog_dir,
|
||||
const char* submodule_dir,
|
||||
const t_arch& Arch,
|
||||
const t_syn_verilog_opts& fpga_verilog_opts) {
|
||||
|
||||
/* Register all the user-defined modules in the module manager
|
||||
* This should be done prior to other steps in this function,
|
||||
* because they will be instanciated by other primitive modules
|
||||
*/
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Registering user-defined modules...\n");
|
||||
|
||||
/* Create a vector to contain all the Verilog netlist names that have been generated in this function */
|
||||
std::vector<std::string> netlist_names;
|
||||
|
||||
add_user_defined_verilog_modules(module_manager, Arch.spice->circuit_lib);
|
||||
|
||||
print_verilog_submodule_essentials(module_manager,
|
||||
netlist_names,
|
||||
std::string(verilog_dir),
|
||||
std::string(submodule_dir),
|
||||
Arch.spice->circuit_lib);
|
||||
|
||||
/* Routing multiplexers */
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Generating modules for routing multiplexers...\n");
|
||||
|
||||
/* 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, netlist_names,
|
||||
mux_lib, Arch.spice->circuit_lib,
|
||||
std::string(verilog_dir), std::string(submodule_dir));
|
||||
print_verilog_submodule_muxes(module_manager, netlist_names, mux_lib, Arch.spice->circuit_lib, cur_sram_orgz_info,
|
||||
std::string(verilog_dir), std::string(submodule_dir),
|
||||
fpga_verilog_opts.dump_explicit_verilog);
|
||||
|
||||
|
||||
/* LUTes */
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Generating modules for LUTs...\n");
|
||||
print_verilog_submodule_luts(module_manager, netlist_names, Arch.spice->circuit_lib, std::string(verilog_dir), std::string(submodule_dir),
|
||||
fpga_verilog_opts.dump_explicit_verilog);
|
||||
|
||||
/* Hard wires */
|
||||
print_verilog_submodule_wires(module_manager, netlist_names, Arch.spice->circuit_lib, std::string(verilog_dir), std::string(submodule_dir));
|
||||
|
||||
/* 4. Memories */
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Generating modules for configuration memory blocks...\n");
|
||||
print_verilog_submodule_memories(module_manager, netlist_names,
|
||||
mux_lib, Arch.spice->circuit_lib,
|
||||
std::string(verilog_dir), std::string(submodule_dir),
|
||||
fpga_verilog_opts.dump_explicit_verilog);
|
||||
|
||||
/* 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, std::string(verilog_dir), std::string(submodule_dir));
|
||||
}
|
||||
|
||||
/* Create a header file to include all the subckts */
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Generating header file for primitive modules...\n");
|
||||
print_verilog_netlist_include_header_file(netlist_names,
|
||||
submodule_dir,
|
||||
submodule_verilog_file_name);
|
||||
}
|
||||
|
|
@ -1,15 +1,16 @@
|
|||
#ifndef VERILOG_SUBMODULES_H
|
||||
#define VERILOG_SUBMODULES_H
|
||||
|
||||
#include "vpr_types.h"
|
||||
#include "module_manager.h"
|
||||
#include "mux_library.h"
|
||||
|
||||
void dump_verilog_submodules(ModuleManager& module_manager,
|
||||
const MuxLibrary& mux_lib,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* verilog_dir,
|
||||
char* submodule_dir,
|
||||
t_arch Arch,
|
||||
t_det_routing_arch* routing_arch,
|
||||
t_syn_verilog_opts fpga_verilog_opts);
|
||||
void print_verilog_submodules(ModuleManager& module_manager,
|
||||
const MuxLibrary& mux_lib,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
const char* verilog_dir,
|
||||
const char* submodule_dir,
|
||||
const t_arch& Arch,
|
||||
const t_syn_verilog_opts& fpga_verilog_opts);
|
||||
|
||||
#endif
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue