nextpnr/gowin/gfx.cc
YRabbit 22e4081c73 gowin: Add GUI.
* Items such as LUT, DFF, MUX, ALU, IOB are displayed;
* Local wires, 1-2-4-8 wires are displayed;
* The clock spines, taps and branches are displayed with some caveats.

For now, you can not create a project in the GUI because of possible
conflict with another PR (about GW1NR-9C support), but you can specify
the board in the command line and load .JSON and .CST in the GUI.

Although ALUs are displayed, but the CIN and COUT wires are not. This is
still an unsolved problem.

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
2022-01-29 14:45:17 +10:00

933 lines
38 KiB
C++

/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include <boost/algorithm/string.hpp>
#include <iostream>
#include "gfx.h"
NEXTPNR_NAMESPACE_BEGIN
const int PIP_SRC_DST_LEN = 20;
static void get_pip_xy(CruSide side, float &off, float &x, float &y)
{
switch (side) {
case Top:
x = off;
y = cru_y + cru_h;
break;
case Bottom:
x = off;
y = cru_y;
break;
case Left:
x = cru_x;
y = off;
break;
case Right:
x = cru_x + cru_w;
y = off;
break;
case Center:
x = cru_x + cru_w / 2.f;
y = off;
break;
}
}
void gfxSetPipDefaultDecal(Arch *arch, PipInfo &pip)
{
DecalXY active, inactive;
std::vector<std::string> split_res;
IdString src_loc_id, dst_loc_id;
char buf[PIP_SRC_DST_LEN];
active.x = inactive.x = pip.loc.x;
active.y = inactive.y = arch->gridDimY - 1. - pip.loc.y;
boost::split(split_res, pip.name.str(arch), [](char c) { return c == '_'; });
src_loc_id = arch->id(split_res.at(1));
dst_loc_id = arch->id(split_res.at(2));
snprintf(buf, PIP_SRC_DST_LEN, "%s_%s_active", src_loc_id.c_str(arch), dst_loc_id.c_str(arch));
IdString active_id = arch->id(buf);
active.decal = active_id;
snprintf(buf, PIP_SRC_DST_LEN, "%s_%s_inactive", src_loc_id.c_str(arch), dst_loc_id.c_str(arch));
IdString inactive_id = arch->id(buf);
inactive.decal = inactive_id;
// create if absent
if (arch->decal_graphics.count(active_id) == 0) {
// clock?
if (dst_loc_id == id_GT00 || dst_loc_id == id_GT10) {
WireInfo &wi = arch->wire_info(pip.srcWire);
if (wi.type.str(arch).substr(0, 3) != "UNK") {
// create pip
GraphicElement el;
el.type = GraphicElement::TYPE_LOCAL_LINE;
el.style = GraphicElement::STYLE_ACTIVE;
if (dst_loc_id == id_GT00) {
el.x1 = WIRE_X(CLK_GT00_X);
} else {
el.x1 = WIRE_X(CLK_GT10_X);
}
el.x2 = el.x1 + spine_pip_off;
el.y2 = spineY.at(arch->wire_info(pip.srcWire).type);
el.y1 = el.y2 - spine_pip_off;
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(inactive_id, el);
}
} else {
// XXX
if (pipPoint.count(src_loc_id) == 0 || pipPoint.count(dst_loc_id) == 0) {
// std::cout << "*R" << pip.loc.y + 1 << "C" << pip.loc.x + 1 << " no " << pip.name.str(arch) << " " <<
// buf << std::endl;
} else {
GraphicElement el;
el.type = GraphicElement::TYPE_LOCAL_ARROW;
el.style = GraphicElement::STYLE_ACTIVE;
CruSide srcSide = pipPoint.at(src_loc_id).first;
float srcOff = pipPoint.at(src_loc_id).second;
CruSide dstSide = pipPoint.at(dst_loc_id).first;
float dstOff = pipPoint.at(dst_loc_id).second;
if (srcSide != dstSide) {
get_pip_xy(srcSide, srcOff, el.x1, el.y1);
get_pip_xy(dstSide, dstOff, el.x2, el.y2);
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_HIDDEN;
arch->addDecalGraphic(inactive_id, el);
} else {
get_pip_xy(srcSide, srcOff, el.x1, el.y1);
float dst_x = 0, dst_y = 0, m_x = 0, m_y = 0;
get_pip_xy(dstSide, dstOff, dst_x, dst_y);
switch (dstSide) {
case Top:
m_x = el.x1 + (dst_x - el.x1) / 2.f;
m_y = dst_y - std::max(cru_h * 0.1f, std::min(cru_h * 0.4f, std::abs(el.x1 - dst_x)));
break;
case Bottom:
m_x = el.x1 + (dst_x - el.x1) / 2.f;
m_y = dst_y + std::max(cru_h * 0.1f, std::min(cru_h * 0.4f, std::abs(el.x1 - dst_x)));
break;
case Right:
m_x = dst_x - std::max(cru_w * 0.1f, std::min(cru_w * 0.4f, std::abs(el.y1 - dst_y)));
m_y = el.y1 + (dst_y - el.y1) / 2.f;
break;
case Left:
m_x = dst_x + std::max(cru_w * 0.1f, std::min(cru_w * 0.4f, std::abs(el.y1 - dst_y)));
m_y = el.y1 + (dst_y - el.y1) / 2.f;
break;
default: // unreachable
break;
}
el.x2 = m_x;
el.y2 = m_y;
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_HIDDEN;
arch->addDecalGraphic(inactive_id, el);
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = m_x;
el.y1 = m_y;
el.x2 = dst_x;
el.y2 = dst_y;
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_HIDDEN;
arch->addDecalGraphic(inactive_id, el);
}
}
}
}
arch->setPipDecal(pip.name, active, inactive);
}
const int WIRE_ID_LEN = 30;
void gfxSetWireDefaultDecal(Arch *arch, WireInfo &wire)
{
DecalXY active, inactive;
IdString active_id, inactive_id;
GraphicElement el;
std::vector<std::string> split_res;
char buf[WIRE_ID_LEN];
if (std::find(decalless_wires.begin(), decalless_wires.end(), wire.name) != decalless_wires.end()) {
arch->setWireDecal(wire.type, DecalXY(), DecalXY());
return;
}
// local to cell
if (arch->haveBelType(wire.x, wire.y, id_SLICE) && sliceLocalWires.count(wire.type) != 0) {
snprintf(buf, sizeof(buf), "%s_active", wire.type.c_str(arch));
active_id = arch->id(buf);
active.decal = active_id;
snprintf(buf, sizeof(buf), "%s_inactive", wire.type.c_str(arch));
inactive_id = arch->id(buf);
inactive.decal = inactive_id;
active.x = inactive.x = wire.x;
active.y = inactive.y = arch->gridDimY - 1. - wire.y;
// create if absent
if (arch->decal_graphics.count(active_id) == 0) {
el.type = GraphicElement::TYPE_LOCAL_LINE;
for (auto seg : sliceLocalWires.at(wire.type)) {
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = std::get<0>(seg);
el.y1 = std::get<1>(seg);
el.x2 = std::get<2>(seg);
el.y2 = std::get<3>(seg);
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(inactive_id, el);
}
}
arch->setWireDecal(wire.name, active, inactive);
return;
}
// spines
if (spineY.count(wire.type) != 0) {
snprintf(buf, sizeof(buf), "%s_active", wire.type.c_str(arch));
active_id = arch->id(buf);
active.decal = active_id;
snprintf(buf, sizeof(buf), "%s_inactive", wire.type.c_str(arch));
inactive_id = arch->id(buf);
inactive.decal = inactive_id;
active.x = inactive.x = 0.;
active.y = inactive.y = 0.;
// update clock spines cache
arch->updateClockSpinesCache(wire.type, wire.name);
if (arch->decal_graphics.count(active_id) == 0) {
el.type = GraphicElement::TYPE_LINE;
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = 0.2; // cell's x will be added later in fixClockSpineDecals
el.x2 = 0.7; // cell's x will be added later in fixClockSpineDecals
el.y1 = spineY.at(wire.type) + arch->gridDimY - 1.; // cell's y will be added later in fixClockSpineDecals
el.y2 = el.y1;
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_HIDDEN;
arch->addDecalGraphic(inactive_id, el);
}
arch->setWireDecal(wire.name, active, inactive);
return;
}
// global simple wires like IMUX
if (globalSimpleWires.count(wire.type) != 0) {
snprintf(buf, sizeof(buf), "%s_active", wire.name.c_str(arch));
active_id = arch->id(buf);
active.decal = active_id;
snprintf(buf, sizeof(buf), "%s_inactive", wire.name.c_str(arch));
inactive_id = arch->id(buf);
inactive.decal = inactive_id;
active.x = inactive.x = 0;
active.y = inactive.y = 0;
// create if absent
if (arch->decal_graphics.count(active_id) == 0) {
el.type = GraphicElement::TYPE_LINE;
for (auto seg : globalSimpleWires.at(wire.type)) {
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = std::get<0>(seg) + wire.x;
el.y1 = std::get<1>(seg) + arch->gridDimY - 1. - wire.y;
el.x2 = std::get<2>(seg) + wire.x;
el.y2 = std::get<3>(seg) + arch->gridDimY - 1. - wire.y;
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(inactive_id, el);
}
}
arch->setWireDecal(wire.name, active, inactive);
return;
}
// global
boost::split(split_res, wire.name.str(arch), [](char c) { return c == '_'; });
if (split_res.size() >= 2) {
IdString wire_id = arch->id(split_res.at(1));
// wrap
if ((wire.y == (arch->gridDimY - 1) && split_res.at(1).at(0) == 'S') ||
(wire.y == 0 && split_res.at(1).at(0) == 'N')) {
wire_id = arch->id(split_res.at(1) + "_loop0");
}
if ((wire.x == (arch->gridDimX - 1) && split_res.at(1).at(0) == 'E') ||
(wire.x == 0 && split_res.at(1).at(0) == 'W')) {
wire_id = arch->id(split_res.at(1) + "_loop0");
}
// SN wires
if (split_res.at(1).substr(0, 2) == "SN") {
if (wire.y == 0) {
wire_id = arch->id(split_res.at(1) + "_loop_n");
} else {
if (wire.y == (arch->gridDimY - 1)) {
wire_id = arch->id(split_res.at(1) + "_loop_s");
}
}
} else {
// wrap 2 hop
if ((wire.y == (arch->gridDimY - 2) && split_res.at(1).substr(0, 2) == "S2") ||
(wire.y == 1 && split_res.at(1).substr(0, 2) == "N2")) {
wire_id = arch->id(split_res.at(1) + "_loop1");
}
// wrap 4 hop
if (split_res.at(1).substr(0, 2) == "S8" || split_res.at(1).substr(0, 2) == "N8") {
char loop_buf[5 + 2];
if (split_res.at(1).substr(0, 2) == "N8") {
if (wire.y < 8) {
snprintf(loop_buf, sizeof(loop_buf), "_loop%1u", wire.y);
wire_id = arch->id(split_res.at(1) + loop_buf);
}
} else {
if (arch->gridDimY - 1 - wire.y < 8) {
snprintf(loop_buf, sizeof(loop_buf), "_loop%1u", arch->gridDimY - 1 - wire.y);
wire_id = arch->id(split_res.at(1) + loop_buf);
}
}
}
}
// EW wires
if (split_res.at(1).substr(0, 2) == "EW") {
if (wire.x == 0) {
wire_id = arch->id(split_res.at(1) + "_loop_w");
} else {
if (wire.x == (arch->gridDimX - 1)) {
wire_id = arch->id(split_res.at(1) + "_loop_e");
}
}
} else {
// wrap 2 hop
if ((wire.x == (arch->gridDimX - 2) && split_res.at(1).substr(0, 2) == "E2") ||
(wire.x == 1 && split_res.at(1).substr(0, 2) == "W2")) {
wire_id = arch->id(split_res.at(1) + "_loop1");
}
// wrap 4 hop
if (split_res.at(1).substr(0, 2) == "E8" || split_res.at(1).substr(0, 2) == "W8") {
char loop_buf[5 + 2];
if (split_res.at(1).substr(0, 2) == "W8") {
if (wire.x < 8) {
snprintf(loop_buf, sizeof(loop_buf), "_loop%1u", wire.x);
wire_id = arch->id(split_res.at(1) + loop_buf);
}
} else {
if (arch->gridDimX - 1 - wire.x < 8) {
snprintf(loop_buf, sizeof(loop_buf), "_loop%1u", arch->gridDimX - 1 - wire.x);
wire_id = arch->id(split_res.at(1) + loop_buf);
}
}
}
}
// really create decal
if (globalWires.count(wire_id) != 0) {
snprintf(buf, sizeof(buf), "%s_active", wire.name.c_str(arch));
active_id = arch->id(buf);
active.decal = active_id;
snprintf(buf, sizeof(buf), "%s_inactive", wire.name.c_str(arch));
inactive_id = arch->id(buf);
inactive.decal = inactive_id;
active.x = inactive.x = 0;
active.y = inactive.y = 0;
// create if absent
if (arch->decal_graphics.count(active_id) == 0) {
el.type = GraphicElement::TYPE_LINE;
for (auto seg : globalWires.at(wire_id)) {
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = std::get<0>(seg) + wire.x;
el.y1 = std::get<1>(seg) + arch->gridDimY - 1. - wire.y;
el.x2 = std::get<2>(seg) + wire.x;
el.y2 = std::get<3>(seg) + arch->gridDimY - 1. - wire.y;
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(inactive_id, el);
}
}
arch->setWireDecal(wire.name, active, inactive);
return;
}
// clock branches
// # of rows is unknown so generate wire ids at runtime
if (split_res.at(1).substr(0, 3) == "GBO") {
snprintf(buf, sizeof(buf), "%s_active", wire.name.c_str(arch));
active_id = arch->id(buf);
active.decal = active_id;
inactive_id = IdString();
inactive.decal = inactive_id;
active.x = inactive.x = 0;
active.y = inactive.y = 0;
float pip_x = PIP_X(id_GBO0);
float line_y = WIRE_Y(CLK_GBO0_Y) + arch->gridDimY - 1. - wire.y;
float line_0 = WIRE_Y(0) + arch->gridDimY - 1. - wire.y;
if (split_res.at(1).at(3) == '1') {
pip_x = PIP_X(id_GBO1);
line_y = WIRE_Y(CLK_GBO1_Y) + arch->gridDimY - 1. - wire.y;
}
// create if absent
if (arch->decal_graphics.count(active_id) == 0) {
el.type = GraphicElement::TYPE_LINE;
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = wire.x + pip_x;
el.y1 = line_y;
el.x2 = el.x1;
el.y2 = line_0;
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_HIDDEN;
arch->addDecalGraphic(inactive_id, el);
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = pip_x;
el.y1 = line_y;
el.x2 = pip_x + arch->gridDimX - 1.;
el.y2 = el.y1;
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_HIDDEN;
arch->addDecalGraphic(inactive_id, el);
}
arch->setWireDecal(wire.name, active, inactive);
return;
} else {
if (split_res.at(1).substr(0, 2) == "GT") {
snprintf(buf, sizeof(buf), "%s_active", wire.name.c_str(arch));
active_id = arch->id(buf);
active.decal = active_id;
// snprintf(buf, sizeof(buf), "%s_inactive", wire.name.c_str(arch));
// inactive_id = arch->id(buf);
inactive_id = IdString();
inactive.decal = inactive_id;
active.x = inactive.x = 0;
active.y = inactive.y = 0;
float pip_y = PIP_Y(id_GT00);
float line_x = WIRE_X(CLK_GT00_X) + wire.x;
float line_0 = WIRE_X(0) + wire.x;
if (split_res.at(1).at(2) == '1') {
pip_y = PIP_Y(id_GT10);
line_x = WIRE_X(CLK_GT10_X) + wire.x;
}
// create if absent
if (arch->decal_graphics.count(active_id) == 0) {
el.type = GraphicElement::TYPE_LINE;
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = line_x;
el.y1 = pip_y + arch->gridDimY - 1.;
el.x2 = el.x1;
el.y2 = pip_y;
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_HIDDEN;
arch->addDecalGraphic(inactive_id, el);
for (int i = 0; i <= arch->gridDimY - 1; ++i) {
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = line_x;
el.y1 = pip_y + arch->gridDimY - 1. - i;
el.x2 = line_0;
el.y2 = el.y1;
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_HIDDEN;
arch->addDecalGraphic(inactive_id, el);
}
}
arch->setWireDecal(wire.name, active, inactive);
return;
} else {
if (split_res.at(1).substr(0, 2) == "GB") {
snprintf(buf, sizeof(buf), "%s_active", wire.name.c_str(arch));
active_id = arch->id(buf);
active.decal = active_id;
snprintf(buf, sizeof(buf), "%s_inactive", wire.name.c_str(arch));
inactive_id = arch->id(buf);
inactive.decal = inactive_id;
active.x = inactive.x = 0;
active.y = inactive.y = 0;
float line_y = WIRE_Y(CLK_GBO0_Y) + arch->gridDimY - 1. - wire.y;
float line_0 = WIRE_Y(0) + arch->gridDimY - 1. - wire.y;
float pip_x = PIP_X(arch->id(split_res.at(1)));
if (split_res.at(1).at(2) >= '4') {
line_y = WIRE_Y(CLK_GBO1_Y) + arch->gridDimY - 1. - wire.y;
}
// create if absent
if (arch->decal_graphics.count(active_id) == 0) {
el.type = GraphicElement::TYPE_LINE;
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = wire.x + pip_x;
el.y1 = line_y;
el.x2 = el.x1;
el.y2 = line_0;
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(inactive_id, el);
}
arch->setWireDecal(wire.name, active, inactive);
return;
}
}
}
}
// std::cout << wire.name.str(arch) << ":" << wire.type.str(arch) << " R" << wire.y + 1 << "C" << wire.x + 1 <<
// std::endl;
}
void gfxCreateBelDecals(Arch *arch)
{
GraphicElement el;
// LUTs
el.type = GraphicElement::TYPE_BOX;
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = lut_x;
el.x2 = el.x1 + lut_w;
el.y1 = 0.;
el.y2 = el.y1 + lut_h;
arch->addDecalGraphic(id_DECAL_LUT_ACTIVE, el);
arch->addDecalGraphic(id_DECAL_LUTDFF_ACTIVE, el);
arch->addDecalGraphic(id_DECAL_LUT_UNUSED_DFF_ACTIVE, el);
arch->addDecalGraphic(id_DECAL_ALU_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(id_DECAL_LUT_INACTIVE, el);
arch->addDecalGraphic(id_DECAL_LUTDFF_INACTIVE, el);
el.x1 = dff_x;
el.x2 = el.x1 + dff_w;
el.y1 = 0.;
el.y2 = el.y1 + lut_h;
arch->addDecalGraphic(id_DECAL_LUTDFF_INACTIVE, el);
arch->addDecalGraphic(id_DECAL_LUT_UNUSED_DFF_ACTIVE, el);
arch->addDecalGraphic(id_DECAL_ALU_ACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_LUTDFF_ACTIVE, el);
el.type = GraphicElement::TYPE_LOCAL_LINE;
el.x1 = lut_x + 0.33f * lut_w;
el.x2 = el.x1 + 0.33f * lut_w;
el.y1 = 0.66f * lut_h;
el.y2 = el.y1;
arch->addDecalGraphic(id_DECAL_ALU_ACTIVE, el);
el.y1 = 0.3f * lut_h;
el.y2 = el.y1;
arch->addDecalGraphic(id_DECAL_ALU_ACTIVE, el);
el.x1 = lut_x + 0.5f * lut_w;
el.x2 = el.x1;
el.y1 = 0.5f * lut_h;
el.y2 = el.y1 + 0.33f * lut_h;
arch->addDecalGraphic(id_DECAL_ALU_ACTIVE, el);
// LUT group
el.type = GraphicElement::TYPE_BOX;
el.style = GraphicElement::STYLE_FRAME;
el.x1 = grp_lut_x;
el.x2 = el.x1 + grp_lut_w;
el.y1 = 0.;
el.y2 = el.y1 + grp_lut_h;
arch->addDecalGraphic(id_DECAL_GRP_LUT, el);
// CRU group
el.type = GraphicElement::TYPE_BOX;
el.style = GraphicElement::STYLE_FRAME;
el.x1 = cru_x;
el.x2 = el.x1 + cru_w;
el.y1 = cru_y;
el.y2 = el.y1 + cru_h;
arch->addDecalGraphic(id_DECAL_CRU, el);
// Mux with upper 1 input
el.type = GraphicElement::TYPE_LINE;
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = 0.;
el.x2 = mux_w;
el.y1 = 0.;
el.y2 = mux_f;
arch->addDecalGraphic(id_DECAL_MUXUPPER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXUPPER_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = el.x2;
el.y1 = el.y2;
el.y2 = mux_h - mux_f;
arch->addDecalGraphic(id_DECAL_MUXUPPER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXUPPER_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x2 = 0.;
el.y1 = el.y2;
el.y2 = mux_h;
arch->addDecalGraphic(id_DECAL_MUXUPPER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXUPPER_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = el.x2;
el.y1 = mux_h;
el.y2 = 0.;
arch->addDecalGraphic(id_DECAL_MUXUPPER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXUPPER_ACTIVE, el);
// 1
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = 0.0038;
el.x2 = 0.0118;
el.y1 = el.y2 = 0.0598;
arch->addDecalGraphic(id_DECAL_MUXUPPER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXUPPER_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = (el.x1 + el.x2) / 2.;
el.x2 = el.x1;
el.y2 = 0.0808;
arch->addDecalGraphic(id_DECAL_MUXUPPER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXUPPER_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x2 = 0.0038;
el.y1 = el.y2;
el.y2 = 0.0797;
arch->addDecalGraphic(id_DECAL_MUXUPPER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXUPPER_ACTIVE, el);
// Mux with lower 1 input
el.type = GraphicElement::TYPE_LINE;
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = 0.;
el.x2 = mux_w;
el.y1 = 0.;
el.y2 = mux_f;
arch->addDecalGraphic(id_DECAL_MUXLOWER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXLOWER_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = el.x2;
el.y1 = el.y2;
el.y2 = mux_h - mux_f;
arch->addDecalGraphic(id_DECAL_MUXLOWER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXLOWER_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x2 = 0.;
el.y1 = el.y2;
el.y2 = mux_h;
arch->addDecalGraphic(id_DECAL_MUXLOWER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXLOWER_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = el.x2;
el.y1 = mux_h;
el.y2 = 0.;
arch->addDecalGraphic(id_DECAL_MUXLOWER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXLOWER_ACTIVE, el);
// 1
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = 0.0038;
el.x2 = 0.0118;
el.y1 = el.y2 = 0.0140;
arch->addDecalGraphic(id_DECAL_MUXLOWER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXLOWER_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = (el.x1 + el.x2) / 2.;
el.x2 = el.x1;
el.y2 = 0.0352;
arch->addDecalGraphic(id_DECAL_MUXLOWER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXLOWER_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x2 = 0.0038;
el.y1 = el.y2;
el.y2 = 0.0341;
arch->addDecalGraphic(id_DECAL_MUXLOWER_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_MUXLOWER_ACTIVE, el);
// IOB
el.type = GraphicElement::TYPE_LINE;
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = 0.;
el.x2 = io_w;
el.y1 = 0.;
el.y2 = el.y1;
arch->addDecalGraphic(id_DECAL_IOB_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_IOB_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = el.x2;
el.y2 = io_h;
arch->addDecalGraphic(id_DECAL_IOB_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_IOB_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = 0.;
el.y1 = el.y2;
arch->addDecalGraphic(id_DECAL_IOB_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_IOB_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x2 = el.x1;
el.y2 = 0.;
arch->addDecalGraphic(id_DECAL_IOB_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_IOB_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = io_w;
el.x2 = io_w * 1.3f;
el.y2 = el.y1 = io_h / 2.f;
arch->addDecalGraphic(id_DECAL_IOB_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_IOB_ACTIVE, el);
// IOBS
el.type = GraphicElement::TYPE_LINE;
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = 0.;
el.x2 = ios_w;
el.y1 = 0.;
el.y2 = el.y1;
arch->addDecalGraphic(id_DECAL_IOBS_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_IOBS_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = el.x2;
el.y2 = ios_h;
arch->addDecalGraphic(id_DECAL_IOBS_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_IOBS_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = 0.;
el.y1 = el.y2;
arch->addDecalGraphic(id_DECAL_IOBS_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_IOBS_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x2 = el.x1;
el.y2 = 0.;
arch->addDecalGraphic(id_DECAL_IOBS_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_IOBS_ACTIVE, el);
el.style = GraphicElement::STYLE_INACTIVE;
el.x1 = ios_w;
el.x2 = ios_w * 1.3f;
el.y2 = el.y1 = ios_h / 2.f;
arch->addDecalGraphic(id_DECAL_IOBS_INACTIVE, el);
el.style = GraphicElement::STYLE_ACTIVE;
arch->addDecalGraphic(id_DECAL_IOBS_ACTIVE, el);
}
void gfxSetBelDefaultDecal(Arch *arch, BelInfo &bel)
{
DecalXY active, inactive;
switch (bel.type.hash()) {
case ID_SLICE:
active.x = inactive.x = bel.x;
active.y = inactive.y = arch->gridDimY - 1. - bel.y + lut_y[bel.z];
if (bel.z < 6) {
active.decal = id_DECAL_LUTDFF_ACTIVE;
inactive.decal = id_DECAL_LUTDFF_INACTIVE;
} else {
active.decal = id_DECAL_LUT_ACTIVE;
inactive.decal = id_DECAL_LUT_INACTIVE;
}
arch->setBelDecal(bel.name, active, inactive);
break;
case ID_GW_MUX2_LUT5:
active.x = inactive.x = bel.x + mux2lut5_x;
active.y = inactive.y = arch->gridDimY - 1. - bel.y + mux2lut5_y[(bel.z - arch->mux_0_z) >> 1];
active.decal = id_DECAL_MUXUPPER_ACTIVE;
inactive.decal = id_DECAL_MUXUPPER_INACTIVE;
arch->setBelDecal(bel.name, active, inactive);
break;
case ID_GW_MUX2_LUT6:
active.x = inactive.x = bel.x + mux2lut6_x;
active.y = inactive.y = arch->gridDimY - 1. - bel.y + mux2lut6_y[(bel.z - arch->mux_0_z) / 5];
active.decal = id_DECAL_MUXLOWER_ACTIVE;
inactive.decal = id_DECAL_MUXLOWER_INACTIVE;
arch->setBelDecal(bel.name, active, inactive);
break;
case ID_GW_MUX2_LUT7:
active.x = inactive.x = bel.x + mux2lut7_x;
active.y = inactive.y = arch->gridDimY - 1. - bel.y + mux2lut7_y;
active.decal = id_DECAL_MUXLOWER_ACTIVE;
inactive.decal = id_DECAL_MUXLOWER_INACTIVE;
arch->setBelDecal(bel.name, active, inactive);
break;
case ID_GW_MUX2_LUT8:
active.x = inactive.x = bel.x + mux2lut8_x;
active.y = inactive.y = arch->gridDimY - 1. - bel.y + mux2lut8_y;
active.decal = id_DECAL_MUXUPPER_ACTIVE;
inactive.decal = id_DECAL_MUXUPPER_INACTIVE;
arch->setBelDecal(bel.name, active, inactive);
break;
case ID_IOB:
active.x = inactive.x = bel.x + io_x;
active.y = inactive.y = arch->gridDimY - 1. - bel.y + io_y + bel.z * (2 * io_gap + io_h);
active.decal = id_DECAL_IOB_ACTIVE;
inactive.decal = id_DECAL_IOB_INACTIVE;
arch->setBelDecal(bel.name, active, inactive);
gfxSetIOBWireDecals(arch, bel);
break;
case ID_IOBS:
active.x = inactive.x = bel.x + ios_x + (ios_w + ios_gap_x) * (bel.z % 3);
active.y = inactive.y = arch->gridDimY - 1. - bel.y + ios_y + (ios_h + ios_gap_y) * (bel.z / 3);
active.decal = id_DECAL_IOBS_ACTIVE;
inactive.decal = id_DECAL_IOBS_INACTIVE;
arch->setBelDecal(bel.name, active, inactive);
gfxSetIOBSWireDecals(arch, bel);
break;
default:
break;
}
}
void gfxSetIOBWireDecals(Arch *arch, BelInfo &bel)
{
DecalXY active, inactive;
GraphicElement el;
char buf[20];
// set decals for I, O and OE input wires
for (auto pi : bel.pins) {
WireInfo &wi = arch->wire_info(pi.second.wire);
// decal name: wire_port_z_active|inactive
snprintf(buf, sizeof(buf), "%s_%s_%u_active", wi.type.c_str(arch), pi.first.c_str(arch), bel.z);
IdString active_id = arch->id(buf);
active.decal = active_id;
snprintf(buf, sizeof(buf), "%s_%s_%u_inactive", wi.type.c_str(arch), pi.first.c_str(arch), bel.z);
IdString inactive_id = arch->id(buf);
inactive.decal = inactive_id;
active.x = inactive.x = bel.x;
active.y = inactive.y = arch->gridDimY - 1. - bel.y;
if (arch->decal_graphics.count(active_id) == 0) {
el.type = GraphicElement::TYPE_LOCAL_LINE;
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = cru_x + cru_w;
el.y1 = pipPoint.at(wi.type).second;
el.x2 = io_x;
el.y2 = portPoint.at(pi.first) + io_y + bel.z * (2 * io_gap + io_h);
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(inactive_id, el);
for (auto seg : portSign.at(pi.first)) {
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = std::get<0>(seg) + io_x;
el.y1 = std::get<1>(seg) + io_y + bel.z * (2 * io_gap + io_h);
el.x2 = std::get<2>(seg) + io_x;
el.y2 = std::get<3>(seg) + io_y + bel.z * (2 * io_gap + io_h);
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(inactive_id, el);
}
}
arch->setWireDecal(wi.name, active, inactive);
}
}
void gfxSetIOBSWireDecals(Arch *arch, BelInfo &bel)
{
DecalXY active, inactive;
GraphicElement el;
char buf[20];
// set decals for I, O and OE input wires
for (auto pi : bel.pins) {
WireInfo &wi = arch->wire_info(pi.second.wire);
// decal name: ios_wire_port_z_active|inactive
snprintf(buf, sizeof(buf), "ios_%s_%s_%u_active", wi.type.c_str(arch), pi.first.c_str(arch), bel.z);
IdString active_id = arch->id(buf);
active.decal = active_id;
snprintf(buf, sizeof(buf), "ios_%s_%s_%u_inactive", wi.type.c_str(arch), pi.first.c_str(arch), bel.z);
IdString inactive_id = arch->id(buf);
inactive.decal = inactive_id;
active.x = inactive.x = bel.x;
active.y = inactive.y = arch->gridDimY - 1. - bel.y;
if (arch->decal_graphics.count(active_id) == 0) {
// leftmost wires
el.type = GraphicElement::TYPE_LOCAL_LINE;
if (bel.z % 3 == 0) {
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = cru_x + cru_w;
el.y1 = pipPoint.at(wi.type).second;
el.x2 = ios_x;
el.y2 = ios_scl * portPoint.at(pi.first) + ios_y + (ios_h + ios_gap_y) * (bel.z / 3);
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(inactive_id, el);
} else {
float col = (bel.z % 3) - 1;
float rel_port = portPoint.at(pi.first) / io_h;
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = cru_x + cru_w;
el.y1 = pipPoint.at(wi.type).second;
el.x2 = ios_x * (0.97 - 0.02 * col);
el.y2 = (rel_port + col) * 0.5 * ios_gap_y + ios_y + ios_h + (ios_h + ios_gap_y) * (bel.z / 3);
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(inactive_id, el);
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = ios_x + (ios_w + ios_gap_x) * (col + 1) - ios_gap_x + ios_w * 0.3 +
rel_port * (ios_gap_x - 0.3 * ios_w);
el.y1 = el.y2;
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(inactive_id, el);
el.style = GraphicElement::STYLE_ACTIVE;
el.x2 = el.x1;
el.y2 = ios_scl * portPoint.at(pi.first) + ios_y + (ios_h + ios_gap_y) * (bel.z / 3);
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(inactive_id, el);
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = ios_x + (ios_w + ios_gap_x) * (col + 1);
el.y1 = el.y2;
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(inactive_id, el);
el.style = GraphicElement::STYLE_ACTIVE;
}
// signs
for (auto seg : portSign.at(pi.first)) {
el.style = GraphicElement::STYLE_ACTIVE;
el.x1 = ios_scl * std::get<0>(seg) + ios_x + (ios_w + ios_gap_x) * (bel.z % 3);
el.y1 = ios_scl * std::get<1>(seg) + ios_y + (ios_h + ios_gap_y) * (bel.z / 3);
el.x2 = ios_scl * std::get<2>(seg) + ios_x + (ios_w + ios_gap_x) * (bel.z % 3);
el.y2 = ios_scl * std::get<3>(seg) + ios_y + (ios_h + ios_gap_y) * (bel.z / 3);
arch->addDecalGraphic(active_id, el);
el.style = GraphicElement::STYLE_INACTIVE;
arch->addDecalGraphic(inactive_id, el);
}
}
arch->setWireDecal(wi.name, active, inactive);
}
}
DecalXY gfxGetLutGroupDecalXY(int x, int y, int z)
{
DecalXY decalxy;
decalxy.decal = id_DECAL_GRP_LUT;
decalxy.x = x;
decalxy.y = y + grp_lut_y[z];
return decalxy;
}
DecalXY gfxGetCruGroupDecalXY(int x, int y)
{
DecalXY decalxy;
decalxy.decal = id_DECAL_CRU;
decalxy.x = x;
decalxy.y = y;
return decalxy;
}
NEXTPNR_NAMESPACE_END