Skip to content

vpr: interchange: add interchange netlist reading support #1924

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/kokoro/continuous/strong_sanitized.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

build_file: "vtr-verilog-to-routing/.github/kokoro/run-vtr.sh"

# 2 hour
timeout_mins: 120
# 4 hour
timeout_mins: 240

action {
define_artifacts {
Expand Down
4 changes: 2 additions & 2 deletions .github/kokoro/presubmit/strong_sanitized.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

build_file: "vtr-verilog-to-routing/.github/kokoro/run-vtr.sh"

# 2 hour
timeout_mins: 120
# 4 hour
timeout_mins: 240

action {
define_artifacts {
Expand Down
28 changes: 17 additions & 11 deletions .github/kokoro/steps/hostsetup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ echo "Host adding PPAs"
echo "----------------------------------------"
wget --no-check-certificate -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add -
sudo apt-add-repository 'deb https://apt.kitware.com/ubuntu/ xenial main'
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
echo "----------------------------------------"

echo
Expand All @@ -55,48 +56,53 @@ sudo apt-get install -y \
bison \
build-essential \
ca-certificates \
clang \
cmake \
colordiff \
coreutils \
curl \
flex \
gawk \
gcc-9 \
g++-9 \
git \
graphviz \
inkscape \
jq \
libboost-filesystem-dev \
libboost-python-dev \
libboost-system-dev \
libffi-dev \
libgtk-3-dev \
libreadline-dev \
libx11-dev \
make \
ninja-build \
nodejs \
pkg-config \
psmisc \
python \
python3 \
python3-dev \
python3-virtualenv \
python3-yaml \
qt5-default \
virtualenv \
clang \
libreadline-dev \
gawk \
tcl-dev \
libffi-dev \
virtualenv \
xdot \
pkg-config \
libboost-system-dev \
libboost-python-dev \
libboost-filesystem-dev \
zlib1g-dev \
zlib1g-dev
#Don't include libtbb-dev since it may increase memory usage
#libtbb-dev \

export PATH="$PATH:/home/kbuilder/.local/bin"

export CC=gcc-9
export CXX=g++-9

pyenv install -f 3.6.3
pyenv global 3.6.3
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python3 get-pip.py
python3 get-pip.py
rm get-pip.py
python3 -m pip install -r requirements.txt

Expand Down
33 changes: 33 additions & 0 deletions libs/libarchfpga/src/physical_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1732,6 +1732,12 @@ struct t_clock_arch_spec {
std::vector<t_clock_connection_arch> clock_connections_arch;
};

struct t_lut_cell {
std::string name;
std::string init_param;
std::vector<std::string> inputs;
};

/* Detailed routing architecture */
struct t_arch {
mutable vtr::string_internment strings;
Expand All @@ -1750,11 +1756,38 @@ struct t_arch {
int num_switches;
t_direct_inf* Directs = nullptr;
int num_directs = 0;

t_model* models = nullptr;
t_model* model_library = nullptr;

t_power_arch* power = nullptr;
t_clock_arch* clocks = nullptr;

// Constants
// VCC and GND cells are special virtual cells that are
// used to handle the constant network of the device.
//
// Similarly, the constant nets are defined to identify
// the generic name for the constant network.
//
// Given that usually, the constants have a dedicated network in
// real FPGAs, this information becomes relevant to identify which
// nets from the circuit netlist are belonging to the constant network,
// and assigned to it accordingly.
//
// NOTE: At the moment, the constant cells and nets are primarly used
// for the interchange netlist format, to determine which are the constants
// net names and which virtual cell is responsible to generate them.
// The information is present in the device database.
std::string gnd_cell;
std::string vcc_cell;

std::string gnd_net = "$__gnd_net";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When reading the vpr/src/base/read_interchange_netlist.cpp, I notice that the net names are used to identify GND and VCC signals in interchangeable files.
So the question is should we put it in the architecture data structure?

  • If this is universal for all the FPGA architectures and netlists, it is reasonable.
  • If not, should we consider put the constant strings gnd_net and vcc_net in the vpr/src/base/read_interchange_netlist.cpp?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, in general, the name of the GND and VCC nets do come from the interchange device description, but they might be absent from the schema, as they are optional. For instance, the Xilinx device have the constant nets specified as GLOBAL_LOGIC_0 and GLOBAL_LOGIC_1.

Given that these net names are variable from arch to arch, they need to be parased from the device file, and this would need to happen in the libarchfpga library.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense. Would you mind giving more insights about what client functions require these data?
Currently I see it is used by netlist readers. I am sure it will be used by netlist writers.
When adding the information to the architecture database, we expect they may be used by packer, placer, router as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, for now I only expect the constant nets to be used in the front-end and back-end only, but it is not excluded that they might come in handy in core algorithms, especially in the packer.

The main reason it is added to the architecture database is because of accessibility of the information stored in the interchange device database and needs to be read in the netlist reader.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Maybe it is better to add additional comments to the source file, so that developers know what these variables are.
It is important to clarify

  • if the vcc_cell and gnd_cell physically exist in an FPGA fabric/architecture or that they are just virtual. I understand that in commerical FPGAs, there are dedicated circuitry to generate these constant signals.
  • if the vcc_net and gnd_net are the required net names for input netlists (.blif, .eblif etc.) to represent vcc and gnd signal. And just briefly explain why they should be in the architecture database and their relationship with the vcc_cell and gnd_cell

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All right, I have added some extra comments around that, hopefully those help clarify a bit more on this.

std::string vcc_net = "$__vcc_net";

// Luts
std::vector<t_lut_cell> lut_cells;

//The name of the switch used for the input connection block (i.e. to
//connect routing tracks to block pins).
//This should correspond to a switch in Switches
Expand Down
28 changes: 28 additions & 0 deletions libs/libarchfpga/src/read_fpga_interchange_arch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ struct ArchReader {
}

void read_arch() {
process_luts();
process_models();
process_device();

Expand Down Expand Up @@ -232,6 +233,14 @@ struct ArchReader {
"Model output ports can not have combinational sink ports");
}

model_port->min_size = 1;
model_port->size = 1;
if (port.isBus()) {
int s = port.getBus().getBusStart();
int e = port.getBus().getBusEnd();
model_port->size = std::abs(e - s) + 1;
}

port_names.insert(std::pair<std::string, enum PORTS>(model_port->name, dir));
//Add the port
if (dir == IN_PORT) {
Expand All @@ -245,6 +254,25 @@ struct ArchReader {
}
}

void process_luts() {
// Add LUT Cell definitions
// This is helpful to understand which cells are LUTs
auto lut_def = ar_.getLutDefinitions();

for (auto lut_cell : lut_def.getLutCells()) {
t_lut_cell cell;
cell.name = lut_cell.getCell().cStr();
for (auto input : lut_cell.getInputPins())
cell.inputs.push_back(input.cStr());

auto equation = lut_cell.getEquation();
if (equation.isInitParam())
cell.init_param = equation.getInitParam().cStr();

arch_->lut_cells.push_back(cell);
}
}

// Layout Processing
void process_layout() {
auto strList = ar_.getStrList();
Expand Down
10 changes: 10 additions & 0 deletions libs/libvtrutil/src/vtr_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ inline void hash_combine(std::size_t& seed, const T& v) {
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

struct hash_pair {
template<class T1, class T2>
std::size_t operator()(const std::pair<T1, T2>& pair) const noexcept {
auto hash1 = std::hash<T1>{}(pair.first);
auto hash2 = std::hash<T2>{}(pair.second);

return hash1 ^ hash2;
}
};

} // namespace vtr

#endif
7 changes: 5 additions & 2 deletions vpr/src/base/atom_netlist_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) {
AtomPinId pin = *netlist.block_pins(blk_id).begin();

std::string blk_name = netlist.block_name(blk_id);
std::string out_name(blk_name.begin() + 4, blk_name.end()); //+4 to trim out: prefix

std::string out_prefix("out:");
int strip_size = blk_name.substr(0, out_prefix.size()) == out_prefix ? out_prefix.size() : 0;
std::string out_name(blk_name.begin() + strip_size, blk_name.end()); //+4 to trim out: prefix if present

fprintf(f, "%s%s", INDENT, out_name.c_str());

Expand Down Expand Up @@ -307,7 +310,7 @@ void print_netlist_as_blif(FILE* f, const AtomNetlist& netlist) {
ports.push_back(port_id);
}

fprintf(f, ".subckt %s \\\n", blk_model->name);
fprintf(f, ".subckt %s \\\n", netlist.block_name(blk_id).c_str());
for (size_t i = 0; i < ports.size(); i++) {
auto width = netlist.port_width(ports[i]);
for (size_t j = 0; j < width; ++j) {
Expand Down
44 changes: 29 additions & 15 deletions vpr/src/base/read_circuit.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "read_circuit.h"
#include "read_blif.h"
#include "read_interchange_netlist.h"
#include "atom_netlist.h"
#include "atom_netlist_utils.h"
#include "echo_files.h"
Expand All @@ -21,20 +22,23 @@ static void process_circuit(AtomNetlist& netlist,

static void show_circuit_stats(const AtomNetlist& netlist);

AtomNetlist read_and_process_circuit(e_circuit_format circuit_format,
const char* circuit_file,
const t_model* user_models,
const t_model* library_models,
e_const_gen_inference const_gen_inference,
bool should_absorb_buffers,
bool should_sweep_dangling_primary_ios,
bool should_sweep_dangling_nets,
bool should_sweep_dangling_blocks,
bool should_sweep_constant_primary_outputs,
int verbosity) {
AtomNetlist read_and_process_circuit(e_circuit_format circuit_format, t_vpr_setup& vpr_setup, t_arch& arch) {
// Options
const char* circuit_file = vpr_setup.PackerOpts.circuit_file_name.c_str();
const t_model* user_models = vpr_setup.user_models;
const t_model* library_models = vpr_setup.library_models;
e_const_gen_inference const_gen_inference = vpr_setup.NetlistOpts.const_gen_inference;
bool should_absorb_buffers = vpr_setup.NetlistOpts.absorb_buffer_luts;
bool should_sweep_dangling_primary_ios = vpr_setup.NetlistOpts.sweep_dangling_primary_ios;
bool should_sweep_dangling_nets = vpr_setup.NetlistOpts.sweep_dangling_nets;
bool should_sweep_dangling_blocks = vpr_setup.NetlistOpts.sweep_dangling_blocks;
bool should_sweep_constant_primary_outputs = vpr_setup.NetlistOpts.sweep_constant_primary_outputs;
bool verbosity = vpr_setup.NetlistOpts.netlist_verbosity;

if (circuit_format == e_circuit_format::AUTO) {
auto name_ext = vtr::split_ext(circuit_file);

VTR_LOGV(verbosity, "Circuit file: %s\n", circuit_file);
if (name_ext[1] == ".blif") {
circuit_format = e_circuit_format::BLIF;
} else if (name_ext[1] == ".eblif") {
Expand All @@ -49,10 +53,20 @@ AtomNetlist read_and_process_circuit(e_circuit_format circuit_format,
{
vtr::ScopedStartFinishTimer t("Load circuit");

VTR_ASSERT(circuit_format == e_circuit_format::BLIF
|| circuit_format == e_circuit_format::EBLIF);

netlist = read_blif(circuit_format, circuit_file, user_models, library_models);
switch (circuit_format) {
case e_circuit_format::BLIF:
case e_circuit_format::EBLIF:
netlist = read_blif(circuit_format, circuit_file, user_models, library_models);
break;
case e_circuit_format::FPGA_INTERCHANGE:
netlist = read_interchange_netlist(circuit_file, arch);
break;
default:
VPR_FATAL_ERROR(VPR_ERROR_ATOM_NETLIST,
"Unable to identify circuit file format for '%s'. Expect [blif|eblif|fpga-interchange]!\n",
circuit_file);
break;
}
}

if (isEchoFileEnabled(E_ECHO_ATOM_NETLIST_ORIG)) {
Expand Down
19 changes: 5 additions & 14 deletions vpr/src/base/read_circuit.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,11 @@
#include "vpr_types.h"

enum class e_circuit_format {
AUTO, ///<Infer from file extension
BLIF, ///<Strict structural BLIF
EBLIF ///<Structural blif with extensions
AUTO, ///<Infer from file extension
BLIF, ///<Strict structural BLIF
EBLIF, ///<Structural blif with extensions
FPGA_INTERCHANGE ///<FPGA Interhange logical netlis format
};

AtomNetlist read_and_process_circuit(const e_circuit_format circuit_format,
const char* circuit_file,
const t_model* user_models,
const t_model* library_models,
e_const_gen_inference const_gen_inference,
bool should_absorb_buffers,
bool should_sweep_dangling_primary_ios,
bool should_sweep_dangling_nets,
bool should_sweep_dangling_blocks,
bool should_sweep_constant_primary_outputs,
int verbosity);
AtomNetlist read_and_process_circuit(e_circuit_format circuit_format, t_vpr_setup& vpr_setup, t_arch& arch);
#endif
Loading