Merge branch 'multimode_clb' into fpga_spice

This commit is contained in:
tangxifan 2019-06-15 15:37:26 -06:00
commit 28f54961b2
83 changed files with 7573 additions and 500 deletions

View File

@ -11,12 +11,12 @@ compiled_file="compiled_$benchmark"
tb_formal_postfix="_top_formal_verification_random_tb"
verilog_output_dirname="${benchmark}_Verilog"
log_file="${benchmark}_sim.log"
new_reg_sh="my_regression.sh"
cd $fpga_flow_scripts
perl rewrite_path_in_file.pl -i $vpr_path/regression_verilog.sh
perl rewrite_path_in_file.pl -i $vpr_path/VerilogNetlists/ff.v
perl rewrite_path_in_file.pl -i $vpr_path/regression_verilog.sh -o $vpr_path/$new_reg_sh
cd $my_pwd
@ -28,7 +28,7 @@ rm -f $log_file
rm -f $compiled_file
# Start the script -> run the fpga generation -> run the simulation -> check the log file
source regression_verilog.sh
source $new_reg_sh
iverilog -o $compiled_file $verilog_output_dirname/SRC/$benchmark$include_netlists -s $benchmark$tb_formal_postfix
vvp $compiled_file -j 16 >> $log_file

View File

@ -137,6 +137,7 @@ enable_testing()
add_subdirectory(yosys)
add_subdirectory(abc)
add_subdirectory(ace2)
add_subdirectory(libs)
add_subdirectory(vpr7_x2p)
# run make to extract compiler options, linker options and list of source files
@ -175,8 +176,13 @@ set_target_properties(libace ace
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ace2"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ace2")
# Set output locations to be in the main source tree under the relevant folder
set_target_properties(libvtrutil
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libs/libvtrutil"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libs/libvtrutil"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libs/libvtrutil")
set_target_properties(libarchfpga read_arch
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/vpr7_x2p/libarchfpga"

View File

@ -330,7 +330,7 @@
<port type="output" prefix="out" size="1"/>
</spice_model>
<!--DFF subckt ports should be defined as <D> <Q> <CLK> <RESET> <SET> -->
<spice_model type="ff" name="static_dff" prefix="dff" spice_netlist="OPENFPGAPATHKEYWORD/vpr7_x2p/vpr/SpiceNetlists/ff.sp" verilog_netlist="OPENFPGAPATHKEYWORD/vpr7_x2p/vpr/VerilogNetlists/ff.v">
<spice_model type="ff" name="static_dff" prefix="dff" spice_netlist="OPENFPGAPATHKEYWORD/vpr7_x2p/vpr/SpiceNetlists/ff.sp" verilog_netlist="FFPATHKEYWORD">
<design_technology type="cmos"/>
<input_buffer exist="on" spice_model_name="INV1X"/>
<output_buffer exist="on" spice_model_name="INV1X"/>
@ -372,7 +372,7 @@
<port type="sram" prefix="mode" size="2" mode_select="true" spice_model_name="sc_dff_compact" default_val="1"/>
</spice_model>
<!--Scan-chain DFF subckt ports should be defined as <D> <Q> <Qb> <CLK> <RESET> <SET> -->
<spice_model type="sff" name="sc_dff_compact" prefix="scff" spice_netlist="OPENFPGAPATHKEYWORD/vpr7_x2p/vpr/SpiceNetlists/ff.sp" verilog_netlist="OPENFPGAPATHKEYWORD/vpr7_x2p/vpr/VerilogNetlists/ff.v">
<spice_model type="sff" name="sc_dff_compact" prefix="scff" spice_netlist="OPENFPGAPATHKEYWORD/vpr7_x2p/vpr/SpiceNetlists/ff.sp" verilog_netlist="FFPATHKEYWORD">
<design_technology type="cmos"/>
<input_buffer exist="on" spice_model_name="INV1X"/>
<output_buffer exist="on" spice_model_name="INV1X"/>

View File

@ -1,172 +0,0 @@
----------------------------------- Summary ------------------------------------
Circuit: /research/ece/lnis/USERS/tang/github/OpenFPGA/fpga_flow/benchmarks/Blif/Test_Modes/test_modes
Architecture: k6_N10_sram_chain_HC_template.xml
Technology (nm): 45
Voltage: 0.90
Temperature: 85
Critical Path: 5.8141e-09
Size of FPGA: 2 x 2
Channel Width: 200
----------------------------------- Warnings -----------------------------------
No transistor counter function for BLIF model: .frac_lut6
No transistor counter function for BLIF model: .subckt adder
No transistor counter function for BLIF model: .subckt shift
Attempted to search for a transistor with a capacitance smaller than the smallest in the technology file.
No dynamic power defined for BLIF model: .subckt adder
No leakage power defined for BLIF model: .subckt adder
No dynamic power defined for BLIF model: .frac_lut6
No leakage power defined for BLIF model: .frac_lut6
No dynamic power defined for BLIF model: .subckt shift
No leakage power defined for BLIF model: .subckt shift
------------------------------- Power Breakdown --------------------------------
Component Power (W) %-Total %-Dynamic Method
Total 0.0002701 1 0.7897
Routing 0.0001289 0.4773 0.7668
Switch Box 2.212e-05 0.08191 0
Connection Box 0.0001068 0.3954 0.9256
Global Wires 0 0 -nan
PB Types 8.066e-05 0.2986 0.6884
Primitives 4.913e-05 0.1819 0.8837
Interc Structures 8.866e-06 0.03283 0.5489
Buffers and Wires 2.266e-05 0.08389 0.3197
Other Estimation Methods 0 0 -nan
Clock 6.051e-05 0.224 0.9736
---------------------------- Power Breakdown by PB -----------------------------
This sections provides a detailed breakdown of power usage by PB (physical
block). For each PB, the power is listed, which is the sum power of all
instances of the block. It also indicates its percentage of total power (entire
FPGA), as well as the percentage of its power that is dynamic (vs. static). It
also indicates the method used for power estimation.
The data includes:
Modes: When a pb contains multiple modes, each mode is listed, with
its power statistics.
Bufs/Wires: Power of all local buffers and local wire switching
(transistor-level estimation only).
Interc: Power of local interconnect multiplexers (transistor-
level estimation only)
Description of Estimation Methods:
Transistor Auto-Size: Transistor-level power estimation. Local buffers and
wire lengths are automatically sized. This is the default estimation
method.
Transistor Specify-Size: Transistor-level power estimation. Local buffers
and wire lengths are only inserted where specified by the user in the
architecture file.
Pin-Toggle: Dynamic power is calculated using enery-per-toggle of the PB
input pins. Static power is absolute.
C-Internal: Dynamic power is calculated using an internal equivalent
capacitance for PB type. Static power is absolute.
Absolute: Dynamic and static power are absolutes from the architecture file.
Sum of Children: Power of PB is only the sum of all child PBs; interconnect
between the PB and its children is ignored.
Ignore: Power of PB is ignored.
Component Power (W) %-Total %-Dynamic Method
io 0 0 -nan Ignore
clb 8.066e-05 0.2986 0.6884 Transistor Auto-Size
Bufs/Wires 1.43e-05 0.05294 0.2804
Interc: 8.462e-06 0.03133 0.542
crossbar0 3.015e-06 0.01116 0.5188
crossbar1 3.264e-06 0.01208 0.5568
crossbar2 1.076e-06 0.003984 0.5484
crossbar3 8.245e-07 0.003053 0.5364
crossbar4 0 0 -nan
crossbar5 0 0 -nan
clks 0 0 -nan
carry_in 2.821e-07 0.001045 0.6112
fle 5.79e-05 0.2144 0.8106 Transistor Auto-Size
Bufs/Wires 6.769e-06 0.02506 0.3446
Mode:fle_phy 3.361e-05 0.1244 0.9139
Interc: 0 0 -nan
direct_clk 0 0 -nan
mux1 0 0 -nan
mux2 0 0 -nan
frac_logic 3.388e-07 0.001254 0 Transistor Auto-Size
Bufs/Wires 3.388e-07 0.001254 0
Interc: 0 0 -nan
mux1 0 0 -nan
mux2 0 0 -nan
frac_lut6 0 0 -nan Transistor Auto-Size
Bufs/Wires 0 0 -nan
adder_phy 0 0 -nan Transistor Auto-Size
Bufs/Wires 0 0 -nan
ff_phy 3.327e-05 0.1232 0.9232 Transistor Auto-Size
Bufs/Wires 0 0 -nan
Mode:n2_lut5 1.741e-05 0.06444 0.7925
Interc: 0 0 -nan
lut5inter 1.741e-05 0.06444 0.7925 Transistor Auto-Size
Bufs/Wires 5.658e-07 0.002095 0.6977
Interc: 0 0 -nan
complete1 0 0 -nan
ble5 1.684e-05 0.06235 0.7956 Transistor Auto-Size
Bufs/Wires 0 0 -nan
Mode:blut5 1.12e-05 0.04146 0.8091
Interc: 0 0 -nan
flut5 1.12e-05 0.04146 0.8091 Transistor Auto-Size
Bufs/Wires 2.007e-07 0.000743 0.7628
Interc: 2.646e-07 0.0009797 0.684
mux1 2.646e-07 0.0009797 0.684
lut5 1.655e-06 0.006127 0.2417 Transistor Auto-Size
Bufs/Wires 0 0 -nan
Mode:wire 0 0 -nan
Interc: 0 0 -nan
complete:lut5 0 0 -nan
Mode:lut5 1.655e-06 0.006127 0.2417
Interc: 0 0 -nan
lut 1.655e-06 0.006127 0.2417 Transistor Auto-Size
Bufs/Wires 0 0 -nan
ff 9.079e-06 0.03361 0.9173 Transistor Auto-Size
Bufs/Wires 0 0 -nan
Mode:arithmetic 5.641e-06 0.02088 0.7689
Interc: 0 0 -nan
arithmetic 5.641e-06 0.02088 0.7689 Transistor Auto-Size
Bufs/Wires 3.732e-07 0.001382 0.7081
Interc: 1.399e-07 0.0005179 0.708
sumout 1.399e-07 0.0005179 0.708
lut4 7.913e-07 0.00293 0 Transistor Auto-Size
Bufs/Wires 0 0 -nan
Mode:wire 0 0 -nan
Interc: 0 0 -nan
complete:lut4 0 0 -nan
Mode:lut4 7.913e-07 0.00293 0
Interc: 0 0 -nan
lut 7.913e-07 0.00293 0 Transistor Auto-Size
Bufs/Wires 0 0 -nan
adder 0 0 -nan Transistor Auto-Size
Bufs/Wires 0 0 -nan
ff 4.336e-06 0.01606 0.9163 Transistor Auto-Size
Bufs/Wires 0 0 -nan
Mode:n1_lut6 0 0 -nan
Interc: 0 0 -nan
ble6 0 0 -nan Transistor Auto-Size
Bufs/Wires 0 0 -nan
Interc: 0 0 -nan
mux1 0 0 -nan
lut6 0 0 -nan Transistor Auto-Size
Bufs/Wires 0 0 -nan
Mode:wire 0 0 -nan
Interc: 0 0 -nan
complete:lut6 0 0 -nan
Mode:lut6 0 0 -nan
Interc: 0 0 -nan
lut 0 0 -nan Transistor Auto-Size
Bufs/Wires 0 0 -nan
ff 0 0 -nan Transistor Auto-Size
Bufs/Wires 0 0 -nan
Mode:shift_register 1.134e-07 0.0004199 0.7826
Interc: 0 0 -nan
ble_shift 1.134e-07 0.0004199 0.7826 Transistor Auto-Size
Bufs/Wires 1.134e-07 0.0004199 0.7826
Interc: 0 0 -nan
direct3 0 0 -nan
ff 0 0 -nan Transistor Auto-Size
Bufs/Wires 0 0 -nan

View File

@ -1,122 +0,0 @@
#!usr/bin/perl -w
use strict;
use Cwd;
#use Shell;
use FileHandle;
#Use the time
use Time::gmtime;
my $arch_file;
my $new_arch_file;
my $overwrite = "TRUE";
my $keyword = "OPENFPGAPATHKEYWORD";
my $folder_top = "OpenFPGA";
sub print_usage()
{
print "Usage:\n";
print " perl <script_name.pl> [-options]\n";
print " Options:(Mandatory!)\n";
print " -i <input_architecture_file_path>\n";
print " Options:(Optional)\n";
print " -o <output_architecture_file_path>\n";
print "\n";
return;
}
sub opts_read()
{
if ($#ARGV == -1){
print "Error: Not enough input argument!\n";
&print_usage();
exit(1);
} else {
for (my $iargv = 0; $iargv < $#ARGV+1; $iargv++){
if ("-i" eq $ARGV[$iargv]){
$arch_file = $ARGV[$iargv+1];
$iargv++;
} elsif ("-o" eq $ARGV[$iargv]){
$new_arch_file = $ARGV[$iargv+1];
$overwrite = "FALSE";
$iargv++;
} else {
die "WRONG ARGUMENT";
}
}
}
return;
}
sub rewriting_required_check($)
{
my ($arch) = @_;
open(F, $arch);
my @lines=<F>;
close F;
my $grep_result = grep ($keyword, @lines);
if($grep_result >= 1){
print "Rewrite needed\n";
return 1;
} else {
print "Rewrite NOT needed\n";
return 0;
}
}
sub save_original($)
{
my ($template) = @_;
my $renamed_template = "$template".".bak";
rename($template, $renamed_template);
return $renamed_template;
}
sub findPath(){
my $path;
my $dir = cwd;
my @folders = split("/", $dir);
for(my $count = 0; $count < ($#folders -1); $count++){
print "path fragment = $folders[$count]\n";
if($folders[$count] eq ""){
} else {
$path = "$path"."/"."$folders[$count]";
if($folders[$count] eq $folder_top){
print "$path\n";
return $path;
}
}
}
die "ERROR: Script launched from the outside of the $folder_top folder!\n";
}
sub rewrite_file($ $)
{
my ($arch, $template) = @_;
my $myPath = &findPath();
open(IN, '<'.$template);
open(OUT, '>'.$arch);
while(<IN>){
$_ =~ s/$keyword/$myPath/g;
print OUT $_;
}
return;
}
sub main()
{
&opts_read();
my $rewrite_needed = &rewriting_required_check($arch_file);
if($rewrite_needed == 1){
if($overwrite eq "true"){
my $template_file = &save_original($arch_file);
&rewrite_file($arch_file, $template_file);
} else {
&rewrite_file($new_arch_file, $arch_file);
}
}
return;
}
&main();
exit(1);

View File

@ -6,8 +6,12 @@ use FileHandle;
#Use the time
use Time::gmtime;
my $my_file;
my $arch_file;
my $new_arch_file;
my $overwrite = "TRUE";
my $keyword = "OPENFPGAPATHKEYWORD";
my $default_keyword = "TRUE";
my $change_to;
my $folder_top = "OpenFPGA";
sub print_usage()
@ -15,7 +19,10 @@ sub print_usage()
print "Usage:\n";
print " perl <script_name.pl> [-options]\n";
print " Options:(Mandatory!)\n";
print " -i <input_file_path>\n";
print " -i <input_architecture_file_path>\n";
print " Options:(Optional)\n";
print " -o <output_architecture_file_path>\n";
print " -k <keyword> <new_value>\n";
print "\n";
return;
}
@ -29,7 +36,17 @@ sub opts_read()
} else {
for (my $iargv = 0; $iargv < $#ARGV+1; $iargv++){
if ("-i" eq $ARGV[$iargv]){
$my_file = $ARGV[$iargv+1];
$arch_file = $ARGV[$iargv+1];
$iargv++;
} elsif ("-o" eq $ARGV[$iargv]){
$new_arch_file = $ARGV[$iargv+1];
$overwrite = "FALSE";
$iargv++;
} elsif ("-k" eq $ARGV[$iargv]){
$keyword = $ARGV[$iargv+1];
$change_to = $ARGV[$iargv+2];
$default_keyword = "FALSE";
$iargv++;
$iargv++;
} else {
die "WRONG ARGUMENT";
@ -41,8 +58,8 @@ sub opts_read()
sub rewriting_required_check($)
{
my ($file) = @_;
open(F, $file);
my ($arch) = @_;
open(F, $arch);
my @lines=<F>;
close F;
my $grep_result = grep ($keyword, @lines);
@ -68,7 +85,7 @@ sub findPath(){
my $path;
my $dir = cwd;
my @folders = split("/", $dir);
for(my $count = 0; $count < $#folders; $count++){
for(my $count = 0; $count < ($#folders -1); $count++){
if($folders[$count] eq ""){
} else {
$path = "$path"."/"."$folders[$count]";
@ -81,15 +98,23 @@ sub findPath(){
die "ERROR: Script launched from the outside of the $folder_top folder!\n";
}
sub create_new($ $)
sub rewrite_file($ $)
{
my ($file, $template) = @_;
my $myPath = &findPath();
my ($arch, $template) = @_;
open(IN, '<'.$template);
open(OUT, '>'.$file);
while(<IN>){
$_ =~ s/$keyword/$myPath/g;
print OUT $_;
open(OUT, '>'.$arch);
if($default_keyword eq "TRUE"){
my $myPath = &findPath();
while(<IN>){
$_ =~ s/$keyword/$myPath/g;
print OUT $_;
}
} else {
while(<IN>){
$_ =~ s/$keyword/$change_to/g;
print OUT $_;
}
}
return;
}
@ -97,12 +122,17 @@ sub create_new($ $)
sub main()
{
&opts_read();
my $rewrite_needed = &rewriting_required_check($my_file);
my $rewrite_needed = &rewriting_required_check($arch_file);
if($rewrite_needed == 1){
my $template_file = &save_original($my_file);
&create_new($my_file, $template_file);
if($overwrite eq "TRUE"){
my $template_file = &save_original($arch_file);
&rewrite_file($arch_file, $template_file);
} else {
&rewrite_file($new_arch_file, $arch_file);
}
}
return;
}
&main();
exit(1);

10
libs/CMakeLists.txt Normal file
View File

@ -0,0 +1,10 @@
#VTR developed libraries
#add_subdirectory(libarchfpga)
add_subdirectory(libvtrutil)
add_subdirectory(liblog)
#add_subdirectory(libpugiutil)
#add_subdirectory(libeasygl)
#add_subdirectory(librtlnumber)
#Externally developed libraries
#add_subdirectory(EXTERNAL)

View File

@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 2.8.12)
project("liblog")
file(GLOB_RECURSE EXEC_SOURCES src/main.cpp)
file(GLOB_RECURSE LIB_SOURCES src/*.cpp)
file(GLOB_RECURSE LIB_HEADERS src/*.h)
files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS)
#Remove test executable from library
list(REMOVE_ITEM LIB_SOURCES ${EXEC_SOURCES})
#Create the library
add_library(liblog STATIC
${LIB_HEADERS}
${LIB_SOURCES})
target_include_directories(liblog PUBLIC ${LIB_INCLUDE_DIRS})
set_target_properties(liblog PROPERTIES PREFIX "") #Avoid extra 'lib' prefix
#Create the test executable
add_executable(test_log ${EXEC_SOURCES})
target_link_libraries(test_log liblog)
install(TARGETS test_log liblog DESTINATION bin)

21
libs/liblog/LICENSE.txt Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Jason Luu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

13
libs/liblog/Readme.txt Normal file
View File

@ -0,0 +1,13 @@
Simple Logger Library
Author: Jason Luu
Date: Sept 5, 2014
This library provides simple logging operations.
- Output messages to both file and terminal
- Tag messages based on feedback type (eg. info, warning, or error)
- Track number of warnings and errors
Specialized programming knowledge:
- Requires usage of variable arguments in <stdarg.h> standard C library to properly wrap printf and fprintf

121
libs/liblog/src/log.cpp Normal file
View File

@ -0,0 +1,121 @@
/**
* Lightweight logging tool. Automatically prepend messages with prefixes and store in log file.
*
* Author: Jason Luu
* Date: Sept 5, 2014
*/
#include <stdio.h>
#include <stdarg.h> /* Allows for variable arguments, necessary for wrapping printf */
#include "log.h"
#define LOG_DEFAULT_FILE_NAME "output.log"
static int log_warning = 0;
static int log_error = 0;
FILE *log_stream = nullptr;
static void check_init();
/* Set the output file of logger.
If different than current log file, close current log file and reopen to new log file
*/
void log_set_output_file(const char *filename) {
if(log_stream != nullptr) {
fclose(log_stream);
}
if (filename == nullptr) {
log_stream = nullptr;
} else {
log_stream = fopen(filename, "w");
if(log_stream == nullptr) {
printf("Error writing to file %s\n\n", filename);
}
}
}
void log_print_direct(const char* message, ...) {
va_list args;
va_start(args, message);
vprintf(message, args);
va_end(args);
}
void log_print_info(const char* message, ...) {
check_init(); /* Check if output log file setup, if not, then this function also sets it up */
va_list args;
va_start(args, message);
vprintf(message, args);
va_end(args);
if (log_stream) {
va_start(args, message); /* Must reset variable arguments so that they can be read again */
vfprintf(log_stream, message, args);
va_end(args);
fflush(log_stream);
}
}
void log_print_warning(const char* /*filename*/, unsigned int /*line_num*/, const char* message, ...) {
check_init(); /* Check if output log file setup, if not, then this function also sets it up */
va_list args;
va_start(args, message);
log_warning++;
printf("Warning %d: ", log_warning);
vprintf(message, args);
va_end(args);
if (log_stream) {
va_start(args, message); /* Must reset variable arguments so that they can be read again */
fprintf(log_stream, "Warning %d: ", log_warning);
vfprintf(log_stream, message, args);
va_end(args);
fflush(log_stream);
}
}
void log_print_error(const char* /*filename*/, unsigned int /*line_num*/, const char* message, ...) {
check_init(); /* Check if output log file setup, if not, then this function also sets it up */
va_list args;
va_start(args, message);
log_error++;
check_init();
fprintf(stderr, "Error %d: ", log_error);
vfprintf(stderr, message, args);
va_end(args);
if (log_stream) {
va_start(args, message); /* Must reset variable arguments so that they can be read again */
fprintf(log_stream, "Error %d: ", log_error);
vfprintf(log_stream, message, args);
va_end(args);
fflush(log_stream);
}
}
/**
* Check if output log file setup, if not, then this function also sets it up
*/
static void check_init() {
//We now allow a nullptr log_stream (i.e. no log file) so nothing to do here
}
void log_close() {
if (log_stream) {
fclose(log_stream);
}
}

22
libs/liblog/src/log.h Normal file
View File

@ -0,0 +1,22 @@
/**
* Lightweight logging tool. Automatically prepend messages with prefixes and store in log file.
*
* Init/Change name of log file using log_set_output_file, when done, call log_close
*
* Author: Jason Luu
* Date: Sept 5, 2014
*/
#ifndef LOG_H
#define LOG_H
void log_set_output_file(const char *filename);
void log_print_direct(const char* message, ...);
void log_print_info(const char* message, ...);
void log_print_warning(const char* filename, unsigned int line_num, const char* message, ...);
void log_print_error(const char* filename, unsigned int line_num, const char* message, ...);
void log_close();
#endif

18
libs/liblog/src/main.cpp Normal file
View File

@ -0,0 +1,18 @@
/** Jason Luu
* Test program for logger
*/
#include "log.h"
int main() {
int x = 10, y = 20;
float a = 1.5f, b = -2.01f;
log_print_info("Testing logger\n\n");
log_print_info("Output separate strings: %s %s\n", "pass", "[PASS]");
log_print_info("Output two integers: x = %d y = %d\n", x, y);
log_print_warning(__FILE__, __LINE__, "Test warning on floating point arguments %g %g\n", a, b);
log_print_error(__FILE__, __LINE__, "Test error on two variables %g %g \n\n", a - x, b + y);
log_print_info("Test complete\n");
return 0;
}

View File

@ -0,0 +1,91 @@
cmake_minimum_required(VERSION 2.8.12)
project("libvtrutil")
#Version info
set(VTR_VERSION_FILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/src/vtr_version.cpp.in)
set(VTR_VERSION_FILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/vtr_version.cpp)
#Compiler info
set(VTR_COMPILER_INFO "${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} on ${CMAKE_SYSTEM} ${CMAKE_SYSTEM_PROCESSOR}")
#Set default version numbers in case not specified
if(NOT DEFINED VTR_VERSION_MAJOR)
set(VTR_VERSION_MAJOR 0)
endif()
if(NOT DEFINED VTR_VERSION_MINOR)
set(VTR_VERSION_MINOR 0)
endif()
if(NOT DEFINED VTR_VERSION_PATCH)
set(VTR_VERSION_PATCH 0)
endif()
# We always update the vtr_version.cpp file every time the project is built,
# to ensure the git revision and dirty status are up to date.
#
# We need to do this in two stages:
#
# 1) We a custom target 'version' (which is always out of date) so it will always be run.
# It touches the unprocessed version input file so it too will always be out of date.
#
# 2) The custom command depends on the touched version input file and generates the processed
# version file, with updated values. The custom command uses the configure_version.cmake
# script to generate the up-to-date vtr_version.cpp
add_custom_target(version ALL
COMMAND ${CMAKE_COMMAND} -E touch ${VTR_VERSION_FILE_IN})
add_custom_command(OUTPUT ${VTR_VERSION_FILE_OUT}
COMMAND ${CMAKE_COMMAND}
-D IN_FILE=${VTR_VERSION_FILE_IN}
-D OUT_FILE=${VTR_VERSION_FILE_OUT}
-D VTR_VERSION_MAJOR=${VTR_VERSION_MAJOR}
-D VTR_VERSION_MINOR=${VTR_VERSION_MINOR}
-D VTR_VERSION_PATCH=${VTR_VERSION_PATCH}
-D VTR_VERSION_PRERELEASE=${VTR_VERSION_PRERELEASE}
-D VTR_COMPILER_INFO=${VTR_COMPILER_INFO}
-D VTR_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/configure_version.cmake
MAIN_DEPENDENCY ${VTR_VERSION_FILE_IN}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
VERBATIM)
#
# Source files and library
#
file(GLOB_RECURSE LIB_SOURCES src/*.cpp)
file(GLOB_RECURSE LIB_HEADERS src/*.hpp src/*.h)
files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS)
#Add the version file to the sources
list(APPEND LIB_SOURCES ${VTR_VERSION_FILE_OUT})
#Create the library
add_library(libvtrutil STATIC
${LIB_HEADERS}
${LIB_SOURCES})
target_include_directories(libvtrutil PUBLIC ${LIB_INCLUDE_DIRS})
set_target_properties(libvtrutil PROPERTIES PREFIX "") #Avoid extra 'lib' prefix
#Ensure version is always up to date by requiring version to be run first
add_dependencies(libvtrutil version)
#Specify link-time dependancies
target_link_libraries(libvtrutil
liblog)
install(TARGETS libvtrutil DESTINATION bin)
#
# Unit Tests
#
#file(GLOB_RECURSE TEST_SOURCES test/*.cpp)
#add_executable(test_vtrutil ${TEST_SOURCES})
#target_link_libraries(test_vtrutil
# libvtrutil
# libcatch)
#add_test(NAME test_vtrutil COMMAND test_vtrutil --use-colour=yes)

View File

@ -0,0 +1,40 @@
#
# Versioning information
#
#Figure out the git revision
find_package(Git QUIET)
if(GIT_FOUND)
exec_program(${GIT_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}
ARGS describe --always --long --dirty
OUTPUT_VARIABLE VTR_VCS_REVISION
RETURN_VALUE GIT_DESCRIBE_RETURN_VALUE)
if(NOT GIT_DESCRIBE_RETURN_VALUE EQUAL 0)
#Git describe failed, usually this means we
#aren't in a git repo -- so don't set a VCS
#revision
set(VTR_VCS_REVISION "unkown")
endif()
else()
#Couldn't find git, so can't look-up VCS revision
set(VTR_VCS_REVISION "unkown")
endif()
#Set the version according to semver.org
set(VTR_VERSION "${VTR_VERSION_MAJOR}.${VTR_VERSION_MINOR}.${VTR_VERSION_PATCH}")
if(VTR_VERSION_PRERELEASE)
set(VTR_VERSION "${VTR_VERSION}-${VTR_VERSION_PRERELEASE}")
endif()
set(VTR_VERSION_SHORT ${VTR_VERSION})
if(VTR_VCS_REVISION)
set(VTR_VERSION "${VTR_VERSION}+${VTR_VCS_REVISION}")
endif()
#Other build meta-data
string(TIMESTAMP VTR_BUILD_TIMESTAMP)
set(VTR_BUILD_TIMESTAMP "${VTR_BUILD_TIMESTAMP} (${VTR_BUILD_TYPE} build)")
message(STATUS "VTR Version: ${VTR_VERSION}")
configure_file(${IN_FILE} ${OUT_FILE})

View File

@ -0,0 +1,366 @@
/*
The MIT License (MIT)
Copyright (C) 2014 okdshin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef PICOSHA2_H
#define PICOSHA2_H
//picosha2:20140213
#include <iostream>
#include <vector>
#include <iterator>
#include <cassert>
#include <sstream>
#include <algorithm>
namespace picosha2
{
typedef unsigned long word_t;
typedef unsigned char byte_t;
namespace detail
{
inline byte_t mask_8bit(byte_t x){
return x&0xff;
}
inline word_t mask_32bit(word_t x){
return x&0xffffffff;
}
const word_t add_constant[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
const word_t initial_message_digest[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
inline word_t ch(word_t x, word_t y, word_t z){
return (x&y)^((~x)&z);
}
inline word_t maj(word_t x, word_t y, word_t z){
return (x&y)^(x&z)^(y&z);
}
inline word_t rotr(word_t x, std::size_t n){
assert(n < 32);
return mask_32bit((x>>n)|(x<<(32-n)));
}
inline word_t bsig0(word_t x){
return rotr(x, 2)^rotr(x, 13)^rotr(x, 22);
}
inline word_t bsig1(word_t x){
return rotr(x, 6)^rotr(x, 11)^rotr(x, 25);
}
inline word_t shr(word_t x, std::size_t n){
assert(n < 32);
return x >> n;
}
inline word_t ssig0(word_t x){
return rotr(x, 7)^rotr(x, 18)^shr(x, 3);
}
inline word_t ssig1(word_t x){
return rotr(x, 17)^rotr(x, 19)^shr(x, 10);
}
template<typename RaIter1, typename RaIter2>
void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 /*last*/){
word_t w[64];
std::fill(w, w+64, 0);
for(std::size_t i = 0; i < 16; ++i){
w[i] = (static_cast<word_t>(mask_8bit(*(first+i*4)))<<24)
|(static_cast<word_t>(mask_8bit(*(first+i*4+1)))<<16)
|(static_cast<word_t>(mask_8bit(*(first+i*4+2)))<<8)
|(static_cast<word_t>(mask_8bit(*(first+i*4+3))));
}
for(std::size_t i = 16; i < 64; ++i){
w[i] = mask_32bit(ssig1(w[i-2])+w[i-7]+ssig0(w[i-15])+w[i-16]);
}
word_t a = *message_digest;
word_t b = *(message_digest+1);
word_t c = *(message_digest+2);
word_t d = *(message_digest+3);
word_t e = *(message_digest+4);
word_t f = *(message_digest+5);
word_t g = *(message_digest+6);
word_t h = *(message_digest+7);
for(std::size_t i = 0; i < 64; ++i){
word_t temp1 = h+bsig1(e)+ch(e,f,g)+add_constant[i]+w[i];
word_t temp2 = bsig0(a)+maj(a,b,c);
h = g;
g = f;
f = e;
e = mask_32bit(d+temp1);
d = c;
c = b;
b = a;
a = mask_32bit(temp1+temp2);
}
*message_digest += a;
*(message_digest+1) += b;
*(message_digest+2) += c;
*(message_digest+3) += d;
*(message_digest+4) += e;
*(message_digest+5) += f;
*(message_digest+6) += g;
*(message_digest+7) += h;
for(std::size_t i = 0; i < 8; ++i){
*(message_digest+i) = mask_32bit(*(message_digest+i));
}
}
}//namespace detail
template<typename InIter>
void output_hex(InIter first, InIter last, std::ostream& os){
std::ios::fmtflags orig_flags = os.flags();
std::streamsize orig_width = os.width();
char orig_fill = os.fill();
os.setf(std::ios::hex, std::ios::basefield);
while(first != last){
os.width(2);
os.fill('0');
os << static_cast<unsigned int>(*first);
++first;
}
os.flags(orig_flags);
os.fill(orig_fill);
os.width(orig_width);
}
template<typename InIter>
void bytes_to_hex_string(InIter first, InIter last, std::string& hex_str){
std::ostringstream oss;
output_hex(first, last, oss);
hex_str.assign(oss.str());
}
template<typename InContainer>
void bytes_to_hex_string(const InContainer& bytes, std::string& hex_str){
bytes_to_hex_string(bytes.begin(), bytes.end(), hex_str);
}
template<typename InIter>
std::string bytes_to_hex_string(InIter first, InIter last){
std::string hex_str;
bytes_to_hex_string(first, last, hex_str);
return hex_str;
}
template<typename InContainer>
std::string bytes_to_hex_string(const InContainer& bytes){
std::string hex_str;
bytes_to_hex_string(bytes, hex_str);
return hex_str;
}
class hash256_one_by_one {
public:
hash256_one_by_one(){
init();
}
void init(){
buffer_.clear();
std::fill(data_length_digits_, data_length_digits_+4, 0);
std::copy(detail::initial_message_digest, detail::initial_message_digest+8, h_);
}
template<typename RaIter>
void process(RaIter first, RaIter last){
add_to_data_length(std::distance(first, last));
std::copy(first, last, std::back_inserter(buffer_));
std::size_t i = 0;
for(;i+64 <= buffer_.size(); i+=64){
detail::hash256_block(h_, buffer_.begin()+i, buffer_.begin()+i+64);
}
buffer_.erase(buffer_.begin(), buffer_.begin()+i);
}
void finish(){
byte_t temp[64];
std::fill(temp, temp+64, 0);
std::size_t remains = buffer_.size();
std::copy(buffer_.begin(), buffer_.end(), temp);
temp[remains] = 0x80;
if(remains > 55){
std::fill(temp+remains+1, temp+64, 0);
detail::hash256_block(h_, temp, temp+64);
std::fill(temp, temp+64-4, 0);
}
else {
std::fill(temp+remains+1, temp+64-4, 0);
}
write_data_bit_length(&(temp[56]));
detail::hash256_block(h_, temp, temp+64);
}
template<typename OutIter>
void get_hash_bytes(OutIter first, OutIter last)const{
for(const word_t* iter = h_; iter != h_+8; ++iter){
for(std::size_t i = 0; i < 4 && first != last; ++i){
*(first++) = detail::mask_8bit(static_cast<byte_t>((*iter >> (24-8*i))));
}
}
}
private:
void add_to_data_length(word_t n) {
word_t carry = 0;
data_length_digits_[0] += n;
for(std::size_t i = 0; i < 4; ++i) {
data_length_digits_[i] += carry;
if(data_length_digits_[i] >= 65536u) {
carry = data_length_digits_[i]>>16;
data_length_digits_[i] &= 65535u;
}
else {
break;
}
}
}
void write_data_bit_length(byte_t* begin) {
word_t data_bit_length_digits[4];
std::copy(
data_length_digits_, data_length_digits_+4,
data_bit_length_digits
);
// convert byte length to bit length (multiply 8 or shift 3 times left)
word_t carry = 0;
for(std::size_t i = 0; i < 4; ++i) {
word_t before_val = data_bit_length_digits[i];
data_bit_length_digits[i] <<= 3;
data_bit_length_digits[i] |= carry;
data_bit_length_digits[i] &= 65535u;
carry = (before_val >> (16-3)) & 65535u;
}
// write data_bit_length
for(int i = 3; i >= 0; --i) {
(*begin++) = static_cast<byte_t>(data_bit_length_digits[i] >> 8);
(*begin++) = static_cast<byte_t>(data_bit_length_digits[i]);
}
}
std::vector<byte_t> buffer_;
word_t data_length_digits_[4]; //as 64bit integer (16bit x 4 integer)
word_t h_[8];
};
inline void get_hash_hex_string(const hash256_one_by_one& hasher, std::string& hex_str){
byte_t hash[32];
hasher.get_hash_bytes(hash, hash+32);
return bytes_to_hex_string(hash, hash+32, hex_str);
}
inline std::string get_hash_hex_string(const hash256_one_by_one& hasher){
std::string hex_str;
get_hash_hex_string(hasher, hex_str);
return hex_str;
}
template<typename RaIter, typename OutIter>
void hash256(RaIter first, RaIter last, OutIter first2, OutIter last2){
hash256_one_by_one hasher;
//hasher.init();
hasher.process(first, last);
hasher.finish();
hasher.get_hash_bytes(first2, last2);
}
template<typename RaIter, typename OutContainer>
void hash256(RaIter first, RaIter last, OutContainer& dst){
hash256(first, last, dst.begin(), dst.end());
}
template<typename RaContainer, typename OutIter>
void hash256(const RaContainer& src, OutIter first, OutIter last){
hash256(src.begin(), src.end(), first, last);
}
template<typename RaContainer, typename OutContainer>
void hash256(const RaContainer& src, OutContainer& dst){
hash256(src.begin(), src.end(), dst.begin(), dst.end());
}
template<typename RaIter>
void hash256_hex_string(RaIter first, RaIter last, std::string& hex_str){
byte_t hashed[32];
hash256(first, last, hashed, hashed+32);
std::ostringstream oss;
output_hex(hashed, hashed+32, oss);
hex_str.assign(oss.str());
}
template<typename RaIter>
std::string hash256_hex_string(RaIter first, RaIter last){
std::string hex_str;
hash256_hex_string(first, last, hex_str);
return hex_str;
}
inline void hash256_hex_string(const std::string& src, std::string& hex_str){
hash256_hex_string(src.begin(), src.end(), hex_str);
}
template<typename RaContainer>
void hash256_hex_string(const RaContainer& src, std::string& hex_str){
hash256_hex_string(src.begin(), src.end(), hex_str);
}
template<typename RaContainer>
std::string hash256_hex_string(const RaContainer& src){
return hash256_hex_string(src.begin(), src.end());
}
}//namespace picosha2
#endif //PICOSHA2_H

View File

@ -0,0 +1,21 @@
#include "vtr_assert.h"
#include <cstdio> //fprintf, stderr
#include <cstdlib> //abort
namespace vtr { namespace assert {
void handle_assert(const char* expr, const char* file, unsigned int line, const char* function, const char* msg) {
fprintf(stderr, "%s:%d", file, line);
if(function) {
fprintf(stderr, " %s:", function);
}
fprintf(stderr, " Assertion '%s' failed", expr);
if(msg) {
fprintf(stderr, " (%s)", msg);
}
fprintf(stderr, ".\n");
std::abort();
}
}} //namespace

View File

@ -0,0 +1,133 @@
#ifndef VTR_ASSERT_H
#define VTR_ASSERT_H
/*
* The header defines useful assertion macros for VTR projects.
*
* Three types of assertions are defined:
* VTR_ASSERT_OPT - low overhead assertions that should always be enabled
* VTR_ASSERT - medium overhead assertions that are usually be enabled
* VTR_ASSERT_SAFE - high overhead assertions typically enabled only for debugging
* VTR_ASSERT_DEBUG - very high overhead assertions typically enabled only for extreme debugging
* Each of the above assertions also have a *_MSG variants (e.g. VTR_ASSERT_MSG(expr, msg))
* which takes an additional argument specifying additional message text to be shown.
* By convention the message should state the condition *being checked* (and not the failure condition),
* since that the condition failed is obvious from the assertion failure itself.
*
* The macro VTR_ASSERT_LEVEL specifies the level of assertion checking desired:
*
* VTR_ASSERT_LEVEL == 4: VTR_ASSERT_OPT, VTR_ASSERT, VTR_ASSERT_SAFE, VTR_ASSERT_DEBUG enabled
* VTR_ASSERT_LEVEL == 3: VTR_ASSERT_OPT, VTR_ASSERT, VTR_ASSERT_SAFE enabled
* VTR_ASSERT_LEVEL == 2: VTR_ASSERT_OPT, VTR_ASSERT enabled
* VTR_ASSERT_LEVEL == 1: VTR_ASSERT_OPT enabled
* VTR_ASSERT_LEVEL == 0: No assertion checking enabled
* Note that an assertion levels beyond 4 are currently treated the same as level 4
*/
//Set a default assertion level if none is specified
#ifndef VTR_ASSERT_LEVEL
# define VTR_ASSERT_LEVEL 2
#endif
//Enable the assertions based on the specified level
#if VTR_ASSERT_LEVEL >= 4
# define VTR_ASSERT_DEBUG_ENABLED
#endif
#if VTR_ASSERT_LEVEL >= 3
# define VTR_ASSERT_SAFE_ENABLED
#endif
#if VTR_ASSERT_LEVEL >= 2
#define VTR_ASSERT_ENABLED
#endif
#if VTR_ASSERT_LEVEL >= 1
# define VTR_ASSERT_OPT_ENABLED
#endif
//Define the user assertion macros
#ifdef VTR_ASSERT_DEBUG_ENABLED
# define VTR_ASSERT_DEBUG(expr) VTR_ASSERT_IMPL(expr, nullptr)
# define VTR_ASSERT_DEBUG_MSG(expr, msg) VTR_ASSERT_IMPL(expr, msg)
#else
# define VTR_ASSERT_DEBUG(expr) VTR_ASSERT_IMPL_NOP(expr, nullptr)
# define VTR_ASSERT_DEBUG_MSG(expr, msg) VTR_ASSERT_IMPL_NOP(expr, msg)
#endif
#ifdef VTR_ASSERT_SAFE_ENABLED
# define VTR_ASSERT_SAFE(expr) VTR_ASSERT_IMPL(expr, nullptr)
# define VTR_ASSERT_SAFE_MSG(expr, msg) VTR_ASSERT_IMPL(expr, msg)
#else
# define VTR_ASSERT_SAFE(expr) VTR_ASSERT_IMPL_NOP(expr, nullptr)
# define VTR_ASSERT_SAFE_MSG(expr, msg) VTR_ASSERT_IMPL_NOP(expr, msg)
#endif
#ifdef VTR_ASSERT_ENABLED
# define VTR_ASSERT(expr) VTR_ASSERT_IMPL(expr, nullptr)
# define VTR_ASSERT_MSG(expr, msg) VTR_ASSERT_IMPL(expr, msg)
#else
# define VTR_ASSERT(expr) VTR_ASSERT_IMPL_NOP(expr, nullptr)
# define VTR_ASSERT_MSG(expr, msg) VTR_ASSERT_IMPL_NOP(expr, msg)
#endif
#ifdef VTR_ASSERT_OPT_ENABLED
# define VTR_ASSERT_OPT(expr) VTR_ASSERT_IMPL(expr, nullptr)
# define VTR_ASSERT_OPT_MSG(expr, msg) VTR_ASSERT_IMPL(expr, msg)
#else
# define VTR_ASSERT_OPT(expr) VTR_ASSERT_IMPL_NOP(expr, nullptr)
# define VTR_ASSERT_OPT_MSG(expr, msg) VTR_ASSERT_IMPL_NOP(expr, msg)
#endif
//Define the assertion implementation macro
// We wrap the check in a do {} while() to ensure the function-like
// macro can be always be followed by a ';'
#define VTR_ASSERT_IMPL(expr, msg) do { \
if(!(expr)) { \
vtr::assert::handle_assert(#expr, __FILE__, __LINE__, VTR_ASSERT_FUNCTION, msg); \
} \
} while(false)
//Define the no-op assertion implementation macro
// We wrap the check in a do {} while() to ensure the function-like
// macro can be always be followed by a ';'
//
// Note that to avoid 'unused' variable warnings when assertions are
// disabled, we pass the expr and msg to sizeof(). We use sizeof specifically
// since it accepts expressions, and the C++ standard gaurentees sizeof's arguments
// are never evaluated (ensuring any expensive expressions are not evaluated when
// assertions are disabled). To avoid warnings about the unused result of sizeof()
// we cast it to void.
#define VTR_ASSERT_IMPL_NOP(expr, msg) do { \
static_cast<void>(sizeof(expr)); \
static_cast<void>(sizeof(msg)); \
} while(false)
//Figure out what macro to use to get the name of the current function
// We default to __func__ which is defined in C99
//
// g++ > 2.6 define __PRETTY_FUNC__ which includes class/namespace/overload
// information, so we prefer to use it if possible
#define VTR_ASSERT_FUNCTION __func__
#ifdef __GNUC__
# ifdef __GNUC_MINOR__
# if __GNUC__ >= 2 && __GNUC_MINOR__ > 6
# undef VTR_ASSERT_FUNCTION
# define VTR_ASSERT_FUNCTION __PRETTY_FUNCTION__
# endif
# endif
#endif
namespace vtr { namespace assert {
//Assertion handling routine
//
//Note that we mark the routine with the standard C++11
//attribute 'noreturn' which tells the compiler this
//function will never return. This should ensure the
//compiler won't warn about detected conditions such as
//dead-code or potential null pointer dereferences
//which are gaurded against by assertions.
[[noreturn]] void handle_assert(const char* expr, const char* file, unsigned int line, const char* function, const char* msg);
}} //namespace
#endif //VTR_ASSERT_H

View File

@ -0,0 +1,142 @@
#ifndef VTR_BIMAP
#define VTR_BIMAP
#include <map>
#include <unordered_map>
#include "vtr_flat_map.h"
#include "vtr_linear_map.h"
#include "vtr_error.h"
namespace vtr {
/*
* A map-like class which provides a bi-directonal mapping between key and value
*
* Keys and values can be looked up directly by passing either the key or value.
* the indexing operator will throw if the key/value does not exist.
*/
template<class K, class V, template<typename ...> class Map=std::map, template<typename ...> class InvMap=std::map>
class bimap {
public: //Public types
typedef typename Map<K,V>::const_iterator iterator;
typedef typename InvMap<V,K>::const_iterator inverse_iterator;
public: //Accessors
//Iterators
iterator begin() const { return map_.begin(); }
iterator end() const { return map_.end(); }
inverse_iterator inverse_begin() const { return inverse_map_.begin(); }
inverse_iterator inverse_end() const { return inverse_map_.end(); }
//Return an iterator to the key-value pair matching key, or end() if not found
iterator find(const K key) const {
return map_.find(key);
}
//Return an iterator to the value-key pair matching value, or inverse_end() if not found
inverse_iterator find(const V value) const {
return inverse_map_.find(value);
}
//Return an immutable reference to the value matching key
//Will throw an exception if key is not found
const V& operator[] (const K key) const {
auto iter = find(key);
if(iter == end()) {
throw VtrError("Invalid bimap key during look-up", __FILE__, __LINE__);
}
return iter->second;
}
//Return an immutable reference to the key matching value
//Will throw an exception if value is not found
const K& operator[] (const V value) const {
auto iter = find(value);
if(iter == inverse_end()) {
throw VtrError("Invalid bimap value during inverse look-up", __FILE__, __LINE__);
}
return iter->second;
}
//Return the number of key-value pairs stored
std::size_t size() const { VTR_ASSERT(map_.size() == inverse_map_.size()); return map_.size(); }
//Return true if there are no key-value pairs stored
bool empty() const { return (size() == 0); }
//Return true if the specified key exists
bool contains(const K key) const { return find(key) != end(); }
//Return true if the specified value exists
bool contains(const V value) const { return find(value) != inverse_end(); }
public: //Mutators
//Drop all stored key-values
void clear() { map_.clear(); inverse_map_.clear(); }
//Insert a key-value pair, if not already in map
std::pair<iterator,bool> insert(const K key, const V value) {
auto ret1 = map_.insert({key,value});
auto ret2 = inverse_map_.insert({value,key});
VTR_ASSERT(ret1.second == ret2.second);
//Return true if inserted
return ret1;
}
//Update a key-value pair, will insert if not already in map
void update(const K key, const V value) {
map_[key] = value;
inverse_map_[value] = key;
}
//Remove the specified key (and it's associated value)
void erase(const K key) {
auto iter = map_.find(key);
if(iter != map_.end()) {
V val = iter->second;
map_.erase(iter);
auto inv_iter = inverse_map_.find(val);
VTR_ASSERT(inv_iter != inverse_map_.end());
inverse_map_.erase(inv_iter);
}
}
//Remove the specified value (and it's associated key)
void erase(const V val) {
auto inv_iter = inverse_map_.find(val);
if(inv_iter != inverse_map_.end()) {
K key = inv_iter->second;
inverse_map_.erase(inv_iter);
auto iter = map_.find(key);
VTR_ASSERT(iter != map_.end());
map_.erase(iter);
}
}
//Swap (this enables std::swap via ADL)
friend void swap(bimap<K,V,Map,InvMap>& x, bimap<K,V,Map,InvMap>& y) {
std::swap(x.map_, y.map_);
std::swap(x.inverse_map_, y.inverse_map_);
}
private:
Map<K,V> map_;
InvMap<V,K> inverse_map_;
};
template<class K, class V>
using unordered_bimap = bimap<K,V,std::unordered_map,std::unordered_map>;
template<class K, class V>
using flat_bimap = bimap<K,V,vtr::flat_map,vtr::flat_map>;
template<class K, class V>
using linear_bimap = bimap<K,V,vtr::linear_map,vtr::linear_map>;
}
#endif

View File

@ -0,0 +1,831 @@
#include <cmath>
#include <cstddef>
#include "vtr_color_map.h"
#include "vtr_assert.h"
namespace vtr {
//Inferno data from MatPlotLib
static std::vector<Color<float>> inferno_data = {
{0.001462f, 0.000466f, 0.013866f},
{0.002267f, 0.001270f, 0.018570f},
{0.003299f, 0.002249f, 0.024239f},
{0.004547f, 0.003392f, 0.030909f},
{0.006006f, 0.004692f, 0.038558f},
{0.007676f, 0.006136f, 0.046836f},
{0.009561f, 0.007713f, 0.055143f},
{0.011663f, 0.009417f, 0.063460f},
{0.013995f, 0.011225f, 0.071862f},
{0.016561f, 0.013136f, 0.080282f},
{0.019373f, 0.015133f, 0.088767f},
{0.022447f, 0.017199f, 0.097327f},
{0.025793f, 0.019331f, 0.105930f},
{0.029432f, 0.021503f, 0.114621f},
{0.033385f, 0.023702f, 0.123397f},
{0.037668f, 0.025921f, 0.132232f},
{0.042253f, 0.028139f, 0.141141f},
{0.046915f, 0.030324f, 0.150164f},
{0.051644f, 0.032474f, 0.159254f},
{0.056449f, 0.034569f, 0.168414f},
{0.061340f, 0.036590f, 0.177642f},
{0.066331f, 0.038504f, 0.186962f},
{0.071429f, 0.040294f, 0.196354f},
{0.076637f, 0.041905f, 0.205799f},
{0.081962f, 0.043328f, 0.215289f},
{0.087411f, 0.044556f, 0.224813f},
{0.092990f, 0.045583f, 0.234358f},
{0.098702f, 0.046402f, 0.243904f},
{0.104551f, 0.047008f, 0.253430f},
{0.110536f, 0.047399f, 0.262912f},
{0.116656f, 0.047574f, 0.272321f},
{0.122908f, 0.047536f, 0.281624f},
{0.129285f, 0.047293f, 0.290788f},
{0.135778f, 0.046856f, 0.299776f},
{0.142378f, 0.046242f, 0.308553f},
{0.149073f, 0.045468f, 0.317085f},
{0.155850f, 0.044559f, 0.325338f},
{0.162689f, 0.043554f, 0.333277f},
{0.169575f, 0.042489f, 0.340874f},
{0.176493f, 0.041402f, 0.348111f},
{0.183429f, 0.040329f, 0.354971f},
{0.190367f, 0.039309f, 0.361447f},
{0.197297f, 0.038400f, 0.367535f},
{0.204209f, 0.037632f, 0.373238f},
{0.211095f, 0.037030f, 0.378563f},
{0.217949f, 0.036615f, 0.383522f},
{0.224763f, 0.036405f, 0.388129f},
{0.231538f, 0.036405f, 0.392400f},
{0.238273f, 0.036621f, 0.396353f},
{0.244967f, 0.037055f, 0.400007f},
{0.251620f, 0.037705f, 0.403378f},
{0.258234f, 0.038571f, 0.406485f},
{0.264810f, 0.039647f, 0.409345f},
{0.271347f, 0.040922f, 0.411976f},
{0.277850f, 0.042353f, 0.414392f},
{0.284321f, 0.043933f, 0.416608f},
{0.290763f, 0.045644f, 0.418637f},
{0.297178f, 0.047470f, 0.420491f},
{0.303568f, 0.049396f, 0.422182f},
{0.309935f, 0.051407f, 0.423721f},
{0.316282f, 0.053490f, 0.425116f},
{0.322610f, 0.055634f, 0.426377f},
{0.328921f, 0.057827f, 0.427511f},
{0.335217f, 0.060060f, 0.428524f},
{0.341500f, 0.062325f, 0.429425f},
{0.347771f, 0.064616f, 0.430217f},
{0.354032f, 0.066925f, 0.430906f},
{0.360284f, 0.069247f, 0.431497f},
{0.366529f, 0.071579f, 0.431994f},
{0.372768f, 0.073915f, 0.432400f},
{0.379001f, 0.076253f, 0.432719f},
{0.385228f, 0.078591f, 0.432955f},
{0.391453f, 0.080927f, 0.433109f},
{0.397674f, 0.083257f, 0.433183f},
{0.403894f, 0.085580f, 0.433179f},
{0.410113f, 0.087896f, 0.433098f},
{0.416331f, 0.090203f, 0.432943f},
{0.422549f, 0.092501f, 0.432714f},
{0.428768f, 0.094790f, 0.432412f},
{0.434987f, 0.097069f, 0.432039f},
{0.441207f, 0.099338f, 0.431594f},
{0.447428f, 0.101597f, 0.431080f},
{0.453651f, 0.103848f, 0.430498f},
{0.459875f, 0.106089f, 0.429846f},
{0.466100f, 0.108322f, 0.429125f},
{0.472328f, 0.110547f, 0.428334f},
{0.478558f, 0.112764f, 0.427475f},
{0.484789f, 0.114974f, 0.426548f},
{0.491022f, 0.117179f, 0.425552f},
{0.497257f, 0.119379f, 0.424488f},
{0.503493f, 0.121575f, 0.423356f},
{0.509730f, 0.123769f, 0.422156f},
{0.515967f, 0.125960f, 0.420887f},
{0.522206f, 0.128150f, 0.419549f},
{0.528444f, 0.130341f, 0.418142f},
{0.534683f, 0.132534f, 0.416667f},
{0.540920f, 0.134729f, 0.415123f},
{0.547157f, 0.136929f, 0.413511f},
{0.553392f, 0.139134f, 0.411829f},
{0.559624f, 0.141346f, 0.410078f},
{0.565854f, 0.143567f, 0.408258f},
{0.572081f, 0.145797f, 0.406369f},
{0.578304f, 0.148039f, 0.404411f},
{0.584521f, 0.150294f, 0.402385f},
{0.590734f, 0.152563f, 0.400290f},
{0.596940f, 0.154848f, 0.398125f},
{0.603139f, 0.157151f, 0.395891f},
{0.609330f, 0.159474f, 0.393589f},
{0.615513f, 0.161817f, 0.391219f},
{0.621685f, 0.164184f, 0.388781f},
{0.627847f, 0.166575f, 0.386276f},
{0.633998f, 0.168992f, 0.383704f},
{0.640135f, 0.171438f, 0.381065f},
{0.646260f, 0.173914f, 0.378359f},
{0.652369f, 0.176421f, 0.375586f},
{0.658463f, 0.178962f, 0.372748f},
{0.664540f, 0.181539f, 0.369846f},
{0.670599f, 0.184153f, 0.366879f},
{0.676638f, 0.186807f, 0.363849f},
{0.682656f, 0.189501f, 0.360757f},
{0.688653f, 0.192239f, 0.357603f},
{0.694627f, 0.195021f, 0.354388f},
{0.700576f, 0.197851f, 0.351113f},
{0.706500f, 0.200728f, 0.347777f},
{0.712396f, 0.203656f, 0.344383f},
{0.718264f, 0.206636f, 0.340931f},
{0.724103f, 0.209670f, 0.337424f},
{0.729909f, 0.212759f, 0.333861f},
{0.735683f, 0.215906f, 0.330245f},
{0.741423f, 0.219112f, 0.326576f},
{0.747127f, 0.222378f, 0.322856f},
{0.752794f, 0.225706f, 0.319085f},
{0.758422f, 0.229097f, 0.315266f},
{0.764010f, 0.232554f, 0.311399f},
{0.769556f, 0.236077f, 0.307485f},
{0.775059f, 0.239667f, 0.303526f},
{0.780517f, 0.243327f, 0.299523f},
{0.785929f, 0.247056f, 0.295477f},
{0.791293f, 0.250856f, 0.291390f},
{0.796607f, 0.254728f, 0.287264f},
{0.801871f, 0.258674f, 0.283099f},
{0.807082f, 0.262692f, 0.278898f},
{0.812239f, 0.266786f, 0.274661f},
{0.817341f, 0.270954f, 0.270390f},
{0.822386f, 0.275197f, 0.266085f},
{0.827372f, 0.279517f, 0.261750f},
{0.832299f, 0.283913f, 0.257383f},
{0.837165f, 0.288385f, 0.252988f},
{0.841969f, 0.292933f, 0.248564f},
{0.846709f, 0.297559f, 0.244113f},
{0.851384f, 0.302260f, 0.239636f},
{0.855992f, 0.307038f, 0.235133f},
{0.860533f, 0.311892f, 0.230606f},
{0.865006f, 0.316822f, 0.226055f},
{0.869409f, 0.321827f, 0.221482f},
{0.873741f, 0.326906f, 0.216886f},
{0.878001f, 0.332060f, 0.212268f},
{0.882188f, 0.337287f, 0.207628f},
{0.886302f, 0.342586f, 0.202968f},
{0.890341f, 0.347957f, 0.198286f},
{0.894305f, 0.353399f, 0.193584f},
{0.898192f, 0.358911f, 0.188860f},
{0.902003f, 0.364492f, 0.184116f},
{0.905735f, 0.370140f, 0.179350f},
{0.909390f, 0.375856f, 0.174563f},
{0.912966f, 0.381636f, 0.169755f},
{0.916462f, 0.387481f, 0.164924f},
{0.919879f, 0.393389f, 0.160070f},
{0.923215f, 0.399359f, 0.155193f},
{0.926470f, 0.405389f, 0.150292f},
{0.929644f, 0.411479f, 0.145367f},
{0.932737f, 0.417627f, 0.140417f},
{0.935747f, 0.423831f, 0.135440f},
{0.938675f, 0.430091f, 0.130438f},
{0.941521f, 0.436405f, 0.125409f},
{0.944285f, 0.442772f, 0.120354f},
{0.946965f, 0.449191f, 0.115272f},
{0.949562f, 0.455660f, 0.110164f},
{0.952075f, 0.462178f, 0.105031f},
{0.954506f, 0.468744f, 0.099874f},
{0.956852f, 0.475356f, 0.094695f},
{0.959114f, 0.482014f, 0.089499f},
{0.961293f, 0.488716f, 0.084289f},
{0.963387f, 0.495462f, 0.079073f},
{0.965397f, 0.502249f, 0.073859f},
{0.967322f, 0.509078f, 0.068659f},
{0.969163f, 0.515946f, 0.063488f},
{0.970919f, 0.522853f, 0.058367f},
{0.972590f, 0.529798f, 0.053324f},
{0.974176f, 0.536780f, 0.048392f},
{0.975677f, 0.543798f, 0.043618f},
{0.977092f, 0.550850f, 0.039050f},
{0.978422f, 0.557937f, 0.034931f},
{0.979666f, 0.565057f, 0.031409f},
{0.980824f, 0.572209f, 0.028508f},
{0.981895f, 0.579392f, 0.026250f},
{0.982881f, 0.586606f, 0.024661f},
{0.983779f, 0.593849f, 0.023770f},
{0.984591f, 0.601122f, 0.023606f},
{0.985315f, 0.608422f, 0.024202f},
{0.985952f, 0.615750f, 0.025592f},
{0.986502f, 0.623105f, 0.027814f},
{0.986964f, 0.630485f, 0.030908f},
{0.987337f, 0.637890f, 0.034916f},
{0.987622f, 0.645320f, 0.039886f},
{0.987819f, 0.652773f, 0.045581f},
{0.987926f, 0.660250f, 0.051750f},
{0.987945f, 0.667748f, 0.058329f},
{0.987874f, 0.675267f, 0.065257f},
{0.987714f, 0.682807f, 0.072489f},
{0.987464f, 0.690366f, 0.079990f},
{0.987124f, 0.697944f, 0.087731f},
{0.986694f, 0.705540f, 0.095694f},
{0.986175f, 0.713153f, 0.103863f},
{0.985566f, 0.720782f, 0.112229f},
{0.984865f, 0.728427f, 0.120785f},
{0.984075f, 0.736087f, 0.129527f},
{0.983196f, 0.743758f, 0.138453f},
{0.982228f, 0.751442f, 0.147565f},
{0.981173f, 0.759135f, 0.156863f},
{0.980032f, 0.766837f, 0.166353f},
{0.978806f, 0.774545f, 0.176037f},
{0.977497f, 0.782258f, 0.185923f},
{0.976108f, 0.789974f, 0.196018f},
{0.974638f, 0.797692f, 0.206332f},
{0.973088f, 0.805409f, 0.216877f},
{0.971468f, 0.813122f, 0.227658f},
{0.969783f, 0.820825f, 0.238686f},
{0.968041f, 0.828515f, 0.249972f},
{0.966243f, 0.836191f, 0.261534f},
{0.964394f, 0.843848f, 0.273391f},
{0.962517f, 0.851476f, 0.285546f},
{0.960626f, 0.859069f, 0.298010f},
{0.958720f, 0.866624f, 0.310820f},
{0.956834f, 0.874129f, 0.323974f},
{0.954997f, 0.881569f, 0.337475f},
{0.953215f, 0.888942f, 0.351369f},
{0.951546f, 0.896226f, 0.365627f},
{0.950018f, 0.903409f, 0.380271f},
{0.948683f, 0.910473f, 0.395289f},
{0.947594f, 0.917399f, 0.410665f},
{0.946809f, 0.924168f, 0.426373f},
{0.946392f, 0.930761f, 0.442367f},
{0.946403f, 0.937159f, 0.458592f},
{0.946903f, 0.943348f, 0.474970f},
{0.947937f, 0.949318f, 0.491426f},
{0.949545f, 0.955063f, 0.507860f},
{0.951740f, 0.960587f, 0.524203f},
{0.954529f, 0.965896f, 0.540361f},
{0.957896f, 0.971003f, 0.556275f},
{0.961812f, 0.975924f, 0.571925f},
{0.966249f, 0.980678f, 0.587206f},
{0.971162f, 0.985282f, 0.602154f},
{0.976511f, 0.989753f, 0.616760f},
{0.982257f, 0.994109f, 0.631017f},
{0.988362f, 0.998364f, 0.644924f}};
//Plasma data from MatPlotLib
static std::vector<Color<float>> plasma_data = {
{5.03832136e-02f, 2.98028976e-02f, 5.27974883e-01f},
{6.35363639e-02f, 2.84259729e-02f, 5.33123681e-01f},
{7.53531234e-02f, 2.72063728e-02f, 5.38007001e-01f},
{8.62217979e-02f, 2.61253206e-02f, 5.42657691e-01f},
{9.63786097e-02f, 2.51650976e-02f, 5.47103487e-01f},
{1.05979704e-01f, 2.43092436e-02f, 5.51367851e-01f},
{1.15123641e-01f, 2.35562500e-02f, 5.55467728e-01f},
{1.23902903e-01f, 2.28781011e-02f, 5.59423480e-01f},
{1.32380720e-01f, 2.22583774e-02f, 5.63250116e-01f},
{1.40603076e-01f, 2.16866674e-02f, 5.66959485e-01f},
{1.48606527e-01f, 2.11535876e-02f, 5.70561711e-01f},
{1.56420649e-01f, 2.06507174e-02f, 5.74065446e-01f},
{1.64069722e-01f, 2.01705326e-02f, 5.77478074e-01f},
{1.71573925e-01f, 1.97063415e-02f, 5.80805890e-01f},
{1.78950212e-01f, 1.92522243e-02f, 5.84054243e-01f},
{1.86212958e-01f, 1.88029767e-02f, 5.87227661e-01f},
{1.93374449e-01f, 1.83540593e-02f, 5.90329954e-01f},
{2.00445260e-01f, 1.79015512e-02f, 5.93364304e-01f},
{2.07434551e-01f, 1.74421086e-02f, 5.96333341e-01f},
{2.14350298e-01f, 1.69729276e-02f, 5.99239207e-01f},
{2.21196750e-01f, 1.64970484e-02f, 6.02083323e-01f},
{2.27982971e-01f, 1.60071509e-02f, 6.04867403e-01f},
{2.34714537e-01f, 1.55015065e-02f, 6.07592438e-01f},
{2.41396253e-01f, 1.49791041e-02f, 6.10259089e-01f},
{2.48032377e-01f, 1.44393586e-02f, 6.12867743e-01f},
{2.54626690e-01f, 1.38820918e-02f, 6.15418537e-01f},
{2.61182562e-01f, 1.33075156e-02f, 6.17911385e-01f},
{2.67702993e-01f, 1.27162163e-02f, 6.20345997e-01f},
{2.74190665e-01f, 1.21091423e-02f, 6.22721903e-01f},
{2.80647969e-01f, 1.14875915e-02f, 6.25038468e-01f},
{2.87076059e-01f, 1.08554862e-02f, 6.27294975e-01f},
{2.93477695e-01f, 1.02128849e-02f, 6.29490490e-01f},
{2.99855122e-01f, 9.56079551e-03f, 6.31623923e-01f},
{3.06209825e-01f, 8.90185346e-03f, 6.33694102e-01f},
{3.12543124e-01f, 8.23900704e-03f, 6.35699759e-01f},
{3.18856183e-01f, 7.57551051e-03f, 6.37639537e-01f},
{3.25150025e-01f, 6.91491734e-03f, 6.39512001e-01f},
{3.31425547e-01f, 6.26107379e-03f, 6.41315649e-01f},
{3.37683446e-01f, 5.61830889e-03f, 6.43048936e-01f},
{3.43924591e-01f, 4.99053080e-03f, 6.44710195e-01f},
{3.50149699e-01f, 4.38202557e-03f, 6.46297711e-01f},
{3.56359209e-01f, 3.79781761e-03f, 6.47809772e-01f},
{3.62553473e-01f, 3.24319591e-03f, 6.49244641e-01f},
{3.68732762e-01f, 2.72370721e-03f, 6.50600561e-01f},
{3.74897270e-01f, 2.24514897e-03f, 6.51875762e-01f},
{3.81047116e-01f, 1.81356205e-03f, 6.53068467e-01f},
{3.87182639e-01f, 1.43446923e-03f, 6.54176761e-01f},
{3.93304010e-01f, 1.11388259e-03f, 6.55198755e-01f},
{3.99410821e-01f, 8.59420809e-04f, 6.56132835e-01f},
{4.05502914e-01f, 6.78091517e-04f, 6.56977276e-01f},
{4.11580082e-01f, 5.77101735e-04f, 6.57730380e-01f},
{4.17642063e-01f, 5.63847476e-04f, 6.58390492e-01f},
{4.23688549e-01f, 6.45902780e-04f, 6.58956004e-01f},
{4.29719186e-01f, 8.31008207e-04f, 6.59425363e-01f},
{4.35733575e-01f, 1.12705875e-03f, 6.59797077e-01f},
{4.41732123e-01f, 1.53984779e-03f, 6.60069009e-01f},
{4.47713600e-01f, 2.07954744e-03f, 6.60240367e-01f},
{4.53677394e-01f, 2.75470302e-03f, 6.60309966e-01f},
{4.59622938e-01f, 3.57374415e-03f, 6.60276655e-01f},
{4.65549631e-01f, 4.54518084e-03f, 6.60139383e-01f},
{4.71456847e-01f, 5.67758762e-03f, 6.59897210e-01f},
{4.77343929e-01f, 6.97958743e-03f, 6.59549311e-01f},
{4.83210198e-01f, 8.45983494e-03f, 6.59094989e-01f},
{4.89054951e-01f, 1.01269996e-02f, 6.58533677e-01f},
{4.94877466e-01f, 1.19897486e-02f, 6.57864946e-01f},
{5.00677687e-01f, 1.40550640e-02f, 6.57087561e-01f},
{5.06454143e-01f, 1.63333443e-02f, 6.56202294e-01f},
{5.12206035e-01f, 1.88332232e-02f, 6.55209222e-01f},
{5.17932580e-01f, 2.15631918e-02f, 6.54108545e-01f},
{5.23632990e-01f, 2.45316468e-02f, 6.52900629e-01f},
{5.29306474e-01f, 2.77468735e-02f, 6.51586010e-01f},
{5.34952244e-01f, 3.12170300e-02f, 6.50165396e-01f},
{5.40569510e-01f, 3.49501310e-02f, 6.48639668e-01f},
{5.46157494e-01f, 3.89540334e-02f, 6.47009884e-01f},
{5.51715423e-01f, 4.31364795e-02f, 6.45277275e-01f},
{5.57242538e-01f, 4.73307585e-02f, 6.43443250e-01f},
{5.62738096e-01f, 5.15448092e-02f, 6.41509389e-01f},
{5.68201372e-01f, 5.57776706e-02f, 6.39477440e-01f},
{5.73631859e-01f, 6.00281369e-02f, 6.37348841e-01f},
{5.79028682e-01f, 6.42955547e-02f, 6.35126108e-01f},
{5.84391137e-01f, 6.85790261e-02f, 6.32811608e-01f},
{5.89718606e-01f, 7.28775875e-02f, 6.30407727e-01f},
{5.95010505e-01f, 7.71902878e-02f, 6.27916992e-01f},
{6.00266283e-01f, 8.15161895e-02f, 6.25342058e-01f},
{6.05485428e-01f, 8.58543713e-02f, 6.22685703e-01f},
{6.10667469e-01f, 9.02039303e-02f, 6.19950811e-01f},
{6.15811974e-01f, 9.45639838e-02f, 6.17140367e-01f},
{6.20918555e-01f, 9.89336721e-02f, 6.14257440e-01f},
{6.25986869e-01f, 1.03312160e-01f, 6.11305174e-01f},
{6.31016615e-01f, 1.07698641e-01f, 6.08286774e-01f},
{6.36007543e-01f, 1.12092335e-01f, 6.05205491e-01f},
{6.40959444e-01f, 1.16492495e-01f, 6.02064611e-01f},
{6.45872158e-01f, 1.20898405e-01f, 5.98867442e-01f},
{6.50745571e-01f, 1.25309384e-01f, 5.95617300e-01f},
{6.55579615e-01f, 1.29724785e-01f, 5.92317494e-01f},
{6.60374266e-01f, 1.34143997e-01f, 5.88971318e-01f},
{6.65129493e-01f, 1.38566428e-01f, 5.85582301e-01f},
{6.69845385e-01f, 1.42991540e-01f, 5.82153572e-01f},
{6.74522060e-01f, 1.47418835e-01f, 5.78688247e-01f},
{6.79159664e-01f, 1.51847851e-01f, 5.75189431e-01f},
{6.83758384e-01f, 1.56278163e-01f, 5.71660158e-01f},
{6.88318440e-01f, 1.60709387e-01f, 5.68103380e-01f},
{6.92840088e-01f, 1.65141174e-01f, 5.64521958e-01f},
{6.97323615e-01f, 1.69573215e-01f, 5.60918659e-01f},
{7.01769334e-01f, 1.74005236e-01f, 5.57296144e-01f},
{7.06177590e-01f, 1.78437000e-01f, 5.53656970e-01f},
{7.10548747e-01f, 1.82868306e-01f, 5.50003579e-01f},
{7.14883195e-01f, 1.87298986e-01f, 5.46338299e-01f},
{7.19181339e-01f, 1.91728906e-01f, 5.42663338e-01f},
{7.23443604e-01f, 1.96157962e-01f, 5.38980786e-01f},
{7.27670428e-01f, 2.00586086e-01f, 5.35292612e-01f},
{7.31862231e-01f, 2.05013174e-01f, 5.31600995e-01f},
{7.36019424e-01f, 2.09439071e-01f, 5.27908434e-01f},
{7.40142557e-01f, 2.13863965e-01f, 5.24215533e-01f},
{7.44232102e-01f, 2.18287899e-01f, 5.20523766e-01f},
{7.48288533e-01f, 2.22710942e-01f, 5.16834495e-01f},
{7.52312321e-01f, 2.27133187e-01f, 5.13148963e-01f},
{7.56303937e-01f, 2.31554749e-01f, 5.09468305e-01f},
{7.60263849e-01f, 2.35975765e-01f, 5.05793543e-01f},
{7.64192516e-01f, 2.40396394e-01f, 5.02125599e-01f},
{7.68090391e-01f, 2.44816813e-01f, 4.98465290e-01f},
{7.71957916e-01f, 2.49237220e-01f, 4.94813338e-01f},
{7.75795522e-01f, 2.53657797e-01f, 4.91170517e-01f},
{7.79603614e-01f, 2.58078397e-01f, 4.87539124e-01f},
{7.83382636e-01f, 2.62499662e-01f, 4.83917732e-01f},
{7.87132978e-01f, 2.66921859e-01f, 4.80306702e-01f},
{7.90855015e-01f, 2.71345267e-01f, 4.76706319e-01f},
{7.94549101e-01f, 2.75770179e-01f, 4.73116798e-01f},
{7.98215577e-01f, 2.80196901e-01f, 4.69538286e-01f},
{8.01854758e-01f, 2.84625750e-01f, 4.65970871e-01f},
{8.05466945e-01f, 2.89057057e-01f, 4.62414580e-01f},
{8.09052419e-01f, 2.93491117e-01f, 4.58869577e-01f},
{8.12611506e-01f, 2.97927865e-01f, 4.55337565e-01f},
{8.16144382e-01f, 3.02368130e-01f, 4.51816385e-01f},
{8.19651255e-01f, 3.06812282e-01f, 4.48305861e-01f},
{8.23132309e-01f, 3.11260703e-01f, 4.44805781e-01f},
{8.26587706e-01f, 3.15713782e-01f, 4.41315901e-01f},
{8.30017584e-01f, 3.20171913e-01f, 4.37835947e-01f},
{8.33422053e-01f, 3.24635499e-01f, 4.34365616e-01f},
{8.36801237e-01f, 3.29104836e-01f, 4.30905052e-01f},
{8.40155276e-01f, 3.33580106e-01f, 4.27454836e-01f},
{8.43484103e-01f, 3.38062109e-01f, 4.24013059e-01f},
{8.46787726e-01f, 3.42551272e-01f, 4.20579333e-01f},
{8.50066132e-01f, 3.47048028e-01f, 4.17153264e-01f},
{8.53319279e-01f, 3.51552815e-01f, 4.13734445e-01f},
{8.56547103e-01f, 3.56066072e-01f, 4.10322469e-01f},
{8.59749520e-01f, 3.60588229e-01f, 4.06916975e-01f},
{8.62926559e-01f, 3.65119408e-01f, 4.03518809e-01f},
{8.66077920e-01f, 3.69660446e-01f, 4.00126027e-01f},
{8.69203436e-01f, 3.74211795e-01f, 3.96738211e-01f},
{8.72302917e-01f, 3.78773910e-01f, 3.93354947e-01f},
{8.75376149e-01f, 3.83347243e-01f, 3.89975832e-01f},
{8.78422895e-01f, 3.87932249e-01f, 3.86600468e-01f},
{8.81442916e-01f, 3.92529339e-01f, 3.83228622e-01f},
{8.84435982e-01f, 3.97138877e-01f, 3.79860246e-01f},
{8.87401682e-01f, 4.01761511e-01f, 3.76494232e-01f},
{8.90339687e-01f, 4.06397694e-01f, 3.73130228e-01f},
{8.93249647e-01f, 4.11047871e-01f, 3.69767893e-01f},
{8.96131191e-01f, 4.15712489e-01f, 3.66406907e-01f},
{8.98983931e-01f, 4.20391986e-01f, 3.63046965e-01f},
{9.01807455e-01f, 4.25086807e-01f, 3.59687758e-01f},
{9.04601295e-01f, 4.29797442e-01f, 3.56328796e-01f},
{9.07364995e-01f, 4.34524335e-01f, 3.52969777e-01f},
{9.10098088e-01f, 4.39267908e-01f, 3.49610469e-01f},
{9.12800095e-01f, 4.44028574e-01f, 3.46250656e-01f},
{9.15470518e-01f, 4.48806744e-01f, 3.42890148e-01f},
{9.18108848e-01f, 4.53602818e-01f, 3.39528771e-01f},
{9.20714383e-01f, 4.58417420e-01f, 3.36165582e-01f},
{9.23286660e-01f, 4.63250828e-01f, 3.32800827e-01f},
{9.25825146e-01f, 4.68103387e-01f, 3.29434512e-01f},
{9.28329275e-01f, 4.72975465e-01f, 3.26066550e-01f},
{9.30798469e-01f, 4.77867420e-01f, 3.22696876e-01f},
{9.33232140e-01f, 4.82779603e-01f, 3.19325444e-01f},
{9.35629684e-01f, 4.87712357e-01f, 3.15952211e-01f},
{9.37990034e-01f, 4.92666544e-01f, 3.12575440e-01f},
{9.40312939e-01f, 4.97642038e-01f, 3.09196628e-01f},
{9.42597771e-01f, 5.02639147e-01f, 3.05815824e-01f},
{9.44843893e-01f, 5.07658169e-01f, 3.02433101e-01f},
{9.47050662e-01f, 5.12699390e-01f, 2.99048555e-01f},
{9.49217427e-01f, 5.17763087e-01f, 2.95662308e-01f},
{9.51343530e-01f, 5.22849522e-01f, 2.92274506e-01f},
{9.53427725e-01f, 5.27959550e-01f, 2.88883445e-01f},
{9.55469640e-01f, 5.33093083e-01f, 2.85490391e-01f},
{9.57468770e-01f, 5.38250172e-01f, 2.82096149e-01f},
{9.59424430e-01f, 5.43431038e-01f, 2.78700990e-01f},
{9.61335930e-01f, 5.48635890e-01f, 2.75305214e-01f},
{9.63202573e-01f, 5.53864931e-01f, 2.71909159e-01f},
{9.65023656e-01f, 5.59118349e-01f, 2.68513200e-01f},
{9.66798470e-01f, 5.64396327e-01f, 2.65117752e-01f},
{9.68525639e-01f, 5.69699633e-01f, 2.61721488e-01f},
{9.70204593e-01f, 5.75028270e-01f, 2.58325424e-01f},
{9.71835007e-01f, 5.80382015e-01f, 2.54931256e-01f},
{9.73416145e-01f, 5.85761012e-01f, 2.51539615e-01f},
{9.74947262e-01f, 5.91165394e-01f, 2.48151200e-01f},
{9.76427606e-01f, 5.96595287e-01f, 2.44766775e-01f},
{9.77856416e-01f, 6.02050811e-01f, 2.41387186e-01f},
{9.79232922e-01f, 6.07532077e-01f, 2.38013359e-01f},
{9.80556344e-01f, 6.13039190e-01f, 2.34646316e-01f},
{9.81825890e-01f, 6.18572250e-01f, 2.31287178e-01f},
{9.83040742e-01f, 6.24131362e-01f, 2.27937141e-01f},
{9.84198924e-01f, 6.29717516e-01f, 2.24595006e-01f},
{9.85300760e-01f, 6.35329876e-01f, 2.21264889e-01f},
{9.86345421e-01f, 6.40968508e-01f, 2.17948456e-01f},
{9.87332067e-01f, 6.46633475e-01f, 2.14647532e-01f},
{9.88259846e-01f, 6.52324832e-01f, 2.11364122e-01f},
{9.89127893e-01f, 6.58042630e-01f, 2.08100426e-01f},
{9.89935328e-01f, 6.63786914e-01f, 2.04858855e-01f},
{9.90681261e-01f, 6.69557720e-01f, 2.01642049e-01f},
{9.91364787e-01f, 6.75355082e-01f, 1.98452900e-01f},
{9.91984990e-01f, 6.81179025e-01f, 1.95294567e-01f},
{9.92540939e-01f, 6.87029567e-01f, 1.92170500e-01f},
{9.93031693e-01f, 6.92906719e-01f, 1.89084459e-01f},
{9.93456302e-01f, 6.98810484e-01f, 1.86040537e-01f},
{9.93813802e-01f, 7.04740854e-01f, 1.83043180e-01f},
{9.94103226e-01f, 7.10697814e-01f, 1.80097207e-01f},
{9.94323596e-01f, 7.16681336e-01f, 1.77207826e-01f},
{9.94473934e-01f, 7.22691379e-01f, 1.74380656e-01f},
{9.94553260e-01f, 7.28727890e-01f, 1.71621733e-01f},
{9.94560594e-01f, 7.34790799e-01f, 1.68937522e-01f},
{9.94494964e-01f, 7.40880020e-01f, 1.66334918e-01f},
{9.94355411e-01f, 7.46995448e-01f, 1.63821243e-01f},
{9.94140989e-01f, 7.53136955e-01f, 1.61404226e-01f},
{9.93850778e-01f, 7.59304390e-01f, 1.59091984e-01f},
{9.93482190e-01f, 7.65498551e-01f, 1.56890625e-01f},
{9.93033251e-01f, 7.71719833e-01f, 1.54807583e-01f},
{9.92505214e-01f, 7.77966775e-01f, 1.52854862e-01f},
{9.91897270e-01f, 7.84239120e-01f, 1.51041581e-01f},
{9.91208680e-01f, 7.90536569e-01f, 1.49376885e-01f},
{9.90438793e-01f, 7.96858775e-01f, 1.47869810e-01f},
{9.89587065e-01f, 8.03205337e-01f, 1.46529128e-01f},
{9.88647741e-01f, 8.09578605e-01f, 1.45357284e-01f},
{9.87620557e-01f, 8.15977942e-01f, 1.44362644e-01f},
{9.86509366e-01f, 8.22400620e-01f, 1.43556679e-01f},
{9.85314198e-01f, 8.28845980e-01f, 1.42945116e-01f},
{9.84031139e-01f, 8.35315360e-01f, 1.42528388e-01f},
{9.82652820e-01f, 8.41811730e-01f, 1.42302653e-01f},
{9.81190389e-01f, 8.48328902e-01f, 1.42278607e-01f},
{9.79643637e-01f, 8.54866468e-01f, 1.42453425e-01f},
{9.77994918e-01f, 8.61432314e-01f, 1.42808191e-01f},
{9.76264977e-01f, 8.68015998e-01f, 1.43350944e-01f},
{9.74443038e-01f, 8.74622194e-01f, 1.44061156e-01f},
{9.72530009e-01f, 8.81250063e-01f, 1.44922913e-01f},
{9.70532932e-01f, 8.87896125e-01f, 1.45918663e-01f},
{9.68443477e-01f, 8.94563989e-01f, 1.47014438e-01f},
{9.66271225e-01f, 9.01249365e-01f, 1.48179639e-01f},
{9.64021057e-01f, 9.07950379e-01f, 1.49370428e-01f},
{9.61681481e-01f, 9.14672479e-01f, 1.50520343e-01f},
{9.59275646e-01f, 9.21406537e-01f, 1.51566019e-01f},
{9.56808068e-01f, 9.28152065e-01f, 1.52409489e-01f},
{9.54286813e-01f, 9.34907730e-01f, 1.52921158e-01f},
{9.51726083e-01f, 9.41670605e-01f, 1.52925363e-01f},
{9.49150533e-01f, 9.48434900e-01f, 1.52177604e-01f},
{9.46602270e-01f, 9.55189860e-01f, 1.50327944e-01f},
{9.44151742e-01f, 9.61916487e-01f, 1.46860789e-01f},
{9.41896120e-01f, 9.68589814e-01f, 1.40955606e-01f},
{9.40015097e-01f, 9.75158357e-01f, 1.31325517e-01f}};
//Viridis data from MatPlotLib
static std::vector<Color<float>> viridis_data = {
{0.26700401f, 0.00487433f, 0.32941519f},
{0.26851048f, 0.00960483f, 0.33542652f},
{0.26994384f, 0.01462494f, 0.34137895f},
{0.27130489f, 0.01994186f, 0.34726862f},
{0.27259384f, 0.02556309f, 0.35309303f},
{0.27380934f, 0.03149748f, 0.35885256f},
{0.27495242f, 0.03775181f, 0.36454323f},
{0.27602238f, 0.04416723f, 0.37016418f},
{0.2770184f , 0.05034437f, 0.37571452f},
{0.27794143f, 0.05632444f, 0.38119074f},
{0.27879067f, 0.06214536f, 0.38659204f},
{0.2795655f , 0.06783587f, 0.39191723f},
{0.28026658f, 0.07341724f, 0.39716349f},
{0.28089358f, 0.07890703f, 0.40232944f},
{0.28144581f, 0.0843197f , 0.40741404f},
{0.28192358f, 0.08966622f, 0.41241521f},
{0.28232739f, 0.09495545f, 0.41733086f},
{0.28265633f, 0.10019576f, 0.42216032f},
{0.28291049f, 0.10539345f, 0.42690202f},
{0.28309095f, 0.11055307f, 0.43155375f},
{0.28319704f, 0.11567966f, 0.43611482f},
{0.28322882f, 0.12077701f, 0.44058404f},
{0.28318684f, 0.12584799f, 0.44496f },
{0.283072f , 0.13089477f, 0.44924127f},
{0.28288389f, 0.13592005f, 0.45342734f},
{0.28262297f, 0.14092556f, 0.45751726f},
{0.28229037f, 0.14591233f, 0.46150995f},
{0.28188676f, 0.15088147f, 0.46540474f},
{0.28141228f, 0.15583425f, 0.46920128f},
{0.28086773f, 0.16077132f, 0.47289909f},
{0.28025468f, 0.16569272f, 0.47649762f},
{0.27957399f, 0.17059884f, 0.47999675f},
{0.27882618f, 0.1754902f , 0.48339654f},
{0.27801236f, 0.18036684f, 0.48669702f},
{0.27713437f, 0.18522836f, 0.48989831f},
{0.27619376f, 0.19007447f, 0.49300074f},
{0.27519116f, 0.1949054f , 0.49600488f},
{0.27412802f, 0.19972086f, 0.49891131f},
{0.27300596f, 0.20452049f, 0.50172076f},
{0.27182812f, 0.20930306f, 0.50443413f},
{0.27059473f, 0.21406899f, 0.50705243f},
{0.26930756f, 0.21881782f, 0.50957678f},
{0.26796846f, 0.22354911f, 0.5120084f },
{0.26657984f, 0.2282621f , 0.5143487f },
{0.2651445f , 0.23295593f, 0.5165993f },
{0.2636632f , 0.23763078f, 0.51876163f},
{0.26213801f, 0.24228619f, 0.52083736f},
{0.26057103f, 0.2469217f , 0.52282822f},
{0.25896451f, 0.25153685f, 0.52473609f},
{0.25732244f, 0.2561304f , 0.52656332f},
{0.25564519f, 0.26070284f, 0.52831152f},
{0.25393498f, 0.26525384f, 0.52998273f},
{0.25219404f, 0.26978306f, 0.53157905f},
{0.25042462f, 0.27429024f, 0.53310261f},
{0.24862899f, 0.27877509f, 0.53455561f},
{0.2468114f , 0.28323662f, 0.53594093f},
{0.24497208f, 0.28767547f, 0.53726018f},
{0.24311324f, 0.29209154f, 0.53851561f},
{0.24123708f, 0.29648471f, 0.53970946f},
{0.23934575f, 0.30085494f, 0.54084398f},
{0.23744138f, 0.30520222f, 0.5419214f },
{0.23552606f, 0.30952657f, 0.54294396f},
{0.23360277f, 0.31382773f, 0.54391424f},
{0.2316735f , 0.3181058f , 0.54483444f},
{0.22973926f, 0.32236127f, 0.54570633f},
{0.22780192f, 0.32659432f, 0.546532f },
{0.2258633f , 0.33080515f, 0.54731353f},
{0.22392515f, 0.334994f , 0.54805291f},
{0.22198915f, 0.33916114f, 0.54875211f},
{0.22005691f, 0.34330688f, 0.54941304f},
{0.21812995f, 0.34743154f, 0.55003755f},
{0.21620971f, 0.35153548f, 0.55062743f},
{0.21429757f, 0.35561907f, 0.5511844f },
{0.21239477f, 0.35968273f, 0.55171011f},
{0.2105031f , 0.36372671f, 0.55220646f},
{0.20862342f, 0.36775151f, 0.55267486f},
{0.20675628f, 0.37175775f, 0.55311653f},
{0.20490257f, 0.37574589f, 0.55353282f},
{0.20306309f, 0.37971644f, 0.55392505f},
{0.20123854f, 0.38366989f, 0.55429441f},
{0.1994295f , 0.38760678f, 0.55464205f},
{0.1976365f , 0.39152762f, 0.55496905f},
{0.19585993f, 0.39543297f, 0.55527637f},
{0.19410009f, 0.39932336f, 0.55556494f},
{0.19235719f, 0.40319934f, 0.55583559f},
{0.19063135f, 0.40706148f, 0.55608907f},
{0.18892259f, 0.41091033f, 0.55632606f},
{0.18723083f, 0.41474645f, 0.55654717f},
{0.18555593f, 0.4185704f , 0.55675292f},
{0.18389763f, 0.42238275f, 0.55694377f},
{0.18225561f, 0.42618405f, 0.5571201f },
{0.18062949f, 0.42997486f, 0.55728221f},
{0.17901879f, 0.43375572f, 0.55743035f},
{0.17742298f, 0.4375272f , 0.55756466f},
{0.17584148f, 0.44128981f, 0.55768526f},
{0.17427363f, 0.4450441f , 0.55779216f},
{0.17271876f, 0.4487906f , 0.55788532f},
{0.17117615f, 0.4525298f , 0.55796464f},
{0.16964573f, 0.45626209f, 0.55803034f},
{0.16812641f, 0.45998802f, 0.55808199f},
{0.1666171f , 0.46370813f, 0.55811913f},
{0.16511703f, 0.4674229f , 0.55814141f},
{0.16362543f, 0.47113278f, 0.55814842f},
{0.16214155f, 0.47483821f, 0.55813967f},
{0.16066467f, 0.47853961f, 0.55811466f},
{0.15919413f, 0.4822374f , 0.5580728f },
{0.15772933f, 0.48593197f, 0.55801347f},
{0.15626973f, 0.4896237f , 0.557936f },
{0.15481488f, 0.49331293f, 0.55783967f},
{0.15336445f, 0.49700003f, 0.55772371f},
{0.1519182f , 0.50068529f, 0.55758733f},
{0.15047605f, 0.50436904f, 0.55742968f},
{0.14903918f, 0.50805136f, 0.5572505f },
{0.14760731f, 0.51173263f, 0.55704861f},
{0.14618026f, 0.51541316f, 0.55682271f},
{0.14475863f, 0.51909319f, 0.55657181f},
{0.14334327f, 0.52277292f, 0.55629491f},
{0.14193527f, 0.52645254f, 0.55599097f},
{0.14053599f, 0.53013219f, 0.55565893f},
{0.13914708f, 0.53381201f, 0.55529773f},
{0.13777048f, 0.53749213f, 0.55490625f},
{0.1364085f , 0.54117264f, 0.55448339f},
{0.13506561f, 0.54485335f, 0.55402906f},
{0.13374299f, 0.54853458f, 0.55354108f},
{0.13244401f, 0.55221637f, 0.55301828f},
{0.13117249f, 0.55589872f, 0.55245948f},
{0.1299327f , 0.55958162f, 0.55186354f},
{0.12872938f, 0.56326503f, 0.55122927f},
{0.12756771f, 0.56694891f, 0.55055551f},
{0.12645338f, 0.57063316f, 0.5498411f },
{0.12539383f, 0.57431754f, 0.54908564f},
{0.12439474f, 0.57800205f, 0.5482874f },
{0.12346281f, 0.58168661f, 0.54744498f},
{0.12260562f, 0.58537105f, 0.54655722f},
{0.12183122f, 0.58905521f, 0.54562298f},
{0.12114807f, 0.59273889f, 0.54464114f},
{0.12056501f, 0.59642187f, 0.54361058f},
{0.12009154f, 0.60010387f, 0.54253043f},
{0.11973756f, 0.60378459f, 0.54139999f},
{0.11951163f, 0.60746388f, 0.54021751f},
{0.11942341f, 0.61114146f, 0.53898192f},
{0.11948255f, 0.61481702f, 0.53769219f},
{0.11969858f, 0.61849025f, 0.53634733f},
{0.12008079f, 0.62216081f, 0.53494633f},
{0.12063824f, 0.62582833f, 0.53348834f},
{0.12137972f, 0.62949242f, 0.53197275f},
{0.12231244f, 0.63315277f, 0.53039808f},
{0.12344358f, 0.63680899f, 0.52876343f},
{0.12477953f, 0.64046069f, 0.52706792f},
{0.12632581f, 0.64410744f, 0.52531069f},
{0.12808703f, 0.64774881f, 0.52349092f},
{0.13006688f, 0.65138436f, 0.52160791f},
{0.13226797f, 0.65501363f, 0.51966086f},
{0.13469183f, 0.65863619f, 0.5176488f },
{0.13733921f, 0.66225157f, 0.51557101f},
{0.14020991f, 0.66585927f, 0.5134268f },
{0.14330291f, 0.66945881f, 0.51121549f},
{0.1466164f , 0.67304968f, 0.50893644f},
{0.15014782f, 0.67663139f, 0.5065889f },
{0.15389405f, 0.68020343f, 0.50417217f},
{0.15785146f, 0.68376525f, 0.50168574f},
{0.16201598f, 0.68731632f, 0.49912906f},
{0.1663832f , 0.69085611f, 0.49650163f},
{0.1709484f , 0.69438405f, 0.49380294f},
{0.17570671f, 0.6978996f , 0.49103252f},
{0.18065314f, 0.70140222f, 0.48818938f},
{0.18578266f, 0.70489133f, 0.48527326f},
{0.19109018f, 0.70836635f, 0.48228395f},
{0.19657063f, 0.71182668f, 0.47922108f},
{0.20221902f, 0.71527175f, 0.47608431f},
{0.20803045f, 0.71870095f, 0.4728733f },
{0.21400015f, 0.72211371f, 0.46958774f},
{0.22012381f, 0.72550945f, 0.46622638f},
{0.2263969f , 0.72888753f, 0.46278934f},
{0.23281498f, 0.73224735f, 0.45927675f},
{0.2393739f , 0.73558828f, 0.45568838f},
{0.24606968f, 0.73890972f, 0.45202405f},
{0.25289851f, 0.74221104f, 0.44828355f},
{0.25985676f, 0.74549162f, 0.44446673f},
{0.26694127f, 0.74875084f, 0.44057284f},
{0.27414922f, 0.75198807f, 0.4366009f },
{0.28147681f, 0.75520266f, 0.43255207f},
{0.28892102f, 0.75839399f, 0.42842626f},
{0.29647899f, 0.76156142f, 0.42422341f},
{0.30414796f, 0.76470433f, 0.41994346f},
{0.31192534f, 0.76782207f, 0.41558638f},
{0.3198086f , 0.77091403f, 0.41115215f},
{0.3277958f , 0.77397953f, 0.40664011f},
{0.33588539f, 0.7770179f , 0.40204917f},
{0.34407411f, 0.78002855f, 0.39738103f},
{0.35235985f, 0.78301086f, 0.39263579f},
{0.36074053f, 0.78596419f, 0.38781353f},
{0.3692142f , 0.78888793f, 0.38291438f},
{0.37777892f, 0.79178146f, 0.3779385f },
{0.38643282f, 0.79464415f, 0.37288606f},
{0.39517408f, 0.79747541f, 0.36775726f},
{0.40400101f, 0.80027461f, 0.36255223f},
{0.4129135f , 0.80304099f, 0.35726893f},
{0.42190813f, 0.80577412f, 0.35191009f},
{0.43098317f, 0.80847343f, 0.34647607f},
{0.44013691f, 0.81113836f, 0.3409673f },
{0.44936763f, 0.81376835f, 0.33538426f},
{0.45867362f, 0.81636288f, 0.32972749f},
{0.46805314f, 0.81892143f, 0.32399761f},
{0.47750446f, 0.82144351f, 0.31819529f},
{0.4870258f , 0.82392862f, 0.31232133f},
{0.49661536f, 0.82637633f, 0.30637661f},
{0.5062713f , 0.82878621f, 0.30036211f},
{0.51599182f, 0.83115784f, 0.29427888f},
{0.52577622f, 0.83349064f, 0.2881265f },
{0.5356211f , 0.83578452f, 0.28190832f},
{0.5455244f , 0.83803918f, 0.27562602f},
{0.55548397f, 0.84025437f, 0.26928147f},
{0.5654976f , 0.8424299f , 0.26287683f},
{0.57556297f, 0.84456561f, 0.25641457f},
{0.58567772f, 0.84666139f, 0.24989748f},
{0.59583934f, 0.84871722f, 0.24332878f},
{0.60604528f, 0.8507331f , 0.23671214f},
{0.61629283f, 0.85270912f, 0.23005179f},
{0.62657923f, 0.85464543f, 0.22335258f},
{0.63690157f, 0.85654226f, 0.21662012f},
{0.64725685f, 0.85839991f, 0.20986086f},
{0.65764197f, 0.86021878f, 0.20308229f},
{0.66805369f, 0.86199932f, 0.19629307f},
{0.67848868f, 0.86374211f, 0.18950326f},
{0.68894351f, 0.86544779f, 0.18272455f},
{0.69941463f, 0.86711711f, 0.17597055f},
{0.70989842f, 0.86875092f, 0.16925712f},
{0.72039115f, 0.87035015f, 0.16260273f},
{0.73088902f, 0.87191584f, 0.15602894f},
{0.74138803f, 0.87344918f, 0.14956101f},
{0.75188414f, 0.87495143f, 0.14322828f},
{0.76237342f, 0.87642392f, 0.13706449f},
{0.77285183f, 0.87786808f, 0.13110864f},
{0.78331535f, 0.87928545f, 0.12540538f},
{0.79375994f, 0.88067763f, 0.12000532f},
{0.80418159f, 0.88204632f, 0.11496505f},
{0.81457634f, 0.88339329f, 0.11034678f},
{0.82494028f, 0.88472036f, 0.10621724f},
{0.83526959f, 0.88602943f, 0.1026459f },
{0.84556056f, 0.88732243f, 0.09970219f},
{0.8558096f , 0.88860134f, 0.09745186f},
{0.86601325f, 0.88986815f, 0.09595277f},
{0.87616824f, 0.89112487f, 0.09525046f},
{0.88627146f, 0.89237353f, 0.09537439f},
{0.89632002f, 0.89361614f, 0.09633538f},
{0.90631121f, 0.89485467f, 0.09812496f},
{0.91624212f, 0.89609127f, 0.1007168f },
{0.92610579f, 0.89732977f, 0.10407067f},
{0.93590444f, 0.8985704f , 0.10813094f},
{0.94563626f, 0.899815f , 0.11283773f},
{0.95529972f, 0.90106534f, 0.11812832f},
{0.96489353f, 0.90232311f, 0.12394051f},
{0.97441665f, 0.90358991f, 0.13021494f},
{0.98386829f, 0.90486726f, 0.13689671f},
{0.99324789f, 0.90615657f, 0.1439362f }};
ColorMap::ColorMap(float min_val, float max_val, const std::vector<Color<float>>& color_data)
: min_(min_val)
, max_(max_val)
, color_data_(color_data) {
VTR_ASSERT(max_ >= min_);
}
Color<float> ColorMap::color(float value) const {
VTR_ASSERT(value >= min_);
VTR_ASSERT(value <= max_);
float norm_value;
if (range() == 0) {
norm_value = 0;
} else {
norm_value = (value - min_) / range();
}
size_t color_idx = std::round(norm_value * (color_data_.size() - 1));
VTR_ASSERT(color_idx < color_data_.size());
return color_data_[color_idx];
}
float ColorMap::min() const {
return min_;
}
float ColorMap::max() const {
return max_;
}
float ColorMap::range() const {
return max() - min();
}
InfernoColorMap::InfernoColorMap(float min_val, float max_val)
: ColorMap(min_val, max_val, inferno_data) {}
PlasmaColorMap::PlasmaColorMap(float min_val, float max_val)
: ColorMap(min_val, max_val, plasma_data) {}
ViridisColorMap::ViridisColorMap(float min_val, float max_val)
: ColorMap(min_val, max_val, viridis_data) {}
} //namespace

View File

@ -0,0 +1,45 @@
#ifndef VTR_CMAP_H
#define VTR_CMAP_H
#include <vector>
namespace vtr {
template<class T>
struct Color {
T r;
T g;
T b;
};
class ColorMap {
public:
ColorMap(float min, float max, const std::vector<Color<float>>& color_data);
virtual ~ColorMap() = default;
Color<float> color(float value) const;
float min() const;
float max() const;
float range() const;
private:
float min_;
float max_;
std::vector<Color<float>> color_data_;
};
class InfernoColorMap : public ColorMap {
public:
InfernoColorMap(float min, float max);
};
class PlasmaColorMap : public ColorMap {
public:
PlasmaColorMap(float min, float max);
};
class ViridisColorMap : public ColorMap {
public:
ViridisColorMap(float min, float max);
};
} //namespace
#endif

View File

@ -0,0 +1,39 @@
#include "vtr_digest.h"
#include "vtr_error.h"
#include <iostream>
#include <fstream>
#include <array>
#include "picosha2.h"
namespace vtr {
std::string secure_digest_file(const std::string& filepath) {
std::ifstream is(filepath);
if (!is) {
throw VtrError("Failed to open file", filepath);
}
return secure_digest_stream(is);
}
std::string secure_digest_stream(std::istream& is) {
//Read the stream in chunks and calculate the SHA256 digest
picosha2::hash256_one_by_one hasher;
std::array<char, 1024> buf;
while(!is.eof()) {
//Process a chunk
is.read(buf.data(), buf.size());
hasher.process(buf.begin(), buf.begin() + is.gcount());
}
hasher.finish();
//Return the digest as a hex string, prefixed with the hash type
//
//Prefixing with the hash type should allow us to differentiate if the
//hash type is ever changed in the future
return "SHA256:" + picosha2::get_hash_hex_string(hasher);
}
} //namespace

View File

@ -0,0 +1,16 @@
#ifndef VTR_DIGEST_H
#define VTR_DIGEST_H
#include <iosfwd>
#include <string>
namespace vtr {
//Generate a secure hash of the file at filepath
std::string secure_digest_file(const std::string& filepath);
//Generate a secure hash of a stream
std::string secure_digest_stream(std::istream& is);
} //namespace
#endif

View File

@ -0,0 +1,32 @@
#ifndef VTR_ERROR_H
#define VTR_ERROR_H
#include <stdexcept>
#include <string>
namespace vtr {
class VtrError : public std::runtime_error {
public:
VtrError(std::string msg="", std::string new_filename="", size_t new_linenumber=-1)
: std::runtime_error(msg)
, filename_(new_filename)
, linenumber_(new_linenumber) {}
//Returns the filename associated with this error
//returns an empty string if none is specified
std::string filename() const { return filename_; }
const char* filename_c_str() const { return filename_.c_str(); }
//Returns the line number associated with this error
//returns zero if none is specified
size_t line() const { return linenumber_; }
private:
std::string filename_;
size_t linenumber_;
};
}
#endif

View File

@ -0,0 +1,349 @@
#ifndef VTR_FLAT_MAP
#define VTR_FLAT_MAP
#include <functional>
#include <vector>
#include <algorithm>
#include <stdexcept>
#include "vtr_assert.h"
namespace vtr {
//Forward declaration
template<class K, class V, class Compare=std::less<K>>
class flat_map;
template<class K, class V, class Compare=std::less<K>>
class flat_map2;
//Helper function to create a flat map from a vector of pairs
//without haveing to explicity specify the key and value types
template<class K, class V>
flat_map<K,V> make_flat_map(std::vector<std::pair<K, V>> vec) {
return flat_map<K,V>(vec);
}
//
// flat_map is a (nearly) std::map compatible container which uses a vector
// as it's underlying storage. Internally the stored elements are kept sorted
// allowing efficient look-up in O(logN) time via binary search.
//
// This container is typically useful in the following scenarios:
// * Reduced memory usage if key/value are small (std::map needs to store pointers to
// other BST nodes which can add substantial overhead for small keys/values)
// * Faster search/iteration by exploiting data locality (all elments are in continguous
// memory enabling better spatial locality)
//
// The container deviates from the behaviour of std::map in the following important ways:
// * Insertion/erase takes O(N) instead of O(logN) time
// * Iterators may be invalidated on insertion/erase (i.e. if the vector is reallocated)
//
// The slow insertion/erase performance makes this container poorly suited to maps that
// frequently add/remove new keys. If this is required you likely want std::map or
// std::unordered_map. However if the map is constructed once and then repeatedly quieried,
// consider using the range or vector-based constructors which initializes the flat_map in
// O(NlogN) time.
//
template<class K, class T, class Compare>
class flat_map {
public:
typedef K key_type;
typedef T mapped_type;
typedef std::pair<K,T> value_type;
typedef Compare key_compare;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef typename std::vector<value_type>::iterator iterator;
typedef typename std::vector<value_type>::const_iterator const_iterator;
typedef typename std::vector<value_type>::reverse_iterator reverse_iterator;
typedef typename std::vector<value_type>::const_reverse_iterator const_reverse_iterator;
typedef typename std::vector<value_type>::difference_type difference_type;
typedef typename std::vector<value_type>::size_type size_type;
class value_compare;
public:
//Standard big 5
flat_map() = default;
flat_map(const flat_map&) = default;
flat_map(flat_map&&) = default;
flat_map& operator=(const flat_map&) = default;
flat_map& operator=(flat_map&&) = default;
//range constructor
template <class InputIterator>
flat_map(InputIterator first, InputIterator last) {
//Copy the values
std::copy(first, last, std::back_inserter(vec_));
sort();
uniquify();
}
//direct vector constructor
flat_map(std::vector<value_type> values) {
//By moving the values this should be more efficient
//than the range constructor which must copy each element
vec_ = std::move(values);
sort();
uniquify();
}
iterator begin() { return vec_.begin(); }
const_iterator begin() const { return vec_.begin(); }
iterator end() { return vec_.end(); }
const_iterator end() const { return vec_.end(); }
reverse_iterator rbegin() { return vec_.rbegin(); }
const_reverse_iterator rbegin() const { return vec_.rbegin(); }
reverse_iterator rend() { return vec_.rend(); }
const_reverse_iterator rend() const { return vec_.rend(); }
const_iterator cbegin() const { return vec_.begin(); }
const_iterator cend() const { return vec_.end(); }
const_reverse_iterator crbegin() const { return vec_.rbegin(); }
const_reverse_iterator crend() const { return vec_.rend(); }
bool empty() const { return vec_.empty(); }
size_type size() const { return vec_.size(); }
size_type max_size() const { return vec_.max_size(); }
const mapped_type& operator[](const key_type& key) const {
auto iter = find(key);
if(iter == end()) {
//Not found
throw std::out_of_range("Invalid key");
}
return iter->second;
}
mapped_type& operator[](const key_type& key) {
auto iter = find(key);
if(iter == end()) {
//Not found
iter = insert(std::make_pair(key,mapped_type())).first;
}
return iter->second;
}
mapped_type& at(const key_type& key) {
return const_cast<mapped_type&>(const_cast<const flat_map*>(this)->at(key));
}
const mapped_type& at(const key_type& key) const {
auto iter = find(key);
if(iter == end()) {
throw std::out_of_range("Invalid key");
}
return iter->second;
}
//Insert value
std::pair<iterator,bool> insert(const value_type& value) {
auto iter = lower_bound(value.first);
if(iter != end() && keys_equivalent(iter->first, value.first)) {
//Found existing
return std::make_pair(iter, false);
} else {
//Insert
iter = insert(iter, value);
return std::make_pair(iter, true);
}
}
//Insert value with position hint
iterator insert(const_iterator position, const value_type& value) {
//In a legal position
VTR_ASSERT(position == begin() || value_comp()(*(position - 1), value));
VTR_ASSERT(position == --end() || position == end() || !value_comp()(*(position + 1), value));
iterator iter = vec_.insert(position, value);
return iter;
}
//Insert range
template<class InputIterator>
void insert(InputIterator first, InputIterator last) {
vec_.insert(vec_.end(), first, last);
//TODO: could be more efficient
sort();
uniquify();
}
//Erase by key
void erase(const key_type& key) {
auto iter = find(key);
if(iter != end()) {
vec_.erase(iter);
}
}
//Erase at iterator
void erase(const_iterator position) {
vec_.erase(position);
}
//Erase range
void erase(const_iterator first, const_iterator last) {
vec_.erase(first,last);
}
void swap(flat_map& other) { std::swap(*this, other); }
void clear() { vec_.clear(); }
template<class ...Args>
iterator emplace(const key_type& key, Args&&... args) {
auto iter = lower_bound(key);
if(iter != end() && keys_equivalent(iter->first, key)) {
//Found
return std::make_pair(iter, false);
} else {
//Emplace
iter = emplace_hint(iter, key, std::forward<Args>(args)...);
return std::make_pair(iter, true);
}
}
template<class ...Args>
iterator emplace_hint(const_iterator position, Args&&... args) {
return vec_.emplace(position, std::forward<Args>(args)...);
}
void reserve(size_type n) { vec_.reserve(n); }
void shrink_to_fit() { vec_.shrink_to_fit(); }
key_compare key_comp() const { return key_compare(); }
value_compare value_comp() const { return value_compare(key_comp()); }
iterator find(const key_type& key) {
const_iterator const_iter = const_cast<const flat_map*>(this)->find(key);
return convert_to_iterator(const_iter);
}
const_iterator find(const key_type& key) const {
auto iter = lower_bound(key);
if(iter != end() && keys_equivalent(iter->first, key)) {
//Found
return iter;
}
return end();
}
size_type count(const key_type& key) const {
return (find(key) == end()) ? 0 : 1;
}
iterator lower_bound(const key_type& key) {
const_iterator const_iter = const_cast<const flat_map*>(this)->lower_bound(key);
return convert_to_iterator(const_iter);
}
const_iterator lower_bound(const key_type& key) const {
return std::lower_bound(begin(), end(), key, value_comp());
}
iterator upper_bound(const key_type& key) {
const_iterator const_iter = const_cast<const flat_map*>(this)->upper_bound(key);
return convert_to_iterator(const_iter);
}
const_iterator upper_bound(const key_type& key) const {
return std::upper_bound(begin(), end(), key, key_compare());
}
std::pair<iterator,iterator> equal_range(const key_type& key) {
auto const_iter_pair = const_cast<const flat_map*>(this)->equal_range(key);
return std::pair<iterator,iterator>(iterator(const_iter_pair.first), iterator(const_iter_pair.second));
}
std::pair<const_iterator,const_iterator> equal_range(const key_type& key) const {
return std::equal_range(begin(), end(), key);
}
public:
friend void swap(flat_map& lhs, flat_map& rhs) { std::swap(lhs.vec_, rhs.vec_); }
private:
bool keys_equivalent(const key_type& lhs, const key_type& rhs) const {
return !key_comp()(lhs, rhs) && !key_comp()(rhs, lhs);
}
void sort() {
std::sort(vec_.begin(), vec_.end(), value_comp());
}
void uniquify() {
//Uniquify
auto key_equal_pred = [this](const value_type& lhs, const value_type& rhs) {
return !value_comp()(lhs, rhs) && !value_comp()(rhs, lhs);
};
vec_.erase(std::unique(vec_.begin(), vec_.end(), key_equal_pred), vec_.end());
}
iterator convert_to_iterator(const_iterator const_iter) {
//This is a work around for the fact that there is no conversion between
//a const_iterator and iterator.
//
//We intiailize i to the start of the container and then advance it by
//the distance to const_iter. The resulting i points to the same element
//as const_iter
//
//Note that to be able to call std::distance with an iterator and
//const_iterator we need to specify the type as const_iterator (relying
//on the implicit conversion from iterator to const_iterator for i)
//
//Since the iterators are really vector (i.e. random-access) iterators
//this takes constant time
iterator i = begin();
std::advance(i, std::distance<const_iterator>(i, const_iter));
return i;
}
private:
std::vector<value_type> vec_;
};
//Like flat_map, but operator[] never inserts and directly returns the mapped value
template<class K, class T, class Compare>
class flat_map2 : public flat_map<K,T,Compare> {
public:
const T& operator[](const K& key) const {
auto itr = this->find(key);
if (itr == this->end()) {
throw std::logic_error("Key not found");
}
return itr->second;
}
T& operator[](const K& key) {
return const_cast<T&>(const_cast<const flat_map2*>(this)->operator[](key));
}
};
template<class K, class T, class Compare>
class flat_map<K,T,Compare>::value_compare {
friend class flat_map;
public:
bool operator() (const value_type& x, const value_type& y) const {
return comp(x.first, y.first);
}
//For std::lower_bound/std::upper_bound
bool operator() (const value_type& x, const key_type& y) const {
return comp(x.first, y);
}
private:
value_compare(Compare c) : comp(c) {}
Compare comp;
};
} //namespace
#endif

View File

@ -0,0 +1,167 @@
#ifndef VTR_GEOMETRY_H
#define VTR_GEOMETRY_H
#include <vector>
#include <tuple>
#include <limits>
#include "vtr_range.h"
namespace vtr {
/*
* Forward declarations
*/
template<class T>
class Point;
template<class T>
class Rect;
template<class T>
class Line;
template<class T>
class RectUnion;
template<class T>
bool operator==(Point<T> lhs, Point<T> rhs);
template<class T>
bool operator!=(Point<T> lhs, Point<T> rhs);
template<class T>
bool operator<(Point<T> lhs, Point<T> rhs);
template<class T>
bool operator==(const Rect<T>& lhs, const Rect<T>& rhs);
template<class T>
bool operator!=(const Rect<T>& lhs, const Rect<T>& rhs);
template<class T>
bool operator==(const RectUnion<T>& lhs, const RectUnion<T>& rhs);
template<class T>
bool operator!=(const RectUnion<T>& lhs, const RectUnion<T>& rhs);
/*
* Class Definitions
*/
//A point in 2D space
template<class T>
class Point {
public: //Constructors
Point(T x_val, T y_val);
public: //Accessors
//Coordinates
T x() const;
T y() const;
friend bool operator== <>(Point<T> lhs, Point<T> rhs);
friend bool operator!= <>(Point<T> lhs, Point<T> rhs);
friend bool operator< <>(Point<T> lhs, Point<T> rhs);
private:
T x_;
T y_;
};
//A 2D rectangle
template<class T>
class Rect {
public: //Constructors
Rect(T left_val, T bottom_val, T right_val, T top_val);
Rect(Point<T> bottom_left_val, Point<T> top_right_val);
Rect(); /* For RRGraph obj */
public: //Accessors
//Co-ordinates
T xmin() const;
T xmax() const;
T ymin() const;
T ymax() const;
Point<T> bottom_left() const;
Point<T> top_right() const;
T width() const;
T height() const;
//Returns true if the point is fully contained within the rectangle (excluding the top-right edges)
bool contains(Point<T> point) const;
//Returns true if the point is strictly contained within the region (excluding all edges)
bool strictly_contains(Point<T> point) const;
//Returns true if the point is coincident with the rectangle (including the top-right edges)
bool coincident(Point<T> point) const;
friend bool operator== <>(const Rect<T>& lhs, const Rect<T>& rhs);
friend bool operator!= <>(const Rect<T>& lhs, const Rect<T>& rhs);
private:
Point<T> bottom_left_;
Point<T> top_right_;
};
//A 2D line
template<class T>
class Line {
public: //Types
typedef typename std::vector<Point<T>>::const_iterator point_iter;
typedef vtr::Range<point_iter> point_range;
public: //Constructors
Line(std::vector<Point<T>> line_points);
public: //Accessors
//Returns the bounding box
Rect<T> bounding_box() const;
//Returns a range of constituent points
point_range points() const;
private:
std::vector<Point<T>> points_;
};
//A union of 2d rectangles
template<class T>
class RectUnion {
public: //Types
typedef typename std::vector<Rect<T>>::const_iterator rect_iter;
typedef vtr::Range<rect_iter> rect_range;
public: //Constructors
//Construct from a set of rectangles
RectUnion(std::vector<Rect<T>> rects);
public: //Accessors
//Returns the bounding box of all rectangles in the union
Rect<T> bounding_box() const;
//Returns true if the point is fully contained within the region (excluding top-right edges)
bool contains(Point<T> point) const;
//Returns true if the point is strictly contained within the region (excluding all edges)
bool strictly_contains(Point<T> point) const;
//Returns true if the point is coincident with the region (including the top-right edges)
bool coincident(Point<T> point) const;
//Returns a range of all constituent rectangles
rect_range rects() const;
//Checks whether two RectUnions have identical representations
// Note: does not check whether the representations they are equivalent
friend bool operator== <>(const RectUnion<T>& lhs, const RectUnion<T>& rhs);
friend bool operator!= <>(const RectUnion<T>& lhs, const RectUnion<T>& rhs);
private:
//Note that a union of rectanges may have holes and may not be contiguous
std::vector<Rect<T>> rects_;
};
} //namespace
#include "vtr_geometry.tpp"
#endif

View File

@ -0,0 +1,248 @@
namespace vtr {
/*
* Point
*/
template<class T>
Point<T>::Point(T x_val, T y_val)
: x_(x_val)
, y_(y_val) {
//pass
}
template<class T>
T Point<T>::x() const {
return x_;
}
template<class T>
T Point<T>::y() const {
return y_;
}
template<class T>
bool operator==(Point<T> lhs, Point<T> rhs) {
return lhs.x() == rhs.x()
&& lhs.y() == rhs.y();
}
template<class T>
bool operator!=(Point<T> lhs, Point<T> rhs) {
return !(lhs == rhs);
}
template<class T>
bool operator<(Point<T> lhs, Point<T> rhs) {
return std::make_tuple(lhs.x(), lhs.y()) < std::make_tuple(rhs.x(), rhs.y());
}
/*
* Rect
*/
template<class T>
Rect<T>::Rect(T left_val, T bottom_val, T right_val, T top_val)
: Rect<T>(Point<T>(left_val, bottom_val), Point<T>(right_val, top_val)) {
//pass
}
template<class T>
Rect<T>::Rect(Point<T> bottom_left_val, Point<T> top_right_val)
: bottom_left_(bottom_left_val)
, top_right_(top_right_val) {
//pass
}
/* A new contructor which initialize everything to be zero*/
template<class T>
Rect<T>::Rect()
: Rect<T>(Point<T>(0, 0), Point<T>(0, 0)) {
//pass
}
template<class T>
T Rect<T>::xmin() const {
return bottom_left_.x();
}
template<class T>
T Rect<T>::xmax() const {
return top_right_.x();
}
template<class T>
T Rect<T>::ymin() const {
return bottom_left_.y();
}
template<class T>
T Rect<T>::ymax() const {
return top_right_.y();
}
template<class T>
Point<T> Rect<T>::bottom_left() const {
return bottom_left_;
}
template<class T>
Point<T> Rect<T>::top_right() const {
return top_right_;
}
template<class T>
T Rect<T>::width() const {
return xmax() - xmin();
}
template<class T>
T Rect<T>::height() const {
return ymax() - ymin();
}
template<class T>
bool Rect<T>::contains(Point<T> point) const {
//Up-to but not including right or top edges
return point.x() >= xmin() && point.x() < xmax()
&& point.y() >= ymin() && point.y() < ymax();
}
template<class T>
bool Rect<T>::strictly_contains(Point<T> point) const {
//Excluding edges
return point.x() > xmin() && point.x() < xmax()
&& point.y() > ymin() && point.y() < ymax();
}
template<class T>
bool Rect<T>::coincident(Point<T> point) const {
//Including right or top edges
return point.x() >= xmin() && point.x() <= xmax()
&& point.y() >= ymin() && point.y() <= ymax();
}
template<class T>
bool operator==(const Rect<T>& lhs, const Rect<T>& rhs) {
return lhs.bottom_left() == rhs.bottom_left()
&& lhs.top_right() == rhs.top_right();
}
template<class T>
bool operator!=(const Rect<T>& lhs, const Rect<T>& rhs) {
return !(lhs == rhs);
}
/*
* Line
*/
template<class T>
Line<T>::Line(std::vector<Point<T>> line_points)
: points_(line_points) {
//pass
}
template<class T>
Rect<T> Line<T>::bounding_box() const {
T xmin = std::numeric_limits<T>::max();
T ymin = std::numeric_limits<T>::max();
T xmax = std::numeric_limits<T>::min();
T ymax = std::numeric_limits<T>::min();
for (const auto& point : points()) {
xmin = std::min(xmin, point.x());
ymin = std::min(ymin, point.y());
xmax = std::max(xmax, point.x());
ymax = std::max(ymax, point.y());
}
return Rect<T>(xmin, ymin, xmax, ymax);
}
template<class T>
typename Line<T>::point_range Line<T>::points() const {
return vtr::make_range(points_.begin(), points_.end());
}
/*
* RectUnion
*/
template<class T>
RectUnion<T>::RectUnion(std::vector<Rect<T>> rectangles)
: rects_(rectangles) {
//pass
}
template<class T>
Rect<T> RectUnion<T>::bounding_box() const {
T xmin = std::numeric_limits<T>::max();
T ymin = std::numeric_limits<T>::max();
T xmax = std::numeric_limits<T>::min();
T ymax = std::numeric_limits<T>::min();
for (const auto& rect : rects_) {
xmin = std::min(xmin, rect.xmin());
ymin = std::min(ymin, rect.ymin());
xmax = std::max(xmax, rect.xmax());
ymax = std::max(ymax, rect.ymax());
}
return Rect<T>(xmin, ymin, xmax, ymax);
}
template<class T>
bool RectUnion<T>::contains(Point<T> point) const {
for(const auto& rect : rects()) {
if (rect.contains(point)) {
return true;
}
}
return false;
}
template<class T>
bool RectUnion<T>::strictly_contains(Point<T> point) const {
for(const auto& rect : rects()) {
if (rect.strictly_contains(point)) {
return true;
}
}
return false;
}
template<class T>
bool RectUnion<T>::coincident(Point<T> point) const {
for(const auto& rect : rects()) {
if (rect.coincident(point)) {
return true;
}
}
return false;
}
template<class T>
typename RectUnion<T>::rect_range RectUnion<T>::rects() const {
return vtr::make_range(rects_.begin(), rects_.end());
}
template<class T>
bool operator==(const RectUnion<T>& lhs, const RectUnion<T>& rhs) {
//Currently checks for an identical *representation* (not whether the
//representations are equivalent)
if (lhs.rects_.size() != rhs.rects_.size()) {
return false;
}
for (size_t i = 0; i < lhs.rects_.size(); ++i) {
if (lhs.rects_[i] != rhs.rects_[i]) {
return false;
}
}
return true;
}
template<class T>
bool operator!=(const RectUnion<T>& lhs, const RectUnion<T>& rhs) {
return !(lhs == rhs);
}
} //namespace

View File

@ -0,0 +1,19 @@
#ifndef VTR_HASH_H
#define VTR_HASH_H
#include <functional>
namespace vtr {
//Hashes v and combines it with seed (as in boost)
//
//This is typically used to implement std::hash for composite types.
template <class T>
inline void hash_combine(std::size_t& seed, const T& v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
} //namespace
#endif

View File

@ -0,0 +1,263 @@
#ifndef VTR_LINEAR_MAP_H
#define VTR_LINEAR_MAP_H
#include <vector>
#include <stdexcept>
#include "vtr_sentinels.h"
namespace vtr {
//A std::map-like container which is indexed by K
//
//The main use of this container is to behave like a std::map which is optimized to hold
//mappings between a dense linear range of keys (e.g. vtr::StrongId).
//
//Requires that K be convertable to size_t with the size_t operator (i.e. size_t()), and
//that the conversion results in a linearly increasing index into the underlying vector.
//Also requires that K() return the sentinel value used to mark invalid entries.
//
//If you only need to access the value associated with the key consider using vtr::vector_map
//instead, which provides a similar but more std::vector-like interface.
//
//Note that it is possible to use linear_map with sparse/non-contiguous keys, but this is typically
//memory inefficient as the underlying vector will allocate space for [0..size_t(max_key)-1],
//where max_key is the largest key that has been inserted.
//
//As with a std::vector, it is the caller's responsibility to ensure there is sufficient space
//when a given index/key before it is accessed. The exception to this are the find() and insert()
//methods which handle non-existing keys gracefully.
template<class K, class T, class Sentinel=DefaultSentinel<K>>
class linear_map {
public:
typedef K key_type;
typedef T mapped_type;
typedef std::pair<K,T> value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef typename std::vector<value_type>::iterator iterator;
typedef typename std::vector<value_type>::const_iterator const_iterator;
typedef typename std::vector<value_type>::reverse_iterator reverse_iterator;
typedef typename std::vector<value_type>::const_reverse_iterator const_reverse_iterator;
typedef typename std::vector<value_type>::difference_type difference_type;
typedef typename std::vector<value_type>::size_type size_type;
public:
//Standard big 5
linear_map() = default;
linear_map(const linear_map&) = default;
linear_map(linear_map&&) = default;
linear_map& operator=(const linear_map&) = default;
linear_map& operator=(linear_map&&) = default;
linear_map(size_t num_keys)
: vec_(num_keys, std::make_pair(sentinel(), T())) //Initialize all with sentinel values
{}
iterator begin() { return vec_.begin(); }
const_iterator begin() const { return vec_.begin(); }
iterator end() { return vec_.end(); }
const_iterator end() const { return vec_.end(); }
reverse_iterator rbegin() { return vec_.rbegin(); }
const_reverse_iterator rbegin() const { return vec_.rbegin(); }
reverse_iterator rend() { return vec_.rend(); }
const_reverse_iterator rend() const { return vec_.rend(); }
const_iterator cbegin() const { return vec_.begin(); }
const_iterator cend() const { return vec_.end(); }
const_reverse_iterator crbegin() const { return vec_.rbegin(); }
const_reverse_iterator crend() const { return vec_.rend(); }
bool empty() const { return vec_.empty(); }
size_type size() const { return vec_.size(); }
size_type max_size() const { return vec_.max_size(); }
mapped_type& operator[](const key_type& key) {
auto iter = find(key);
if(iter == end()) {
//Not found, create it
iter = insert(std::make_pair(key,mapped_type())).first;
}
return iter->second;
}
mapped_type& at(const key_type& key) {
return const_cast<mapped_type&>(const_cast<const linear_map*>(this)->at(key));
}
const mapped_type& at(const key_type& key) const {
auto iter = find(key);
if(iter == end()) {
throw std::out_of_range("Invalid key");
}
return iter->second;
}
//Insert value
std::pair<iterator,bool> insert(const value_type& value) {
auto iter = find(value.first);
if(iter != end()) {
//Found existing
return std::make_pair(iter, false);
} else {
//Insert
size_t index = size_t(value.first);
if(index >= vec_.size()) {
//Make space, initialize empty slots with sentinel values
vec_.resize(index + 1, std::make_pair(sentinel(), T()));
}
vec_[index] = value;
return std::make_pair(vec_.begin() + index, true);
}
}
//Insert range
template<class InputIterator>
void insert(InputIterator first, InputIterator last) {
for(InputIterator iter = first; iter != last; ++iter) {
insert(*iter);
}
}
//Erase by key
void erase(const key_type& key) {
auto iter = find(key);
if(iter != end()) {
erase(iter);
}
}
//Erase at iterator
void erase(const_iterator position) {
iterator pos = convert_to_iterator(position);
pos->first = sentinel(); //Mark invalid
}
//Erase range
void erase(const_iterator first, const_iterator last) {
for(auto iter = first; iter != last; ++iter) {
erase(iter);
}
}
void swap(linear_map& other) { std::swap(vec_, other.vec_); }
void clear() { vec_.clear(); }
template<class ...Args>
std::pair<iterator,bool> emplace(const key_type& key, Args&&... args) {
auto iter = find(key);
if(iter != end()) {
//Found
return std::make_pair(iter, false);
} else {
//Emplace
size_t index = size_t(key);
if(index >= vec_.size()) {
//Make space, initialize empty slots with sentinel values
vec_.resize(index + 1, value_type(sentinel(), T()));
}
vec_[index] = value_type(key, std::forward<Args>(args)...);
return std::make_pair(vec_.begin() + index, true);
}
}
void reserve(size_type n) { vec_.reserve(n); }
void shrink_to_fit() { vec_.shrink_to_fit(); }
iterator find(const key_type& key) {
const_iterator const_iter = const_cast<const linear_map*>(this)->find(key);
return convert_to_iterator(const_iter);
}
const_iterator find(const key_type& key) const {
size_t index = size_t(key);
if(index < vec_.size() && vec_[index].first != sentinel()) {
return vec_.begin() + index;
}
return end();
}
size_type count(const key_type& key) const {
return (find(key) == end()) ? 0 : 1;
}
iterator lower_bound(const key_type& key) {
const_iterator const_iter = const_cast<const linear_map*>(this)->lower_bound(key);
return convert_to_iterator(const_iter);
}
const_iterator lower_bound(const key_type& key) const {
return find(key);
}
iterator upper_bound(const key_type& key) {
const_iterator const_iter = const_cast<const linear_map*>(this)->upper_bound(key);
return convert_to_iterator(const_iter);
}
const_iterator upper_bound(const key_type& key) const {
auto iter = find(key);
return (iter != end()) ? iter + 1 : end();
}
std::pair<iterator,iterator> equal_range(const key_type& key) {
auto const_iter_pair = const_cast<const linear_map*>(this)->equal_range(key);
return std::pair<iterator,iterator>(iterator(const_iter_pair.first), iterator(const_iter_pair.second));
}
std::pair<const_iterator,const_iterator> equal_range(const key_type& key) const {
auto lb_iter = lower_bound(key);
auto ub_iter = upper_bound(key);
return (lb_iter != end()) ? std::make_pair(lb_iter, ub_iter) : std::make_pair(ub_iter, ub_iter);
}
size_type valid_size() const {
size_t valid_cnt = 0;
for(const auto& kv : vec_) {
if(kv.first != sentinel()) {
++valid_cnt;
}
}
return valid_cnt;
}
public:
friend void swap(linear_map& lhs, linear_map& rhs) {
std::swap(lhs.vec_, rhs.vec_);
}
private:
iterator convert_to_iterator(const_iterator const_iter) {
//This is a work around for the fact that there is no conversion between
//a const_iterator and iterator.
//
//We intiailize i to the start of the container and then advance it by
//the distance to const_iter. The resulting i points to the same element
//as const_iter
//
//Note that to be able to call std::distance with an iterator and
//const_iterator we need to specify the type as const_iterator (relying
//on the implicit conversion from iterator to const_iterator for i)
//
//Since the iterators are really vector (i.e. random-access) iterators
//both distance and advance take constant time
iterator i = begin();
std::advance(i, std::distance<const_iterator>(i, const_iter));
return i;
}
constexpr K sentinel() const { return Sentinel::INVALID(); }
private:
std::vector<value_type> vec_;
};
} //namespace
#endif

View File

@ -0,0 +1,34 @@
#include <cstdlib>
#include "vtr_list.h"
#include "vtr_memory.h"
namespace vtr {
t_linked_vptr *insert_in_vptr_list(t_linked_vptr *head, void *vptr_to_add) {
/* Inserts a new element at the head of a linked list of void pointers. *
* Returns the new head of the list. */
t_linked_vptr *linked_vptr;
linked_vptr = (t_linked_vptr *) vtr::malloc(sizeof(t_linked_vptr));
linked_vptr->data_vptr = vptr_to_add;
linked_vptr->next = head;
return (linked_vptr); /* New head of the list */
}
/* Deletes the element at the head of a linked list of void pointers. *
* Returns the new head of the list. */
t_linked_vptr *delete_in_vptr_list(t_linked_vptr *head) {
t_linked_vptr *linked_vptr;
if (head == nullptr )
return nullptr ;
linked_vptr = head->next;
free(head);
return linked_vptr; /* New head of the list */
}
} //namespace

View File

@ -0,0 +1,16 @@
#ifndef VTR_LIST_H
#define VTR_LIST_H
namespace vtr {
/* Linked lists of void pointers and integers, respectively. */
struct t_linked_vptr {
void *data_vptr;
struct t_linked_vptr *next;
};
t_linked_vptr *insert_in_vptr_list(t_linked_vptr *head,
void *vptr_to_add);
t_linked_vptr *delete_in_vptr_list(t_linked_vptr *head);
}
#endif

View File

@ -0,0 +1,17 @@
#include "vtr_log.h"
#include "log.h"
namespace vtr {
PrintHandlerInfo printf = log_print_info;
PrintHandlerInfo printf_info = log_print_info;
PrintHandlerWarning printf_warning = log_print_warning;
PrintHandlerError printf_error = log_print_error;
PrintHandlerDirect printf_direct = log_print_direct;
void set_log_file(const char* filename) {
log_set_output_file(filename);
}
} //namespace

View File

@ -0,0 +1,133 @@
#ifndef VTR_LOG_H
#define VTR_LOG_H
#include <tuple>
/*
* This header defines useful logging macros for VTR projects.
*
* Message Type
* ============
*
* Three types of log message types are defined:
* VTR_LOG - The standard 'info' type log message
* VTR_LOG_WARN - A warning log message
* VTR_LOG_ERROR - An error log message
*
* For example:
*
* VTR_LOG("This produces a regular '%s' message\n", "info");
* VTR_LOG_WARN("This produces a '%s' message\n", "warning");
* VTR_LOG_ERROR("This produces an '%s' message\n", "error");
*
* Conditional Logging
* ===================
*
* Each of the three message types also have a VTR_LOGV_* variant,
* which will cause the message to be logged if a user-defined condition
* is satisifed.
*
* For example:
*
* VTR_LOGV(verbosity > 5, "This message will be logged only if verbosity is greater than %d\n", 5);
* VTR_LOGV_WARN(verbose, "This warning message will be logged if verbose is true\n");
* VTR_LOGV_ERROR(false, "This error message will never be logged\n");
*
* Custom Location Logging
* =======================
*
* Each of the three message types also have a VTR_LOGF_* variant,
* which will cause the message to be logged for a custom file and
* line loation.
*
* For example:
*
* VTR_LOGF("my_file.txt", 42 "This message will be logged from file 'my_file.txt' line %d\n", 42);
*
* Debug Logging
* =============
*
* For debug purposes it may be useful to have additional logging.
* This is supported by VTR_LOG_DEBUG() and VTR_LOGV_DEBUG().
*
* To avoid run-time overhead, these are only enabled if VTR_ENABLE_DEBUG_LOGGING
* is defined (disabled by default).
*/
//Unconditional logging macros
#define VTR_LOG(...) VTR_LOGV(true, __VA_ARGS__)
#define VTR_LOG_WARN(...) VTR_LOGV_WARN(true, __VA_ARGS__)
#define VTR_LOG_ERROR(...) VTR_LOGV_ERROR(true, __VA_ARGS__)
#define VTR_LOG_NOP(...) VTR_LOGV_NOP(true, __VA_ARGS__)
//Conditional logging macros
#define VTR_LOGV(expr, ...) VTR_LOGVF(expr, __FILE__, __LINE__, __VA_ARGS__)
#define VTR_LOGV_WARN(expr, ...) VTR_LOGVF_WARN(expr, __FILE__, __LINE__, __VA_ARGS__)
#define VTR_LOGV_ERROR(expr, ...) VTR_LOGVF_ERROR(expr, __FILE__, __LINE__, __VA_ARGS__)
#define VTR_LOGV_NOP(expr, ...) VTR_LOGVF_NOP(expr, __FILE__, __LINE__, __VA_ARGS__)
//Custom file-line location logging macros
#define VTR_LOGF(file, line, ...) VTR_LOGVF(true, file, line, __VA_ARGS__)
#define VTR_LOGF_WARN(file, line, ...) VTR_LOGVF_WARN(true, file, line, __VA_ARGS__)
#define VTR_LOGF_ERROR(file, line, ...) VTR_LOGVF_ERROR(true, file, line, __VA_ARGS__)
#define VTR_LOGF_NOP(file, line, ...) VTR_LOGVF_NOP(true, file, line, __VA_ARGS__)
//Conditional logging and custom file-line location macros
#define VTR_LOGVF(expr, file, line, ...) \
do { \
if (expr) vtr::printf(__VA_ARGS__); \
} while (false)
#define VTR_LOGVF_WARN(expr, file, line, ...) \
do { \
if (expr) vtr::printf_warning(file, line, __VA_ARGS__); \
} while (false)
#define VTR_LOGVF_ERROR(expr, file, line, ...) \
do { \
if (expr) vtr::printf_error(file, line, __VA_ARGS__); \
} while (false)
//No-op version of logging macro which avoids unused parameter warnings.
//
//Note that to avoid unused parameter warnings we call sizeof() and cast
//the result to void. sizeof is evaluated at compile time so there is no
//run-time overhead.
//
//Also note the use of std::make_tuple to ensure all arguments in VA_ARGS
//are used.
#define VTR_LOGVF_NOP(expr, file, line, ...) \
do { \
static_cast<void>(sizeof(expr)); \
static_cast<void>(sizeof(file)); \
static_cast<void>(sizeof(line)); \
static_cast<void>(sizeof(std::make_tuple(__VA_ARGS__))); \
} while (false)
//Debug logging macros
#ifdef VTR_ENABLE_DEBUG_LOGGING //Enable
# define VTR_LOG_DEBUG(...) VTR_LOG(__VA_ARGS__)
# define VTR_LOGV_DEBUG(expr, ...) VTR_LOGV(expr, __VA_ARGS__)
#else //Disable
# define VTR_LOG_DEBUG(...) VTR_LOG_NOP(__VA_ARGS__)
# define VTR_LOGV_DEBUG(expr, ...) VTR_LOGV_NOP(expr, __VA_ARGS__)
#endif
namespace vtr {
typedef void (*PrintHandlerInfo)(const char* pszMessage, ... );
typedef void (*PrintHandlerWarning)(const char* pszFileName, unsigned int lineNum, const char* pszMessage, ... );
typedef void (*PrintHandlerError)(const char* pszFileName, unsigned int lineNum, const char* pszMessage, ... );
typedef void (*PrintHandlerDirect)(const char* pszMessage, ... );
extern PrintHandlerInfo printf; //Same as printf_info
extern PrintHandlerInfo printf_info;
extern PrintHandlerWarning printf_warning;
extern PrintHandlerError printf_error;
extern PrintHandlerDirect printf_direct;
void set_log_file(const char* filename);
} //namespace
#endif

View File

@ -0,0 +1,15 @@
#ifndef VTR_LOGIC_H
#define VTR_LOGIC_H
namespace vtr {
enum class LogicValue {
FALSE = 0,
TRUE = 1,
DONT_CARE = 2,
UNKOWN = 3
};
} //namespace
#endif

View File

@ -0,0 +1,45 @@
#ifndef VTR_MAP_UTIL_H
#define VTR_MAP_UTIL_H
#include "vtr_pair_util.h"
#include "vtr_range.h"
namespace vtr {
//An iterator who wraps a std::map iterator to return it's key
template<typename Iter>
using map_key_iter = pair_first_iter<Iter>;
//An iterator who wraps a std::map iterator to return it's value
template<typename Iter>
using map_value_iter = pair_second_iter<Iter>;
//Returns a range iterating over a std::map's keys
template<typename T>
auto make_key_range(T b, T e) {
using key_iter = map_key_iter<T>;
return vtr::make_range(key_iter(b), key_iter(e));
}
//Returns a range iterating over a std::map's keys
template<typename Container>
auto make_key_range(const Container& c) {
return make_key_range(std::begin(c), std::end(c));
}
//Returns a range iterating over a std::map's values
template<typename T>
auto make_value_range(T b, T e) {
using value_iter = map_value_iter<T>;
return vtr::make_range(value_iter(b), value_iter(e));
}
//Returns a range iterating over a std::map's values
template<typename Container>
auto make_value_range(const Container& c) {
return make_value_range(std::begin(c), std::end(c));
}
} //namespace
#endif

View File

@ -0,0 +1,86 @@
#include <map>
#include "vtr_assert.h"
#include "vtr_error.h"
#include "vtr_math.h"
namespace vtr {
int ipow(int base, int exp) {
int result = 1;
VTR_ASSERT(exp >= 0);
while (exp) {
if (exp & 1)
result *= base;
exp >>= 1;
base *= base;
}
return result;
}
/* Performs linear interpolation or extrapolation on the set of (x,y) values specified by the xy_map.
A requested x value is passed in, and we return the interpolated/extrapolated y value at this requested value of x.
Meant for maps where both key and element are numbers.
This is specifically enforced by the explicit instantiations below this function. i.e. only templates
using those types listed in the explicit instantiations below are allowed */
template<typename X, typename Y> Y linear_interpolate_or_extrapolate(const std::map<X,Y> *xy_map, X requested_x){
Y result;
/* the intention of this function is to interpolate/extrapolate. we can't do so with less than 2 values in the xy_map */
if (xy_map->size() < 2){
throw VtrError("linear_interpolate_or_extrapolate: cannot interpolate/extrapolate based on less than 2 (x,y) pairs", __FILE__, __LINE__);
}
auto itr = xy_map->find(requested_x);
if (itr != xy_map->end()){
/* requested x already exists in the x,y map */
result = itr->second;
} else {
/* requested x does not exist in the x,y map. need to interpolate/extrapolate */
typename std::map<X,Y>::const_iterator it;
double x_low, x_high, y_low, y_high;
double slope, reference_y, delta_x;
/* get first x greater than the one requested */
it = xy_map->upper_bound(requested_x);
if(it == xy_map->end()){
/* need to extrapolate to higher x. based on the y values at the two largest x values */
it--;
x_high = (double)it->first;
y_high = (double)it->second;
it--;
x_low = (double)it->first;
y_low = (double)it->second;
} else if (it == xy_map->begin()){
/* need to extrapolate to lower x. based on the y values at the two smallest x */
x_low = (double)it->first;
y_low = (double)it->second;
it++;
x_high = (double)it->first;
y_high = (double)it->second;
} else {
/* need to interpolate. based on y values at x just above/below
the one we want */
x_high = (double)it->first;
y_high = (double)it->second;
it--;
x_low = (double)it->first;
y_low = (double)it->second;
}
slope = (y_high - y_low) / (x_high - x_low);
reference_y = y_low;
delta_x = (double)requested_x - x_low;
result = (Y)(reference_y + (slope * delta_x));
}
return result;
}
template double linear_interpolate_or_extrapolate(const std::map<int,double> *xy_map, int requested_x); /* (int,double) */
template double linear_interpolate_or_extrapolate(const std::map<double,double> *xy_map, double requested_x); /* (double,double) */
}

View File

@ -0,0 +1,139 @@
#ifndef VTR_MATH_H
#define VTR_MATH_H
#include <map>
#include <cmath>
#include "vtr_assert.h"
namespace vtr {
/*********************** Math operations *************************************/
int ipow(int base, int exp);
template<typename X, typename Y>
Y linear_interpolate_or_extrapolate(const std::map<X,Y> *xy_map, X requested_x);
constexpr int nint(float val) { return static_cast<int>(val + 0.5); }
//Returns a 'safe' ratio which evaluates to zero if the denominator is zero
template<typename T>
T safe_ratio(T numerator, T denominator) {
if (denominator == T(0)) {
return 0;
}
return numerator / denominator;
}
template<typename InputIterator>
double median(InputIterator first, InputIterator last) {
auto len = std::distance(first, last);
auto iter = first + len / 2;
if (len % 2 == 0) {
return (*iter + *(iter + 1)) / 2;
} else {
return *iter;
}
}
template<typename Container>
double median(Container c) {
return median(std::begin(c), std::end(c));
}
template<typename InputIterator>
double geomean(InputIterator first, InputIterator last, double init=1.) {
//Compute the geometric mean of the elments in range [first, last)
//
//To avoid potential round-off issues we transform the standard formula:
//
// geomean = ( v_1 * v_2 * ... * v_n) ^ (1/n)
//
//by taking the log:
//
// geomean = exp( (1 / n) * (log(v_1) + log(v_2) + ... + log(v_n)))
double log_sum = std::log(init);
size_t n = 0;
for(auto iter = first; iter != last; ++iter) {
log_sum += std::log(*iter);
n += 1;
}
VTR_ASSERT(n > 0.);
return std::exp( (1. / n) * log_sum );
}
template<typename Container>
double geomean(Container c) {
return geomean(std::begin(c), std::end(c));
}
template<typename InputIterator>
double arithmean(InputIterator first, InputIterator last, double init=0.) {
double sum = init;
size_t n = 0;
for (auto iter = first; iter != last; ++iter) {
sum += *iter;
n += 1;
}
VTR_ASSERT(n > 0.);
return sum / n;
}
template<typename Container>
double arithmean(Container c) {
return arithmean(std::begin(c), std::end(c));
}
//Return the greatest common divisor of x and y
// Note that T should be an integral type
template<typename T>
static T gcd(T x, T y){
static_assert(std::is_integral<T>::value, "T must be integral");
//Euclidean algorithm
if (y == 0){
return x;
}
return gcd(y, x % y);
}
//Return the least common multiple of x and y
// Note that T should be an integral type
template<typename T>
T lcm(T x, T y) {
static_assert(std::is_integral<T>::value, "T must be integral");
if (x == 0 && y == 0) {
return 0;
} else {
return (x / gcd(x,y)) * y;
}
}
constexpr double DEFAULT_REL_TOL = 1e-9;
constexpr double DEFAULT_ABS_TOL = 0;
template<class T>
bool isclose(T a, T b, T rel_tol, T abs_tol) {
if (std::isinf(a) && std::isinf(b)) return (std::signbit(a) == std::signbit(b));
if (std::isnan(a) && std::isnan(b)) return false;
T abs_largest = std::max(std::abs(a), std::abs(b));
return std::abs(a - b) <= std::max(rel_tol * abs_largest, abs_tol);
}
template<class T>
bool isclose(T a, T b) {
return isclose<T>(a, b, DEFAULT_REL_TOL, DEFAULT_ABS_TOL);
}
}
#endif

View File

@ -0,0 +1,177 @@
#include <cstddef>
#include <cstdlib>
#include "vtr_assert.h"
#include "vtr_list.h"
#include "vtr_memory.h"
#include "vtr_error.h"
#include "vtr_util.h"
#ifndef __GLIBC__
#include <stdlib.h>
#else
#include <malloc.h>
#endif
namespace vtr {
#ifndef __GLIBC__
int malloc_trim(size_t /*pad*/) {
return 0;
}
#else
int malloc_trim(size_t pad) {
return ::malloc_trim(pad);
}
#endif
void* free(void *some){
if(some){
std::free(some);
some = nullptr;
}
return nullptr;
}
void* calloc(size_t nelem, size_t size) {
void *ret;
if (nelem == 0) {
return nullptr ;
}
if ((ret = std::calloc(nelem, size)) == nullptr ) {
throw VtrError("Unable to calloc memory.", __FILE__, __LINE__);
}
return (ret);
}
void* malloc(size_t size) {
void *ret;
if (size == 0) {
return nullptr ;
}
if ((ret = std::malloc(size)) == nullptr && size != 0) {
throw VtrError("Unable to malloc memory.", __FILE__, __LINE__);
}
return (ret);
}
void* realloc(void *ptr, size_t size) {
void *ret;
ret = std::realloc(ptr, size);
if (nullptr == ret && size != 0) {
throw VtrError(string_fmt("Unable to realloc memory (ptr=%p, size=%d).", ptr, size),
__FILE__, __LINE__);
}
return (ret);
}
void* chunk_malloc(size_t size, t_chunk *chunk_info) {
/* This routine should be used for allocating fairly small data *
* structures where memory-efficiency is crucial. This routine allocates *
* large "chunks" of data, and parcels them out as requested. Whenever *
* it mallocs a new chunk it adds it to the linked list pointed to by *
* chunk_info->chunk_ptr_head. This list can be used to free the *
* chunked memory. *
* Information about the currently open "chunk" must be stored by the *
* user program. chunk_info->mem_avail_ptr points to an int storing *
* how many bytes are left in the current chunk, while *
* chunk_info->next_mem_loc_ptr is the address of a pointer to the *
* next free bytes in the chunk. To start a new chunk, simply set *
* chunk_info->mem_avail_ptr = 0. Each independent set of data *
* structures should use a new chunk. */
/* To make sure the memory passed back is properly aligned, I must *
* only send back chunks in multiples of the worst-case alignment *
* restriction of the machine. On most machines this should be *
* a long, but on 64-bit machines it might be a long long or a *
* double. Change the typedef below if this is the case. */
typedef size_t Align;
constexpr int CHUNK_SIZE = 32768;
constexpr int FRAGMENT_THRESHOLD = 100;
char *tmp_ptr;
int aligned_size;
VTR_ASSERT(chunk_info->mem_avail >= 0);
if ((size_t) (chunk_info->mem_avail) < size) { /* Need to malloc more memory. */
if (size > CHUNK_SIZE) { /* Too big, use standard routine. */
tmp_ptr = (char *) vtr::malloc(size);
/* When debugging, uncomment the code below to see if memory allocation size */
/* makes sense */
//#ifdef DEBUG
// vtr_printf("NB: my_chunk_malloc got a request for %d bytes.\n", size);
// vtr_printf("You should consider using vtr::malloc for such big requests.\n");
// #endif
VTR_ASSERT(chunk_info != nullptr);
chunk_info->chunk_ptr_head = insert_in_vptr_list(
chunk_info->chunk_ptr_head, tmp_ptr);
return (tmp_ptr);
}
if (chunk_info->mem_avail < FRAGMENT_THRESHOLD) { /* Only a small scrap left. */
chunk_info->next_mem_loc_ptr = (char *) vtr::malloc(CHUNK_SIZE);
chunk_info->mem_avail = CHUNK_SIZE;
VTR_ASSERT(chunk_info != nullptr);
chunk_info->chunk_ptr_head = insert_in_vptr_list(
chunk_info->chunk_ptr_head, chunk_info->next_mem_loc_ptr);
}
/* Execute else clause only when the chunk we want is pretty big, *
* and would leave too big an unused fragment. Then we use malloc *
* to allocate normally. */
else {
tmp_ptr = (char *) vtr::malloc(size);
VTR_ASSERT(chunk_info != nullptr);
chunk_info->chunk_ptr_head = insert_in_vptr_list(
chunk_info->chunk_ptr_head, tmp_ptr);
return (tmp_ptr);
}
}
/* Find the smallest distance to advance the memory pointer and keep *
* everything aligned. */
if (size % sizeof(Align) == 0) {
aligned_size = size;
} else {
aligned_size = size + sizeof(Align) - size % sizeof(Align);
}
tmp_ptr = chunk_info->next_mem_loc_ptr;
chunk_info->next_mem_loc_ptr += aligned_size;
chunk_info->mem_avail -= aligned_size;
return (tmp_ptr);
}
void free_chunk_memory(t_chunk *chunk_info) {
/* Frees the memory allocated by a sequence of calls to my_chunk_malloc. */
t_linked_vptr *curr_ptr, *prev_ptr;
curr_ptr = chunk_info->chunk_ptr_head;
while (curr_ptr != nullptr ) {
free(curr_ptr->data_vptr); /* Free memory "chunk". */
prev_ptr = curr_ptr;
curr_ptr = curr_ptr->next;
free(prev_ptr); /* Free memory used to track "chunk". */
}
chunk_info->chunk_ptr_head = nullptr;
chunk_info->mem_avail = 0;
chunk_info->next_mem_loc_ptr = nullptr;
}
} //namespace

View File

@ -0,0 +1,51 @@
#ifndef VTR_MEMORY_H
#define VTR_MEMORY_H
#include <cstddef>
namespace vtr {
struct t_linked_vptr; //Forward declaration
/* This structure is to keep track of chunks of memory that is being *
* allocated to save overhead when allocating very small memory pieces. *
* For a complete description, please see the comment in chunk_malloc*/
struct t_chunk {
t_linked_vptr *chunk_ptr_head = nullptr;
/* chunk_ptr_head->data_vptr: head of the entire linked
* list of allocated "chunk" memory;
* chunk_ptr_head->next: pointer to the next chunk on the linked list*/
int mem_avail = 0; /* number of bytes left in the current chunk */
char *next_mem_loc_ptr = nullptr;/* pointer to the first available (free) *
* byte in the current chunk */
};
void* free(void *some);
void* calloc(size_t nelem, size_t size);
void* malloc(size_t size);
void* realloc(void *ptr, size_t size);
void* chunk_malloc(size_t size, t_chunk *chunk_info);
void free_chunk_memory(t_chunk *chunk_info);
//Like chunk_malloc, but with proper C++ object initialization
template<typename T>
T* chunk_new(t_chunk *chunk_info) {
void* block = chunk_malloc(sizeof(T), chunk_info);
return new (block) T(); //Placement new
}
//Call the destructor of an obj which must have been allocated in the specified chunk
template<typename T>
void chunk_delete(T* obj, t_chunk * /*chunk_info*/) {
if (obj) {
obj->~T(); //Manually call destructor
//Currently we don't mark the unused memory as free
}
}
//Cross platform wrapper around GNU's malloc_trim()
// TODO: This is only used in one place within VPR, consider removing it
int malloc_trim(size_t pad);
}
#endif

View File

@ -0,0 +1,359 @@
#ifndef VTR_ND_MATRIX_H
#define VTR_ND_MATRIX_H
#include <array>
#include <memory>
#include "vtr_assert.h"
namespace vtr {
//Proxy class for a sub-matrix of a NdMatrix class.
//This is used to allow chaining of array indexing [] operators in a natural way.
//
//Each instance of this class peels off one-dimension and returns a NdMatrixProxy representing
//the resulting sub-matrix. This is repeated recursively until we hit the 1-dimensional base-case.
//
//Since this expansion happens at compiler time all the proxy classes get optimized away,
//yielding both high performance and generality.
//
//Recursive case: N-dimensional array
template<typename T, size_t N>
class NdMatrixProxy {
public:
static_assert(N > 0, "Must have at least one dimension");
//Construct a matrix proxy object
//
// dim_sizes: Array of dimension sizes
// idim: The dimension associated with this proxy
// dim_stride: The stride of this dimension (i.e. how many element in memory between indicies of this dimension)
// start: Pointer to the start of the sub-matrix this proxy represents
NdMatrixProxy<T,N>(const size_t* dim_sizes, size_t idim, size_t dim_stride, T* start)
: dim_sizes_(dim_sizes)
, idim_(idim)
, dim_stride_(dim_stride)
, start_(start) {}
const NdMatrixProxy<T,N-1> operator[](size_t index) const {
VTR_ASSERT_SAFE_MSG(index >= 0, "Index out of range (below dimension minimum)");
VTR_ASSERT_SAFE_MSG(index < dim_sizes_[idim_], "Index out of range (above dimension maximum)");
size_t next_dim_size = dim_sizes_[idim_ + 1];
VTR_ASSERT_SAFE_MSG(next_dim_size > 0, "Can not index into zero-sized dimension");
//Determine the stride of the next dimension
size_t next_dim_stride = dim_stride_ / next_dim_size;
//Strip off one dimension
return NdMatrixProxy<T,N-1>(dim_sizes_, //Pass the dimension information
idim_ + 1, //Pass the next dimension
next_dim_stride, //Pass the stride for the next dimension
start_ + dim_stride_*index); //Advance to index in this dimension
}
NdMatrixProxy<T,N-1> operator[](size_t index) {
//Call the const version and cast-away constness
return const_cast<const NdMatrixProxy<T,N>*>(this)->operator[](index);
}
private:
const size_t* dim_sizes_;
const size_t idim_;
const size_t dim_stride_;
T* start_;
};
//Base case: 1-dimensional array
template<typename T>
class NdMatrixProxy<T,1> {
public:
NdMatrixProxy<T,1>(const size_t* dim_sizes, size_t idim, size_t dim_stride, T* start)
: dim_sizes_(dim_sizes)
, idim_(idim)
, dim_stride_(dim_stride)
, start_(start) {}
const T& operator[](size_t index) const {
VTR_ASSERT_SAFE_MSG(dim_stride_ == 1, "Final dimension must have stride 1");
VTR_ASSERT_SAFE_MSG(index >= 0, "Index out of range (below dimension minimum)");
VTR_ASSERT_SAFE_MSG(index < dim_sizes_[idim_], "Index out of range (above dimension maximum)");
//Base case
return start_[index];
}
T& operator[](size_t index) {
//Call the const version and cast-away constness
return const_cast<T&>(const_cast<const NdMatrixProxy<T,1>*>(this)->operator[](index));
}
//For legacy compatibility (i.e. code expecting a pointer) we allow this base dimension
//case to retrieve a raw pointer to the last dimension elements.
//
//Note that it is the caller's responsibility to use this correctly; care must be taken
//not to clobber elements in other dimensions
const T* data() const {
return start_;
}
T* data() {
//Call the const version and cast-away constness
return const_cast<T*>(const_cast<const NdMatrixProxy<T,1>*>(this)->data());
}
private:
const size_t* dim_sizes_;
const size_t idim_;
const size_t dim_stride_;
T* start_;
};
//Base class for an N-dimensional matrix supporting arbitrary index ranges per dimension.
//This class implements all of the matrix handling (lifetime etc.) except for indexing
//(which is implemented in the NdMatrix class). Indexing is split out to allows specialization
//of indexing for N = 1.
//
//Implementation:
//
//This class uses a single linear array to store the matrix in c-style (row major)
//order. That is, the right-most index is laid out contiguous memory.
//
//This should improve memory usage (no extra pointers to store for each dimension),
//and cache locality (less indirection via pointers, predictable strides).
//
//The indicies are calculated based on the dimensions to access the appropriate elements.
//Since the indexing calculations are visible to the compiler at compile time they can be
//optimized to be efficient.
template<typename T, size_t N>
class NdMatrixBase {
public:
static_assert(N >= 1, "Minimum dimension 1");
//An empty matrix (all dimensions size zero)
NdMatrixBase() {
clear();
}
//Specified dimension sizes:
// [0..dim_sizes[0])
// [0..dim_sizes[1])
// ...
//with optional fill value
NdMatrixBase(std::array<size_t,N> dim_sizes, T value=T()) {
resize(dim_sizes, value);
}
public: //Accessors
//Returns the size of the matrix (number of elements)
size_t size() const {
VTR_ASSERT_DEBUG_MSG(calc_size() == size_, "Calculated and current matrix size must be consistent");
return size_;
}
//Returns true if there are no elements in the matrix
bool empty() const {
return size() == 0;
}
//Returns the number of dimensions (i.e. N)
size_t ndims() const {
return dim_sizes_.size();
}
//Returns the size of the ith dimension
size_t dim_size(size_t i) const {
VTR_ASSERT_SAFE(i < ndims());
return dim_sizes_[i];
}
//Returns the starting index of ith dimension
size_t begin_index(size_t i) const {
VTR_ASSERT_SAFE(i < ndims());
return 0;
}
//Returns the one-past-the-end index of the ith dimension
size_t end_index(size_t i) const {
VTR_ASSERT_SAFE(i < ndims());
return dim_sizes_[i];
}
public: //Mutators
//Set all elements to 'value'
void fill(T value) {
std::fill(data_.get(), data_.get() + size(), value);
}
//Resize the matrix to the specified dimension ranges
//
//If 'value' is specified all elements will be initialized to it,
//otherwise they will be default constructed.
void resize(std::array<size_t,N> dim_sizes, T value=T()) {
dim_sizes_ = dim_sizes;
size_ = calc_size();
alloc();
fill(value);
}
//Reset the matrix to size zero
void clear() {
data_.reset(nullptr);
dim_sizes_.fill(0);
size_ = 0;
}
public: //Lifetime management
//Copy constructor
NdMatrixBase(const NdMatrixBase& other)
: NdMatrixBase(other.dim_sizes_) {
std::copy(other.data_.get(), other.data_.get() + other.size(), data_.get());
}
//Move constructor
NdMatrixBase(NdMatrixBase&& other)
: NdMatrixBase() {
swap(*this, other);
}
//Copy/move assignment
//
//Note that rhs is taken by value (copy-swap idiom)
NdMatrixBase& operator=(NdMatrixBase rhs) {
swap(*this, rhs);
return *this;
}
//Swap two NdMatrixBase objects
friend void swap(NdMatrixBase<T,N>& m1, NdMatrixBase<T,N>& m2) {
using std::swap;
swap(m1.size_, m2.size_);
swap(m1.dim_sizes_, m2.dim_sizes_);
swap(m1.data_, m2.data_);
}
private:
//Allocate space for all the elements
void alloc() {
data_ = std::make_unique<T[]>(size());
}
//Returns the size of the matrix (number of elements) calucated
//from the current dimensions
size_t calc_size() const {
//Size is the product of all dimension sizes
size_t cnt = dim_size(0);
for (size_t idim = 1; idim < ndims(); ++idim) {
cnt *= dim_size(idim);
}
return cnt;
}
protected:
size_t size_ = 0;
std::array<size_t,N> dim_sizes_;
std::unique_ptr<T[]> data_ = nullptr;
};
//An N-dimensional matrix supporting arbitrary (continuous) index ranges
//per dimension.
//
//Examples:
//
// //A 2-dimensional matrix with indicies [0..4][0..9]
// NdMatrix<int,2> m1({5,10});
//
// //Accessing an element
// int i = m1[3][5];
//
// //Setting an element
// m1[2][8] = 0;
//
// //A 3-dimensional matrix with indicies [0..4][0..9][0..19]
// NdMatrix<int,3> m2({5,10,20});
//
// //A 2-dimensional matrix with indicies [0..4][0..9], with all entries
// //initialized to 42
// NdMatrix<int,2> m3({5,10}, 42);
//
// //Filling all entries with value 101
// m3.fill(101);
//
// //Resizing an existing matrix (all values reset to default constucted value)
// m3.resize({5,5})
//
// //Resizing an existing matrix (all elements set to value 88)
// m3.resize({15,55}, 88)
template<typename T, size_t N>
class NdMatrix : public NdMatrixBase<T,N> {
//General case
static_assert(N >= 2, "Minimum dimension 2");
public:
//Use the base constructors
using NdMatrixBase<T,N>::NdMatrixBase;
public:
//Access an element
//
//Returns a proxy-object to allow chained array-style indexing (N >= 2 case)
const NdMatrixProxy<T,N-1> operator[](size_t index) const {
VTR_ASSERT_SAFE_MSG(this->dim_size(0) > 0, "Can not index into size zero dimension");
VTR_ASSERT_SAFE_MSG(this->dim_size(1) > 0, "Can not index into size zero dimension");
VTR_ASSERT_SAFE_MSG(index >= 0, "Index out of range (below dimension minimum)");
VTR_ASSERT_SAFE_MSG(index < this->dim_sizes_[0], "Index out of range (above dimension maximum)");
//Calculate the stride for the current dimension
size_t dim_stride = this->size() / this->dim_size(0);
//Calculate the stride for the next dimension
size_t next_dim_stride = dim_stride / this->dim_size(1);
//Peel off the first dimension
return NdMatrixProxy<T,N-1>(this->dim_sizes_.data(), //Pass the dimension information
1, //Pass the next dimension
next_dim_stride, //Pass the stride for the next dimension
this->data_.get() + dim_stride*index); //Advance to index in this dimension
}
//Access an element
//
//Returns a proxy-object to allow chained array-style indexing
NdMatrixProxy<T,N-1> operator[](size_t index) {
//Call the const version, since returned by value don't need to worry about const
return const_cast<const NdMatrix<T,N>*>(this)->operator[](index);
}
};
template<typename T>
class NdMatrix<T,1> : public NdMatrixBase<T,1> {
//Specialization for N = 1
public:
//Use the base constructors
using NdMatrixBase<T,1>::NdMatrixBase;
public:
//Access an element (immutable)
const T& operator[](size_t index) const {
VTR_ASSERT_SAFE_MSG(this->dim_size(0) > 0, "Can not index into size zero dimension");
VTR_ASSERT_SAFE_MSG(index >= 0, "Index out of range (below dimension minimum)");
VTR_ASSERT_SAFE_MSG(index < this->dim_sizes_[0], "Index out of range (above dimension maximum)");
return this->data_[index];
}
//Access an element (mutable)
T& operator[](size_t index) {
//Call the const version, and cast away const-ness
return const_cast<T&>(const_cast<const NdMatrix<T,1>*>(this)->operator[](index));
}
};
//Convenient short forms for common NdMatricies
template<typename T>
using Matrix = NdMatrix<T,2>;
} //namespace
#endif

View File

@ -0,0 +1,400 @@
#ifndef VTR_ND_OFFSET_MATRIX_H
#define VTR_ND_OFFSET_MATRIX_H
#include <array>
#include <memory>
#include "vtr_assert.h"
namespace vtr {
//A half-open range specification for a matrix dimension [begin_index, last_index),
//with valid indicies from [begin_index() ... end_index()-1], provided size() > 0.
class DimRange {
public:
DimRange() = default;
DimRange(size_t begin, size_t end)
: begin_index_(begin)
, end_index_(end) {}
size_t begin_index() const { return begin_index_; }
size_t end_index() const { return end_index_; }
size_t size() const { return end_index_ - begin_index_; }
private:
size_t begin_index_ = 0;
size_t end_index_ = 0;
};
//Proxy class for a sub-matrix of a NdOffsetMatrix class.
//This is used to allow chaining of array indexing [] operators in a natural way.
//
//Each instance of this class peels off one-dimension and returns a NdOffsetMatrixProxy representing
//the resulting sub-matrix. This is repeated recursively until we hit the 1-dimensional base-case.
//
//Since this expansion happens at compiler time all the proxy classes get optimized away,
//yielding both high performance and generality.
//
//Recursive case: N-dimensional array
template<typename T, size_t N>
class NdOffsetMatrixProxy {
public:
static_assert(N > 0, "Must have at least one dimension");
//Construct a matrix proxy object
//
// dim_ranges: Array of DimRange objects
// idim: The dimension associated with this proxy
// dim_stride: The stride of this dimension (i.e. how many element in memory between indicies of this dimension)
// start: Pointer to the start of the sub-matrix this proxy represents
NdOffsetMatrixProxy<T,N>(const DimRange* dim_ranges, size_t idim, size_t dim_stride, T* start)
: dim_ranges_(dim_ranges)
, idim_(idim)
, dim_stride_(dim_stride)
, start_(start) {}
const NdOffsetMatrixProxy<T,N-1> operator[](size_t index) const {
VTR_ASSERT_SAFE_MSG(index >= dim_ranges_[idim_].begin_index(), "Index out of range (below dimension minimum)");
VTR_ASSERT_SAFE_MSG(index < dim_ranges_[idim_].end_index(), "Index out of range (above dimension maximum)");
//The elements are stored in zero-indexed form, so we need to adjust
//for any non-zero minimum index
size_t effective_index = index - dim_ranges_[idim_].begin_index();
//Determine the stride of the next dimension
size_t next_dim_stride = dim_stride_ / dim_ranges_[idim_ + 1].size();
//Strip off one dimension
return NdOffsetMatrixProxy<T,N-1>(dim_ranges_, //Pass the dimension information
idim_ + 1, //Pass the next dimension
next_dim_stride, //Pass the stride for the next dimension
start_ + dim_stride_*effective_index); //Advance to index in this dimension
}
NdOffsetMatrixProxy<T,N-1> operator[](size_t index) {
//Call the const version and cast-away constness
return const_cast<const NdOffsetMatrixProxy<T,N>*>(this)->operator[](index);
}
private:
const DimRange* dim_ranges_;
const size_t idim_;
const size_t dim_stride_;
T* start_;
};
//Base case: 1-dimensional array
template<typename T>
class NdOffsetMatrixProxy<T,1> {
public:
NdOffsetMatrixProxy<T,1>(const DimRange* dim_ranges, size_t idim, size_t dim_stride, T* start)
: dim_ranges_(dim_ranges)
, idim_(idim)
, dim_stride_(dim_stride)
, start_(start) {}
const T& operator[](size_t index) const {
VTR_ASSERT_SAFE_MSG(dim_stride_ == 1, "Final dimension must have stride 1");
VTR_ASSERT_SAFE_MSG(index >= dim_ranges_[idim_].begin_index(), "Index out of range (below dimension minimum)");
VTR_ASSERT_SAFE_MSG(index < dim_ranges_[idim_].end_index(), "Index out of range (above dimension maximum)");
//The elements are stored in zero-indexed form, so we need to adjust
//for any non-zero minimum index
size_t effective_index = index - dim_ranges_[idim_].begin_index();
//Base case
return start_[effective_index];
}
T& operator[](size_t index) {
//Call the const version and cast-away constness
return const_cast<T&>(const_cast<const NdOffsetMatrixProxy<T,1>*>(this)->operator[](index));
}
private:
const DimRange* dim_ranges_;
const size_t idim_;
const size_t dim_stride_;
T* start_;
};
//Base class for an N-dimensional matrix supporting arbitrary index ranges per dimension.
//This class implements all of the matrix handling (lifetime etc.) except for indexing
//(which is implemented in the NdOffsetMatrix class). Indexing is split out to allows specialization
//of indexing for N = 1.
//
//Implementation:
//
//This class uses a single linear array to store the matrix in c-style (row major)
//order. That is, the right-most index is laid out contiguous memory.
//
//This should improve memory usage (no extra pointers to store for each dimension),
//and cache locality (less indirection via pointers, predictable strides).
//
//The indicies are calculated based on the dimensions to access the appropriate elements.
//Since the indexing calculations are visible to the compiler at compile time they can be
//optimized to be efficient.
template<typename T, size_t N>
class NdOffsetMatrixBase {
public:
static_assert(N >= 1, "Minimum dimension 1");
//An empty matrix (all dimensions size zero)
NdOffsetMatrixBase() {
clear();
}
//Specified dimension sizes:
// [0..dim_sizes[0])
// [0..dim_sizes[1])
// ...
//with optional fill value
NdOffsetMatrixBase(std::array<size_t,N> dim_sizes, T value=T()) {
resize(dim_sizes, value);
}
//Specified dimension index ranges:
// [dim_ranges[0].begin_index() ... dim_ranges[1].end_index())
// [dim_ranges[1].begin_index() ... dim_ranges[1].end_index())
// ...
//with optional fill value
NdOffsetMatrixBase(std::array<DimRange,N> dim_ranges, T value=T()) {
resize(dim_ranges, value);
}
public: //Accessors
//Returns the size of the matrix (number of elements)
size_t size() const {
//Size is the product of all dimension sizes
size_t cnt = dim_size(0);
for (size_t idim = 1; idim < ndims(); ++idim) {
cnt *= dim_size(idim);
}
return cnt;
}
//Returns true if there are no elements in the matrix
bool empty() const {
return size() == 0;
}
//Returns the number of dimensions (i.e. N)
size_t ndims() const {
return dim_ranges_.size();
}
//Returns the size of the ith dimension
size_t dim_size(size_t i) const {
VTR_ASSERT_SAFE(i < ndims());
return dim_ranges_[i].size();
}
//Returns the starting index of ith dimension
size_t begin_index(size_t i) const {
VTR_ASSERT_SAFE(i < ndims());
return dim_ranges_[i].begin_index();
}
//Returns the one-past-the-end index of the ith dimension
size_t end_index(size_t i) const {
VTR_ASSERT_SAFE(i < ndims());
return dim_ranges_[i].end_index();
}
public: //Mutators
//Set all elements to 'value'
void fill(T value) {
std::fill(data_.get(), data_.get() + size(), value);
}
//Resize the matrix to the specified dimensions
//
//If 'value' is specified all elements will be initialized to it,
//otherwise they will be default constructed.
void resize(std::array<size_t,N> dim_sizes, T value=T()) {
//Convert dimension to range [0..dim)
for(size_t i = 0; i < dim_sizes.size(); ++i) {
dim_ranges_[i] = {0, dim_sizes[i]};
}
alloc();
fill(value);
}
//Resize the matrix to the specified dimension ranges
//
//If 'value' is specified all elements will be initialized to it,
//otherwise they will be default constructed.
void resize(std::array<DimRange,N> dim_ranges, T value=T()) {
dim_ranges_ = dim_ranges;
alloc();
fill(value);
}
//Reset the matrix to size zero
void clear() {
data_.reset(nullptr);
for(size_t i = 0; i < dim_ranges_.size(); ++i) {
dim_ranges_[i] = {0, 0};
}
}
public: //Lifetime management
//Copy constructor
NdOffsetMatrixBase(const NdOffsetMatrixBase& other)
: NdOffsetMatrixBase(other.dim_ranges_) {
std::copy(other.data_.get(), other.data_.get() + other.size(), data_.get());
}
//Move constructor
NdOffsetMatrixBase(NdOffsetMatrixBase&& other)
: NdOffsetMatrixBase() {
swap(*this, other);
}
//Copy/move assignment
//
//Note that rhs is taken by value (copy-swap idiom)
NdOffsetMatrixBase& operator=(NdOffsetMatrixBase rhs) {
swap(*this, rhs);
return *this;
}
//Swap two NdOffsetMatrixBase objects
friend void swap(NdOffsetMatrixBase<T,N>& m1, NdOffsetMatrixBase<T,N>& m2) {
using std::swap;
swap(m1.dim_ranges_, m2.dim_ranges_);
swap(m1.data_, m2.data_);
}
private:
//Allocate space for all the elements
void alloc() {
data_ = std::make_unique<T[]>(size());
}
protected:
std::array<DimRange,N> dim_ranges_;
std::unique_ptr<T[]> data_ = nullptr;
};
//An N-dimensional matrix supporting arbitrary (continuous) index ranges
//per dimension.
//
//If no second template parameter is provided defaults to a 2-dimensional
//matrix
//
//Examples:
//
// //A 2-dimensional matrix with indicies [0..4][0..9]
// NdOffsetMatrix<int,2> m1({5,10});
//
// //Accessing an element
// int i = m4[3][5];
//
// //Setting an element
// m4[6][20] = 0;
//
// //A 2-dimensional matrix with indicies [2..6][5..9]
// // Note that C++ requires one more set of curly brace than you would expect
// NdOffsetMatrix<int,2> m2({{{2,7},{5,10}}});
//
// //A 3-dimensional matrix with indicies [0..4][0..9][0..19]
// NdOffsetMatrix<int,3> m3({5,10,20});
//
// //A 3-dimensional matrix with indicies [2..6][1..19][50..89]
// NdOffsetMatrix<int,3> m4({{{2,7}, {1,20}, {50,90}}});
//
// //A 2-dimensional matrix with indicies [2..6][1..20], with all entries
// //intialized to 42
// NdOffsetMatrix<int,2> m4({{{2,7}, {1,21}}}, 42);
//
// //A 2-dimensional matrix with indicies [0..4][0..9], with all entries
// //initialized to 42
// NdOffsetMatrix<int,2> m1({5,10}, 42);
//
// //Filling all entries with value 101
// m1.fill(101);
//
// //Resizing an existing matrix (all values reset to default constucted value)
// m1.resize({5,5})
//
// //Resizing an existing matrix (all elements set to value 88)
// m1.resize({15,55}, 88)
template<typename T, size_t N>
class NdOffsetMatrix : public NdOffsetMatrixBase<T,N> {
//General case
static_assert(N >= 2, "Minimum dimension 2");
public:
//Use the base constructors
using NdOffsetMatrixBase<T,N>::NdOffsetMatrixBase;
public:
//Access an element
//
//Returns a proxy-object to allow chained array-style indexing (N >= 2 case)
//template<typename = typename std::enable_if<N >= 2>::type, typename T1=T>
const NdOffsetMatrixProxy<T,N-1> operator[](size_t index) const {
VTR_ASSERT_SAFE_MSG(this->dim_size(0) > 0, "Can not index into size zero dimension");
VTR_ASSERT_SAFE_MSG(this->dim_size(1) > 0, "Can not index into size zero dimension");
VTR_ASSERT_SAFE_MSG(index >= this->dim_ranges_[0].begin_index(), "Index out of range (below dimension minimum)");
VTR_ASSERT_SAFE_MSG(index < this->dim_ranges_[0].end_index(), "Index out of range (above dimension maximum)");
//The elements are stored in zero-indexed form, so adjust for any
//non-zero minimum index in this dimension
size_t effective_index = index - this->dim_ranges_[0].begin_index();
//Calculate the stride for the current dimension
size_t dim_stride = this->size() / this->dim_size(0);
//Calculate the stride for the next dimension
size_t next_dim_stride = dim_stride / this->dim_size(1);
//Peel off the first dimension
return NdOffsetMatrixProxy<T,N-1>(this->dim_ranges_.data(), //Pass the dimension information
1, //Pass the next dimension
next_dim_stride, //Pass the stride for the next dimension
this->data_.get() + dim_stride*effective_index); //Advance to index in this dimension
}
//Access an element
//
//Returns a proxy-object to allow chained array-style indexing
NdOffsetMatrixProxy<T,N-1> operator[](size_t index) {
//Call the const version, since returned by value don't need to worry about const
return const_cast<const NdOffsetMatrix<T,N>*>(this)->operator[](index);
}
};
template<typename T>
class NdOffsetMatrix<T,1> : public NdOffsetMatrixBase<T,1> {
//Specialization for N = 1
public:
//Use the base constructors
using NdOffsetMatrixBase<T,1>::NdOffsetMatrixBase;
public:
//Access an element (immutable)
const T& operator[](size_t index) const {
VTR_ASSERT_SAFE_MSG(this->dim_size(0) > 0, "Can not index into size zero dimension");
VTR_ASSERT_SAFE_MSG(index >= this->dim_ranges_[0].begin_index(), "Index out of range (below dimension minimum)");
VTR_ASSERT_SAFE_MSG(index < this->dim_ranges_[0].end_index(), "Index out of range (above dimension maximum)");
return this->data_[index];
}
//Access an element (mutable)
T& operator[](size_t index) {
//Call the const version, and cast away const-ness
return const_cast<T&>(const_cast<const NdOffsetMatrix<T,1>*>(this)->operator[](index));
}
};
//Convenient short forms for common NdMatricies
template<typename T>
using OffsetMatrix = NdOffsetMatrix<T,2>;
} //namespace
#endif

View File

@ -0,0 +1,39 @@
#ifndef VTR_OSTREAM_GUARD_H
#define VTR_OSTREAM_GUARD_H
namespace vtr {
//A RAII guard class to ensure restoration of output stream format
class OsFormatGuard {
public:
explicit OsFormatGuard(std::ostream& os)
: os_(os)
, flags_(os_.flags()) //Save formatting flag state
, width_(os_.width())
, precision_(os.precision())
, fill_(os.fill())
{}
~OsFormatGuard() {
os_.flags(flags_); //Restore
os_.width(width_);
os_.precision(precision_);
os_.fill(fill_);
}
OsFormatGuard(const OsFormatGuard&) = delete;
OsFormatGuard& operator=(const OsFormatGuard&) = delete;
OsFormatGuard(const OsFormatGuard&&) = delete;
OsFormatGuard& operator=(const OsFormatGuard&&) = delete;
private:
std::ostream& os_;
std::ios::fmtflags flags_;
std::streamsize width_;
std::streamsize precision_;
char fill_;
};
} //namespace
#endif

View File

@ -0,0 +1,57 @@
#ifndef VTR_PAIR_UTIL_H
#define VTR_PAIR_UTIL_H
#include "vtr_range.h"
namespace vtr {
//Iterator which derefernces the 'first' element of a std::pair iterator
template<typename PairIter>
class pair_first_iter {
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename PairIter::value_type::first_type;
using difference_type = void;
using pointer = value_type*;
using reference = value_type&;
pair_first_iter(PairIter init): iter_(init) {}
auto operator++() { iter_++; return *this; }
auto operator--() { iter_--; return *this; }
auto operator*() { return iter_->first; }
auto operator->() { return &iter_->first; }
friend bool operator== (const pair_first_iter lhs, const pair_first_iter rhs) { return lhs.iter_ == rhs.iter_; }
friend bool operator!= (const pair_first_iter lhs, const pair_first_iter rhs) { return !(lhs == rhs); }
private:
PairIter iter_;
};
//Iterator which derefernces the 'second' element of a std::pair iterator
template<typename PairIter>
class pair_second_iter {
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename PairIter::value_type::second_type;
using difference_type = void;
using pointer = value_type*;
using reference = value_type&;
pair_second_iter(PairIter init): iter_(init) {}
auto operator++() { iter_++; return *this; }
auto operator--() { iter_--; return *this; }
auto operator*() { return iter_->second; }
auto operator->() { return &iter_->second; }
friend bool operator== (const pair_second_iter lhs, const pair_second_iter rhs) { return lhs.iter_ == rhs.iter_; }
friend bool operator!= (const pair_second_iter lhs, const pair_second_iter rhs) { return !(lhs == rhs); }
private:
PairIter iter_;
};
} //namespace
#endif

View File

@ -0,0 +1,87 @@
#include "vtr_path.h"
#include "vtr_util.h"
//TODO: currently this file assumes unix-like
// in the future support windows
#include <unistd.h>
#include <sstream>
namespace vtr {
const std::string PATH_DELIM = "/";
//Splits off the name and extension (including ".") of the specified filename
std::array<std::string,2> split_ext(const std::string& filename) {
std::array<std::string,2> name_ext;
auto pos = filename.find_last_of('.');
if (pos == std::string::npos) {
//No extension
pos = filename.size();
}
name_ext[0] = std::string(filename, 0, pos);
name_ext[1] = std::string(filename, pos, filename.size() - pos);
return name_ext;
}
std::string basename(const std::string& path) {
auto elements = split(path, PATH_DELIM);
std::string str;
if(elements.size() > 0) {
//Return the last path element
str = elements[elements.size() - 1];
}
return str;
}
std::string dirname(const std::string& path) {
auto elements = split(path, PATH_DELIM);
std::string str;
if(elements.size() > 0) {
//We need to start the dirname with a PATH_DELIM if path started with one
if(starts_with(path, PATH_DELIM)) {
str += PATH_DELIM;
}
//Join all except the last path element
str += join(elements.begin(), elements.end() - 1, PATH_DELIM);
//We append a final PATH_DELIM to allow clients to just append directly to the
//returned value
str += PATH_DELIM;
}
return str;
}
std::string getcwd() {
constexpr size_t BUF_SIZE = 500;
char buf [BUF_SIZE];
if (::getcwd(buf, BUF_SIZE)) {
return std::string(buf);
}
//Check the global errno
int error = errno;
switch (error) {
case EACCES:
throw std::runtime_error("Access denied");
default: {
std::stringstream str;
str << "Unrecognised error" << error;
throw std::runtime_error(str.str());
}
}
}
} //namespace

View File

@ -0,0 +1,23 @@
#ifndef VTR_PATH_H
#define VTR_PATH_H
#include <string>
#include <array>
namespace vtr {
//Splits off the name and extension (including ".") of the specified filename
std::array<std::string,2> split_ext(const std::string& filename);
//Returns the basename of path (i.e. the last filename component)
// For example, the path "/home/user/my_files/test.blif" -> "test.blif"
std::string basename(const std::string& path);
//Returns the dirname of path (i.e. everything except the last filename component)
// For example, the path "/home/user/my_files/test.blif" -> "/home/user/my_files/"
std::string dirname(const std::string& path);
//Returns the current working directory
std::string getcwd();
}
#endif

View File

@ -0,0 +1,76 @@
#include <cstddef>
#include "vtr_random.h"
#include "vtr_util.h"
#include "vtr_error.h"
#define CHECK_RAND
namespace vtr {
/* Portable random number generator defined below. Taken from ANSI C by *
* K & R. Not a great generator, but fast, and good enough for my needs. */
constexpr size_t IA = 1103515245u;
constexpr size_t IC = 12345u;
constexpr size_t IM = 2147483648u;
static RandState random_state = 0;
void srandom(int seed) {
random_state = (unsigned int) seed;
}
/* returns the random_state value */
RandState get_random_state() {
return random_state;
}
int irand(int imax, RandState& state) {
/* Creates a random integer between 0 and imax, inclusive. i.e. [0..imax] */
int ival;
/* state = (state * IA + IC) % IM; */
state = state * IA + IC; /* Use overflow to wrap */
ival = state & (IM - 1); /* Modulus */
ival = (int) ((float) ival * (float) (imax + 0.999) / (float) IM);
#ifdef CHECK_RAND
if ((ival < 0) || (ival > imax)) {
if (ival == imax + 1) {
/* Due to random floating point rounding, sometimes above calculation gives number greater than ival by 1 */
ival = imax;
} else {
throw VtrError(string_fmt("Bad value in my_irand, imax = %d ival = %d", imax, ival), __FILE__, __LINE__);
}
}
#endif
return ival;
}
int irand(int imax) {
return irand(imax, random_state);
}
float frand() {
/* Creates a random float between 0 and 1. i.e. [0..1). */
float fval;
int ival;
random_state = random_state * IA + IC; /* Use overflow to wrap */
ival = random_state & (IM - 1); /* Modulus */
fval = (float) ival / (float) IM;
#ifdef CHECK_RAND
if ((fval < 0) || (fval > 1.)) {
throw VtrError(string_fmt("Bad value in my_frand, fval = %g", fval), __FILE__, __LINE__);
}
#endif
return (fval);
}
} //namespace

View File

@ -0,0 +1,32 @@
#ifndef VTR_RANDOM_H
#define VTR_RANDOM_H
#include <algorithm> //For std::swap
namespace vtr {
/*********************** Portable random number generators *******************/
typedef unsigned RandState;
void srandom(int seed);
RandState get_random_state();
int irand(int imax);
int irand(int imax, RandState& rand_state);
float frand();
//Portable/invariant version of std::shuffle
//
//Note that std::shuffle relies on std::uniform_int_distribution
//which can produce different sequences accross different
//compilers/compiler versions.
//
//This version should be deterministic/invariant. However, since
//it uses vtr::irand(), may not be as well distributed as std::shuffle.
template<typename Iter>
void shuffle(Iter first, Iter last, RandState& rand_state) {
for (auto i = (last - first) - 1; i > 0; --i) {
using std::swap;
swap(first[i], first[irand(i, rand_state)]);
}
}
} //namespace
#endif

View File

@ -0,0 +1,73 @@
#ifndef VTR_RANGE_H
#define VTR_RANGE_H
#include <iterator>
namespace vtr {
/*
* The vtr::Range template models a range defined by two iterators of type T.
*
* It allows conveniently returning a range from a single function call
* without having to explicity expose the underlying container, or make two
* explicit calls to retrieve the associated begin and end iterators.
* It also enables the easy use of range-based-for loops.
*
* For example:
*
* class My Data {
* public:
* typdef std::vector<int>::const_iterator my_iter;
* vtr::Range<my_iter> data();
* ...
* private:
* std::vector<int> data_;
* };
*
* ...
*
* MyDat my_data;
*
* //fill my_data
*
* for(int val : my_data.data()) {
* //work with values stored in my_data
* }
*
* The empty() and size() methods are convenience wrappers around the relevant
* iterator comparisons.
*
* Note that size() is only constant time if T is a random-access iterator!
*/
template<typename T>
class Range {
public:
Range(T b, T e): begin_(b), end_(e) {}
T begin() { return begin_; }
T end() { return end_; }
bool empty() { return begin_ == end_; }
size_t size() { return std::distance(begin_, end_); }
private:
T begin_;
T end_;
};
/*
* Creates a vtr::Range from a pair of iterators.
*
* Unlike using the vtr::Range() constructor (which requires specifying
* the template type T, using vtr::make_range() infers T from the arguments.
*
* Example usage:
* auto my_range = vtr::make_range(my_vec.begin(), my_vec.end());
*/
template<typename T>
auto make_range(T b, T e) { return Range<T>(b, e); }
/*
* Creates a vtr::Range from a container
*/
template<typename Container>
auto make_range(const Container& c) { return make_range(std::begin(c), std::end(c)); }
} //namespace
#endif

View File

@ -0,0 +1,29 @@
#include "vtr_rusage.h"
#ifdef __unix__
# include <sys/time.h>
# include <sys/resource.h>
#endif
namespace vtr {
size_t get_max_rss() {
size_t max_rss = 0;
#ifdef __unix__
rusage usage;
int result = getrusage(RUSAGE_SELF, &usage);
if (result == 0) { //Success
//ru_maxrss is in kilobytes, convert to bytes
max_rss = usage.ru_maxrss * 1024;
}
#else
//Do nothing, other platform specific code could be added here
//with appropriate defines
#endif
return max_rss;
}
} //namespace

View File

@ -0,0 +1,12 @@
#ifndef VTR_RUSAGE_H
#define VTR_RUSAGE_H
#include <cstddef>
namespace vtr {
//Returns the maximum resident set size in bytes,
//or zero if unable to determine.
size_t get_max_rss();
}
#endif

View File

@ -0,0 +1,40 @@
#ifndef VTR_SENTINELS_H
#define VTR_SENTINELS_H
namespace vtr {
//Some specialized containers like vtr::linear_map and
//vtr::vector_map require sentinel values to mark invalid/uninitialized
//values. By convention, such containers query the sentinel objects static
//INVALID() member function to retrieve the sentinel value.
//
//These classes allows users to specify a custom sentinel value.
//
//Usually the containers default to DefaultSentinel
//The sentinel value is the default constructed value of the type
template<class T>
class DefaultSentinel {
public:
constexpr static T INVALID() { return T(); }
};
//Specialization for pointer types
template<class T>
class DefaultSentinel<T*> {
public:
constexpr static T* INVALID() { return nullptr; }
};
//The sentile value is a specified value of the type
template<class T, T val>
class CustomSentinel {
public:
constexpr static T INVALID() { return T(val); }
};
//The common case where -1 is used as the sentinel value
template<class T>
using MinusOneSentinel = CustomSentinel<T,-1>;
} //namespace
#endif

View File

@ -0,0 +1,233 @@
#ifndef VTR_STRONG_ID_H
#define VTR_STRONG_ID_H
/*
* This header provides the StrongId class, a template which can be used to
* create strong Id's which avoid accidental type conversions (generating
* compiler errors when they occur).
*
* Motivation
* ==========
* It is common to use an Id (typically an integer) to identify and represent a component.
* A basic example (poor style):
*
* size_t count_net_terminals(int net_id);
*
* Where a plain int is used to represent the net identifier.
* Using a plain basic type is poor style since it makes it unclear that the parameter is
* an Id.
*
* A better example is to use a typedef:
*
* typedef int NetId;
*
* size_t count_net_teriminals(NetId net_id);
*
* It is now clear that the parameter is expecting an Id.
*
* However this approach has some limitations. In particular, typedef's only create type
* aliases, and still allow conversions. This is problematic if there are multiple types
* of Ids. For example:
*
* typedef int NetId;
* typedef int BlkId;
*
* size_t count_net_teriminals(NetId net_id);
*
* BlkId blk_id = 10;
* NetId net_id = 42;
*
* count_net_teriminals(net_id); //OK
* count_net_teriminals(blk_id); //Bug: passed a BlkId as a NetId
*
* Since typdefs are aliases the compiler issues no errors or warnings, and silently passes
* the BlkId where a NetId is expected. This results in hard to diagnose bugs.
*
* We can avoid this issue by using a StrongId:
*
* struct net_id_tag; //Phantom tag for NetId
* struct blk_id_tag; //Phantom tag for BlkId
*
* typedef StrongId<net_id_tag> NetId;
* typedef StrongId<blk_id_tag> BlkId;
*
* size_t count_net_teriminals(NetId net_id);
*
* BlkId blk_id = 10;
* NetId net_id = 42;
*
* count_net_teriminals(net_id); //OK
* count_net_teriminals(blk_id); //Compiler Error: NetId expected!
*
* StrongId is a template which implements the basic features of an Id, but disallows silent conversions
* between different types of Ids. It uses another 'tag' type (passed as the first template parameter)
* to uniquely identify the type of the Id (preventing conversions between different types of Ids).
*
* Usage
* =====
*
* The StrongId template class takes one required and three optional template parameters:
*
* 1) Tag - the unique type used to identify this type of Ids [Required]
* 2) T - the underlying integral id type (default: int) [Optional]
* 3) T sentinel - a value representing an invalid Id (default: -1) [Optional]
*
* If no value is supllied during construction the StrongId is initialized to the invalid/sentinel value.
*
* Example 1: default definition
*
* struct net_id_tag;
* typedef StrongId<net_id_tag> NetId; //Internally stores an integer Id, -1 represents invalid
*
* Example 2: definition with custom underlying type
*
* struct blk_id_tag;
* typedef StrongId<net_id_tag,size_t> BlkId; //Internally stores a size_t Id, -1 represents invalid
*
* Example 3: definition with custom underlying type and custom sentinel value
*
* struct pin_id_tag;
* typedef StrongId<net_id_tag,size_t,0> PinId; //Internally stores a size_t Id, 0 represents invalid
*
* Example 4: Creating Ids
*
* struct net_id_tag;
* typedef StrongId<net_id_tag> MyId; //Internally stores an integer Id, -1 represents invalid
*
* MyId my_id; //Defaults to the sentinel value (-1 by default)
* MyId my_other_id = 5; //Explicit construction
* MyId my_thrid_id(25); //Explicit construction
*
* Example 5: Comparing Ids
*
* struct net_id_tag;
* typedef StrongId<net_id_tag> MyId; //Internally stores an integer Id, -1 represents invalid
*
* MyId my_id; //Defaults to the sentinel value (-1 by default)
* MyId my_id_one = 1;
* MyId my_id_two = 2;
* MyId my_id_also_one = 1;
*
* my_id_one == my_id_also_one; //True
* my_id_one == my_id; //False
* my_id_one == my_id_two; //False
* my_id_one != my_id_two; //True
*
* Example 5: Checking for invalid Ids
*
* struct net_id_tag;
* typedef StrongId<net_id_tag> MyId; //Internally stores an integer Id, -1 represents invalid
*
* MyId my_id; //Defaults to the sentinel value
* MyId my_id_one = 1;
*
* //Comparison against a constructed invalid id
* my_id == MyId::INVALID(); //True
* my_id_one == MyId::INVALID(); //False
* my_id_one != MyId::INVALID(); //True
*
* //The Id can also be evaluated in a boolean context against the sentinel value
* if(my_id) //False, my_id is invalid
* if(!my_id) //True my_id is valid
* if(my_id_one) //True my_id_one is valid
*
* Example 6: Indexing data structures
*
* struct my_id_tag;
* typedef StrongId<net_id_tag> MyId; //Internally stores an integer Id, -1 represents invalid
*
* std::vector<int> my_vec = {0, 1, 2, 3, 4, 5};
*
* MyId my_id = 2;
*
* my_vec[size_t(my_id)]; //Access the third element via explicit conversion
*/
#include <type_traits> //for std::is_integral
#include <cstddef> //for std::size_t
#include <functional> //for std::hash
namespace vtr {
//Forward declare the class (needed for operator declarations)
template<typename tag, typename T, T sentinel>
class StrongId;
//Forward declare the equality/inequality operators
// We need to do this before the class definition so the class can
// friend them
template<typename tag, typename T, T sentinel>
bool operator==(const StrongId<tag,T,sentinel>& lhs, const StrongId<tag,T,sentinel>& rhs);
template<typename tag, typename T, T sentinel>
bool operator!=(const StrongId<tag,T,sentinel>& lhs, const StrongId<tag,T,sentinel>& rhs);
template<typename tag, typename T, T sentinel>
bool operator<(const StrongId<tag,T,sentinel>& lhs, const StrongId<tag,T,sentinel>& rhs);
//Class template definition with default template parameters
template<typename tag, typename T=int, T sentinel=T(-1)>
class StrongId {
static_assert(std::is_integral<T>::value, "T must be integral");
public:
//Gets the invalid Id
static constexpr StrongId INVALID() { return StrongId(); }
//Default to the sentinel value
constexpr StrongId() : id_(sentinel) {}
//Only allow explict constructions from a raw Id (no automatic conversions)
explicit constexpr StrongId(T id): id_(id) {}
//Allow some explicit conversion to useful types
//Allow explicit conversion to bool (e.g. if(id))
explicit operator bool() const { return *this != INVALID(); }
//Allow explicit conversion to size_t (e.g. my_vector[size_t(strong_id)])
explicit operator std::size_t() const { return static_cast<std::size_t>(id_); }
//To enable hasing Ids
friend std::hash<StrongId<tag,T,sentinel>>;
//To enable comparisions between Ids
// Note that since these are templated functions we provide an empty set of template parameters
// after the function name (i.e. <>)
friend bool operator== <>(const StrongId<tag,T,sentinel>& lhs, const StrongId<tag,T,sentinel>& rhs);
friend bool operator!= <>(const StrongId<tag,T,sentinel>& lhs, const StrongId<tag,T,sentinel>& rhs);
friend bool operator< <>(const StrongId<tag,T,sentinel>& lhs, const StrongId<tag,T,sentinel>& rhs);
private:
T id_;
};
template<typename tag, typename T, T sentinel>
bool operator==(const StrongId<tag,T,sentinel>& lhs, const StrongId<tag,T,sentinel>& rhs) {
return lhs.id_ == rhs.id_;
}
template<typename tag, typename T, T sentinel>
bool operator!=(const StrongId<tag,T,sentinel>& lhs, const StrongId<tag,T,sentinel>& rhs) {
return !(lhs == rhs);
}
//Needed for std::map-like containers
template<typename tag, typename T, T sentinel>
bool operator<(const StrongId<tag,T,sentinel>& lhs, const StrongId<tag,T,sentinel>& rhs) {
return lhs.id_ < rhs.id_;
}
} //namespace vtr
//Specialize std::hash for StrongId's (needed for std::unordered_map-like containers)
namespace std {
template<typename tag, typename T, T sentinel>
struct hash<vtr::StrongId<tag,T,sentinel>> {
std::size_t operator()(const vtr::StrongId<tag,T,sentinel> k) const noexcept {
return std::hash<T>()(k.id_); //Hash with the underlying type
}
};
} //namespace std
#endif

View File

@ -0,0 +1,85 @@
#include "vtr_time.h"
#include "vtr_log.h"
#include "vtr_rusage.h"
namespace vtr {
int f_timer_depth = 0;
Timer::Timer()
: start_(clock::now())
, initial_max_rss_(get_max_rss()) {
}
float Timer::elapsed_sec() const {
return std::chrono::duration<float>(clock::now() - start_).count();
}
float Timer::max_rss_mib() const {
return get_max_rss() / BYTE_TO_MIB;
}
float Timer::delta_max_rss_mib() const {
return (get_max_rss() - initial_max_rss_) / BYTE_TO_MIB;
}
ScopedActionTimer::ScopedActionTimer(std::string action_str)
: action_(action_str)
, depth_(f_timer_depth++) {
}
ScopedActionTimer::~ScopedActionTimer() {
--f_timer_depth;
}
void ScopedActionTimer::quiet(bool value) {
quiet_ = value;
}
bool ScopedActionTimer::quiet() const {
return quiet_;
}
std::string ScopedActionTimer::action() const {
return action_;
}
std::string ScopedActionTimer::pad() const {
if (depth() == 0) {
return "";
}
return std::string(depth(), '#') + " ";
}
int ScopedActionTimer::depth() const {
return depth_;
}
ScopedFinishTimer::ScopedFinishTimer(std::string action_str)
: ScopedActionTimer(action_str) {
}
ScopedFinishTimer::~ScopedFinishTimer() {
if (!quiet()) {
vtr::printf_info("%s%s took %.2f seconds (max_rss %.1f MiB)\n",
pad().c_str(), action().c_str(), elapsed_sec(),
max_rss_mib());
}
}
ScopedStartFinishTimer::ScopedStartFinishTimer(std::string action_str)
: ScopedActionTimer(action_str) {
vtr::printf_info("%s%s\n", pad().c_str(), action().c_str());
}
ScopedStartFinishTimer::~ScopedStartFinishTimer() {
if (!quiet()) {
vtr::printf_info("%s%s took %.2f seconds (max_rss %.1f MiB, delta_rss %+.1f MiB)\n",
pad().c_str(), action().c_str(), elapsed_sec(),
max_rss_mib(), delta_max_rss_mib());
}
}
} //namespace

View File

@ -0,0 +1,94 @@
#ifndef VTR_TIME_H
#define VTR_TIME_H
#include <chrono>
#include <string>
namespace vtr {
//Class for tracking time elapsed since construction
class Timer {
public:
Timer();
virtual ~Timer() = default;
//No copy
Timer(Timer&) = delete;
Timer& operator=(Timer&) = delete;
//No move
Timer(Timer&&) = delete;
Timer& operator=(Timer&&) = delete;
//Return elapsed time in seconds
float elapsed_sec() const;
//Return peak memory resident set size (in MiB)
float max_rss_mib() const;
//Return change in peak memory resident set size (in MiB)
float delta_max_rss_mib() const;
private:
using clock = std::chrono::steady_clock;
std::chrono::time_point<clock> start_;
size_t initial_max_rss_; //Maximum resident set size In bytes
constexpr static float BYTE_TO_MIB = 1024*1024;
};
class ScopedActionTimer : public Timer {
public:
ScopedActionTimer(const std::string action);
~ScopedActionTimer();
void quiet(bool value);
bool quiet() const;
std::string action() const;
protected:
int depth() const;
std::string pad() const;
private:
const std::string action_;
bool quiet_ = false;
int depth_;
};
//Scoped elapsed time class which prints the time elapsed for
//the specified action when it is destructed.
//
//For example:
//
// {
// vtr::ScopedFinishTimer timer("my_action");
//
// //Do other work
//
// //Will print: 'my_action took X.XX seconds' when out-of-scope
// }
class ScopedFinishTimer : public ScopedActionTimer {
public:
ScopedFinishTimer(const std::string action);
~ScopedFinishTimer();
};
//Scoped elapsed time class which prints out the action when
//initialized and again both the action and elapsed time
//when destructed.
//For example:
//
// {
// vtr::ScopedStartFinishTimer timer("my_action") //Will print: 'my_action'
//
// //Do other work
//
// //Will print 'my_action took X.XX seconds' when out of scope
// }
class ScopedStartFinishTimer : public ScopedActionTimer {
public:
ScopedStartFinishTimer(const std::string action);
~ScopedStartFinishTimer();
};
}
#endif

View File

@ -0,0 +1,387 @@
#include <cstdarg>
#include <cstdlib>
#include <cerrno> //For errno
#include <cstring>
#include <memory>
#include <sstream>
#include "vtr_util.h"
#include "vtr_assert.h"
#include "vtr_memory.h"
#include "vtr_error.h"
namespace vtr {
std::string out_file_prefix; /* used by fopen */
static int file_line_number = 0; /* file in line number being parsed (used by fgets) */
static int cont; /* line continued? (used by strtok)*/
//Splits the string 'text' along the specified delimiter characters in 'delims'
//The split strings (excluding the delimiters) are returned
std::vector<std::string> split(const char* text, const std::string delims) {
if(text) {
std::string text_str(text);
return split(text_str, delims);
}
return std::vector<std::string>();
}
std::vector<std::string> split(const std::string& text, const std::string delims) {
std::vector<std::string> tokens;
std::string curr_tok;
for(char c : text) {
if(delims.find(c) != std::string::npos) {
//Delimeter character
if(!curr_tok.empty()) {
//At the end of the token
//Save it
tokens.push_back(curr_tok);
//Reset token
curr_tok.clear();
} else {
//Pass
}
} else {
//Non-delimeter append to token
curr_tok += c;
}
}
//Add last token
if(!curr_tok.empty()) {
//Save it
tokens.push_back(curr_tok);
}
return tokens;
}
std::string replace_first(const std::string& input, const std::string& search, const std::string& replace) {
auto pos = input.find(search);
std::string output(input, 0, pos);
output += replace;
output += std::string(input, pos + search.size());
return output;
}
std::string replace_all(const std::string& input, const std::string& search, const std::string& replace) {
std::string output;
size_t last = 0;
size_t pos = input.find(search, last); //Find the first instance of 'search' starting at or after 'last'
while(pos != std::string::npos) {
output += input.substr(last, pos - last); //Append anything in the input string between last and current match
output += replace; //Add the replacement
last = pos + search.size(); //Advance past the current match
pos = input.find(search, last); //Look for the next match
}
output += input.substr(last, pos - last); //Append anything in 'input' after the last match
return output;
}
//Retruns true if str starts with prefix
bool starts_with(std::string str, std::string prefix) {
return str.find(prefix) == 0;
}
//Returns a std::string formatted using a printf-style format string
std::string string_fmt(const char* fmt, ...) {
// Make a variable argument list
va_list va_args;
// Initialize variable argument list
va_start(va_args, fmt);
//Format string
std::string str = vstring_fmt(fmt, va_args);
// Reset variable argument list
va_end(va_args);
return str;
}
//Returns a std::string formatted using a printf-style format string taking
//an explicit va_list
std::string vstring_fmt(const char* fmt, va_list args) {
// We need to copy the args so we don't change them before the true formating
va_list va_args_copy;
va_copy(va_args_copy, args);
//Determine the formatted length using a copy of the args
int len = std::vsnprintf(nullptr, 0, fmt, va_args_copy);
va_end(va_args_copy); //Clean-up
//Negative if there is a problem with the format string
VTR_ASSERT_MSG(len >= 0, "Problem decoding format string");
size_t buf_size = len + 1; //For terminator
//Allocate a buffer
// unique_ptr will free buffer automatically
std::unique_ptr<char[]> buf(new char[buf_size]);
//Format into the buffer using the original args
len = std::vsnprintf(buf.get(), buf_size, fmt, args);
VTR_ASSERT_MSG(len >= 0, "Problem decoding format string");
VTR_ASSERT(static_cast<size_t>(len) == buf_size - 1);
//Build the string from the buffer
return std::string(buf.get(), len);
}
/* An alternate for strncpy since strncpy doesn't work as most
* people would expect. This ensures null termination */
char* strncpy(char *dest, const char *src, size_t size) {
/* Find string's length */
size_t len = std::strlen(src);
/* Cap length at (num - 1) to leave room for \0 */
if (size <= len)
len = (size - 1);
/* Copy as much of string as we can fit */
std::memcpy(dest, src, len);
/* explicit null termination */
dest[len] = '\0';
return dest;
}
char* strdup(const char *str) {
if (str == nullptr ) {
return nullptr ;
}
size_t Len = std::strlen(str);
//use calloc to already make the last char '\0'
return (char *)std::memcpy(vtr::calloc(Len+1, sizeof(char)), str, Len);;
}
template<class T>
T atoT(const std::string& value, const std::string& type_name) {
//The c version of atof doesn't catch errors.
//
//This version uses stringstream to detect conversion errors
std::istringstream ss(value);
T val;
ss >> val;
if(ss.fail() || !ss.eof()) {
//Failed to convert, or did not consume all input
std::stringstream msg;
msg << "Failed to convert string '" << value << "' to " << type_name;
throw VtrError(msg.str(), __FILE__, __LINE__);
}
return val;
}
int atoi(const std::string& value) {
return atoT<int>(value, "int");
}
double atod(const std::string& value) {
return atoT<double>(value, "double");
}
float atof(const std::string& value) {
return atoT<float>(value, "float");
}
unsigned atou(const std::string& value) {
return atoT<unsigned>(value, "unsigned int");
}
char* strtok(char *ptr, const char *tokens, FILE * fp, char *buf) {
/* Get next token, and wrap to next line if \ at end of line. *
* There is a bit of a "gotcha" in strtok. It does not make a *
* copy of the character array which you pass by pointer on the *
* first call. Thus, you must make sure this array exists for *
* as long as you are using strtok to parse that line. Don't *
* use local buffers in a bunch of subroutines calling each *
* other; the local buffer may be overwritten when the stack is *
* restored after return from the subroutine. */
char *val;
val = std::strtok(ptr, tokens);
for (;;) {
if (val != nullptr || cont == 0)
return (val);
/* return unless we have a null value and a continuation line */
if (vtr::fgets(buf, bufsize, fp) == nullptr )
return (nullptr );
val = std::strtok(buf, tokens);
}
}
FILE* fopen(const char *fname, const char *flag) {
FILE *fp;
size_t Len;
char *new_fname = nullptr;
file_line_number = 0;
/* Appends a prefix string for output files */
if (!out_file_prefix.empty()) {
if (std::strchr(flag, 'w')) {
Len = 1; /* NULL char */
Len += std::strlen(out_file_prefix.c_str());
Len += std::strlen(fname);
new_fname = (char *) vtr::malloc(Len * sizeof(char));
strcpy(new_fname, out_file_prefix.c_str());
strcat(new_fname, fname);
fname = new_fname;
}
}
if (nullptr == (fp = std::fopen(fname, flag))) {
throw VtrError(string_fmt("Error opening file %s for %s access: %s.\n", fname, flag, strerror(errno)), __FILE__, __LINE__);
}
if (new_fname)
std::free(new_fname);
return (fp);
}
int fclose(FILE* f) {
return std::fclose(f);
}
char* fgets(char *buf, int max_size, FILE * fp) {
/* Get an input line, update the line number and cut off *
* any comment part. A \ at the end of a line with no *
* comment part (#) means continue. vtr::fgets should give *
* identical results for Windows (\r\n) and Linux (\n) *
* newlines, since it replaces each carriage return \r *
* by a newline character \n. Returns NULL after EOF. */
int ch;
int i;
cont = 0; /* line continued? */
file_line_number++; /* global variable */
for (i = 0; i < max_size - 1; i++) { /* Keep going until the line finishes or the buffer is full */
ch = std::fgetc(fp);
if (std::feof(fp)) { /* end of file */
if (i == 0) {
return nullptr ; /* required so we can write while (vtr::fgets(...) != NULL) */
} else { /* no newline before end of file - last line must be returned */
buf[i] = '\0';
return buf;
}
}
if (ch == '#') { /* comment */
buf[i] = '\0';
while ((ch = std::fgetc(fp)) != '\n' && !std::feof(fp))
; /* skip the rest of the line */
return buf;
}
if (ch == '\r' || ch == '\n') { /* newline (cross-platform) */
if (i != 0 && buf[i - 1] == '\\') { /* if \ at end of line, line continued */
cont = 1;
buf[i - 1] = '\n'; /* May need this for tokens */
buf[i] = '\0';
} else {
buf[i] = '\n';
buf[i + 1] = '\0';
}
return buf;
}
buf[i] = ch; /* copy character into the buffer */
}
/* Buffer is full but line has not terminated, so error */
throw VtrError(string_fmt("Error on line %d -- line is too long for input buffer.\n"
"All lines must be at most %d characters long.\n", bufsize - 2),
__FILE__, __LINE__);
return nullptr;
}
/*
* Returns line number of last opened and read file
*/
int get_file_line_number_of_last_opened_file() {
return file_line_number;
}
bool file_exists(const char* filename) {
FILE * file;
if (filename == nullptr ) {
return false;
}
file = std::fopen(filename, "r");
if (file) {
std::fclose(file);
return true;
}
return false;
}
/* Date:July 17th, 2013
* Author: Daniel Chen
* Purpose: Checks the file extension of an file to ensure
* correct file format. Returns true if format is
* correct, and false otherwise.
* Note: This is probably a fragile check, but at least
* should prevent common problems such as swapping
* architecture file and blif file on the VPR
* command line.
*/
bool check_file_name_extension(const char* file_name,
const char* file_extension){
const char* str;
int len_extension;
len_extension = std::strlen(file_extension);
str = std::strstr(file_name, file_extension);
if(str == nullptr || (*(str + len_extension) != '\0')){
return false;
}
return true;
}
std::vector<std::string> ReadLineTokens(FILE * InFile, int *LineNum) {
std::unique_ptr<char[]> buf(new char[vtr::bufsize]);
const char* line = vtr::fgets(buf.get(), vtr::bufsize, InFile);
++(*LineNum);
return vtr::split(line);
}
} //namespace

View File

@ -0,0 +1,102 @@
#ifndef VTR_UTIL_H
#define VTR_UTIL_H
#include <vector>
#include <string>
#include <cstdarg>
#include <array>
namespace vtr {
//Splits the string 'text' along the specified delimiter characters in 'delims'
//The split strings (excluding the delimiters) are returned
std::vector<std::string> split(const char* text, const std::string delims=" \t\n");
std::vector<std::string> split(const std::string& text, const std::string delims=" \t\n");
//Returns 'input' with the first instance of 'search' replaced with 'replace'
std::string replace_first(const std::string& input, const std::string& search, const std::string& replace);
//Returns 'input' with all instances of 'search' replaced with 'replace'
std::string replace_all(const std::string& input, const std::string& search, const std::string& replace);
//Retruns true if str starts with prefix
bool starts_with(std::string str, std::string prefix);
//Returns a std::string formatted using a printf-style format string
std::string string_fmt(const char* fmt, ...);
//Returns a std::string formatted using a printf-style format string taking
//an explicit va_list
std::string vstring_fmt(const char* fmt, va_list args);
//Joins a sequence by a specified delimeter
// For example the sequence {"home", "user", "my_files", "test.blif"} with delim="/"
// would return "home/user/my_files/test.blif"
template<typename Iter>
std::string join(Iter begin, Iter end, std::string delim);
template<typename Container>
std::string join(Container container, std::string delim);
template<typename T>
std::string join(std::initializer_list<T> list, std::string delim);
/*
* Legacy c-style function replacements, typically these add extra error checking
* and/or correct 'unexpected' behaviour of the standard c-functions
*/
constexpr size_t bufsize = 32768; /* Maximum line length for various parsing proc. */
char* strncpy(char *dest, const char *src, size_t size);
char* strdup(const char *str);
char* strtok(char *ptr, const char *tokens, FILE * fp, char *buf);
FILE* fopen(const char *fname, const char *flag);
int fclose(FILE* f);
char* fgets(char *buf, int max_size, FILE * fp);
int atoi(const std::string& value);
unsigned atou(const std::string& value);
float atof(const std::string& value);
double atod(const std::string& value);
/*
* File utilities
*/
int get_file_line_number_of_last_opened_file();
bool file_exists(const char * filename);
bool check_file_name_extension(const char* file_name,
const char* file_extension);
extern std::string out_file_prefix;
/*
* Legacy ReadLine Tokening
*/
std::vector<std::string> ReadLineTokens(FILE * InFile, int *LineNum);
/*
* Template implementations
*/
template<typename Iter>
std::string join(Iter begin, Iter end, std::string delim) {
std::string joined_str;
for(auto iter = begin; iter != end; ++iter) {
joined_str += *iter;
if(iter != end - 1) {
joined_str += delim;
}
}
return joined_str;
}
template<typename Container>
std::string join(Container container, std::string delim) {
return join(std::begin(container), std::end(container), delim);
}
template<typename T>
std::string join(std::initializer_list<T> list, std::string delim) {
return join(list.begin(), list.end(), delim);
}
}
#endif

View File

@ -0,0 +1,146 @@
#ifndef VTR_VECTOR
#define VTR_VECTOR
#include <vector>
#include <cstddef>
#include <iterator>
#include "vtr_range.h"
namespace vtr {
//A std::vector container which is indexed by K (instead of size_t).
//
//The main use of this container is to behave like a std::vector which is
//indexed by a vtr::StrongId. It assumes that K is explicitly convertable to size_t
//(i.e. via operator size_t()), and can be explicitly constructed from a size_t.
//
//If you need more std::map-like (instead of std::vector-like) behaviour see
//vtr::vector_map.
template<typename K, typename V>
class vector : private std::vector<V> {
public:
typedef K key_type;
class key_iterator;
typedef vtr::Range<key_iterator> key_range;
public:
//Pass through std::vector's types
using typename std::vector<V>::value_type;
using typename std::vector<V>::allocator_type;
using typename std::vector<V>::reference;
using typename std::vector<V>::const_reference;
using typename std::vector<V>::pointer;
using typename std::vector<V>::const_pointer;
using typename std::vector<V>::iterator;
using typename std::vector<V>::const_iterator;
using typename std::vector<V>::reverse_iterator;
using typename std::vector<V>::const_reverse_iterator;
using typename std::vector<V>::difference_type;
using typename std::vector<V>::size_type;
//Pass through std::vector's methods
using std::vector<V>::vector;
using std::vector<V>::begin;
using std::vector<V>::end;
using std::vector<V>::rbegin;
using std::vector<V>::rend;
using std::vector<V>::cbegin;
using std::vector<V>::cend;
using std::vector<V>::crbegin;
using std::vector<V>::crend;
using std::vector<V>::size;
using std::vector<V>::max_size;
using std::vector<V>::resize;
using std::vector<V>::capacity;
using std::vector<V>::empty;
using std::vector<V>::reserve;
using std::vector<V>::shrink_to_fit;
using std::vector<V>::front;
using std::vector<V>::back;
using std::vector<V>::data;
using std::vector<V>::assign;
using std::vector<V>::push_back;
using std::vector<V>::pop_back;
using std::vector<V>::insert;
using std::vector<V>::erase;
using std::vector<V>::swap;
using std::vector<V>::clear;
using std::vector<V>::emplace;
using std::vector<V>::emplace_back;
using std::vector<V>::get_allocator;
//Don't include operator[] and at() from std::vector,
//since we redine them to take key_type instead of size_t
reference operator[](const key_type id) {
auto i = size_t(id);
return std::vector<V>::operator[](i);
}
const_reference operator[](const key_type id) const {
auto i = size_t(id);
return std::vector<V>::operator[](i);
}
reference at(const key_type id) {
auto i = size_t(id);
return std::vector<V>::at(i);
}
const_reference at(const key_type id) const {
auto i = size_t(id);
return std::vector<V>::at(i);
}
//Returns a range containing the keys
key_range keys() const {
return vtr::make_range(key_begin(), key_end());
}
public:
//Iterator class which is convertable to the key_type
//This allows end-users to call the parent class's keys() member
//to iterate through the keys with a range-based for loop
class key_iterator : public std::iterator<std::bidirectional_iterator_tag, key_type> {
public:
//We use the intermediate type my_iter to avoid a potential ambiguity for which
//clang generates errors and warnings
using my_iter = typename std::iterator<std::bidirectional_iterator_tag, K>;
using typename my_iter::value_type;
using typename my_iter::iterator;
using typename my_iter::pointer;
using typename my_iter::reference;
key_iterator(key_iterator::value_type init): value_(init) {}
//vtr::vector assumes that the key time is convertable to size_t and
//that all the underlying IDs are zero-based and contiguous. That means
//we can just increment the underlying Id to build the next key.
key_iterator operator++() {
value_ = value_type(size_t(value_) + 1);
return *this;
}
key_iterator operator--() {
value_ = value_type(size_t(value_) - 1);
return *this;
}
reference operator*() { return value_; }
pointer operator->() { return &value_; }
friend bool operator== (const key_iterator lhs, const key_iterator rhs) { return lhs.value_ == rhs.value_; }
friend bool operator!= (const key_iterator lhs, const key_iterator rhs) { return !(lhs == rhs); }
private:
value_type value_;
};
private:
key_iterator key_begin() const { return key_iterator(key_type(0)); }
key_iterator key_end() const { return key_iterator(key_type(size())); }
};
} //namespace
#endif

View File

@ -0,0 +1,144 @@
#ifndef VTR_VECTOR_MAP
#define VTR_VECTOR_MAP
#include <vector>
#include "vtr_assert.h"
#include "vtr_sentinels.h"
namespace vtr {
//A vector-like container which is indexed by K (instead of size_t as in std::vector).
//
//The main use of this container is to behave like a std::vector which is indexed by
//vtr::StrongId.
//
//Requires that K be convertable to size_t with the size_t operator (i.e. size_t()), and
//that the conversion results in a linearly increasing index into the underlying vector.
//
//This results in a container that is somewhat similar to a std::map (i.e. converts from one
//type to another), but requires contiguously ascending (i.e. linear) keys. Unlike std::map
//only the values are stored (at the specified index/key), reducing memory usage and improving
//cache locality. Furthermore, operator[] and find() return the value or iterator directly
//associated with the value (like std::vector) rather than a std::pair (like std::map).
//insert() takes both the key and value as separate arguments and has no return value.
//
//Additionally, vector_map will silently create values for 'gaps' in the index range (i.e.
//those elements are initialized with Sentinel::INVALID()).
//
//If you need a fully featured std::map like container without the above differences see
//vtr::linear_map.
//
//If you do not need std::map-like features see vtr::vector.
//
//Note that it is possible to use vector_map with sparse/non-contiguous keys, but this is typically
//memory inefficient as the underlying vector will allocate space for [0..size_t(max_key)-1],
//where max_key is the largest key that has been inserted.
//
//As with a std::vector, it is the caller's responsibility to ensure there is sufficient space
//when a given index/key before it is accessed. The exception to this are the find(), insert() and
//update() methods which handle non-existing keys gracefully.
template<typename K, typename V, typename Sentinel=DefaultSentinel<V>>
class vector_map {
public: //Public types
typedef typename std::vector<V>::const_reference const_reference;
typedef typename std::vector<V>::reference reference;
typedef typename std::vector<V>::iterator iterator;
typedef typename std::vector<V>::const_iterator const_iterator;
typedef typename std::vector<V>::const_reverse_iterator const_reverse_iterator;
public: //Constructor
template<typename... Args>
vector_map(Args&&... args)
: vec_(std::forward<Args>(args)...)
{ }
public: //Accessors
//Iterators
const_iterator begin() const { return vec_.begin(); }
const_iterator end() const { return vec_.end(); }
const_reverse_iterator rbegin() const { return vec_.rbegin(); }
const_reverse_iterator rend() const { return vec_.rend(); }
//Indexing
const_reference operator[] (const K n) const {
size_t index = size_t(n);
VTR_ASSERT_SAFE_MSG(index >= 0 && index < vec_.size(), "Out-of-range index");
return vec_[index];
}
const_iterator find(const K key) const {
if(size_t(key) < vec_.size()) {
return vec_.begin() + size_t(key);
} else {
return vec_.end();
}
}
std::size_t size() const { return vec_.size(); }
bool empty() const { return vec_.empty(); }
bool contains(const K key) const { return size_t(key) < vec_.size(); }
size_t count(const K key) const { return contains(key) ? 1 : 0; }
public: //Mutators
//Delegate potentially overloaded functions to the underlying vector with perfect
//forwarding
template<typename... Args>
void push_back(Args&&... args) { vec_.push_back(std::forward<Args>(args)...); }
template<typename... Args>
void emplace_back(Args&&... args) { vec_.emplace_back(std::forward<Args>(args)...); }
template<typename... Args>
void resize(Args&&... args) { vec_.resize(std::forward<Args>(args)...); }
void clear() { vec_.clear(); }
size_t capacity() const { return vec_.capacity(); }
void shrink_to_fit() { vec_.shrink_to_fit(); }
//Iterators
iterator begin() { return vec_.begin(); }
iterator end() { return vec_.end(); }
//Indexing
reference operator[] (const K n) {
VTR_ASSERT_SAFE_MSG(size_t(n) < vec_.size(), "Out-of-range index");
return vec_[size_t(n)];
}
iterator find(const K key) {
if(size_t(key) < vec_.size()) {
return vec_.begin() + size_t(key);
} else {
return vec_.end();
}
}
void insert(const K key, const V value) {
if(size_t(key) >= vec_.size()) {
//Resize so key is in range
vec_.resize(size_t(key) + 1, Sentinel::INVALID());
}
//Insert the value
operator[](key) = value;
}
void update(const K key, const V value) { insert(key, value); }
//Swap (this enables std::swap via ADL)
friend void swap(vector_map<K,V>& x, vector_map<K,V>& y) {
std::swap(x.vec_, y.vec_);
}
private:
std::vector<V> vec_;
};
} //namespace
#endif

View File

@ -0,0 +1,18 @@
#include "vtr_version.h"
//This file is automatically processed by CMAKE and replaces
//the values between ampersand's with the releveant CMAKE variable
//before being compiled.
namespace vtr {
const char* VERSION = "@VTR_VERSION@";
const char* VERSION_SHORT = "@VTR_VERSION_SHORT@";
const size_t VERSION_MAJOR = @VTR_VERSION_MAJOR@;
const size_t VERSION_MINOR = @VTR_VERSION_MINOR@;
const size_t VERSION_PATCH = @VTR_VERSION_PATCH@;
const char* VERSION_PRERELEASE = "@VTR_VERSION_PRERELEASE@";
const char* VCS_REVISION = "@VTR_VCS_REVISION@";
const char* COMPILER = "@VTR_COMPILER_INFO@";
const char* BUILD_TIMESTAMP = "@VTR_BUILD_TIMESTAMP@";
}

View File

@ -0,0 +1,19 @@
#ifndef VTR_VERSION_H
#define VTR_VERSION_H
#include <cstddef>
namespace vtr {
extern const char* VERSION;
extern const char* VERSION_SHORT;
extern const size_t VERSION_MAJOR;
extern const size_t VERSION_MINOR;
extern const size_t VERSION_PATCH;
extern const char* VCS_REVISION;
extern const char* COMPILER;
extern const char* BUILD_TIMESTAMP;
extern const char* PRERELEASE_TAG;
}
#endif

View File

@ -12,6 +12,8 @@ endif()
project("vpr7_x2p" C CXX)
# idenify if we need graphics
set(ENABLE_VPR_GRAPHIC_CXX_FLAG true)
message(STATUS "Checking VPR graphics option ${ENABLE_VPR_GRAPHICS}")
if (ENABLE_VPR_GRAPHICS)
# check for dependencies
message(STATUS "VPR graphics is turned on, searching for dependencies")
@ -20,11 +22,13 @@ if (ENABLE_VPR_GRAPHICS)
if (NOT X11_FOUND)
message(WARNING "Failed to find required X11 library (on debian/ubuntu try 'sudo apt-get install libx11-dev' to install)")
#Disable
set(ENABLE_VPR_GRAPHICS false)
set(ENABLE_VPR_GRAPHIC_CXX_FLAG false)
endif()
else ()
set(ENABLE_VPR_GRAPHIC_CXX_FLAG false)
endif()
if (NOT ENABLE_VPR_GRAPHICS)
if (NOT ENABLE_VPR_GRAPHIC_CXX_FLAG)
# Add a flag to notify compiler not to consider graphic-related source codes
set (DISABLE_GRAPHIC_FLAGS "-DNO_GRAPHICS")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DISABLE_GRAPHIC_FLAGS}")
@ -56,14 +60,16 @@ target_include_directories(libvpr PUBLIC ${LIB_INCLUDE_DIRS})
set_target_properties(libvpr PROPERTIES PREFIX "") #Avoid extra 'lib' prefix#Create the executable
#Specify link-time dependancies
if (ENABLE_VPR_GRAPHICS)
if (ENABLE_VPR_GRAPHIC_CXX_FLAG)
target_link_libraries(libvpr
libarchfpga
X11
libvtrutil
readline)
else ()
target_link_libraries(libvpr
libarchfpga
libvtrutil
readline)
endif()

View File

@ -35,6 +35,7 @@
#include "arch_types.h"
#include <map>
#include <vector>
/*******************************************************************************
* Global data types and constants
@ -946,6 +947,7 @@ struct s_rr_node {
short yhigh;
short ptc_num;
std::vector<short> track_ids; /* Tileable arch support: Track indices in each GSB */
short cost_index;
short occ;

View File

@ -0,0 +1,268 @@
/**********************************************************
* MIT License
*
* Copyright (c) 2018 LNIS - The University of Utah
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***********************************************************************/
/************************************************************************
* Filename: chan_node_details.cpp
* Created by: Xifan Tang
* Change history:
* +-------------------------------------+
* | Date | Author | Notes
* +-------------------------------------+
* | 2019/06/14 | Xifan Tang | Created
* +-------------------------------------+
***********************************************************************/
/************************************************************************
* This file contains member functions for class ChanNodeDetails
***********************************************************************/
#include <cassert>
#include <algorithm>
#include "chan_node_details.h"
/************************************************************************
* Constructors
***********************************************************************/
ChanNodeDetails::ChanNodeDetails(const ChanNodeDetails& src) {
/* duplicate */
size_t chan_width = src.get_chan_width();
this->reserve(chan_width);
for (size_t itrack = 0; itrack < chan_width; ++itrack) {
track_node_ids_.push_back(src.get_track_node_id(itrack));
track_direction_.push_back(src.get_track_direction(itrack));
seg_length_.push_back(src.get_track_segment_length(itrack));
track_start_.push_back(src.is_track_start(itrack));
track_end_.push_back(src.is_track_end(itrack));
}
}
ChanNodeDetails::ChanNodeDetails() {
this->clear();
}
/************************************************************************
* Accessors
***********************************************************************/
size_t ChanNodeDetails::get_chan_width() const {
assert(validate_chan_width());
return track_node_ids_.size();
}
size_t ChanNodeDetails::get_track_node_id(size_t track_id) const {
assert(validate_track_id(track_id));
return track_node_ids_[track_id];
}
e_direction ChanNodeDetails::get_track_direction(size_t track_id) const {
assert(validate_track_id(track_id));
return track_direction_[track_id];
}
size_t ChanNodeDetails::get_track_segment_length(size_t track_id) const {
assert(validate_track_id(track_id));
return seg_length_[track_id];
}
bool ChanNodeDetails::is_track_start(size_t track_id) const {
assert(validate_track_id(track_id));
return track_start_[track_id];
}
bool ChanNodeDetails::is_track_end(size_t track_id) const {
assert(validate_track_id(track_id));
return track_end_[track_id];
}
/* Track_id is the starting point of group (whose is_start should be true)
* This function will try to find the track_ids with the same directionality as track_id and seg_length
* A group size is the number of such nodes between the starting points (include the 1st starting point)
*/
std::vector<size_t> ChanNodeDetails::get_seg_group(size_t track_id) const {
assert(validate_chan_width());
assert(validate_track_id(track_id));
assert(is_track_start(track_id));
std::vector<size_t> group;
/* Make sure a clean start */
group.clear();
/* track_id is the first element */
group.push_back(track_id);
for (size_t itrack = track_id; itrack < get_chan_width(); ++itrack) {
if ( (get_track_direction(itrack) == get_track_direction(track_id) )
&& (get_track_segment_length(itrack) == get_track_segment_length(track_id)) ) {
if ( (false == is_track_start(itrack))
|| ( (true == is_track_start(itrack)) && (itrack == track_id)) ) {
group.push_back(itrack);
continue;
}
/* Stop if this another starting point */
if (true == is_track_start(itrack)) {
break;
}
}
}
return group;
}
/* Get a list of track_ids with the given list of track indices */
std::vector<size_t> ChanNodeDetails::get_seg_group_node_id(std::vector<size_t> seg_group) const {
std::vector<size_t> group;
/* Make sure a clean start */
group.clear();
for (size_t id = 0; id < seg_group.size(); ++id) {
assert(validate_track_id(seg_group[id]));
group.push_back(get_track_node_id(seg_group[id]));
}
return group;
}
/* Get the number of tracks that starts in this routing channel */
size_t ChanNodeDetails::get_num_starting_tracks() const {
size_t counter = 0;
for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) {
if (false == is_track_start(itrack)) {
continue;
}
counter++;
}
return counter;
}
/* Get the number of tracks that ends in this routing channel */
size_t ChanNodeDetails::get_num_ending_tracks() const {
size_t counter = 0;
for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) {
if (false == is_track_end(itrack)) {
continue;
}
counter++;
}
return counter;
}
/************************************************************************
* Mutators
***********************************************************************/
/* Reserve the capacitcy of vectors */
void ChanNodeDetails::reserve(size_t chan_width) {
track_node_ids_.reserve(chan_width);
track_direction_.reserve(chan_width);
seg_length_.reserve(chan_width);
track_start_.reserve(chan_width);
track_end_.reserve(chan_width);
}
/* Add a track to the channel */
void ChanNodeDetails::add_track(size_t track_node_id, e_direction track_direction, size_t seg_length, size_t is_start, size_t is_end) {
track_node_ids_.push_back(track_node_id);
track_direction_.push_back(track_direction);
seg_length_.push_back(seg_length);
track_start_.push_back(is_start);
track_end_.push_back(is_end);
}
/* Set tracks with a given direction to start */
void ChanNodeDetails::set_tracks_start(e_direction track_direction) {
for (size_t inode = 0; inode < get_chan_width(); ++inode) {
/* Bypass non-match tracks */
if (track_direction != get_track_direction(inode)) {
}
track_start_[inode] = true;
}
}
/* Set tracks with a given direction to end */
void ChanNodeDetails::set_tracks_end(e_direction track_direction) {
for (size_t inode = 0; inode < get_chan_width(); ++inode) {
/* Bypass non-match tracks */
if (track_direction != get_track_direction(inode)) {
}
track_end_[inode] = true;
}
}
/* rotate the track_node_id by an offset */
void ChanNodeDetails::rotate_track_node_id(size_t offset, bool counter_rotate) {
/* Rotate the node_ids by groups
* A group begins from a track_start and ends before another track_start
*/
assert(validate_chan_width());
for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) {
/* Bypass non-start segment */
if (false == is_track_start(itrack) ) {
continue;
}
/* Find the group nodes */
std::vector<size_t> track_group = get_seg_group(itrack);
/* Build a vector of the node ids of the tracks */
std::vector<size_t> track_group_node_id = get_seg_group_node_id(track_group);
/* Rotate or Counter rotate */
if (true == counter_rotate) {
std::rotate(track_group_node_id.begin(), track_group_node_id.end() - offset, track_group_node_id.end());
} else {
std::rotate(track_group_node_id.begin(), track_group_node_id.begin() + offset, track_group_node_id.end());
}
/* Update the node_ids */
for (size_t inode = 0; inode < track_group.size(); ++inode) {
track_node_ids_[track_group[inode]] = track_group_node_id[inode];
}
}
return;
}
void ChanNodeDetails::clear() {
track_node_ids_.clear();
track_direction_.clear();
seg_length_.clear();
track_start_.clear();
track_end_.clear();
}
/************************************************************************
* Validators
***********************************************************************/
bool ChanNodeDetails::validate_chan_width() const {
size_t chan_width = track_node_ids_.size();
if ( (chan_width == track_direction_.size())
&&(chan_width == seg_length_.size())
&&(chan_width == track_start_.size())
&&(chan_width == track_end_.size()) ) {
return true;
}
return false;
}
bool ChanNodeDetails::validate_track_id(size_t track_id) const {
if ( (track_id < track_node_ids_.size())
&& (track_id < track_direction_.size())
&& (track_id < seg_length_.size())
&& (track_id < track_start_.size())
&& (track_id < track_end_.size()) ) {
return true;
}
return false;
}

View File

@ -0,0 +1,105 @@
/**********************************************************
* MIT License
*
* Copyright (c) 2018 LNIS - The University of Utah
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***********************************************************************/
/************************************************************************
* Filename: chan_node_details.h
* Created by: Xifan Tang
* Change history:
* +-------------------------------------+
* | Date | Author | Notes
* +-------------------------------------+
* | 2019/06/11 | Xifan Tang | Created
* +-------------------------------------+
***********************************************************************/
/************************************************************************
* This file contains a class to model the details of routing node
* in a channel:
* 1. segment information: length, frequency etc.
* 2. starting point of segment
* 3. ending point of segment
* 4. potentail track_id(ptc_num) of each segment
***********************************************************************/
/* IMPORTANT:
* The following preprocessing flags are added to
* avoid compilation error when this headers are included in more than 1 times
*/
#ifndef CHAN_NODE_DETAILS_H
#define CHAN_NODE_DETAILS_H
/*
* Notes in include header files in a head file
* Only include the neccessary header files
* that is required by the data types in the function/class declarations!
*/
/* Header files should be included in a sequence */
/* Standard header files required go first */
#include <vector>
#include "vpr_types.h"
/************************************************************************
* ChanNodeDetails records segment length, directionality and starting of routing tracks
* +---------------------------------+
* | Index | Direction | Start Point |
* +---------------------------------+
* | 0 | --------> | Yes |
* +---------------------------------+
***********************************************************************/
class ChanNodeDetails {
public : /* Constructor */
ChanNodeDetails(const ChanNodeDetails&); /* Duplication */
ChanNodeDetails(); /* Initilization */
public: /* Accessors */
size_t get_chan_width() const;
size_t get_track_node_id(size_t track_id) const;
e_direction get_track_direction(size_t track_id) const;
size_t get_track_segment_length(size_t track_id) const;
bool is_track_start(size_t track_id) const;
bool is_track_end(size_t track_id) const;
std::vector<size_t> get_seg_group(size_t track_id) const;
std::vector<size_t> get_seg_group_node_id(std::vector<size_t> seg_group) const;
size_t get_num_starting_tracks() const;
size_t get_num_ending_tracks() const;
public: /* Mutators */
void reserve(size_t chan_width); /* Reserve the capacitcy of vectors */
void add_track(size_t track_node_id, e_direction track_direction, size_t seg_length, size_t is_start, size_t is_end);
void set_tracks_start(e_direction track_direction);
void set_tracks_end(e_direction track_direction);
void rotate_track_node_id(size_t offset, bool counter_rotate); /* rotate the track_node_id by an offset */
void clear();
private: /* validators */
bool validate_chan_width() const;
bool validate_track_id(size_t track_id) const;
private: /* Internal data */
std::vector<size_t> track_node_ids_; /* indices of each track */
std::vector<e_direction> track_direction_; /* direction of each track */
std::vector<size_t> seg_length_; /* Length of each segment */
std::vector<bool> track_start_; /* flag to identify if this is the starting point of the track */
std::vector<bool> track_end_; /* flag to identify if this is the ending point of the track */
};
#endif

View File

@ -0,0 +1,66 @@
/**********************************************************
* MIT License
*
* Copyright (c) 2018 LNIS - The University of Utah
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***********************************************************************/
/************************************************************************
* Filename: rr_graph_gsb.c
* Created by: Xifan Tang
* Change history:
* +-------------------------------------+
* | Date | Author | Notes
* +-------------------------------------+
* | 2019/06/12 | Xifan Tang | Created
* +-------------------------------------+
***********************************************************************/
/************************************************************************
* This file constains the member functions for class GSBConn
************************************************************************/
#include "gsb_graph.h"
#include "vtr_vector_map.h"
/************************************************************************
* Constructors for class GSBGraph
************************************************************************/
/* Duplicate a object */
GSBGraph::GSBGraph(const GSBGraph& gsb_graph) {
}
GSBGraph::GSBGraph() {
coordinator_.clear();
}
/************************************************************************
* Aggregators for class GSBGraph
************************************************************************/
/* Accessors: Aggregators */
GSBGraph::node_range GSBGraph::nodes() const {
return vtr::make_range(node_ids_.begin(), node_ids_.end());
}
GSBGraph::edge_range GSBGraph::edges() const {
return vtr::make_range(edge_ids_.begin(), edge_ids_.end());
}

View File

@ -0,0 +1,166 @@
/**********************************************************
* MIT License
*
* Copyright (c) 2018 LNIS - The University of Utah
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***********************************************************************/
/************************************************************************
* Filename: gsb_graph.h
* Created by: Xifan Tang
* Change history:
* +-------------------------------------+
* | Date | Author | Notes
* +-------------------------------------+
* | 2019/06/12 | Xifan Tang | Created
* +-------------------------------------+
***********************************************************************/
/************************************************************************
* This file constains a class to model the connection of a
* General Switch Block (GSB), which is a unified block of Connection Blocks
* and Switch Blocks.
* This block contains
* 1. A switch block
* 2. A X-direction Connection block locates at the left side of the switch block
* 2. A Y-direction Connection block locates at the top side of the switch block
*
* +---------------------------------+
* | Y-direction CB |
* | [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
*
***********************************************************************/
/* IMPORTANT:
* The following preprocessing flags are added to
* avoid compilation error when this headers are included in more than 1 times
*/
#ifndef GSB_GRAPH_H
#define GSB_GRAPH_H
/*
* Notes in include header files in a head file
* Only include the neccessary header files
* that is required by the data types in the function/class declarations!
*/
/* Header files should be included in a sequence */
/* Standard header files required go first */
#include <vector>
/* External library header files */
#include "vtr_vector.h"
#include "vtr_range.h"
#include "device_coordinator.h"
#include "vpr_types.h"
#include "rr_graph_fwd.h"
/* Define open nodes */
#define OPEN_NODE_ID RRNodeId(-1)
#define OPEN_EDGE_ID RREdgeId(-1)
/***********************************************************************
* This data structure focuses on modeling the internal pin-to-pin connections.
* It is basically a collection of nodes and edges.
* To make the data structure general, the nodes and edges are not linked to any another data
* structures.
*
* node_ids_: a collection of nodes (basically ids) modelling routing tracks
* which locate at each side of the GSB <0..num_nodes_per_side-1>
*
* node_directions_: Indicate if this node is an input or an output of the GSB
* <0..num_nodes_per_side-1>
*
* node_types_: specify the types of the node, CHANX|CHANY|IPIN|OPIN
*
* node_sides_: specify the sides of the node on a GSB, TOP|RIGHT|BOTTOM|LEFT
*
* node_grid_sides_: specify the side of the node on which side of a GRID
* for CHANX and CHANY, it is an invalid value
* <0..num_nodes_per_side-1>
*
* node_in_edges_: indcies of input edges of a node
* <0..num_nodes><0..num_input_edgess-1>
*
* node_out_edges_: indcies of output edges of a node
* <0..num_nodes><0..num_output_edges-1>
*
* edge_ids_: a collection of indices of edges, <0..num_edges-1>, which connects the nodes
*
* edge_src_nodes_: indcies of input nodes of an edge (driving nodes for each edge)
* <0..num_input_nodes-1>
*
* edge_sink_nodes_: indices of output nodes of an edge (fan-out nodes for each edge)
* <0..num_output_nodes-1>
*
***********************************************************************/
class GSBGraph {
public: /* Types */
typedef vtr::vector<RRNodeId, RRNodeId>::const_iterator node_iterator;
typedef vtr::vector<RREdgeId, RREdgeId>::const_iterator edge_iterator;
typedef vtr::Range<node_iterator> node_range;
typedef vtr::Range<edge_iterator> edge_range;
public: /* Constructors */
GSBGraph(const GSBGraph&); /* A constructor to duplicate */
GSBGraph();
public: /* Accessors */
/* Aggregates */
node_range nodes() const;
edge_range edges() const;
private: /* Internal Data */
/* Coordinator of this GSB */
DeviceCoordinator coordinator_;
/* nodes on each side */
vtr::vector<RRNodeId, RRNodeId> node_ids_;
vtr::vector<RRNodeId, t_rr_type> node_types_;
vtr::vector<RRNodeId, enum e_side> node_sides_;
vtr::vector<RRNodeId, enum e_direction> node_directions_;
vtr::vector<RRNodeId, enum e_side> node_grid_sides_;
vtr::vector<RRNodeId, std::vector<RREdgeId>> node_in_edges;
vtr::vector<RRNodeId, std::vector<RREdgeId>> node_out_edges;
/* edges */
vtr::vector<RREdgeId, RREdgeId> edge_ids_;
vtr::vector<RREdgeId, RREdgeId> edge_src_nodes_; /* each element is a node_id */
vtr::vector<RREdgeId, RREdgeId> edge_sink_nodes_; /* each element is a node_id */
};
#endif

View File

@ -0,0 +1,18 @@
#ifndef RR_GRAPH_OBJ_FWD_H
#define RR_GRAPH_OBJ_FWD_H
#include "vtr_strong_id.h"
class RRGraph;
struct rr_node_id_tag;
struct rr_edge_id_tag;
struct rr_switch_id_tag;
struct rr_segment_id_tag;
typedef vtr::StrongId<rr_node_id_tag> RRNodeId;
typedef vtr::StrongId<rr_edge_id_tag> RREdgeId;
typedef vtr::StrongId<rr_switch_id_tag, short> RRSwitchId;
typedef vtr::StrongId<rr_segment_id_tag, short> RRSegmentId;
#endif

View File

@ -44,6 +44,7 @@
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <vector>
#include "vpr_types.h"
#include "globals.h"
#include "vpr_utils.h"
@ -54,6 +55,391 @@
#include "fpga_x2p_types.h"
#include "rr_graph_tileable_builder.h"
#include "chan_node_details.h"
#include "device_coordinator.h"
/************************************************************************
* Local function in the file
***********************************************************************/
/************************************************************************
* Generate the number of tracks for each types of routing segments
* w.r.t. the frequency of each of segments and channel width
* Note that if we dertermine the number of tracks per type using
* chan_width * segment_frequency / total_freq may cause
* The total track num may not match the chan_width,
* therefore, we assign tracks one by one until we meet the frequency requirement
* In this way, we can assign the number of tracks with repect to frequency
***********************************************************************/
static
std::vector<size_t> get_num_tracks_per_seg_type(size_t chan_width,
std::vector<t_segment_inf> segment_inf,
bool use_full_seg_groups) {
std::vector<size_t> result;
std::vector<double> demand;
/* Make sure a clean start */
result.resize(segment_inf.size());
demand.resize(segment_inf.size());
/* Scale factor so we can divide by any length
* and still use integers */
/* Get the sum of frequency */
size_t scale = 1;
size_t freq_sum = 0;
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
scale *= segment_inf[iseg].length;
freq_sum += segment_inf[iseg].frequency;
}
size_t reduce = scale * freq_sum;
/* Init assignments to 0 and set the demand values */
/* Get the fraction of each segment type considering the frequency:
* num_track_per_seg = chan_width * (freq_of_seg / sum_freq)
*/
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
result[iseg] = 0;
demand[iseg] = scale * chan_width * segment_inf[iseg].frequency;
if (true == use_full_seg_groups) {
demand[iseg] /= segment_inf[iseg].length;
}
}
/* check if the sum of num_tracks, matches the chan_width */
/* Keep assigning tracks until we use them up */
size_t assigned = 0;
size_t size = 0;
size_t imax = 0;
while (assigned < chan_width) {
/* Find current maximum demand */
double max = 0;
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
if (demand[iseg] > max) {
imax = iseg;
}
max = std::max(demand[iseg], max);
}
/* Assign tracks to the type and reduce the types demand */
size = (use_full_seg_groups ? segment_inf[imax].length : 1);
demand[imax] -= reduce;
result[imax] += size;
assigned += size;
}
/* Undo last assignment if we were closer to goal without it */
if ((assigned - chan_width) > (size / 2)) {
result[imax] -= size;
}
return result;
}
/************************************************************************
* Build details of routing tracks in a channel
* The function will
* 1. Assign the segments for each routing channel,
* To be specific, for each routing track, we assign a routing segment.
* The assignment is subject to users' specifications, such as
* a. length of each type of segment
* b. frequency of each type of segment.
* c. routing channel width
*
* 2. The starting point of each segment in the channel will be assigned
* For each segment group with same directionality (tracks have the same length),
* every L track will be a starting point (where L denotes the length of segments)
* In this case, if the number of tracks is not a multiple of L,
* indeed we may have some <L segments. This can be considered as a side effect.
* But still the rr_graph is tileable, which is the first concern!
*
* Here is a quick example of Length-4 wires in a W=12 routing channel
* +---------------------------------+
* | Index | Direction | Start Point |
* +---------------------------------+
* | 0 | --------> | Yes |
* +---------------------------------+
* | 1 | <-------- | Yes |
* +---------------------------------+
* | 2 | --------> | No |
* +---------------------------------+
* | 3 | <-------- | No |
* +---------------------------------+
* | 4 | --------> | No |
* +---------------------------------+
* | 5 | <-------- | No |
* +---------------------------------+
* | 7 | --------> | No |
* +---------------------------------+
* | 8 | <-------- | No |
* +---------------------------------+
* | 9 | --------> | Yes |
* +---------------------------------+
* | 10 | <-------- | Yes |
* +---------------------------------+
* | 11 | --------> | No |
* +---------------------------------+
* | 12 | <-------- | No |
* +---------------------------------+
*
* 3. SPECIAL for fringes: TOP|RIGHT|BOTTOM|RIGHT
* if device_side is NUM_SIDES, we assume this channel does not locate on borders
* All segments will start and ends with no exception
*
* 4. IMPORTANT: we should be aware that channel width maybe different
* in X-direction and Y-direction channels!!!
* So we will load segment details for different channels
***********************************************************************/
static
ChanNodeDetails build_unidir_chan_node_details(size_t chan_width, size_t max_seg_length,
enum e_side device_side,
std::vector<t_segment_inf> segment_inf) {
ChanNodeDetails chan_node_details;
/* Correct the chan_width: it should be an even number */
if (0 != chan_width % 2) {
chan_width++; /* increment it to be even */
}
assert (0 == chan_width % 2);
/* Reserve channel width */
chan_node_details.reserve(chan_width);
/* Return if zero width is forced */
if (0 == chan_width) {
return chan_node_details;
}
/* Find the number of segments required by each group */
std::vector<size_t> num_tracks = get_num_tracks_per_seg_type(chan_width/2, segment_inf, TRUE);
/* Add node to ChanNodeDetails */
size_t cur_track = 0;
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
/* segment length will be set to maxium segment length if this is a longwire */
size_t seg_len = segment_inf[iseg].length;
if (TRUE == segment_inf[iseg].longline) {
seg_len = max_seg_length;
}
for (size_t itrack = 0; itrack < num_tracks[iseg]; ++itrack) {
bool seg_start = false;
/* Every length of wire, we set a starting point */
if (0 == itrack % seg_len) {
seg_start = true;
}
/* Since this is a unidirectional routing architecture,
* Add a pair of tracks, 1 INC_DIRECTION track and 1 DEC_DIRECTION track
*/
chan_node_details.add_track(cur_track, INC_DIRECTION, seg_len, seg_start, false);
cur_track++;
chan_node_details.add_track(cur_track, DEC_DIRECTION, seg_len, seg_start, false);
cur_track++;
}
}
/* Check if all the tracks have been satisified */
assert (cur_track == chan_width);
/* If this is on the border of a device, segments should start */
switch (device_side) {
case TOP:
case RIGHT:
/* INC_DIRECTION should all end */
chan_node_details.set_tracks_end(INC_DIRECTION);
/* DEC_DIRECTION should all start */
chan_node_details.set_tracks_start(DEC_DIRECTION);
break;
case BOTTOM:
case LEFT:
/* INC_DIRECTION should all start */
chan_node_details.set_tracks_start(INC_DIRECTION);
/* DEC_DIRECTION should all end */
chan_node_details.set_tracks_end(DEC_DIRECTION);
break;
case NUM_SIDES:
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d]) Invalid device_side!\n",
__FILE__, __LINE__);
exit(1);
}
return chan_node_details;
}
/* Deteremine the side of a io grid */
static
enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size,
const DeviceCoordinator& grid_coordinator) {
/* TOP side IO of FPGA */
if (device_size.get_y() == grid_coordinator.get_y()) {
return BOTTOM; /* Such I/O has only Bottom side pins */
} else if (device_size.get_x() == grid_coordinator.get_x()) { /* RIGHT side IO of FPGA */
return LEFT; /* Such I/O has only Left side pins */
} else if (0 == grid_coordinator.get_y()) { /* BOTTOM side IO of FPGA */
return TOP; /* Such I/O has only Top side pins */
} else if (0 == grid_coordinator.get_x()) { /* LEFT side IO of FPGA */
return RIGHT; /* Such I/O has only Right side pins */
} else {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])I/O Grid is in the center part of FPGA! Currently unsupported!\n",
__FILE__, __LINE__);
exit(1);
}
}
/************************************************************************
* Get a list of pin_index for a grid (either OPIN or IPIN)
* For IO_TYPE, only one side will be used, we consider one side of pins
* For others, we consider all the sides
***********************************************************************/
static
std::vector<int> get_grid_side_pins(const t_grid_tile& cur_grid, enum e_pin_type pin_type, enum e_side pin_side, int pin_height) {
std::vector<int> pin_list;
/* Make sure a clear start */
pin_list.clear();
for (int ipin = 0; ipin < cur_grid.type->num_pins; ++ipin) {
if ( (1 == cur_grid.type->pinloc[pin_height][pin_side][ipin])
&& (pin_type == cur_grid.type->pin_class[ipin]) ) {
pin_list.push_back(ipin);
}
}
return pin_list;
}
/************************************************************************
* Get the number of pins for a grid (either OPIN or IPIN)
* For IO_TYPE, only one side will be used, we consider one side of pins
* For others, we consider all the sides
***********************************************************************/
static
size_t get_grid_num_pins(const t_grid_tile& cur_grid, enum e_pin_type pin_type, enum e_side io_side) {
size_t num_pins = 0;
Side io_side_manager(io_side);
/* For IO_TYPE sides */
for (size_t side = 0; side < NUM_SIDES; ++side) {
Side side_manager(side);
/* skip unwanted sides */
if ( (IO_TYPE == cur_grid.type)
&& (side != io_side_manager.to_size_t()) ) {
continue;
}
/* Get pin list */
for (int height = 0; height < cur_grid.type->height; ++height) {
std::vector<int> pin_list = get_grid_side_pins(cur_grid, pin_type, side_manager.get_side(), height);
num_pins += pin_list.size();
}
}
return num_pins;
}
/************************************************************************
* Estimate the number of rr_nodes per category:
* CHANX, CHANY, IPIN, OPIN, SOURCE, SINK
***********************************************************************/
static
std::vector<size_t> estimate_num_rr_nodes_per_type(const DeviceCoordinator& device_size,
std::vector<std::vector<t_grid_tile>> grids,
std::vector<size_t> chan_width,
std::vector<t_segment_inf> segment_infs) {
std::vector<size_t> num_rr_nodes_per_type;
/* reserve the vector:
* we have the follow type:
* SOURCE = 0, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE, NUM_RR_TYPES
* NUM_RR_TYPES and INTRA_CLUSTER_EDGE will be 0
*/
num_rr_nodes_per_type.resize(NUM_RR_TYPES);
/* Make sure a clean start */
for (size_t i = 0; i < NUM_RR_TYPES; ++i) {
num_rr_nodes_per_type[i] = 0;
}
/************************************************************************
* 1. Search the grid and find the number OPINs and IPINs per grid
* Note that the number of SOURCE nodes are the same as OPINs
* and the number of SINK nodes are the same as IPINs
***********************************************************************/
for (size_t ix = 0; ix < grids.size(); ++ix) {
for (size_t iy = 0; iy < grids[ix].size(); ++iy) {
/* Skip EMPTY tiles */
if (EMPTY_TYPE == grids[ix][iy].type) {
continue;
}
/* Skip height>1 tiles (mostly heterogeneous blocks) */
if (0 < grids[ix][iy].offset) {
continue;
}
enum e_side io_side = NUM_SIDES;
/* If this is the block on borders, we consider IO side */
if (IO_TYPE == grid[ix][iy].type) {
DeviceCoordinator io_device_size(device_size.get_x() - 1, device_size.get_y() - 1);
DeviceCoordinator grid_coordinator(ix, iy);
io_side = determine_io_grid_pin_side(device_size, grid_coordinator);
}
/* get the number of OPINs */
num_rr_nodes_per_type[OPIN] += get_grid_num_pins(grids[ix][iy], DRIVER, io_side);
/* get the number of IPINs */
num_rr_nodes_per_type[IPIN] += get_grid_num_pins(grids[ix][iy], RECEIVER, io_side);
}
}
/* SOURCE and SINK */
num_rr_nodes_per_type[SOURCE] = num_rr_nodes_per_type[OPIN];
num_rr_nodes_per_type[SINK] = num_rr_nodes_per_type[IPIN];
/************************************************************************
* 2. Assign the segments for each routing channel,
* To be specific, for each routing track, we assign a routing segment.
* The assignment is subject to users' specifications, such as
* a. length of each type of segment
* b. frequency of each type of segment.
* c. routing channel width
*
* SPECIAL for fringes:
* All segments will start and ends with no exception
*
* IMPORTANT: we should be aware that channel width maybe different
* in X-direction and Y-direction channels!!!
* So we will load segment details for different channels
***********************************************************************/
/* For X-direction Channel */
/* For LEFT side of FPGA */
ChanNodeDetails left_chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, LEFT, segment_infs);
for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) {
num_rr_nodes_per_type[CHANX] += left_chanx_details.get_num_starting_tracks();
}
/* For RIGHT side of FPGA */
ChanNodeDetails right_chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, RIGHT, segment_infs);
for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) {
num_rr_nodes_per_type[CHANX] += right_chanx_details.get_num_starting_tracks();
}
/* For core of FPGA */
ChanNodeDetails core_chanx_details = build_unidir_chan_node_details(chan_width[1], device_size.get_x() - 2, NUM_SIDES, segment_infs);
for (size_t ix = 1; ix < grids.size() - 2; ++ix) {
for (size_t iy = 1; iy < grids[ix].size() - 2; ++iy) {
num_rr_nodes_per_type[CHANX] += core_chanx_details.get_num_starting_tracks();
}
}
/* For Y-direction Channel */
/* For TOP side of FPGA */
ChanNodeDetails top_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, TOP, segment_infs);
for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) {
num_rr_nodes_per_type[CHANY] += top_chany_details.get_num_starting_tracks();
}
/* For BOTTOM side of FPGA */
ChanNodeDetails bottom_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, BOTTOM, segment_infs);
for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) {
num_rr_nodes_per_type[CHANY] += bottom_chany_details.get_num_starting_tracks();
}
/* For core of FPGA */
ChanNodeDetails core_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, NUM_SIDES, segment_infs);
for (size_t ix = 1; ix < grids.size() - 2; ++ix) {
for (size_t iy = 1; iy < grids[ix].size() - 2; ++iy) {
num_rr_nodes_per_type[CHANY] += core_chany_details.get_num_starting_tracks();
}
}
return num_rr_nodes_per_type;
}
/************************************************************************
* Main function of this file
* Builder for a detailed uni-directional tileable rr_graph
@ -103,9 +489,9 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
INP t_timing_inf timing_inf, INP int wire_to_ipin_switch,
INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs,
INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings,
/*Xifan TANG: Switch Segment Pattern Support*/
INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns,
INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) {
/*Xifan TANG: Switch Segment Pattern Support*/
INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns,
INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) {
/* Create an empty graph */
t_rr_graph rr_graph;
rr_graph.rr_node_indices = NULL;
@ -115,22 +501,55 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
/* Reset warning flag */
*Warnings = RR_GRAPH_NO_WARN;
/* Create a matrix of grid */
DeviceCoordinator device_size(L_nx + 2, L_ny + 2);
std::vector< std::vector<t_grid_tile> > grids;
/* reserve vector capacity to be memory efficient */
grids.resize(L_nx + 2);
for (int ix = 0; ix < (L_nx + 2); ++ix) {
grids[ix].resize(L_ny + 2);
for (int iy = 0; ix < (L_ny + 2); ++iy) {
grid[ix][iy] = L_grid[ix][iy];
}
}
/* Create a vector of channel width, we support X-direction and Y-direction has different W */
std::vector<size_t> device_chan_width;
device_chan_width.push_back(chan_width);
device_chan_width.push_back(chan_width);
/* Create a vector of segment_inf */
std::vector<t_segment_inf> segment_infs;
for (int iseg = 0; iseg < num_seg_types; ++iseg) {
segment_infs.push_back(segment_inf[iseg]);
}
/************************************************************************
* 1. Assign the segments for each routing channel,
* To be specific, for each routing track, we assign a routing segment.
* The assignment is subject to users' specifications, such as
* a. length of each type of segment
* b. frequency of each type of segment.
* c. routing channel width
* 2. Estimate the number of nodes in the rr_graph
* This will estimate the number of
* a. IPINs, input pins of each grid
* b. OPINs, output pins of each grid
* c. SOURCE, virtual node which drives OPINs
* d. SINK, virtual node which is connected to IPINs
* e. CHANX and CHANY, routing segments of each channel
***********************************************************************/
std::vector<size_t> num_rr_nodes_per_type = estimate_num_rr_nodes_per_type(device_size, grids, device_chan_width, segment_infs);
/************************************************************************
* 3. Allocate the rr_nodes
***********************************************************************/
rr_graph.num_rr_nodes = 0;
for (size_t i = 0; i < num_rr_nodes_per_type.size(); ++i) {
rr_graph.num_rr_nodes += num_rr_nodes_per_type[i];
}
/* use calloc to initialize everything to be zero */
rr_graph.rr_node = (t_rr_node*)my_calloc(rr_graph.num_rr_nodes, sizeof(t_rr_node));
/************************************************************************
* 4. Initialize the basic information of rr_nodes:
* coordinators: xlow, ylow, xhigh, yhigh,
* features: capacity, track_ids, ptc_num, direction
* grid_info : pb_graph_pin
***********************************************************************/
/* Check the channel width */
int nodes_per_chan = chan_width;
assert(chan_width > 0);
t_seg_details *seg_details = NULL;
seg_details = alloc_and_load_seg_details(&nodes_per_chan,
std::max(L_nx, L_ny),
num_seg_types, segment_inf,
TRUE, FALSE, UNI_DIRECTIONAL);
/************************************************************************
* 3. Create the connectivity of OPINs
@ -140,7 +559,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
int **Fc_in = NULL; /* [0..num_types-1][0..num_pins-1] */
boolean Fc_clipped;
Fc_clipped = FALSE;
Fc_in = alloc_and_load_actual_fc(L_num_types, types, nodes_per_chan,
Fc_in = alloc_and_load_actual_fc(L_num_types, types, chan_width,
FALSE, UNI_DIRECTIONAL, &Fc_clipped, ignore_Fc_0);
if (Fc_clipped) {
*Warnings |= RR_GRAPH_WARN_FC_CLIPPED;
@ -153,7 +572,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
***********************************************************************/
int **Fc_out = NULL; /* [0..num_types-1][0..num_pins-1] */
Fc_clipped = FALSE;
Fc_out = alloc_and_load_actual_fc(L_num_types, types, nodes_per_chan,
Fc_out = alloc_and_load_actual_fc(L_num_types, types, chan_width,
TRUE, UNI_DIRECTIONAL, &Fc_clipped, ignore_Fc_0);
/************************************************************************
@ -164,6 +583,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
* c. handle direct-connections
***********************************************************************/
/* Alloc node lookups, count nodes, alloc rr nodes */
/*
rr_graph.num_rr_nodes = 0;
rr_graph.rr_node_indices = alloc_and_load_rr_node_indices(nodes_per_chan, L_nx, L_ny,
&(rr_graph.num_rr_nodes), seg_details);
@ -171,6 +591,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
memset(rr_node, 0, sizeof(t_rr_node) * rr_graph.num_rr_nodes);
boolean* L_rr_edge_done = (boolean *) my_malloc(sizeof(boolean) * rr_graph.num_rr_nodes);
memset(L_rr_edge_done, 0, sizeof(boolean) * rr_graph.num_rr_nodes);
*/
/* handle direct-connections */
t_clb_to_clb_directs* clb_to_clb_directs = NULL;
@ -183,7 +604,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
* a. cost_index
* b. RC tree
***********************************************************************/
rr_graph_externals(timing_inf, segment_inf, num_seg_types, nodes_per_chan,
rr_graph_externals(timing_inf, segment_inf, num_seg_types, chan_width,
wire_to_ipin_switch, base_cost_type);
return rr_graph;

View File

@ -403,7 +403,7 @@ void alloc_and_load_rr_graph_route_structs(t_rr_graph* local_rr_graph) {
int inode;
local_rr_graph->rr_node_route_inf = (t_rr_node_route_inf *) my_malloc(local_rr_graph->num_rr_nodes * sizeof(t_rr_node_route_inf));
local_rr_graph->rr_node_route_inf = (t_rr_node_route_inf *) my_calloc(local_rr_graph->num_rr_nodes, sizeof(t_rr_node_route_inf));
for (inode = 0; inode < local_rr_graph->num_rr_nodes; inode++) {
local_rr_graph->rr_node_route_inf[inode].prev_node = NO_PREVIOUS;

View File

@ -1,5 +1,5 @@
#include <cassert>
#include <string>
#include <string.h>
#include <algorithm>
#include <sstream>
@ -1345,55 +1345,71 @@ const char* RRGSB::gen_cb_verilog_routing_track_name(t_rr_type cb_type,
std::string y_str = std::to_string(get_cb_y(cb_type));
std::string track_id_str = std::to_string(track_id);
std::ostringstream oss;
oss << cb_name << "_" << x_str << "__" << y_str << "__midout_" << track_id_str << "_";
std::string ret = oss.str();
return ret.c_str();
char* ret = (char*)my_malloc(sizeof(char)*
( cb_name.length() + 1
+ x_str.length() + 2
+ y_str.length() + 9
+ track_id_str.length() + 1
+ 1));
sprintf (ret, "%s_%s__%s__midout_%s_",
cb_name.c_str(), x_str.c_str(), y_str.c_str(), track_id_str.c_str());
return ret;
}
const char* RRGSB::gen_sb_verilog_module_name() const {
std::string x_str = std::to_string(get_sb_x());
std::string y_str = std::to_string(get_sb_y());
std::ostringstream oss;
oss << "sb_" << x_str << "__" << y_str << "_" ;
std::string ret = oss.str();
char* ret = (char*)my_malloc(sizeof(char)*
( 2 + 1
+ x_str.length() + 2
+ y_str.length() + 1
+ 1));
sprintf (ret, "sb_%s__%s_",
x_str.c_str(), y_str.c_str());
return ret.c_str();
return ret;
}
const char* RRGSB::gen_sb_verilog_instance_name() const {
char* ret = (char*)my_malloc(sizeof(char)*
( strlen(gen_sb_verilog_module_name()) + 3
+ 1));
sprintf (ret, "%s_0_",
gen_sb_verilog_module_name());
std::ostringstream oss;
oss << gen_sb_verilog_module_name() << "_0_" ;
std::string ret = oss.str();
return ret.c_str();
return ret;
}
/* Public Accessors Verilog writer */
const char* RRGSB::gen_sb_verilog_side_module_name(enum e_side side, size_t seg_id) const {
Side side_manager(side);
std::string prefix_str(gen_sb_verilog_module_name());
std::string seg_id_str(std::to_string(seg_id));
std::string side_str(side_manager.to_string());
std::ostringstream oss;
oss << gen_sb_verilog_module_name() << "_" << side_str << "_seg_" << "_" << seg_id_str << "_" ;
std::string ret = oss.str();
char* ret = (char*)my_malloc(sizeof(char)*
( prefix_str.length() + 1
+ side_str.length() + 5
+ seg_id_str.length() + 1
+ 1));
sprintf (ret, "%s_%s_seg_%s_",
prefix_str.c_str(), side_str.c_str(), seg_id_str.c_str());
return ret.c_str();
return ret;
}
const char* RRGSB::gen_sb_verilog_side_instance_name(enum e_side side, size_t seg_id) const {
std::string prefix_str = gen_sb_verilog_side_module_name(side, seg_id);
char* ret = (char*)my_malloc(sizeof(char)*
( prefix_str.length() + 3
+ 1));
sprintf (ret, "%s_0_",
prefix_str.c_str());
std::ostringstream oss;
oss << gen_sb_verilog_side_module_name(side, seg_id) << "_0_" ;
std::string ret = oss.str();
return ret.c_str();
return ret;
}
/* Public Accessors Verilog writer */
@ -1405,23 +1421,29 @@ const char* RRGSB::gen_cb_verilog_module_name(t_rr_type cb_type) const {
std::string x_str = std::to_string(get_cb_x(cb_type));
std::string y_str = std::to_string(get_cb_y(cb_type));
std::ostringstream oss;
oss << prefix_str << "_" << x_str << "__" << y_str << "_" ;
std::string ret = oss.str();
char* ret = (char*)my_malloc(sizeof(char)*
( prefix_str.length() + 1
+ x_str.length() + 2
+ y_str.length() + 1
+ 1));
sprintf (ret, "%s_%s__%s_",
prefix_str.c_str(), x_str.c_str(), y_str.c_str());
return ret.c_str();
return ret;
}
const char* RRGSB::gen_cb_verilog_instance_name(t_rr_type cb_type) const {
/* check */
assert (validate_cb_type(cb_type));
std::ostringstream oss;
oss << gen_cb_verilog_module_name(cb_type) << "_0_" ;
std::string ret = oss.str();
return ret.c_str();
std::string prefix_str = gen_cb_verilog_module_name(cb_type);
char* ret = (char*)my_malloc(sizeof(char)*
(prefix_str.length() + 3
+ 1));
sprintf (ret, "%s_0_",
prefix_str.c_str());
return ret;
}
/* Public mutators */

View File

@ -1,3 +1,38 @@
/**********************************************************
* MIT License
*
* Copyright (c) 2018 LNIS - The University of Utah
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***********************************************************************/
/************************************************************************
* Filename: rr_blocks.h
* Created by: Xifan Tang
* Change history:
* +-------------------------------------+
* | Date | Author | Notes
* +-------------------------------------+
* | 2019/06/12 | Xifan Tang | Created
* +-------------------------------------+
***********************************************************************/
/* IMPORTANT:
* The following preprocessing flags are added to
* avoid compilation error when this headers are included in more than 1 times

View File

@ -10,10 +10,8 @@ char* convert_cb_type_to_string(t_rr_type chan_type) {
switch(chan_type) {
case CHANX:
return "cbx";
break;
case CHANY:
return "cby";
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Invalid type of channel!\n",
@ -26,10 +24,8 @@ char* convert_chan_type_to_string(t_rr_type chan_type) {
switch(chan_type) {
case CHANX:
return "chanx";
break;
case CHANY:
return "chany";
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Invalid type of channel!\n",
@ -42,10 +38,8 @@ char* convert_chan_rr_node_direction_to_string(enum PORTS chan_rr_node_direction
switch(chan_rr_node_direction) {
case IN_PORT:
return "in";
break;
case OUT_PORT:
return "out";
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid type of port!\n", __FILE__, __LINE__);
exit(1);

View File

@ -33,6 +33,8 @@
#include "fpga_x2p_pbtypes_utils.h"
#include "fpga_x2p_globals.h"
#include "fpga_x2p_pb_rr_graph.h"
/* Count the number of rr_graph nodes that should be allocated
* (a) INPUT pins at the top-level pb_graph_node should be a local_rr_node and plus a SOURCE
* (b) CLOCK pins at the top-level pb_graph_node should be a local_rr_node and plus a SOURCE
@ -104,6 +106,7 @@ void init_one_rr_node_pack_cost_for_phy_graph_node(INP t_pb_graph_pin* cur_pb_gr
/* Override the fan-in and fan-out for a top/primitive pb_graph_node */
static
void override_one_rr_node_for_top_primitive_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_pin,
INOUTP t_rr_graph* local_rr_graph,
int cur_rr_node_index,
@ -151,6 +154,7 @@ void override_one_rr_node_for_top_primitive_phy_pb_graph_node(INP t_pb_graph_pin
}
/* initialize a rr_node in a rr_graph of phyical pb_graph_node */
static
void init_one_rr_node_for_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_pin,
INOUTP t_rr_graph* local_rr_graph,
int cur_rr_node_index,
@ -206,7 +210,9 @@ void init_one_rr_node_for_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_pin
local_rr_graph->rr_node[cur_rr_node_index].prev_edge = OPEN;
local_rr_graph->rr_node[cur_rr_node_index].capacity = 1;
local_rr_graph->rr_node[cur_rr_node_index].occ = 0;
local_rr_graph->rr_node[cur_rr_node_index].type = rr_node_type;
local_rr_graph->rr_node[cur_rr_node_index].cost_index = 0;
return;
}
@ -270,6 +276,7 @@ void connect_one_rr_node_for_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_
/* Recursively configure all the rr_nodes in the rr_graph
* Initialize the routing cost, fan-in rr_nodes and fan-out rr_nodes, and switches
*/
static
void rec_init_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* cur_pb_graph_node,
INOUTP t_rr_graph* local_rr_graph,
int* cur_rr_node_index) {
@ -418,6 +425,7 @@ void rec_init_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* cur_pb_graph_n
/* Recursively connect all the rr_nodes in the rr_graph
* output_edges, output_switches
*/
static
void rec_connect_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* cur_pb_graph_node,
INOUTP t_rr_graph* local_rr_graph,
int* cur_rr_node_index) {
@ -598,6 +606,7 @@ void alloc_and_load_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* top_pb_g
/* Check the vpack_net_num of a rr_node mapped to a pb_graph_pin and
* mark the used vpack_net_num in the list
*/
static
void mark_vpack_net_used_in_pb_pin(t_pb* cur_op_pb, t_pb_graph_pin* cur_pb_graph_pin,
int L_num_vpack_nets, boolean* vpack_net_used_in_pb) {
int inode;
@ -621,6 +630,7 @@ void mark_vpack_net_used_in_pb_pin(t_pb* cur_op_pb, t_pb_graph_pin* cur_pb_graph
/* Recursively visit all the child pbs and
* mark the used vpack_net_num in the list
*/
static
void mark_vpack_net_used_in_pb(t_pb* cur_op_pb,
int L_num_vpack_nets, boolean* vpack_net_used_in_pb) {
int mode_index, ipb, jpb;
@ -718,6 +728,7 @@ void alloc_and_load_phy_pb_rr_graph_nets(INP t_pb* cur_op_pb,
}
/* Find the rr_node in the primitive node of a pb_rr_graph*/
static
void sync_pb_graph_pin_vpack_net_num_to_phy_pb(t_rr_node* cur_op_pb_rr_graph,
t_pb_graph_pin* cur_pb_graph_pin,
t_rr_graph* local_rr_graph) {
@ -787,6 +798,7 @@ void sync_pb_graph_pin_vpack_net_num_to_phy_pb(t_rr_node* cur_op_pb_rr_graph,
return;
}
static
void rec_sync_wired_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb_graph_node* cur_pb_graph_node,
t_rr_node* op_pb_rr_graph,
t_rr_graph* local_rr_graph) {
@ -851,6 +863,7 @@ void rec_sync_wired_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb_graph_node* cur_pb_
* synchronize the vpack_net_num of the top-level/primitive pb_graph_pin
* to the physical pb rr_node nodes
*/
static
void rec_sync_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb* cur_op_pb,
t_rr_graph* local_rr_graph) {
int mode_index, ipb, jpb;
@ -921,6 +934,7 @@ void rec_sync_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb* cur_op_pb,
* 3. Find the SOURCE and SINK rr_nodes related to the pb_graph_pin
* 4. Configure the net_rr_terminals with the SINK/SOURCE rr_nodes
*/
static
void alloc_and_load_phy_pb_rr_graph_net_rr_terminals(INP t_pb* cur_op_pb,
t_rr_graph* local_rr_graph) {
int inet, inode, rr_node_net_name;
@ -1013,10 +1027,11 @@ void alloc_and_load_phy_pb_rr_graph_net_rr_terminals(INP t_pb* cur_op_pb,
return;
}
static
void alloc_pb_rr_graph_rr_indexed_data(t_rr_graph* local_rr_graph) {
/* inside a cluster, I do not consider rr_indexed_data cost, set to 1 since other costs are multiplied by it */
alloc_rr_graph_rr_indexed_data(local_rr_graph, 1);
local_rr_graph->rr_indexed_data[0].base_cost = 1;
local_rr_graph->rr_indexed_data[0].base_cost = 1.;
return;
}
@ -1025,8 +1040,8 @@ void alloc_pb_rr_graph_rr_indexed_data(t_rr_graph* local_rr_graph) {
* Add an output edge to the rr_node of the used input
* connect it to the rr_node of the used LUT output
*/
static
void add_rr_node_edge_to_one_wired_lut(t_pb_graph_node* cur_pb_graph_node,
t_pb_type* cur_pb_type,
t_rr_node* op_pb_rr_graph,
t_rr_graph* local_rr_graph) {
int iport, ipin;
@ -1140,6 +1155,7 @@ void add_rr_node_edge_to_one_wired_lut(t_pb_graph_node* cur_pb_graph_node,
/* Add rr edges connecting from an input of a LUT to its output
* IMPORTANT: this is only applied to LUT which operates in wire mode (a buffer)
*/
static
void rec_add_unused_rr_graph_wired_lut_rr_edges(INP t_pb_graph_node* cur_op_pb_graph_node,
INP t_rr_node* cur_op_pb_rr_graph,
INOUTP t_rr_graph* local_rr_graph) {
@ -1162,7 +1178,6 @@ void rec_add_unused_rr_graph_wired_lut_rr_edges(INP t_pb_graph_node* cur_op_pb_g
* connect it to the rr_node of the used LUT output
*/
add_rr_node_edge_to_one_wired_lut(cur_op_pb_graph_node,
cur_pb_type,
cur_op_pb_rr_graph,
local_rr_graph);
}
@ -1194,6 +1209,7 @@ void rec_add_unused_rr_graph_wired_lut_rr_edges(INP t_pb_graph_node* cur_op_pb_g
/* Add rr edges connecting from an input of a LUT to its output
* IMPORTANT: this is only applied to LUT which operates in wire mode (a buffer)
*/
static
void rec_add_rr_graph_wired_lut_rr_edges(INP t_pb* cur_op_pb,
INOUTP t_rr_graph* local_rr_graph) {
int mode_index, ipb, jpb, imode;
@ -1214,7 +1230,6 @@ void rec_add_rr_graph_wired_lut_rr_edges(INP t_pb* cur_op_pb,
* connect it to the rr_node of the used LUT output
*/
add_rr_node_edge_to_one_wired_lut(cur_op_pb->pb_graph_node,
cur_pb_type,
cur_op_pb->rr_graph,
local_rr_graph);
}
@ -1253,6 +1268,7 @@ void rec_add_rr_graph_wired_lut_rr_edges(INP t_pb* cur_op_pb,
* For each multiple-source net, I add a new source as the unique source in routing purpose
* As so, edges have to be added to the decendents of sources
*/
static
int add_virtual_sources_to_rr_graph_multi_sources(t_rr_graph* local_rr_graph) {
int inet, isrc;
int unique_src_node;
@ -1271,6 +1287,8 @@ int add_virtual_sources_to_rr_graph_multi_sources(t_rr_graph* local_rr_graph) {
unique_src_node = local_rr_graph->num_rr_nodes - 1;
local_rr_graph->rr_node[unique_src_node].type = SOURCE;
local_rr_graph->rr_node[unique_src_node].capacity = 1;
local_rr_graph->rr_node[unique_src_node].occ = 0;
local_rr_graph->rr_node[unique_src_node].cost_index = 0;
local_rr_graph->rr_node[unique_src_node].fan_in = 0;
local_rr_graph->rr_node[unique_src_node].num_drive_rr_nodes = 0;
local_rr_graph->rr_node[unique_src_node].drive_rr_nodes = NULL;
@ -1314,6 +1332,9 @@ void alloc_and_load_rr_graph_for_phy_pb(INP t_pb* cur_op_pb,
/* Allocate rr_graph*/
cur_phy_pb->rr_graph = (t_rr_graph*) my_calloc(1, sizeof(t_rr_graph));
/* Allocate and initialize cost index */
alloc_pb_rr_graph_rr_indexed_data(cur_phy_pb->rr_graph);
/* Create rr_graph */
alloc_and_load_rr_graph_for_phy_pb_graph_node(cur_phy_pb->pb_graph_node, cur_phy_pb->rr_graph);
@ -1332,8 +1353,6 @@ void alloc_and_load_rr_graph_for_phy_pb(INP t_pb* cur_op_pb,
/* Allocate trace in rr_graph */
alloc_rr_graph_route_static_structs(cur_phy_pb->rr_graph, nx * ny); /* TODO: nx * ny should be reduced for pb-only routing */
alloc_pb_rr_graph_rr_indexed_data(cur_phy_pb->rr_graph);
/* Fill the net_rr_terminals with
* 1. pin-to-pin mapping in pb_graph_node in cur_op_pb
* 2. rr_graph in the cur_op_pb

View File

@ -419,11 +419,10 @@ void dump_compact_verilog_one_physical_block(t_sram_orgz_info* cur_sram_orgz_inf
/* Local wires for memory configurations */
if (0 < temp_conf_bits_msb) {
dump_verilog_sram_config_bus_internal_wires(fp, cur_sram_orgz_info,
0, temp_conf_bits_msb - 1);
dump_verilog_sram_config_bus_internal_wires(fp, cur_sram_orgz_info,
0, temp_conf_bits_msb - 1);
}
/* Quote all the sub blocks*/
for (iz = 0; iz < phy_block_type->capacity; iz++) {
/* Local Vdd and Gnd, subckt name*/

View File

@ -464,16 +464,19 @@ void dump_verilog_membank_config_module(FILE* fp,
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, //---- Normal Bit lines \n",
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);\n");
fprintf(fp, " //---- Normal Word lines\n");
}
if (1 == num_blb_ports) {
fprintf(fp, " output wire [%d:%d] %s%s",
@ -482,13 +485,13 @@ void dump_verilog_membank_config_module(FILE* fp,
if (1 == num_wlb_ports) {
fprintf(fp, ", //---- Inverted Normal Bit lines \n");
} else {
fprintf(fp, " //---- Inverted Normal Bit lines \n);\n");
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");
}
fprintf(fp, ");\n");
break;
case SPICE_MODEL_DESIGN_RRAM:
/* Check: there should be reserved BLs and WLs */

View File

@ -350,6 +350,51 @@ void stats_mux_verilog_model_pb_node_rec(t_llist** muxes_head,
return;
}
/* Print a port of pb_types,
* SRAM ports are not printed here!!!
* Important feature: manage the comma between ports
* Make sure there is no redundant comma and there is no comma after the last element if specified
*/
static
void dump_verilog_pb_type_one_bus_port(FILE* fp,
t_pb_type* cur_pb_type,
char* port_prefix,
char* port_type_str,
t_port* pb_type_port,
boolean dump_port_type,
boolean dump_explicit_port_map) {
if (TRUE == dump_port_type) {
fprintf(fp, "%s ", port_type_str);
fprintf(fp, "[0:%d] %s__%s ",
pb_type_port->num_pins - 1,
port_prefix, pb_type_port->name);
} else {
if ((NULL != cur_pb_type->spice_model)
&& (TRUE == dump_explicit_port_map)
&& (TRUE == cur_pb_type->spice_model->dump_explicit_port_map)) {
fprintf(fp, ".%s(",
pb_type_port->spice_model_port->lib_name);
}
fprintf(fp, "{");
for (int ipin = 0; ipin < pb_type_port->num_pins; ++ipin) {
if (0 < ipin) {
fprintf(fp, ", ");
}
fprintf(fp, "%s",
gen_verilog_one_pb_type_pin_name(port_prefix, pb_type_port, ipin));
}
fprintf(fp, "}");
if ((NULL != cur_pb_type->spice_model)
&& (TRUE == dump_explicit_port_map)
&& (TRUE == cur_pb_type->spice_model->dump_explicit_port_map)) {
fprintf(fp, ")");
}
}
return;
}
/* Print ports of pb_types,
* SRAM ports are not printed here!!!
* Important feature: manage the comma between ports
@ -360,7 +405,8 @@ void dump_verilog_pb_type_bus_ports(FILE* fp,
int use_global_clock,
t_pb_type* cur_pb_type,
boolean dump_port_type,
boolean dump_last_comma) {
boolean dump_last_comma,
boolean dump_explicit_port_map) {
int iport;
int num_pb_type_input_port = 0;
t_port** pb_type_input_ports = NULL;
@ -398,16 +444,9 @@ void dump_verilog_pb_type_bus_ports(FILE* fp,
fprintf(fp, ", ");
}
}
if (TRUE == dump_port_type) {
fprintf(fp, "inout ");
fprintf(fp, "[0:%d] %s__%s ",
pb_type_inout_ports[iport]->num_pins - 1,
formatted_port_prefix, pb_type_inout_ports[iport]->name);
} else {
fprintf(fp, "%s__%s[0:%d] ",
formatted_port_prefix, pb_type_inout_ports[iport]->name,
pb_type_inout_ports[iport]->num_pins - 1);
}
dump_verilog_pb_type_one_bus_port(fp, cur_pb_type, formatted_port_prefix, "inout",
pb_type_inout_ports[iport], dump_port_type, dump_explicit_port_map);
/* Update the counter */
num_dumped_port++;
}
@ -424,16 +463,8 @@ void dump_verilog_pb_type_bus_ports(FILE* fp,
fprintf(fp, ", ");
}
}
if (TRUE == dump_port_type) {
fprintf(fp, "input ");
fprintf(fp, " [0:%d] %s__%s ",
pb_type_input_ports[iport]->num_pins - 1,
formatted_port_prefix, pb_type_input_ports[iport]->name);
} else {
fprintf(fp, " %s__%s[0:%d] ",
formatted_port_prefix, pb_type_input_ports[iport]->name,
pb_type_input_ports[iport]->num_pins - 1);
}
dump_verilog_pb_type_one_bus_port(fp, cur_pb_type, formatted_port_prefix, "input",
pb_type_input_ports[iport], dump_port_type, dump_explicit_port_map);
/* Update the counter */
num_dumped_port++;
}
@ -450,44 +481,30 @@ void dump_verilog_pb_type_bus_ports(FILE* fp,
fprintf(fp, ", ");
}
}
if (TRUE == dump_port_type) {
fprintf(fp, "output ");
fprintf(fp, " %s__%s[0:%d]",
formatted_port_prefix, pb_type_output_ports[iport]->name,
pb_type_output_ports[iport]->num_pins - 1);
} else {
fprintf(fp, " %s__%s[0:%d]",
formatted_port_prefix, pb_type_output_ports[iport]->name,
pb_type_output_ports[iport]->num_pins - 1);
}
dump_verilog_pb_type_one_bus_port(fp, cur_pb_type, formatted_port_prefix, "output",
pb_type_output_ports[iport], dump_port_type, dump_explicit_port_map);
/* Update the counter */
num_dumped_port++;
}
/* Clocks */
/* Find pb_type clock ports */
pb_type_clk_ports = find_pb_type_ports_match_spice_model_port_type(cur_pb_type, SPICE_MODEL_PORT_CLOCK, &num_pb_type_clk_port);
/* Print all the clk ports */
for (iport = 0; iport < num_pb_type_clk_port; iport++) {
if (0 < num_dumped_port) {
if (TRUE == dump_port_type) {
fprintf(fp, ",\n");
} else {
fprintf(fp, ", ");
if (0 == use_global_clock) {
pb_type_clk_ports = find_pb_type_ports_match_spice_model_port_type(cur_pb_type, SPICE_MODEL_PORT_CLOCK, &num_pb_type_clk_port);
/* Print all the clk ports */
for (iport = 0; iport < num_pb_type_clk_port; iport++) {
if (0 < num_dumped_port) {
if (TRUE == dump_port_type) {
fprintf(fp, ",\n");
} else {
fprintf(fp, ", ");
}
}
dump_verilog_pb_type_one_bus_port(fp, cur_pb_type, formatted_port_prefix, "input",
pb_type_clk_ports[iport], dump_port_type, dump_explicit_port_map);
/* Update the counter */
num_dumped_port++;
}
if (TRUE == dump_port_type) {
fprintf(fp, "input");
fprintf(fp, " %s__%s[0:%d]",
formatted_port_prefix, pb_type_clk_ports[iport]->name,
pb_type_output_ports[iport]->num_pins - 1);
} else {
fprintf(fp, " %s__%s[0:%d]",
formatted_port_prefix, pb_type_clk_ports[iport]->name,
pb_type_output_ports[iport]->num_pins - 1);
}
/* Update the counter */
num_dumped_port++;
}
/* Dump the last comma, when the option is enabled and there is something dumped */

View File

@ -23,7 +23,8 @@ void dump_verilog_pb_type_bus_ports(FILE* fp,
int use_global_clock,
t_pb_type* cur_pb_type,
boolean dump_port_type,
boolean dump_last_comma);
boolean dump_last_comma,
boolean dump_explicit_port_map);
void dump_verilog_pb_type_ports(FILE* fp,
char* port_prefix,

View File

@ -235,7 +235,7 @@ void dump_verilog_pb_generic_primitive(t_sram_orgz_info* cur_sram_orgz_info,
/* assert */
num_sram = count_num_sram_bits_one_spice_model(verilog_model, -1);
/* print ports --> input ports */
dump_verilog_pb_type_ports(fp, port_prefix, 0, prim_pb_type, FALSE, FALSE, TRUE);
dump_verilog_pb_type_bus_ports(fp, port_prefix, 1, prim_pb_type, FALSE, FALSE, verilog_model->dump_explicit_port_map);
/* IOPADs requires a specical port to output */
if (SPICE_MODEL_IOPAD == verilog_model->type) {
@ -573,32 +573,6 @@ void dump_verilog_pb_primitive_lut(t_sram_orgz_info* cur_sram_orgz_info,
fprintf(fp, ");\n");
/* Definition ends*/
/* Specify inputs are wires */
pb_type_input_ports = find_pb_type_ports_match_spice_model_port_type(cur_pb_type, SPICE_MODEL_PORT_INPUT, &num_pb_type_input_port);
assert(1 == num_pb_type_input_port);
fprintf(fp, "wire [0:%d] %s__%s;\n",
input_ports[0]->size - 1, port_prefix, pb_type_input_ports[0]->name);
for (i = 0; i < input_ports[0]->size; i++) {
fprintf(fp, "assign %s__%s[%d] = %s__%s_%d_;\n",
port_prefix, pb_type_input_ports[0]->name, i,
port_prefix, pb_type_input_ports[0]->name, i);
}
/* Specify outputs are wires */
pb_type_output_ports = find_pb_type_ports_match_spice_model_port_type(cur_pb_type, SPICE_MODEL_PORT_OUTPUT, &num_pb_type_output_port);
for (i = 0; i < num_pb_type_output_port; i++) {
fprintf(fp, "wire [0:%d] %s__%s;\n",
output_ports[i]->size - 1, port_prefix, pb_type_output_ports[i]->name);
}
/* Make sure we have the same number outputs */
assert (num_pb_type_output_port == num_output_port);
for (i = 0; i < num_output_port; i++) {
for (ipin = 0; ipin < output_ports[i]->size; ipin++) {
fprintf(fp, "assign %s__%s_%d_ = %s__%s[%d];\n",
port_prefix, pb_type_output_ports[i]->name, ipin,
port_prefix, pb_type_output_ports[i]->name, ipin);
}
}
/* 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);
@ -640,7 +614,7 @@ void dump_verilog_pb_primitive_lut(t_sram_orgz_info* cur_sram_orgz_info,
/* Connect inputs*/
/* Connect outputs*/
fprintf(fp, "//----- Input and output ports -----\n");
dump_verilog_pb_type_bus_ports(fp, port_prefix, 0, cur_pb_type, FALSE, TRUE);
dump_verilog_pb_type_bus_ports(fp, port_prefix, 1, cur_pb_type, FALSE, TRUE, verilog_model->dump_explicit_port_map);
fprintf(fp, "\n//----- SRAM ports -----\n");
/* check */

View File

@ -3029,7 +3029,7 @@ void dump_verilog_connection_box_mux(t_sram_orgz_info* cur_sram_orgz_info,
verilog_model->prefix, mux_size, verilog_model->cnt, input_cnt);
int drive_node_index = rr_gsb.get_cb_chan_node_index(cb_type, drive_rr_nodes[inode]);
assert (-1 != drive_node_index);
fprintf(fp, "%s;", rr_gsb.gen_cb_verilog_routing_track_name(cb_type, drive_node_index));
fprintf(fp, "%s;\n", rr_gsb.gen_cb_verilog_routing_track_name(cb_type, drive_node_index));
input_cnt++;
}
assert(input_cnt == mux_size);
@ -4076,13 +4076,9 @@ void dump_verilog_routing_resources(t_sram_orgz_info* cur_sram_orgz_info,
DeviceCoordinator cb_range = device_rr_gsb.get_gsb_range();
/* X - channels [1...nx][0..ny]*/
for (int iy = 0; iy < (ny + 1); iy++) {
for (int ix = 1; ix < (nx + 1); ix++) {
for (size_t icb = 0; icb < device_rr_gsb.get_num_cb_unique_module(CHANX); ++icb) {
const RRGSB& unique_mirror = device_rr_gsb.get_cb_unique_module(CHANX, icb);
dump_verilog_routing_connection_box_unique_module(cur_sram_orgz_info, verilog_dir, subckt_dir, unique_mirror, CHANX);
}
}
for (size_t icb = 0; icb < device_rr_gsb.get_num_cb_unique_module(CHANX); ++icb) {
const RRGSB& unique_mirror = device_rr_gsb.get_cb_unique_module(CHANX, icb);
dump_verilog_routing_connection_box_unique_module(cur_sram_orgz_info, verilog_dir, subckt_dir, unique_mirror, CHANX);
}
/* TODO: when we follow a tile organization,
* updating the conf bits should follow a tile organization: CLB, SB and CBX, CBY */
@ -4094,13 +4090,9 @@ void dump_verilog_routing_resources(t_sram_orgz_info* cur_sram_orgz_info,
}
/* Y - channels [1...ny][0..nx]*/
for (int ix = 0; ix < (nx + 1); ix++) {
for (int iy = 1; iy < (ny + 1); iy++) {
for (size_t icb = 0; icb < device_rr_gsb.get_num_cb_unique_module(CHANY); ++icb) {
const RRGSB& unique_mirror = device_rr_gsb.get_cb_unique_module(CHANY, icb);
dump_verilog_routing_connection_box_unique_module(cur_sram_orgz_info, verilog_dir, subckt_dir, unique_mirror, CHANY);
}
}
for (size_t icb = 0; icb < device_rr_gsb.get_num_cb_unique_module(CHANY); ++icb) {
const RRGSB& unique_mirror = device_rr_gsb.get_cb_unique_module(CHANY, icb);
dump_verilog_routing_connection_box_unique_module(cur_sram_orgz_info, verilog_dir, subckt_dir, unique_mirror, CHANY);
}
for (size_t ix = 0; ix < cb_range.get_x(); ++ix) {

View File

@ -1439,10 +1439,24 @@ void dump_verilog_formal_verification_sram_ports_wiring(FILE* fp,
t_sram_orgz_info* cur_sram_orgz_info,
int sram_lsb, int sram_msb) {
fprintf(fp, "assign ");
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
sram_lsb, sram_msb,
0, VERILOG_PORT_CONKT);
switch (cur_sram_orgz_info->type) {
case SPICE_SRAM_STANDALONE:
break;
case SPICE_SRAM_SCAN_CHAIN:
dump_verilog_sram_one_local_outport(fp, cur_sram_orgz_info,
sram_lsb, sram_msb,
0, VERILOG_PORT_CONKT);
break;
case SPICE_SRAM_MEMORY_BANK:
dump_verilog_sram_one_outport(fp, cur_sram_orgz_info,
sram_lsb, sram_msb,
0, VERILOG_PORT_CONKT);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid SRAM organization type!\n",
__FILE__, __LINE__);
exit(1);
}
fprintf(fp, " = ");

View File

@ -201,6 +201,7 @@ static void power_usage_primitive(t_power_usage * power_usage, t_pb * pb,
}
}
static
void power_usage_local_pin_toggle(t_power_usage * power_usage, t_pb * pb,
t_pb_graph_pin * pin) {
float scale_factor;
@ -222,6 +223,7 @@ void power_usage_local_pin_toggle(t_power_usage * power_usage, t_pb * pb,
/ g_solution_inf.T_crit;
}
static
void power_usage_local_pin_buffer_and_wire(t_power_usage * power_usage,
t_pb * pb, t_pb_graph_pin * pin) {
t_power_usage sub_power_usage;
@ -1027,6 +1029,7 @@ static void power_usage_routing(t_power_usage * power_usage,
}
}
static
void power_alloc_and_init_pb_pin(t_pb_graph_pin * pin) {
int port_idx;
t_port * port_to_find;
@ -1085,6 +1088,7 @@ void power_alloc_and_init_pb_pin(t_pb_graph_pin * pin) {
}
}
static
void power_init_pb_pins_rec(t_pb_graph_node * pb_node) {
int mode;
int type;
@ -1131,6 +1135,7 @@ void power_init_pb_pins_rec(t_pb_graph_node * pb_node) {
}
}
static
void power_pb_pins_init() {
int type_idx;
@ -1141,6 +1146,7 @@ void power_pb_pins_init() {
}
}
static
void power_routing_init(t_det_routing_arch * routing_arch) {
int net_idx;
int rr_node_idx;
@ -1367,7 +1373,7 @@ boolean power_uninit(void) {
}
delete mux_info;
}
free(g_power_commonly_used);
delete g_power_commonly_used;
if (g_power_output->out) {
fclose(g_power_output->out);

View File

@ -5,7 +5,7 @@
// Coder : Xifan TANG
//-----------------------------------------------------
//------ Include defines: preproc flags -----
`include "OPENFPGAPATHKEYWORD/vpr7_x2p/vpr/test_modes_Verilog/SRC/fpga_defines.v"
`include "GENERATED_DIR_KEYWORD/SRC/fpga_defines.v"
module static_dff (
/* Global ports go first */
input set, // set input

View File

@ -16,21 +16,25 @@ act_file="${OpenFPGA_path}/fpga_flow/benchmarks/Blif/Test_Modes/$benchmark.act "
verilog_reference="${OpenFPGA_path}/fpga_flow/benchmarks/Verilog/Test_Modes/$benchmark.v"
vpr_route_chan_width="200"
fpga_flow_script="${OpenFPGA_path}/fpga_flow/scripts"
ff_path="$vpr_path/VerilogNetlists/ff.v"
new_ff_path="$verilog_output_dirpath/$verilog_output_dirname/SRC/ff.v"
ff_keyword="GENERATED_DIR_KEYWORD"
ff_include_path="$verilog_output_dirpath/$verilog_output_dirname"
arch_ff_keyword="FFPATHKEYWORD"
# Step A: Make sure a clean start
# Recompile if needed
#make clean
#make -j32
# Remove previous designs
rm -rf $verilog_output_dirpath/$verilog_output_dirname
mkdir ${OpenFPGA_path}/fpga_flow/arch/generated
cd $fpga_flow_scripts
perl arch_rewrite.pl -i $template_arch_xml_file -o $arch_xml_file
perl rewrite_path_in_file.pl -i $template_arch_xml_file -o $arch_xml_file
perl rewrite_path_in_file.pl -i $arch_xml_file -k $arch_ff_keyword $new_ff_path
cd -
# Run VPR
#valgrind
./vpr $arch_xml_file $blif_file --full_stats --nodisp --activity_file $act_file --fpga_verilog --fpga_verilog_dir $verilog_output_dirpath/$verilog_output_dirname --fpga_x2p_rename_illegal_port --fpga_bitstream_generator --fpga_verilog_print_top_testbench --fpga_verilog_print_input_blif_testbench --fpga_verilog_include_timing --fpga_verilog_include_signal_init --fpga_verilog_print_formal_verification_top_netlist --fpga_verilog_print_autocheck_top_testbench $verilog_reference --fpga_verilog_print_user_defined_template --route_chan_width $vpr_route_chan_width --fpga_verilog_include_icarus_simulator --fpga_verilog_print_report_timing_tcl --power --tech_properties $tech_file --fpga_verilog_print_sdc_pnr --fpga_verilog_print_sdc_analysis --fpga_x2p_compact_routing_hierarchy
cd $fpga_flow_scripts
perl rewrite_path_in_file.pl -i $ff_path -o $new_ff_path -k $ff_keyword $ff_include_path
cd -